Hi,

After a bunch of failures (ld.so can't find libc.so for the install(1))
with parallel make build (-j 4) on an NFS setup I came up with this
simple testcase that shows that rename(2) on NFS is not atomic by
trying to open(2) the file that is being renamed in a tight loop.
I can reproduce this on v2 and v3 mounts served by 5.1 as well as
local v2 and v3 mounts on 5.1 and -current.

To run the testcase just point nfs1 to the nonexistant file on the
NFS (it will refuse to trash an existing file) and then point nfs2
to the same file and it will eventually die:

% /tmp/nfs1 /pub/foobar

% /tmp/nfs2 /pub/foobar
failed after 53 successful opens

(nfs1 can be substituted with a shell loop doing install -S)

The cause of this is currently unknown.

Have a nice day!

Cheers,
Mike

http://www.vantronix.net/~mike/nfs1.c
===========================8<===================================
#include <sys/param.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <err.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

int
main(int argc, char **argv)
{
        char *oldpath = argv[1];
        char newpath[MAXPATHLEN];
        int fd;

        if (argc < 2)
                errx(1, "must specify a path");

        if ((fd = open(oldpath, O_RDWR|O_CREAT|O_EXCL, 0644)) == -1)
                err(1, "open %s", oldpath);
        if (fsync(fd))
                err(1, "fsync %s", oldpath);
        if (close(fd))
                err(1, "close %s", oldpath);

        snprintf(newpath, sizeof newpath, "%s.tmp", oldpath);

        while (1) {
                if ((fd = open(newpath, O_RDWR|O_CREAT|O_EXCL, 0644)) == -1)
                        err(1, "open %s", newpath);
                if (fsync(fd))
                        err(1, "fsync %s", newpath);
                if (close(fd))
                        err(1, "close %s", newpath);
                if (rename(newpath, oldpath))
                        err(1, "rename");
        }

        return (0);
}
===========================8<===================================

http://www.vantronix.net/~mike/nfs2.c
===========================8<===================================
#include <sys/param.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <err.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

int
main(int argc, char **argv)
{
        int fd, nsuccess = 0;

        if (argc < 2)
                errx(1, "must specify a path");

        while (1) {
                if ((fd = open(argv[1], O_RDONLY)) == -1)
                        goto fail;
                nsuccess++;
                close(fd);
        }

fail:
        fprintf(stderr, "failed after %d successful opens\n", nsuccess);
        return (0);
}
===========================8<===================================

Reply via email to