* setfiles and restorecon performance patch
@ 2006-01-03 8:59 Russell Coker
2006-01-03 15:55 ` Steve G
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Russell Coker @ 2006-01-03 8:59 UTC (permalink / raw)
To: SE-Linux, Daniel Walsh, Stephen C. Tweedie
[-- Attachment #1: Type: text/plain, Size: 4539 bytes --]
The attached patch (against policycoreutils-1.29.2-8 from rawhide) makes
setfiles and restorecon fork off a child process to stat the files before the
main process gets to them.
Previously the setfiles process would stat a file (often waiting for several
disk seeks to get the data) then do some regex operations while the disk was
idle, this was inefficient. Now a child process will be reading all the data
from disk (and experiencing the delays from disk seeks) while the parent will
be doing the regex operations thus making more efficient use of the machine.
The child process will write some data to a pipe after each file has been
stat'd, when the pipe buffer (8K) is full the child will block (this prevents
the child from getting too far ahead of the parent - usually disk is faster
than CPU for this). If the child got too far ahead of the parent then the
files it stat'd could have their Inode/dentry data discarded from the cache
before the parent accessed them. At the moment I have 8 bytes sent through
the pipe per file so that the child is at most 1024 files ahead.
Thanks to Steve Tweedie for the idea. He initially suggested this a long time
ago (before I wrote the stem compression optimisation) and at that time disk
IO was not a significant factor in performance (setfiles used 99% CPU time on
most commonly available machines) so there would have been no benefit in
implementing it then.
Here are the times for restorecon on a Compaq desktop machine with P4-1.5GHz,
256M of 133MHz RAM, and a cheap 20G IDE disk. Tests were performed on
the /usr tree.
Original:
78.03user 21.77system 2:07.12elapsed 78%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (0major+3136minor)pagefaults 0swaps
first new ver:
78.66user 15.90system 1:41.25elapsed 93%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (0major+3129minor)pagefaults 0swaps
Reduced the elapsed time by 20.5%! Of course if I had a server class machine
with 15,000rpm disks then the benefit would be a lot less. OTOH if I tested
on a new laptop then the benefit would probably be greater.
second new ver:
77.64user 16.10system 1:39.10elapsed 94%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (0major+3125minor)pagefaults 0swaps
The second version was after optimising the code in terms of using strdupa(),
removing some strlen() type operations, etc. The difference is hardly
noticable as those optimisations weren't on the most critical paths. Still
worth having IMHO.
Here are the times for setfiles on the same machine:
old ver:
78.66user 14.98system 1:59.56elapsed 78%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (0major+4340minor)pagefaults 0swaps
new ver (8):
78.50user 9.40system 1:34.16elapsed 93%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (0major+5065minor)pagefaults 0swaps
21% reduction in elapsed time!
new ver (1):
77.63user 9.42system 1:33.53elapsed 93%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (0major+5064minor)pagefaults 0swaps
Now I repeated my test but wrote a byte at a time instead of 8 bytes at a time
to the pipe, this meant that up to 8192 files could be cached ahead of the
main process. The (8) time is for 8 bytes per operation and the (1) time is
for one byte per operation. The slight performance benefit reported by the
(1) time is not noteworthy as I only did each test once, due to the margin of
error I could get results pointing the other way when there's less than 1%
difference. The issue of whether we use 8 or 1 byte for pipe operations
probably has to be a judgement call of whether 8192 or 1024 files is the best
fit for the cache of commonly available machines (or course 2048 and 4096 are
also options that can be considered).
Stephen, please let me know what your instinct is regarding cache sizes for
this.
I believe that this patch is worthy of inclusion regardless of the issue of
how many bytes we write to the pipe. We can always fine-tune this later.
Also Dan please let me know when you have built an RPM of this and new RPMs of
the SE Linux libraries (based on our discussion of performance patches for
them). I have some other ideas for improvements in this area but I want to
get the current patches all sorted out before I start work.
--
http://www.coker.com.au/selinux/ My NSA Security Enhanced Linux packages
http://www.coker.com.au/bonnie++/ Bonnie++ hard drive benchmark
http://www.coker.com.au/postal/ Postal SMTP/POP benchmark
http://www.coker.com.au/~russell/ My home page
[-- Attachment #2: setf.diff --]
[-- Type: text/x-diff, Size: 10831 bytes --]
diff -rup policycoreutils-1.29.2.orig/restorecon/restorecon.c policycoreutils-1.29.2/restorecon/restorecon.c
--- policycoreutils-1.29.2.orig/restorecon/restorecon.c 2005-12-15 06:16:56.000000000 +1100
+++ policycoreutils-1.29.2/restorecon/restorecon.c 2006-01-03 18:50:29.000000000 +1100
@@ -23,7 +23,9 @@
*
*/
+#define _GNU_SOURCE
#include <stdio.h>
+#include <stdio_ext.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
@@ -45,6 +47,8 @@ static char *progname;
static int errors=0;
static int recurse=0;
static int force=0;
+#define STAT_BLOCK_SIZE 8
+static int pipe_fds[2] = { -1, -1 };
#define MAX_EXCLUDES 100
static int excludeCtr=0;
@@ -115,21 +119,15 @@ void usage(const char * const name)
"usage: %s [-rRnv] [-e excludedir ] [-o filename ] [-f filename | pathname... ]\n", name);
exit(1);
}
-int restore(char *filename) {
+/* filename has trailing '/' removed by nftw or other calling code */
+int restore(const char *filename) {
int retcontext=0;
int retval=0;
security_context_t scontext=NULL;
security_context_t prev_context=NULL;
- int len=strlen(filename);
struct stat st;
char path[PATH_MAX+1];
int user_only_changed=0;
- /*
- Eliminate trailing /
- */
- if (len > 0 && filename[len-1]=='/' && (strcmp(filename,"/") != 0)) {
- filename[len-1]=0;
- }
if (excludeCtr > 0 && exclude(filename)) {
return 0;
@@ -143,7 +141,7 @@ int restore(char *filename) {
if (verbose>1)
fprintf(stderr,"Warning! %s refers to a symbolic link, not following last component.\n", filename);
char *p = NULL, *file_sep;
- char *tmp_path = strdup(filename);
+ char *tmp_path = strdupa(filename);
if (!tmp_path) {
fprintf(stderr,"strdup on %s failed: %s\n", filename,strerror(errno));
return 1;
@@ -155,14 +153,16 @@ int restore(char *filename) {
file_sep++;
p = realpath(tmp_path, path);
}
- if (!p || strlen(path) + strlen(file_sep) + 1 > PATH_MAX) {
+ size_t len = strlen(p);
+ if (!p || len + strlen(file_sep) + 2 > PATH_MAX) {
fprintf(stderr,"realpath(%s) failed %s\n", filename, strerror(errno));
- free(tmp_path);
return 1;
}
- sprintf(p + strlen(p), "/%s", file_sep);
+ p += len;
+ *p = '/';
+ p++;
+ strcpy(p, file_sep);
filename = p;
- free(tmp_path);
} else {
char *p;
p = realpath(filename, path);
@@ -182,10 +182,6 @@ int restore(char *filename) {
fprintf(stderr,"matchpathcon(%s) failed %s\n", filename,strerror(errno));
return 1;
}
- if (strcmp(scontext,"<<none>>")==0) {
- freecon(scontext);
- return 0;
- }
retcontext=lgetfilecon(filename,&prev_context);
if (retcontext >= 0 || errno == ENODATA) {
@@ -230,38 +226,80 @@ int restore(char *filename) {
freecon(scontext);
return errors;
}
+
+static int pre_stat(const char *file_unused __attribute__((unused)),
+ const struct stat *sb_unused __attribute__((unused)),
+ int flag_unused __attribute__((unused)),
+ struct FTW *s_unused __attribute__((unused)))
+{
+ char buf[STAT_BLOCK_SIZE];
+ if(write(pipe_fds[1], buf, STAT_BLOCK_SIZE) != STAT_BLOCK_SIZE)
+ {
+ fprintf(stderr, "Error writing to stat pipe, child exiting.\n");
+ exit(1);
+ }
+ return 0;
+}
+
static int apply_spec(const char *file,
const struct stat *sb_unused __attribute__((unused)),
int flag,
struct FTW *s_unused __attribute__((unused)))
{
+ char buf[STAT_BLOCK_SIZE];
+ if(pipe_fds[0] != -1 && read(pipe_fds[0], buf, STAT_BLOCK_SIZE) != STAT_BLOCK_SIZE)
+ {
+ fprintf(stderr, "Read error on pipe.\n");
+ pipe_fds[0] = -1;
+ }
if (flag == FTW_DNR) {
fprintf(stderr, "%s: unable to read directory %s\n",
progname, file);
return 0;
}
- errors=errors+restore((char *)file);
+ errors=errors+restore(file);
return 0;
}
void process(char *buf) {
+ int rc;
if (recurse) {
- if (nftw
- (buf, apply_spec, 1024, FTW_PHYS)) {
- fprintf(stderr,
- "%s: error while labeling files under %s\n",
+ if(pipe(pipe_fds) == -1)
+ rc = -1;
+ else
+ rc = fork();
+ if(rc == 0)
+ {
+ close(pipe_fds[0]);
+ nftw(buf, pre_stat, 1024, FTW_PHYS);
+ exit(1);
+ }
+ if(rc > 0)
+ close(pipe_fds[1]);
+ if(rc == -1 || rc > 0) {
+ if (nftw(buf, apply_spec, 1024, FTW_PHYS)) {
+ fprintf(stderr, "%s: error while labeling files under %s\n",
progname, buf);
- errors++;
+ errors++;
+ }
}
}
else
- errors=errors+restore(buf);
+ {
+ /* Eliminate trailing / */
+ size_t len = strlen(buf);
+ if (len > 1 && buf[len - 1] == '/') {
+ buf[len - 1] = 0;
+ }
+ errors = errors + restore(buf);
+ }
}
int main(int argc, char **argv) {
int i=0;
char *file_name=NULL;
int file=0;
int opt;
- char buf[PATH_MAX];
+ char *buf = NULL;
+ size_t buf_len;
memset(excludeArray,0, sizeof(excludeArray));
@@ -269,8 +307,6 @@ int main(int argc, char **argv) {
if (is_selinux_enabled() <= 0 )
exit(0);
- memset(buf,0, sizeof(buf));
-
while ((opt = getopt(argc, argv, "FrRnvf:o:e:")) > 0) {
switch (opt) {
case 'n':
@@ -293,6 +329,7 @@ int main(int argc, char **argv) {
optarg, strerror(errno));
usage(argv[0]);
}
+ __fsetlocking(outfile, FSETLOCKING_BYCALLER);
break;
case 'v':
verbose++;
@@ -307,15 +344,16 @@ int main(int argc, char **argv) {
}
if (file) {
FILE *f=stdin;
+ ssize_t len;
if (strcmp(file_name,"-")!=0)
f=fopen(file_name,"r");
-
if (f==NULL) {
fprintf(stderr,"Unable to open %s: %s\n", file_name, strerror(errno));
usage(argv[0]);
}
- while(fgets(buf,PATH_MAX,f)) {
- buf[strlen(buf)-1]=0;
+ __fsetlocking(f, FSETLOCKING_BYCALLER);
+ while((len = getline(&buf, &buf_len, f)) != -1) {
+ buf[len - 1] = 0;
process(buf);
}
if (strcmp(file_name,"-")!=0)
diff -rup policycoreutils-1.29.2.orig/setfiles/setfiles.c policycoreutils-1.29.2/setfiles/setfiles.c
--- policycoreutils-1.29.2.orig/setfiles/setfiles.c 2005-12-15 06:16:57.000000000 +1100
+++ policycoreutils-1.29.2/setfiles/setfiles.c 2006-01-03 18:50:40.000000000 +1100
@@ -62,6 +62,7 @@
#include <stdlib.h>
#include <fcntl.h>
#include <stdio.h>
+#include <stdio_ext.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
@@ -78,6 +79,8 @@
static int add_assoc = 1;
static FILE *outfile=NULL;
static int force=0;
+#define STAT_BLOCK_SIZE 8
+static int pipe_fds[2] = { -1, -1 };
#define MAX_EXCLUDES 100
static int excludeCtr=0;
@@ -244,6 +247,12 @@ static int apply_spec(const char *file,
int i, j, ret;
char *context, *newcon;
int user_only_changed=0;
+ char buf[STAT_BLOCK_SIZE];
+ if(pipe_fds[0] != -1 && read(pipe_fds[0], buf, STAT_BLOCK_SIZE) != STAT_BLOCK_SIZE)
+ {
+ fprintf(stderr, "Read error on pipe.\n");
+ pipe_fds[0] = -1;
+ }
/* Skip the extra slash at the beginning, if present. */
if (file[0] == '/' && file[1] == '/')
@@ -288,17 +297,17 @@ static int apply_spec(const char *file,
ret = lgetfilecon(my_file, &context);
if (ret < 0) {
if (errno == ENODATA) {
- context = malloc(10);
- strcpy(context, "<<none>>");
+ context = NULL;
} else {
perror(my_file);
fprintf(stderr, "%s: unable to obtain attribute for file %s\n",
progname, my_file);
goto err;
}
+ user_only_changed = 0;
}
-
- user_only_changed=only_changed_user(context, newcon);
+ else
+ user_only_changed=only_changed_user(context, newcon);
/*
* Do not relabel the file if the matching specification is
@@ -306,12 +315,12 @@ static int apply_spec(const char *file,
* specification.
*/
if ((strcmp(newcon, "<<none>>") == 0) ||
- (strcmp(context,newcon) == 0)) {
+ (context && (strcmp(context,newcon) == 0))) {
freecon(context);
goto out;
}
- if (! force &&
+ if (! force && context &&
( is_context_customizable(context)>0 )) {
if (verbose > 1) {
fprintf(stderr,"%s: %s not reset customized by admin to %s\n",
@@ -325,20 +334,29 @@ static int apply_spec(const char *file,
* the user has changed but the role and type are the
* same. For "-vv", emit everything. */
if (verbose > 1 || !user_only_changed) {
+ if(context)
printf("%s: relabeling %s from %s to %s\n", progname,
my_file, context, newcon);
+ else
+ printf("%s: labeling %s to %s\n", progname,
+ my_file, newcon);
}
}
if ( log && !user_only_changed ) {
- syslog(LOG_INFO, "relabeling %s from %s to %s\n",
- my_file, context, newcon);
+ if(context)
+ syslog(LOG_INFO, "relabeling %s from %s to %s\n",
+ my_file, context, newcon);
+ else
+ syslog(LOG_INFO, "labeling %s to %s\n",
+ my_file, newcon);
}
if (outfile && !user_only_changed)
fprintf(outfile, "%s\n", my_file);
- freecon(context);
+ if(context)
+ freecon(context);
/*
* Do not relabel the file if -n was used.
@@ -411,6 +429,20 @@ int canoncon(const char *path, unsigned
return !valid;
}
+static int pre_stat(const char *file_unused __attribute__((unused)),
+ const struct stat *sb_unused __attribute__((unused)),
+ int flag_unused __attribute__((unused)),
+ struct FTW *s_unused __attribute__((unused)))
+{
+ char buf[STAT_BLOCK_SIZE];
+ if(write(pipe_fds[1], buf, STAT_BLOCK_SIZE) != STAT_BLOCK_SIZE)
+ {
+ fprintf(stderr, "Error writing to stat pipe, child exiting.\n");
+ exit(1);
+ }
+ return 0;
+}
+
int main(int argc, char **argv)
{
int opt, rc, i;
@@ -435,6 +467,7 @@ int main(int argc, char **argv)
policyfile, strerror(errno));
exit(1);
}
+ __fsetlocking(policystream, FSETLOCKING_BYCALLER);
if (sepol_set_policydb_from_file(policystream) < 0) {
fprintf(stderr, "Error reading policy %s: %s\n", policyfile,
@@ -474,6 +507,7 @@ int main(int argc, char **argv)
usage(argv[0]);
}
+ __fsetlocking(outfile, FSETLOCKING_BYCALLER);
break;
case 'q':
quiet = 1;
@@ -580,15 +614,31 @@ int main(int argc, char **argv)
qprintf("%s: labeling files under %s\n", argv[0],
argv[optind]);
-
+
+ int rc;
+ if(pipe(pipe_fds) == -1)
+ rc = -1;
+ else
+ rc = fork();
+ if(rc == 0)
+ {
+ close(pipe_fds[0]);
+ nftw(argv[optind], pre_stat, 1024, FTW_PHYS);
+ exit(1);
+ }
+ if(rc > 0)
+ close(pipe_fds[1]);
+ if(rc == -1 || rc > 0) {
+
/* Walk the file tree, calling apply_spec on each file. */
- if (nftw
- (argv[optind], apply_spec, 1024,
- FTW_PHYS | FTW_MOUNT)) {
- fprintf(stderr,
+ if (nftw
+ (argv[optind], apply_spec, 1024,
+ FTW_PHYS | FTW_MOUNT)) {
+ fprintf(stderr,
"%s: error while labeling files under %s\n",
argv[0], argv[optind]);
- exit(1);
+ exit(1);
+ }
}
/*
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: setfiles and restorecon performance patch 2006-01-03 8:59 setfiles and restorecon performance patch Russell Coker @ 2006-01-03 15:55 ` Steve G 2006-01-03 19:08 ` Russell Coker 2006-01-07 1:19 ` Stephen Tweedie 2006-01-13 13:55 ` Stephen Smalley 2 siblings, 1 reply; 6+ messages in thread From: Steve G @ 2006-01-03 15:55 UTC (permalink / raw) To: russell, SE-Linux, Daniel Walsh, Stephen C. Tweedie Hi, Just a couple comments: >@@ -143,7 +141,7 @@ int restore(char *filename) { > if (verbose>1) > fprintf(stderr,"Warning! %s refers to a symbolic link, not > following last component.\n", filename); > char *p = NULL, *file_sep; >- char *tmp_path = strdup(filename); >+ char *tmp_path = strdupa(filename); > if (!tmp_path) { > fprintf(stderr,"strdup on %s failed: %s\n", >filename,strerror(errno)); Do you need to check for NULL on strdupa calls? If so, the error message needs to have the function updated, too. Otherwise this can be deleted. >@@ -155,14 +153,16 @@ int restore(char *filename) { > file_sep++; > p = realpath(tmp_path, path); > } >- if (!p || strlen(path) + strlen(file_sep) + 1 > PATH_MAX) { >+ size_t len = strlen(p); >+ if (!p || len + strlen(file_sep) + 2 > PATH_MAX) { What if realpath returned NULL? strlen is using a NULL pointer and then p is checked in the second line to see if its NULL. -Steve __________________________________________ Yahoo! DSL Something to write home about. Just $16.99/mo. or less. dsl.yahoo.com -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message. ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: setfiles and restorecon performance patch 2006-01-03 15:55 ` Steve G @ 2006-01-03 19:08 ` Russell Coker 2006-01-03 20:22 ` Joshua Brindle 0 siblings, 1 reply; 6+ messages in thread From: Russell Coker @ 2006-01-03 19:08 UTC (permalink / raw) To: Steve G, Ulrich Drepper; +Cc: SE-Linux, Daniel Walsh, Stephen C. Tweedie [-- Attachment #1: Type: text/plain, Size: 1524 bytes --] On Wednesday 04 January 2006 02:55, Steve G <linux_4ever@yahoo.com> wrote: > >@@ -143,7 +141,7 @@ int restore(char *filename) { > > if (verbose>1) > > fprintf(stderr,"Warning! %s refers to a symbolic link, not > > following last component.\n", filename); > > char *p = NULL, *file_sep; > >- char *tmp_path = strdup(filename); > >+ char *tmp_path = strdupa(filename); > > if (!tmp_path) { > > fprintf(stderr,"strdup on %s failed: %s\n", > > >filename,strerror(errno)); > > Do you need to check for NULL on strdupa calls? If so, the error message > needs to have the function updated, too. Otherwise this can be deleted. Not sure. The alloca() man page says that the failure result is undefined but the strdupa() man page says nothing (implies that it's the same as strdup()). Ulrich? > >@@ -155,14 +153,16 @@ int restore(char *filename) { > > file_sep++; > > p = realpath(tmp_path, path); > > } > >- if (!p || strlen(path) + strlen(file_sep) + 1 > PATH_MAX) { > >+ size_t len = strlen(p); > >+ if (!p || len + strlen(file_sep) + 2 > PATH_MAX) { > > What if realpath returned NULL? strlen is using a NULL pointer and then p > is checked in the second line to see if its NULL. Fixed that, attached a new patch. -- http://www.coker.com.au/selinux/ My NSA Security Enhanced Linux packages http://www.coker.com.au/bonnie++/ Bonnie++ hard drive benchmark http://www.coker.com.au/postal/ Postal SMTP/POP benchmark http://www.coker.com.au/~russell/ My home page [-- Attachment #2: setf2.diff --] [-- Type: text/x-diff, Size: 10981 bytes --] diff -rup policycoreutils-1.29.2.orig/restorecon/restorecon.c policycoreutils-1.29.2/restorecon/restorecon.c --- policycoreutils-1.29.2.orig/restorecon/restorecon.c 2005-12-15 06:16:56.000000000 +1100 +++ policycoreutils-1.29.2/restorecon/restorecon.c 2006-01-04 06:03:36.000000000 +1100 @@ -23,7 +23,9 @@ * */ +#define _GNU_SOURCE #include <stdio.h> +#include <stdio_ext.h> #include <errno.h> #include <string.h> #include <stdlib.h> @@ -45,6 +47,8 @@ static char *progname; static int errors=0; static int recurse=0; static int force=0; +#define STAT_BLOCK_SIZE 8 +static int pipe_fds[2] = { -1, -1 }; #define MAX_EXCLUDES 100 static int excludeCtr=0; @@ -115,21 +119,15 @@ void usage(const char * const name) "usage: %s [-rRnv] [-e excludedir ] [-o filename ] [-f filename | pathname... ]\n", name); exit(1); } -int restore(char *filename) { +/* filename has trailing '/' removed by nftw or other calling code */ +int restore(const char *filename) { int retcontext=0; int retval=0; security_context_t scontext=NULL; security_context_t prev_context=NULL; - int len=strlen(filename); struct stat st; char path[PATH_MAX+1]; int user_only_changed=0; - /* - Eliminate trailing / - */ - if (len > 0 && filename[len-1]=='/' && (strcmp(filename,"/") != 0)) { - filename[len-1]=0; - } if (excludeCtr > 0 && exclude(filename)) { return 0; @@ -143,9 +141,9 @@ int restore(char *filename) { if (verbose>1) fprintf(stderr,"Warning! %s refers to a symbolic link, not following last component.\n", filename); char *p = NULL, *file_sep; - char *tmp_path = strdup(filename); + char *tmp_path = strdupa(filename); if (!tmp_path) { - fprintf(stderr,"strdup on %s failed: %s\n", filename,strerror(errno)); + fprintf(stderr,"strdupa on %s failed: %s\n", filename,strerror(errno)); return 1; } file_sep = strrchr(tmp_path, '/'); @@ -155,14 +153,18 @@ int restore(char *filename) { file_sep++; p = realpath(tmp_path, path); } - if (!p || strlen(path) + strlen(file_sep) + 1 > PATH_MAX) { + size_t len; + if(p) + len = strlen(p); + if (!p || len + strlen(file_sep) + 2 > PATH_MAX) { fprintf(stderr,"realpath(%s) failed %s\n", filename, strerror(errno)); - free(tmp_path); return 1; } - sprintf(p + strlen(p), "/%s", file_sep); + p += len; + *p = '/'; + p++; + strcpy(p, file_sep); filename = p; - free(tmp_path); } else { char *p; p = realpath(filename, path); @@ -182,10 +184,6 @@ int restore(char *filename) { fprintf(stderr,"matchpathcon(%s) failed %s\n", filename,strerror(errno)); return 1; } - if (strcmp(scontext,"<<none>>")==0) { - freecon(scontext); - return 0; - } retcontext=lgetfilecon(filename,&prev_context); if (retcontext >= 0 || errno == ENODATA) { @@ -230,38 +228,80 @@ int restore(char *filename) { freecon(scontext); return errors; } + +static int pre_stat(const char *file_unused __attribute__((unused)), + const struct stat *sb_unused __attribute__((unused)), + int flag_unused __attribute__((unused)), + struct FTW *s_unused __attribute__((unused))) +{ + char buf[STAT_BLOCK_SIZE]; + if(write(pipe_fds[1], buf, STAT_BLOCK_SIZE) != STAT_BLOCK_SIZE) + { + fprintf(stderr, "Error writing to stat pipe, child exiting.\n"); + exit(1); + } + return 0; +} + static int apply_spec(const char *file, const struct stat *sb_unused __attribute__((unused)), int flag, struct FTW *s_unused __attribute__((unused))) { + char buf[STAT_BLOCK_SIZE]; + if(pipe_fds[0] != -1 && read(pipe_fds[0], buf, STAT_BLOCK_SIZE) != STAT_BLOCK_SIZE) + { + fprintf(stderr, "Read error on pipe.\n"); + pipe_fds[0] = -1; + } if (flag == FTW_DNR) { fprintf(stderr, "%s: unable to read directory %s\n", progname, file); return 0; } - errors=errors+restore((char *)file); + errors=errors+restore(file); return 0; } void process(char *buf) { + int rc; if (recurse) { - if (nftw - (buf, apply_spec, 1024, FTW_PHYS)) { - fprintf(stderr, - "%s: error while labeling files under %s\n", + if(pipe(pipe_fds) == -1) + rc = -1; + else + rc = fork(); + if(rc == 0) + { + close(pipe_fds[0]); + nftw(buf, pre_stat, 1024, FTW_PHYS); + exit(1); + } + if(rc > 0) + close(pipe_fds[1]); + if(rc == -1 || rc > 0) { + if (nftw(buf, apply_spec, 1024, FTW_PHYS)) { + fprintf(stderr, "%s: error while labeling files under %s\n", progname, buf); - errors++; + errors++; + } } } else - errors=errors+restore(buf); + { + /* Eliminate trailing / */ + size_t len = strlen(buf); + if (len > 1 && buf[len - 1] == '/') { + buf[len - 1] = 0; + } + errors = errors + restore(buf); + } } int main(int argc, char **argv) { int i=0; char *file_name=NULL; int file=0; int opt; - char buf[PATH_MAX]; + char *buf = NULL; + size_t buf_len; memset(excludeArray,0, sizeof(excludeArray)); @@ -269,8 +309,6 @@ int main(int argc, char **argv) { if (is_selinux_enabled() <= 0 ) exit(0); - memset(buf,0, sizeof(buf)); - while ((opt = getopt(argc, argv, "FrRnvf:o:e:")) > 0) { switch (opt) { case 'n': @@ -293,6 +331,7 @@ int main(int argc, char **argv) { optarg, strerror(errno)); usage(argv[0]); } + __fsetlocking(outfile, FSETLOCKING_BYCALLER); break; case 'v': verbose++; @@ -307,15 +346,16 @@ int main(int argc, char **argv) { } if (file) { FILE *f=stdin; + ssize_t len; if (strcmp(file_name,"-")!=0) f=fopen(file_name,"r"); - if (f==NULL) { fprintf(stderr,"Unable to open %s: %s\n", file_name, strerror(errno)); usage(argv[0]); } - while(fgets(buf,PATH_MAX,f)) { - buf[strlen(buf)-1]=0; + __fsetlocking(f, FSETLOCKING_BYCALLER); + while((len = getline(&buf, &buf_len, f)) != -1) { + buf[len - 1] = 0; process(buf); } if (strcmp(file_name,"-")!=0) diff -rup policycoreutils-1.29.2.orig/setfiles/setfiles.c policycoreutils-1.29.2/setfiles/setfiles.c --- policycoreutils-1.29.2.orig/setfiles/setfiles.c 2005-12-15 06:16:57.000000000 +1100 +++ policycoreutils-1.29.2/setfiles/setfiles.c 2006-01-04 06:06:02.000000000 +1100 @@ -62,6 +62,7 @@ #include <stdlib.h> #include <fcntl.h> #include <stdio.h> +#include <stdio_ext.h> #include <string.h> #include <errno.h> #include <ctype.h> @@ -78,6 +79,8 @@ static int add_assoc = 1; static FILE *outfile=NULL; static int force=0; +#define STAT_BLOCK_SIZE 8 +static int pipe_fds[2] = { -1, -1 }; #define MAX_EXCLUDES 100 static int excludeCtr=0; @@ -244,6 +247,12 @@ static int apply_spec(const char *file, int i, j, ret; char *context, *newcon; int user_only_changed=0; + char buf[STAT_BLOCK_SIZE]; + if(pipe_fds[0] != -1 && read(pipe_fds[0], buf, STAT_BLOCK_SIZE) != STAT_BLOCK_SIZE) + { + fprintf(stderr, "Read error on pipe.\n"); + pipe_fds[0] = -1; + } /* Skip the extra slash at the beginning, if present. */ if (file[0] == '/' && file[1] == '/') @@ -288,17 +297,17 @@ static int apply_spec(const char *file, ret = lgetfilecon(my_file, &context); if (ret < 0) { if (errno == ENODATA) { - context = malloc(10); - strcpy(context, "<<none>>"); + context = NULL; } else { perror(my_file); fprintf(stderr, "%s: unable to obtain attribute for file %s\n", progname, my_file); goto err; } + user_only_changed = 0; } - - user_only_changed=only_changed_user(context, newcon); + else + user_only_changed=only_changed_user(context, newcon); /* * Do not relabel the file if the matching specification is @@ -306,12 +315,12 @@ static int apply_spec(const char *file, * specification. */ if ((strcmp(newcon, "<<none>>") == 0) || - (strcmp(context,newcon) == 0)) { + (context && (strcmp(context,newcon) == 0))) { freecon(context); goto out; } - if (! force && + if (! force && context && ( is_context_customizable(context)>0 )) { if (verbose > 1) { fprintf(stderr,"%s: %s not reset customized by admin to %s\n", @@ -325,20 +334,29 @@ static int apply_spec(const char *file, * the user has changed but the role and type are the * same. For "-vv", emit everything. */ if (verbose > 1 || !user_only_changed) { + if(context) printf("%s: relabeling %s from %s to %s\n", progname, my_file, context, newcon); + else + printf("%s: labeling %s to %s\n", progname, + my_file, newcon); } } if ( log && !user_only_changed ) { - syslog(LOG_INFO, "relabeling %s from %s to %s\n", - my_file, context, newcon); + if(context) + syslog(LOG_INFO, "relabeling %s from %s to %s\n", + my_file, context, newcon); + else + syslog(LOG_INFO, "labeling %s to %s\n", + my_file, newcon); } if (outfile && !user_only_changed) fprintf(outfile, "%s\n", my_file); - freecon(context); + if(context) + freecon(context); /* * Do not relabel the file if -n was used. @@ -411,6 +429,20 @@ int canoncon(const char *path, unsigned return !valid; } +static int pre_stat(const char *file_unused __attribute__((unused)), + const struct stat *sb_unused __attribute__((unused)), + int flag_unused __attribute__((unused)), + struct FTW *s_unused __attribute__((unused))) +{ + char buf[STAT_BLOCK_SIZE]; + if(write(pipe_fds[1], buf, STAT_BLOCK_SIZE) != STAT_BLOCK_SIZE) + { + fprintf(stderr, "Error writing to stat pipe, child exiting.\n"); + exit(1); + } + return 0; +} + int main(int argc, char **argv) { int opt, rc, i; @@ -435,6 +467,7 @@ int main(int argc, char **argv) policyfile, strerror(errno)); exit(1); } + __fsetlocking(policystream, FSETLOCKING_BYCALLER); if (sepol_set_policydb_from_file(policystream) < 0) { fprintf(stderr, "Error reading policy %s: %s\n", policyfile, @@ -474,6 +507,7 @@ int main(int argc, char **argv) usage(argv[0]); } + __fsetlocking(outfile, FSETLOCKING_BYCALLER); break; case 'q': quiet = 1; @@ -580,15 +614,31 @@ int main(int argc, char **argv) qprintf("%s: labeling files under %s\n", argv[0], argv[optind]); - + + int rc; + if(pipe(pipe_fds) == -1) + rc = -1; + else + rc = fork(); + if(rc == 0) + { + close(pipe_fds[0]); + nftw(argv[optind], pre_stat, 1024, FTW_PHYS); + exit(1); + } + if(rc > 0) + close(pipe_fds[1]); + if(rc == -1 || rc > 0) { + /* Walk the file tree, calling apply_spec on each file. */ - if (nftw - (argv[optind], apply_spec, 1024, - FTW_PHYS | FTW_MOUNT)) { - fprintf(stderr, + if (nftw + (argv[optind], apply_spec, 1024, + FTW_PHYS | FTW_MOUNT)) { + fprintf(stderr, "%s: error while labeling files under %s\n", argv[0], argv[optind]); - exit(1); + exit(1); + } } /* ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: setfiles and restorecon performance patch 2006-01-03 19:08 ` Russell Coker @ 2006-01-03 20:22 ` Joshua Brindle 0 siblings, 0 replies; 6+ messages in thread From: Joshua Brindle @ 2006-01-03 20:22 UTC (permalink / raw) To: russell; +Cc: Steve G, Ulrich Drepper, SE-Linux, Daniel Walsh, Stephen C. Tweedie Russell Coker wrote: > On Wednesday 04 January 2006 02:55, Steve G <linux_4ever@yahoo.com> wrote: > >>>@@ -143,7 +141,7 @@ int restore(char *filename) { >>> if (verbose>1) >>> fprintf(stderr,"Warning! %s refers to a symbolic link, not >>>following last component.\n", filename); >>> char *p = NULL, *file_sep; >>>- char *tmp_path = strdup(filename); >>>+ char *tmp_path = strdupa(filename); >>> if (!tmp_path) { >>> fprintf(stderr,"strdup on %s failed: %s\n", >>> >>>>filename,strerror(errno)); >> >>Do you need to check for NULL on strdupa calls? If so, the error message >>needs to have the function updated, too. Otherwise this can be deleted. > > > Not sure. The alloca() man page says that the failure result is undefined but > the strdupa() man page says nothing (implies that it's the same as strdup()). > > Ulrich? > > >>>@@ -155,14 +153,16 @@ int restore(char *filename) { >>> file_sep++; >>> p = realpath(tmp_path, path); >>> } >>>- if (!p || strlen(path) + strlen(file_sep) + 1 > PATH_MAX) { >>>+ size_t len = strlen(p); >>>+ if (!p || len + strlen(file_sep) + 2 > PATH_MAX) { >> >>What if realpath returned NULL? strlen is using a NULL pointer and then p >>is checked in the second line to see if its NULL. > > > Fixed that, attached a new patch. strdupa man page says it's a GNU extension, does this work on BSD? We should not be making non-portable changes to libraries as SEBSD has the potential to catch up and start using these new libraries. -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message. ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: setfiles and restorecon performance patch 2006-01-03 8:59 setfiles and restorecon performance patch Russell Coker 2006-01-03 15:55 ` Steve G @ 2006-01-07 1:19 ` Stephen Tweedie 2006-01-13 13:55 ` Stephen Smalley 2 siblings, 0 replies; 6+ messages in thread From: Stephen Tweedie @ 2006-01-07 1:19 UTC (permalink / raw) To: russell; +Cc: SE-Linux, Daniel J Walsh, Stephen Tweedie Hi, On Tue, 2006-01-03 at 19:59 +1100, Russell Coker wrote: > Stephen, please let me know what your instinct is regarding cache sizes for > this. 8192 sounds a bit large; 1024 sounds better. In fact, to be honest, a lookahead of a dozen or so would probably be fine in this particular scenario --- the child process doing the stat()s is still going to be fully serialised on its IO, so there's no opportunity to reorder IOs and so no opportunity to schedule disk IO better by giving the kernel a larger pool of IOs to work on. But you're unlikely to exhaust the cache and so evict things during this scan; at least not at 1000 entries. dcache sizes are often in the tens if not hundreds of thousands. Cheers, Stephen -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message. ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: setfiles and restorecon performance patch 2006-01-03 8:59 setfiles and restorecon performance patch Russell Coker 2006-01-03 15:55 ` Steve G 2006-01-07 1:19 ` Stephen Tweedie @ 2006-01-13 13:55 ` Stephen Smalley 2 siblings, 0 replies; 6+ messages in thread From: Stephen Smalley @ 2006-01-13 13:55 UTC (permalink / raw) To: russell; +Cc: SE-Linux, Daniel Walsh, Stephen C. Tweedie On Tue, 2006-01-03 at 19:59 +1100, Russell Coker wrote: > The attached patch (against policycoreutils-1.29.2-8 from rawhide) makes > setfiles and restorecon fork off a child process to stat the files before the > main process gets to them. Merged as of policycoreutils 1.29.7, with the change to STAT_BLOCK_SIZE that we discussed off-list. -- 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 majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message. ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2006-01-13 13:55 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2006-01-03 8:59 setfiles and restorecon performance patch Russell Coker 2006-01-03 15:55 ` Steve G 2006-01-03 19:08 ` Russell Coker 2006-01-03 20:22 ` Joshua Brindle 2006-01-07 1:19 ` Stephen Tweedie 2006-01-13 13:55 ` Stephen Smalley
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.