Date: Tue, 31 Jul 2012 15:07:57 -0400 From: John Baldwin <jhb@freebsd.org> To: src-committers@freebsd.org Cc: svn-src-head@freebsd.org, svn-src-all@freebsd.org Subject: Re: svn commit: r238952 - head/sys/kern Message-ID: <201207311507.57986.jhb@freebsd.org> In-Reply-To: <201207311825.q6VIP113056983@svn.freebsd.org> References: <201207311825.q6VIP113056983@svn.freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
On Tuesday, July 31, 2012 2:25:01 pm John Baldwin wrote: > Author: jhb > Date: Tue Jul 31 18:25:00 2012 > New Revision: 238952 > URL: http://svn.freebsd.org/changeset/base/238952 > > Log: > Reorder the managament of advisory locks on open files so that the advisory > lock is obtained before the write count is increased during open() and the > lock is released after the write count is decreased during close(). > > The first change closes a race where an open() that will block with O_SHLOCK > or O_EXLOCK can increase the write count while it waits. If the process > holding the current lock on the file then tries to call exec() on the file > it has locked, it can fail with ETXTBUSY even though the advisory lock is > preventing other threads from succesfully completeing a writable open(). > > The second change closes a race where a read-only open() with O_SHLOCK or > O_EXLOCK may return successfully while the write count is non-zero due to > another descriptor that had the advisory lock and was blocking the open() > still being in the process of closing. If the process that completed the > open() then attempts to call exec() on the file it locked, it can fail with > ETXTBUSY even though the other process that held a write lock has closed > the file and released the lock. > > Reviewed by: kib > MFC after: 1 month Oops, should have included: Tested by: pho I have a regression test (of sorts) for this. If you run it on an unpatched system it should start emitting errors within a few seconds. #include <sys/types.h> #include <sys/stat.h> #include <sys/wait.h> #include <err.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> static void usage(void) { fprintf(stderr, "Usage: flock_close_race <binary> [args]\n"); exit(1); } static void child(const char *binary) { int fd; /* Exit as soon as our parent exits. */ while (getppid() != 1) { fd = open(binary, O_RDWR | O_EXLOCK); if (fd < 0) { /* * This may get ETXTBSY since exit() will * close its open fd's (thus releasing the * lock), before it releases the vmspace (and * mapping of the binary). */ if (errno == ETXTBSY) continue; err(1, "can't open %s", binary); } close(fd); } exit(0); } static void exec_child(char **av) { int fd; fd = open(av[0], O_RDONLY | O_SHLOCK); execv(av[0], av); err(127, "execv"); } int main(int ac, char **av) { struct stat sb; pid_t pid; if (ac < 2) usage(); if (stat(av[1], &sb) != 0) err(1, "stat(%s)", av[1]); if (!S_ISREG(sb.st_mode)) errx(1, "%s not an executable", av[1]); pid = fork(); if (pid < 0) err(1, "fork"); if (pid == 0) child(av[1]); for (;;) { pid = fork(); if (pid < 0) err(1, "fork"); if (pid == 0) exec_child(av + 1); wait(NULL); } return (0); } -- John Baldwin
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201207311507.57986.jhb>