Messages in this thread |  | | Date | Sun, 14 Oct 2001 19:38:44 -0700 | From | Larry McVoy <> | Subject | Re: NFS file locking? |
| |
> Instead of creating a lock file, create a lock symlink. > Have the content of the symlink be something recognisably unique. > e.g. hostname.pid > If the "symlink" syscall succeeds, you have got the lock. > If it fails, issue a readlink and see if the content is what you > tried to create (RPC packet loss and retransmit could have caused > an incorrect failure return). If it is, you have the lock. > If not, you don't.
OK, tried that too, here's the code. Doesn't work. Neither does the link approach. Am I doing something wrong? It seems to me that I'm completely at the mercy of the client NFS implementation - if it caches stuff wrong, I'm hosed. There has to be some cute trick to get past this.
--lm
int sccs_lockfile(char *lockfile, int seconds) { char *s; char buf[300]; int n, uslp = 1000, waited = 0;
s = aprintf("%u %s", getpid(), sccs_gethost()); for ( ;; ) { if (symlink(s, lockfile) == 0) return (0); n = readlink(lockfile, buf, sizeof(buf)); if (n > 0) { buf[n] = 0; if (streq(s, buf)) return (0); } if (seconds && ((waited / 1000000) >= seconds)) { fprintf(stderr, "timed out waiting for %s\n", lockfile); free(s); return (-1); } usleep(uslp); waited += uslp; if (uslp < 20000) uslp <<= 1; } /* NOTREACHED */ }
/* * Usage: a.out iterations lockfile */ int main(int ac, char **av) { int i, iter; int me = getpid();
unless (ac == 3) return (1); unless ((iter = atoi(av[1])) > 0) return (1); printf("%d starts\n", me); for (i = 1; i <= iter; ++i) { sccs_lockfile(av[2], 0); assert(mine(av[2])); unlink(av[2]); unless (i % 10) printf("%d locked %d times\n", me, i); } printf("%d done\n", me); return (0); }
int mine(char *file) { char buf[300]; char *s; int n;
n = readlink(file, buf, sizeof(buf)); if (n > 0) { s = aprintf("%u %s", getpid(), sccs_gethost()); buf[n] = 0; n = streq(s, buf); unless (n) fprintf(stderr, "%s != %s\n", s, buf); free(s); return (n); } return (0); }
/* * This function works like sprintf(), except it return a * malloc'ed buffer which caller should free when done */ char * aprintf(char *fmt, ...) { va_list ptr; int rc, size = strlen(fmt) + 64; char *buf = malloc(size);
va_start(ptr, fmt); rc = vsnprintf(buf, size, fmt, ptr); va_end(ptr); /* * On IRIX, it truncates and returns size-1. * We can't assume that that is OK, even though that might be * a perfect fit. We always bump up the size and try again. * This can rarely lead to an extra alloc that we didn't need, * but that's tough. */ while ((rc < 0) || (rc >= (size-1))) { size *= 2; free(buf); buf = malloc(size); va_start(ptr, fmt); rc = vsnprintf(buf, size, fmt, ptr); va_end(ptr); } return (buf); /* caller should free */ }
char * sccs_gethost() { static char host[256];
if (gethostname(host, sizeof(host)) == -1) return "?"; return (host); } - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
|  |