Support for bzip compressed modules
RFC 1/1 Support for bzip compressed modules
There was some discussion about bzip compressing policy modules (actually policy packages). The attached patch implements this. The patch is not ready for merging - I'm trying to get feedback since there was opposition to this approach when proposed. This patch should probably wait until after a stable branch is created.
The patch implements this support by changing sepol_policy_file_t to support decompressing files or memory areas into a private memory copy. This support is optional - dlopen is used so that a hard dependency to libbz2 is not introduced. I took the approach of decompressing the entire file or memory area because:
* It is very simple
* The current code depends on the ability to seek within policy files - this is not really possible within compressed streams using the bzip2 library.
The downsides are:
* Increased memory usage
* No transparent support for compressed writing with an fd based policy file.
I didn't want to add additional set functions - I would have preferred to allow sepol_policy_file_set_[mem,fd] to transparently open compressed streams with functions to set other behaviors as options stored in sepol_policy_file_t structs. This was not possible becuase the current set functions do not return errors.
Comments appreciated. Some very crude benchmarking below (note that I am using a patched semodule to allow the globbing syntax - patch for that to follow). The summary is that there is substantial space savings at the expense of some increase in time to complete common actions. An acceptable trade-off in my opinion.
Anyone have suggestions for something as simple as time but for max memory usage?
Karl
Uncompressed
------------
[root@localhost modules]# time semodule -b /usr/share/selinux/strict/base.pp
real 0m15.849s user 0m14.791s sys 0m0.930s
[root@localhost nobz-modules]# time semodule -i *.pp
real 0m15.447s user 0m14.287s sys 0m0.997s
[root@localhost modules]# time semodule -l
real 0m0.153s user 0m0.133s sys 0m0.017s
[root@localhost modules]# du -h
17M ./active/modules 22M ./active 22M .
Compressed
----------
[root@localhost modules]# time semodule -b /root/base.pp.bz2
real 0m16.117s user 0m14.729s sys 0m1.022s
[root@localhost modules]# time semodule -i /root/modules/*.bz2
real 0m18.529s user 0m17.110s sys 0m1.314s
[root@localhost modules]# time semodule -l
real 0m0.851s user 0m0.750s sys 0m0.098s
[root@localhost modules]# du -h
2.0M ./active/modules 4.9M ./active 4.9M .
libsemanage/src/direct_api.c +25 -8
@@ -307,7 +307,15 @@ static int parse_module_headers(semanageERR (sh,"Out of memory!" );return -1 ; } -sepol_policy_file_set_mem (pf, module_data, data_len); +/* We have to assume that this might be a compressed stream, +* so first try to treat this as a bz2 stream. If that fails +* assume that it is not compressed. The bad part of this is +* that it will use at least twice the memory of the original +* data. */ +if (sepol_policy_file_set_mem_bz2 (pf, module_data, data_len,1 ) <0 ) { +sepol_policy_file_set_mem (pf, module_data, data_len); + } +sepol_policy_file_set_handle (pf, sh->sepolh); if (module_data == NULL || data_len == 0 ||
@@ -352,7 +360,13 @@ static int parse_base_headers(semanage_hERR (sh,"Out of memory!" );return -1 ; } -sepol_policy_file_set_mem (pf, module_data, data_len); +/* We have to assume that this might be a compressed stream, +* so first try to treat this as a bz2 stream. If that fails +* assume that it is not compressed. The bad part of this is +* that it will use at least twice the memory of the original +* data. */ +if (sepol_policy_file_set_mem_bz2 (pf, module_data, data_len,1 ) <0 ) +sepol_policy_file_set_mem (pf, module_data, data_len);sepol_policy_file_set_handle (pf, sh->sepolh); if (module_data == NULL || data_len == 0 ||
@@ -915,16 +929,16 @@ static int semanage_direct_list(semanage goto cleanup; } +if ((*modinfo =calloc (num_mod_files,sizeof (**modinfo))) ==NULL ) { +ERR (sh,"Out of memory!" ); + goto cleanup; + } +if (sepol_policy_file_create (&pf)) {ERR (sh,"Out of memory!" ); goto cleanup; }sepol_policy_file_set_handle (pf, sh->sepolh); - -if ((*modinfo =calloc (num_mod_files,sizeof (**modinfo))) ==NULL ) { -ERR (sh,"Out of memory!" ); - goto cleanup; - }for (i =0 ; i < num_mod_files; i++) {FILE *fp;
@@ -936,7 +950,10 @@ static int semanage_direct_list(semanagecontinue ; }__fsetlocking (fp,FSETLOCKING_BYCALLER ); -sepol_policy_file_set_fp (pf, fp); +if (sepol_policy_file_set_fp_bz2 (pf, fp,1 ) <0 ) { +sepol_policy_file_set_fp (pf, fp); + } +if (sepol_module_package_info (pf, &type, &name, &version)) {fclose (fp);free (name);
libsemanage/src/semanage_store.c +7 -1
@@ -1490,7 +1490,13 @@ static int semanage_load_module(semanage goto cleanup; }__fsetlocking (fp,FSETLOCKING_BYCALLER ); -sepol_policy_file_set_fp (pf, fp); +/* Try to set this as a bzip2 compressed file first. If this +* fails it means that the file is not compressed, so fall back +* to normal reading. +*/ +if (sepol_policy_file_set_fp_bz2 (pf, fp,1 ) <0 ) { +sepol_policy_file_set_fp (pf, fp); + }sepol_policy_file_set_handle (pf, sh->sepolh);if (sepol_module_package_read (*package, pf,0 ) ==-1 ) {ERR (sh,"Error while reading from module file %s." , filename);
libsepol/include/sepol/policydb.h +6 -0
@@ -29,6 +29,9 @@ extern void sepol_policy_file_set_mem(seextern void sepol_policy_file_set_mem (sepol_policy_file_t * pf,char *data,size_t len); +extern int sepol_policy_file_set_mem_bz2 (sepol_policy_file_t * pf,char *data, +size_t len,int check); +/* * Get the size of the buffer needed to store a policydb write * previously done on this policy file.
@@ -41,6 +44,9 @@ extern int sepol_policy_file_get_len(sep* to the FILE. */ extern void sepol_policy_file_set_fp (sepol_policy_file_t * pf,FILE * fp); + +extern int sepol_policy_file_set_fp_bz2 (sepol_policy_file_t * pf,FILE * fp, +int check);/* * Associate a handle with a policy file, for use in
libsepol/include/sepol/policydb/policydb.h +1 -0
@@ -562,6 +562,7 @@ typedef struct policy_file {struct sepol_policy_file {struct policy_file pf; +char *orig_data;/* if set, will be freed by sepol_policy_file_free */ }; extern int policydb_read(policydb_t * p, struct policy_file *fp,
libsepol/src/Makefile +1 -1
@@ -20,7 +20,7 @@ all: $(LIBA) $(LIBSO) ranlib $@ $(LIBSO): $(LOBJS) - $(CC) $(LDFLAGS) -shared -o $@ $^ -Wl,-soname,$(LIBSO),--version-script=libsepol.map,-z,defs + $(CC) $(LDFLAGS) -shared -o $@ $^ -Wl,-soname,$(LIBSO),--version-script=libsepol.map,-z,defs -ldl ln -sf $@ $(TARGET) %.o: %.c
libsepol/src/policydb_public.c +253 -1
287 lines not on this page · raw message
policycoreutils/semodule_deps/Makefile +1 -1
@@ -7,7 +7,7 @@ MANDIR ?= $(PREFIX)/share/man CFLAGS ?= -Werror -Wall -W override CFLAGS += -I$(INCLUDEDIR) -LDLIBS = $(LIBDIR)/libsepol.a +LDLIBS = $(LIBDIR)/libsepol.a -ldl all: semodule_deps
Quoted 5 lines · Karl MacMillan
The patch implements this support by changing
sepol_policy_file_tto support decompressing files or memory areas into a private memory copy. This support is optional - dlopen is used so that a hard dependency to libbz2 is not introduced. I took the approach of decompressing the entire file or memory area because:
Why don't we want to depend on libbz, if we are building with bz2
support?
Quoted 11 lines
* It is very simple
* The current code depends on the ability to seek within policy files - this is not really possible within compressed streams using the bzip2 library.The downsides are:
* Increased memory usage
* No transparent support for compressed writing with an fd based policy file.
Quoted 5 lines
I didn't want to add additional set functions - I would have preferred to allow sepol_policy_file_set_[mem,fd] to transparently open compressed streams with functions to set other behaviors as options stored in
sepol_policy_file_tstructs. This was not possible becuase the current set functions do not return errors.
Do we really care about the memory usage, my instinct would be to drop
the FILE specific code and just dump everything into memory and then call the mem_set function and thus. have only one decompression loop (adding the fd version is simple then too).
Calling fstat(fileno(fp)) to read the policy in is probably easier than
a loop.
Quoted 8 lines
Comments appreciated. Some very crude benchmarking below (note that I am using a patched semodule to allow the globbing syntax - patch for that to follow). The summary is that there is substantial space savings at the expense of some increase in time to complete common actions. An acceptable trade-off in my opinion.
Anyone have suggestions for something as simple as time but for max memory usage?
There's memusage in glibc-utils.
---- code ----
The bz2 code looks fine, although the += BUFSIZE in one loop and *= 2
in the other is weird, and there's a couple of minor nits in the interface:
. check is always true in callers, and I'm not sure why you'd have it zero.
. All code paths have:
if (set_foo_bz2() == FAILED)
set_foo();
...which tells me set_foo_bz2() should do that ... in fact it seems sane to just change set_foo() to check of bz2ness and do the right thing, without having to alter the callers.
. A personal minor nit is that free(NULL) works fine, so don't work around it (this idiom seems to be used in sepol).
. sepol_policy_file_free_data() is also called multiple times at the end of the set_foo_bz2() functions (once inside set_foo() and then explicitly immediately after).
I assume the only reason you went with bzip2 over gzip is the "have to
init yourself in the set_mem case"? I've done that before[1], so I can help you get that bit done if you want ... this will drop CPU/memory/dependency requirements (although expecting all Linux to have libbz now isn't a big deal, IMO).
[1] http://www.and.org/vstr/examples/ex_zcat.c
Signature · 1 line
James Antill <[email protected]>
Quoted 7 lines · James Antill
Quoted 1 line · Karl MacMillan
The patch implements this support by changing
sepol_policy_file_tto support decompressing files or memory areas into a private memory copy. This support is optional - dlopen is used so that a hard dependency to libbz2 is not introduced. I took the approach of decompressing the entire file or memory area because:Why don't we want to depend on libbz, if we are building with bz2
support?
This allows the same binary to be installed with or without libbz2. Since libsepol gets pulled into so many installs, it seems preferable to not add additional dependencies.
On the other hand, I don't have a strong preference about that part of the patch. If libbz2 is deemed sufficiently available (or even libz I guess) we can just directly link. Perhaps with compile time options.
Quoted 8 lines
Quoted 8 lines
* It is very simple
* The current code depends on the ability to seek within policy files - this is not really possible within compressed streams using the bzip2 library.The downsides are:
* Increased memory usage
* No transparent support for compressed writing with an fd based policy file.
Quoted 9 lines
Quoted 1 line
I didn't want to add additional set functions - I would have preferred to allow sepol_policy_file_set_[mem,fd] to transparently open compressed streams with functions to set other behaviors as options stored in
sepol_policy_file_tstructs. This was not possible becuase the current set functions do not return errors.Do we really care about the memory usage, my instinct would be to drop
the FILE specific code and just dump everything into memory and then call themem_setfunction and thus. have only one decompression loop (adding the fd version is simple then too).
Calling fstat(fileno(fp)) to read the policy in is probably easier than
a loop.
Not certain what you are getting at - both code paths result in an uncompressed copy of the compressed data in memory. The only difference is whether we are decompressing from an fd or from another memory buffer.
Quoted 6 lines
Quoted 3 lines
Comments appreciated. Some very crude benchmarking below (note that I am using a patched semodule to allow the globbing syntax - patch for that to follow). The summary is that there is substantial space savings at the expense of some increase in time to complete common actions. An acceptable trade-off in my opinion.
Anyone have suggestions for something as simple as time but for max memory usage?
There's memusage in glibc-utils.
Thanks
Quoted 6 lines
---- code ----
The bz2 code looks fine, although the += BUFSIZE in one loop and *= 2
in the other is weird, and there's a couple of minor nits in the interface:
If you look at the loop with *= 2, we are just guessing buffer size so I want to grow the buffer much more quickly if the decompression fails. We start with a 2-1 compression ratio, then try 4-1, etc. If we only adding BUFSIZ then we might loop for a long time growing the buffer.
Quoted 3 lines
. check is always true in callers, and I'm not sure why you'd have it zero.
The magic number checking seems fragile - I'm assuming it might be necessary to force the stream as compressed at some point. Since we are maintaining ABI for this library (and these functions), seems better to be safe.
Quoted 9 lines
. All code paths have:
if (
set_foo_bz2()== FAILED)
set_foo();...which tells me
set_foo_bz2()should do that ... in fact it seems sane to just changeset_foo()to check of bz2ness and do the right thing, without having to alter the callers.
Note my comments with the original patch - this isn't possible because set_foo() has a void return and we want to maintain binary compatibility.
Quoted 3 lines
. A personal minor nit is that free(NULL) works fine, so don't work around it (this idiom seems to be used in sepol).
I don't that I see - maybe you mean:
+ if (pf && pf->orig_data) {
+ free(pf->orig_data);
+ pf->orig_data = NULL;
+ }
This is to allow this function to be called with a null pf - so I have to check before looking in the struct.
Quoted 4 lines
.
sepol_policy_file_free_data()is also called multiple times at the end of theset_foo_bz2()functions (once insideset_foo()and then explicitly immediately after).
Good catch - thanks.
Quoted 3 lines
I assume the only reason you went with bzip2 over gzip is the "have to
init yourself in theset_memcase"?
No - just better compression.
[kmacmill@localhost ~]$ ls -l base.pp.*
-rw-r--r-- 1 kmacmill kmacmill 86379 Jan 9 10:50 base.pp.bz2 -rw-r--r-- 1 kmacmill kmacmill 167382 Jan 9 10:50 base.pp.gz
I've done that before[1], so I can
Quoted 4 lines
help you get that bit done if you want ... this will drop CPU/memory/dependency requirements (although expecting all Linux to have libbz now isn't a big deal, IMO).
Ok - I'd be happy to support both if you want to send a patch.
Thanks - Karl
--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 13 lines · Karl MacMillan
Quoted 11 lines · James Antill
Quoted 5 lines · Karl MacMillan
The patch implements this support by changing
sepol_policy_file_tto support decompressing files or memory areas into a private memory copy. This support is optional - dlopen is used so that a hard dependency to libbz2 is not introduced. I took the approach of decompressing the entire file or memory area because:Why don't we want to depend on libbz, if we are building with bz2
support?
Quoted 7 lines
This allows the same binary to be installed with or without libbz2. Since libsepol gets pulled into so many installs, it seems preferable to not add additional dependencies.
On the other hand, I don't have a strong preference about that part of the patch. If libbz2 is deemed sufficiently available (or even libz I guess) we can just directly link. Perhaps with compile time options.
/sbin/init depends on libsepol, so if libsepol were to have a fixed dependency on libbz2, then you might have a problem there (looks like libbz2.so.1 lives in /usr/lib in Fedora, not in /lib, so it might not even be available if /usr is a separate partition).
Signature · 8 lines
Stephen Smalley National Security Agency -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 17 lines · Karl MacMillan
Quoted 8 lines · James Antill
Quoted 5 lines · Karl MacMillan
I didn't want to add additional set functions - I would have preferred to allow sepol_policy_file_set_[mem,fd] to transparently open compressed streams with functions to set other behaviors as options stored in
sepol_policy_file_tstructs. This was not possible becuase the current set functions do not return errors.Quoted 7 lines
Do we really care about the memory usage, my instinct would be to drop
the FILE specific code and just dump everything into memory and then call themem_setfunction and thus. have only one decompression loop (adding the fd version is simple then too).
Calling fstat(fileno(fp)) to read the policy in is probably easier than
a loop.
Quoted 3 lines
Not certain what you are getting at - both code paths result in an uncompressed copy of the compressed data in memory. The only difference is whether we are decompressing from an fd or from another memory buffer.
Just that it seems easier to have the set_fp() function load all the
data into memory and call the set_mem() function, and have all of the bz2 stuff in just the set_mem() function.
Quoted 8 lines
Quoted 3 lines
. check is always true in callers, and I'm not sure why you'd have it zero.
The magic number checking seems fragile - I'm assuming it might be necessary to force the stream as compressed at some point. Since we are maintaining ABI for this library (and these functions), seems better to be safe.
Do policy files not have a magic value, then? You can also (for bz2)
check that the next value is between 1 and 9 (it's the compression ratio).
I assume this means you'd rely on anything ending in ".bz2" being
compressed, and not otherwise ... do we always have a filename?
Quoted 5 lines
Quoted 5 lines
. All code paths have:
if (
set_foo_bz2()== FAILED)
set_foo();
Quoted 7 lines
Quoted 4 lines
...which tells me
set_foo_bz2()should do that ... in fact it seems sane to just changeset_foo()to check of bz2ness and do the right thing, without having to alter the callers.Note my comments with the original patch - this isn't possible because
set_foo()has a void return and we want to maintain binary compatibility.
Right, but as I said the error paths always just try again without
compression ... so why not just try the compression at the start of the set_foo() code. You get the same behaviour.
Review
Quoted 8 lines
Quoted 2 lines
I assume the only reason you went with bzip2 over gzip is the "have to
init yourself in theset_memcase"?No - just better compression.
[kmacmill@localhost ~]$ ls -l base.pp.*
(quoted diff) +0
-2-rw-r--r-- 1 kmacmill kmacmill 86379 Jan 9 10:50 base.pp.bz2 -rw-r--r-- 1 kmacmill kmacmill 167382 Jan 9 10:50 base.pp.gz
Wow ... that's better than usual. Do you have the same difference for
smaller modules?
Signature · 1 line
James Antill <[email protected]>
Quoted 18 lines · James Antill
Quoted 17 lines · Karl MacMillan
Quoted 15 lines · James Antill
Quoted 5 lines · Karl MacMillan
I didn't want to add additional set functions - I would have preferred to allow sepol_policy_file_set_[mem,fd] to transparently open compressed streams with functions to set other behaviors as options stored in
sepol_policy_file_tstructs. This was not possible becuase the current set functions do not return errors.Do we really care about the memory usage, my instinct would be to drop
the FILE specific code and just dump everything into memory and then call themem_setfunction and thus. have only one decompression loop (adding the fd version is simple then too).
Calling fstat(fileno(fp)) to read the policy in is probably easier than
a loop.
Quoted 8 lines
Quoted 3 lines
Not certain what you are getting at - both code paths result in an uncompressed copy of the compressed data in memory. The only difference is whether we are decompressing from an fd or from another memory buffer.
Just that it seems easier to have the
set_fp()function load all the
data into memory and call theset_mem()function, and have all of the bz2 stuff in just theset_mem()function.
Ah - I see. I prefer the separate decompression paths because the mem case is potentially very inefficient. No strong preference though.
Quoted 10 lines
Quoted 8 lines
Quoted 3 lines
. check is always true in callers, and I'm not sure why you'd have it zero.
The magic number checking seems fragile - I'm assuming it might be necessary to force the stream as compressed at some point. Since we are maintaining ABI for this library (and these functions), seems better to be safe.
Do policy files not have a magic value, then?
They do, but there is no real restriction that these policy file things get used for files containing policy. Currently they are used for a variety of file types and I would hate to hard code a list valid file types into this function.
Quoted 3 lines
You can also (for bz2)
check that the next value is between 1 and 9 (it's the compression ratio).
Ok. Could this be used for sizing the buffer in the memory case? In other words, is it a user setting that was passed to bzip or information about the result of the compression?
Quoted 3 lines
I assume this means you'd rely on anything ending in ".bz2" being
compressed, and not otherwise ... do we always have a filename?
No, and in fact we explicitly rename the policy modules in the store to whatever name is set within the policy. So if you create a module name foo saved in the file bar.pp.bz2, after 'semodule -i bar.pp.bz2' there will be a file called foo.pp in the module store. I didn't change that behavior, so file extension is not useful here.
Quoted 10 lines
Quoted 10 lines
Quoted 9 lines
. All code paths have:
if (
set_foo_bz2()== FAILED)
set_foo();...which tells me
set_foo_bz2()should do that ... in fact it seems sane to just changeset_foo()to check of bz2ness and do the right thing, without having to alter the callers.
Quoted 7 lines
Quoted 2 lines
Note my comments with the original patch - this isn't possible because
set_foo()has a void return and we want to maintain binary compatibility.Right, but as I said the error paths always just try again without
compression ... so why not just try the compression at the start of theset_foo()code. You get the same behaviour.
It is not about returning information about the compression. It is because the compression routines have other error paths (failure to load libbz2, memory allocation, etc.). There is no good way to indicate those errors without changing the prototypes. Even if we didn't change the prototypes, it is valid to not check the current functions for error, so we can't change them in any way that has potential error paths.
Quoted 12 lines
Review
Quoted 8 lines
Quoted 2 lines
I assume the only reason you went with bzip2 over gzip is the "have to
init yourself in theset_memcase"?No - just better compression.
[kmacmill@localhost ~]$ ls -l base.pp.*
(quoted diff) +0
-2-rw-r--r-- 1 kmacmill kmacmill 86379 Jan 9 10:50 base.pp.bz2 -rw-r--r-- 1 kmacmill kmacmill 167382 Jan 9 10:50 base.pp.gzWow ... that's better than usual. Do you have the same difference for
smaller modules?
[kmacmill@localhost ~]$ ls -l alsa.pp*
-rw-r--r-- 1 kmacmill kmacmill 41720 Jan 9 16:13 alsa.pp -rw-r--r-- 1 kmacmill kmacmill 4987 Jan 9 16:13 alsa.pp.bz2 -rw-r--r-- 1 kmacmill kmacmill 5145 Jan 9 16:13 alsa.pp.gz
[kmacmill@localhost ~]$ ls -l apache.pp*
-rw-r--r-- 1 kmacmill kmacmill 416123 Jan 9 16:14 apache.pp -rw-r--r-- 1 kmacmill kmacmill 15800 Jan 9 16:14 apache.pp.bz2 -rw-r--r-- 1 kmacmill kmacmill 26585 Jan 9 16:14 apache.pp.gz
Not quite as dramatic always, but still a significant difference.
Karl
--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 7 lines · Karl MacMillan
Quoted 1 line · James Antill
Do policy files not have a magic value, then?
They do, but there is no real restriction that these policy file things get used for files containing policy. Currently they are used for a variety of file types and I would hate to hard code a list valid file types into this function.
I don't think I'm intelligent enough to understand this sentence :).
What I meant was if they have magic values, they'll never clash so it's always ok to do the check, no?
Or in the other direction, if you can't differentiate on magic value or
the filename how can any piece of code tell whether it should decompress it or treat it as raw data?
Quoted 5 lines
Quoted 3 lines
You can also (for bz2)
check that the next value is between 1 and 9 (it's the compression ratio).Ok. Could this be used for sizing the buffer in the memory case?
No, it's just the "how hard did you want to try" value. So something
compressed with "bzip2 -1" will have a '1' and likewise "bzip2 -9" will have a '9' after the magic.
Quoted 11 lines
Quoted 4 lines
Right, but as I said the error paths always just try again without
compression ... so why not just try the compression at the start of theset_foo()code. You get the same behaviour.It is not about returning information about the compression. It is because the compression routines have other error paths (failure to load libbz2, memory allocation, etc.). There is no good way to indicate those errors without changing the prototypes. Even if we didn't change the prototypes, it is valid to not check the current functions for error, so we can't change them in any way that has potential error paths.
Yes, I know that ... but there isn't a difference in the return value
between "bz2_init() failed" and "is_bz2_file() returned NO". So all the callers just assume the later for all errors, if that's the case we might as well combine it back into set_foo().
Signature · 4 lines
James Antill - <[email protected]> setsockopt(fd, IPPROTO_TCP, TCP_CONGESTION, ...); setsockopt(fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, ...); setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, ...);
Quoted 5 lines · James Antill
I assume the only reason you went with bzip2 over gzip is the "have to init yourself in the
set_memcase"? I've done that before[1], so I can help you get that bit done if you want ... this will drop CPU/memory/dependency requirements (although expecting all Linux to have libbz now isn't a big deal, IMO).
Given that the vast majority of new machines now are AMD64 part of the CPU requirement will be due to bzip2 and gzip not being optimised for AMD64. gzip has i386 assembler optimisation but no AMD64 assembler and runs more slowly on AMD64 because of it (my tests show that on RHEL4 the i386 copy of gzip outperforms the AMD64 version on Opteron machines).
If you compare the AMD64 compiled version of gzip (IE the library) with bzip2 the difference in CPU time is a lot smaller than it is when comparing the i386 versions.
Of course it probably wouldn't be difficult for someone to write some AMD64 assembler code for gzip or bzip2 to change things.
In regard to the following, I think that the 15 seconds for uncompressed operation is the problem not the 1-3 seconds that are added. Is there any chance of optimising the other operations of semodule? If we could get a 10% improvement in the base functionality then "semodule -b" with compression would be expected to give the same performance as currently, if we could get a 20% improvement then "semodule -i" would give the current performance too. Then if you got an AMD64 assembler optimised gzip library the performance would be even better.
Quoted 30 lines · Karl MacMillan
Uncompressed
------------[root@localhost modules]# time semodule -b
/usr/share/selinux/strict/base.ppreal 0m15.849s user 0m14.791s sys 0m0.930s[root@localhost nobz-modules]# time semodule -i *.pp
real 0m15.447s user 0m14.287s sys 0m0.997sCompressed
----------[root@localhost modules]# time semodule -b
/root/base.pp.bz2real 0m16.117s user 0m14.729s sys 0m1.022s[root@localhost modules]# time semodule -i
/root/modules/*.bz2real 0m18.529s user 0m17.110s sys 0m1.314s
Signature · 10 lines
[email protected] http://etbe.blogspot.com/ My Blog http://www.coker.com.au/sponsorship.html Sponsoring Free Software development -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 4 lines · James Antill
Quoted 3 lines · Karl MacMillan
Quoted 1 line · James Antill
Do policy files not have a magic value, then?
Quoted 8 lines
Quoted 4 lines
They do, but there is no real restriction that these policy file things get used for files containing policy. Currently they are used for a variety of file types and I would hate to hard code a list valid file types into this function.
I don't think I'm intelligent enough to understand this sentence :).
What I meant was if they have magic values, they'll never clash so it's always ok to do the check, no?
Policy files can, presumably, be used on arbitrary files or memory areas. So there may or may not be a magic number at the beginning of the stream. I think assuming that there will be is too limiting.
Quoted 4 lines
Or in the other direction, if you can't differentiate on magic value or
the filename how can any piece of code tell whether it should decompress it or treat it as raw data?
User input, information from other parts of the code, etc.
Quoted 10 lines
Quoted 5 lines
Quoted 3 lines
You can also (for bz2)
check that the next value is between 1 and 9 (it's the compression ratio).Ok. Could this be used for sizing the buffer in the memory case?
No, it's just the "how hard did you want to try" value. So something
compressed with "bzip2 -1" will have a '1' and likewise "bzip2 -9" will have a '9' after the magic.
Oh well.
Quoted 12 lines
Quoted 11 lines
Quoted 4 lines
Right, but as I said the error paths always just try again without
compression ... so why not just try the compression at the start of theset_foo()code. You get the same behaviour.It is not about returning information about the compression. It is because the compression routines have other error paths (failure to load libbz2, memory allocation, etc.). There is no good way to indicate those errors without changing the prototypes. Even if we didn't change the prototypes, it is valid to not check the current functions for error, so we can't change them in any way that has potential error paths.
Quoted 5 lines
Yes, I know that ... but there isn't a difference in the return value
between "bz2_init()failed" and "is_bz2_file()returned NO". So all the callers just assume the later for all errors, if that's the case we might as well combine it back intoset_foo().
I'd rather differentiate the error codes.
Karl
--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 13 lines · Russell Coker
Quoted 5 lines · James Antill
I assume the only reason you went with bzip2 over gzip is the "have to
init yourself in theset_memcase"? I've done that before[1], so I can help you get that bit done if you want ... this will drop CPU/memory/dependency requirements (although expecting all Linux to have libbz now isn't a big deal, IMO).Given that the vast majority of new machines now are AMD64 part of the CPU requirement will be due to bzip2 and gzip not being optimised for AMD64. gzip has i386 assembler optimisation but no AMD64 assembler and runs more slowly on AMD64 because of it (my tests show that on RHEL4 the i386 copy of gzip outperforms the AMD64 version on Opteron machines).
Quoted 7 lines
If you compare the AMD64 compiled version of gzip (IE the library) with bzip2 the difference in CPU time is a lot smaller than it is when comparing the i386 versions.
Of course it probably wouldn't be difficult for someone to write some AMD64 assembler code for gzip or bzip2 to change things.
Ok.
Quoted 7 lines
In regard to the following, I think that the 15 seconds for uncompressed operation is the problem not the 1-3 seconds that are added. Is there any chance of optimising the other operations of semodule? If we could get a 10% improvement in the base functionality then "semodule -b" with compression would be expected to give the same performance as currently, if we could get a 20% improvement then "semodule -i" would give the current performance too.
Hopefully these will get faster over time - there has been very little performance work done to that code.
Karl
--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.