fixes
authorMiklos Szeredi <miklos@szeredi.hu>
Sun, 8 Oct 2006 15:41:20 +0000 (15:41 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Sun, 8 Oct 2006 15:41:20 +0000 (15:41 +0000)
ChangeLog
lib/fuse.c
lib/ulockmgr.c
test/test.c
util/Makefile.am
util/udev.rules
util/ulockmgr_server.c

index 29bb805ed2c448b60b9e8a7497f9ce492ccbf95c..c034ccf4461d90089c9cb6636da802c6d4a58425 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2006-10-08  Miklos Szeredi <miklos@szeredi.hu>
+
+       * Make sure inode numers wrap around at 2^32.  This is needed on
+       dual 64bit/32bit architectures, because 32bit applications using
+       the non-largefile interface would otherwise break (EOVERFLOW error
+       would be returned by the stat() system call family)
+
+       * ulockmgr: handle the case, when a locking operation fails
+       because no more file desctriptors are available in
+       ulockmgr_server.  Also work around a Linux kernel bug (known to
+       exist for all Linux kernel versions <= 2.6.19) which may cause
+       sent file descriptors to be lost in the above case
+
+       * ulockmgr: optimize file descriptor use
+
+       * restore needed cpp flags to util/Makefile.am
+
+       * Install udev rules as 99-fuse.rules instead of 60-fuse.rules
+
+       * Minor clean up of udev rules
+
 2006-10-01  Miklos Szeredi <miklos@szeredi.hu>
 
        * Released 2.6.0-rc2
index c87bff3b4e09c9c5f6738d81cb1e13a6580c6f08..8fc1bac1ae04e6cba0def4664369a55da0bd0039 100644 (file)
@@ -256,10 +256,11 @@ static void unref_node(struct fuse *f, struct node *node)
 static fuse_ino_t next_id(struct fuse *f)
 {
     do {
-        f->ctr++;
+        f->ctr = (f->ctr + 1) & 0xffffffff;
         if (!f->ctr)
             f->generation ++;
-    } while (f->ctr == 0 || get_node_nocheck(f, f->ctr) != NULL);
+    } while (f->ctr == 0 || f->ctr == FUSE_UNKNOWN_INO ||
+             get_node_nocheck(f, f->ctr) != NULL);
     return f->ctr;
 }
 
index 012a45073d49eceac77ec3a3cbb7099797a996db..9e9c2b65a1b91676be86c21ebccd9b0c7320ace5 100644 (file)
@@ -22,7 +22,8 @@
 #include <sys/wait.h>
 
 struct message {
-    int intr;
+    unsigned intr : 1;
+    unsigned nofd : 1;
     pthread_t thr;
     int cmd;
     int fd;
@@ -33,7 +34,7 @@ struct message {
 struct fd_store {
     struct fd_store *next;
     int fd;
-    int finished;
+    int inuse;
 };
 
 struct owner {
@@ -176,7 +177,9 @@ static int ulockmgr_send_request(struct message *msg, const void *id,
     int sv[2];
     int cfd;
     struct owner *o;
-    struct fd_store *f;
+    struct fd_store *f = NULL;
+    struct fd_store *newf = NULL;
+    struct fd_store **fp;
     int fd = msg->fd;
     int cmd = msg->cmd;
     int res;
@@ -203,32 +206,51 @@ static int ulockmgr_send_request(struct message *msg, const void *id,
             return -ENOLCK;
     }
 
-    f = calloc(1, sizeof(struct fd_store));
-    if (!f) {
-        fprintf(stderr, "libulockmgr: failed to allocate memory\n");
-        return -ENOLCK;
+    if (unlockall)
+        msg->nofd = 1;
+    else {
+        for (fp = &o->fds; *fp; fp = &(*fp)->next) {
+            f = *fp;
+            if (f->fd == fd) {
+                msg->nofd = 1;
+                break;
+            }
+        }
+    }
+
+    if (!msg->nofd) {
+        newf = f = calloc(1, sizeof(struct fd_store));
+        if (!f) {
+            fprintf(stderr, "libulockmgr: failed to allocate memory\n");
+            return -ENOLCK;
+        }
     }
 
     res = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
     if (res == -1) {
         perror("libulockmgr: socketpair");
-        free(f);
+        free(newf);
         return -ENOLCK;
     }
 
     cfd = sv[1];
     sv[1] = msg->fd;
-    res = ulockmgr_send_message(o->cfd, msg, sizeof(struct message), sv, 2);
+    res = ulockmgr_send_message(o->cfd, msg, sizeof(struct message), sv,
+                                msg->nofd ? 1 : 2);
     close(sv[0]);
     if (res == -1) {
-        free(f);
+        free(newf);
         close(cfd);
         return -EIO;
     }
 
-    f->fd = msg->fd;
-    f->next = o->fds;
-    o->fds = f;
+    if (newf) {
+        newf->fd = msg->fd;
+        newf->next = o->fds;
+        o->fds = newf;
+    }
+    if (f)
+        f->inuse++;
 
     res = recv(cfd, msg, sizeof(struct message), MSG_WAITALL);
     if (res == -1) {
@@ -278,15 +300,13 @@ static int ulockmgr_send_request(struct message *msg, const void *id,
         pthread_mutex_lock(&ulockmgr_lock);
 
     }
-
-    f->finished = 1;
+    if (f)
+        f->inuse--;
     close(cfd);
     if (unlockall) {
-        struct fd_store **fp;
-
         for (fp = &o->fds; *fp;) {
             f = *fp;
-            if (f->fd == fd && f->finished) {
+            if (f->fd == fd && !f->inuse) {
                 *fp = f->next;
                 free(f);
             } else
index bbe937ee7b4f0ca9ca72c5eb32c452222721fbd0..c5ee786a014cbcdd977b4f755565c27ee8c886b1 100644 (file)
@@ -841,6 +841,56 @@ static int test_symlink(void)
     return 0;
 }
 
+static int test_link(void)
+{
+    const char *data = testdata;
+    int datalen = testdatalen;
+    int err = 0;
+    int res;
+
+    start_test("link");
+    res = create_file(testfile, data, datalen);
+    if (res == -1)
+        return -1;
+
+    unlink(testfile2);
+    res = link(testfile, testfile2);
+    if (res == -1) {
+        PERROR("link");
+        return -1;
+    }
+    res = check_type(testfile2, S_IFREG);
+    if (res == -1)
+        return -1;
+    err += check_mode(testfile2, 0644);
+    err += check_nlink(testfile2, 2);
+    err += check_size(testfile2, datalen);
+    err += check_data(testfile2, data, 0, datalen);
+    res = unlink(testfile);
+    if (res == -1) {
+        PERROR("unlink");
+        return -1;
+    }
+    res = check_nonexist(testfile);
+    if (res == -1)
+        return -1;
+
+    err += check_nlink(testfile2, 1);
+    res = unlink(testfile2);
+    if (res == -1) {
+        PERROR("unlink");
+        return -1;
+    }
+    res = check_nonexist(testfile2);
+    if (res == -1)
+        return -1;
+    if (err)
+        return -1;
+
+    success();
+    return 0;
+}
+
 static int test_rename_file(void)
 {
     const char *data = testdata;
@@ -1014,6 +1064,7 @@ int main(int argc, char *argv[])
     sprintf(testdir2, "%s/testdir2", basepath);
     err += test_create();
     err += test_symlink();
+    err += test_link();
     err += test_mkfifo();
     err += test_mkdir();
     err += test_rename_file();
index d963e81461de2fab4ab433db7857c7f8304bb912..6572afe8c1869c90ad91403465922559b328d11b 100644 (file)
@@ -1,10 +1,12 @@
 ## Process this file with automake to produce Makefile.in
 
+AM_CPPFLAGS = -D_FILE_OFFSET_BITS=64 
 bin_PROGRAMS = fusermount ulockmgr_server
 
 fusermount_SOURCES = fusermount.c
 
 ulockmgr_server_SOURCES = ulockmgr_server.c
+ulockmgr_server_CPPFLAGS = -D_FILE_OFFSET_BITS=64 -D_REENTRANT 
 ulockmgr_server_LDFLAGS = -pthread
 
 install-exec-hook:
@@ -34,11 +36,11 @@ install-exec-local:
 
 install-data-local:
        $(mkdir_p) $(DESTDIR)$(UDEV_RULES_PATH)
-       $(INSTALL_DATA) $(srcdir)/udev.rules $(DESTDIR)$(UDEV_RULES_PATH)/60-fuse.rules
+       $(INSTALL_DATA) $(srcdir)/udev.rules $(DESTDIR)$(UDEV_RULES_PATH)/99-fuse.rules
 
 uninstall-local:
        rm -f $(DESTDIR)$(MOUNT_FUSE_PATH)/mount.fuse
-       rm -f $(DESTDIR)$(UDEV_RULES_PATH)/60-fuse.rules
+       rm -f $(DESTDIR)$(UDEV_RULES_PATH)/99-fuse.rules
        rm -f $(DESTDIR)$(INIT_D_PATH)/fuse
        @if test -x /usr/sbin/update-rc.d; then \
                echo "/usr/sbin/update-rc.d fuse remove"; \
index e378073bd7a4679ffc37eb5120a704c11776a942..958511146e7c33e25273a8240f8d9b88cc0d7be1 100644 (file)
@@ -1 +1 @@
-KERNEL=="fuse", NAME="%k", MODE="0666"
+KERNEL=="fuse", MODE="0666"
index a2d686325d1f330f600810d227453c7469eccd04..0d00975f44ca415a1e211d75f2ccaafc2e583d53 100644 (file)
@@ -23,7 +23,8 @@
 #include <sys/wait.h>
 
 struct message {
-    int intr;
+    unsigned intr : 1;
+    unsigned nofd : 1;
     pthread_t thr;
     int cmd;
     int fd;
@@ -35,7 +36,7 @@ struct fd_store {
     struct fd_store *next;
     int fd;
     int origfd;
-    int finished;
+    int inuse;
 };
 
 struct owner {
@@ -53,19 +54,21 @@ struct req_data {
 #define MAX_SEND_FDS 2
 
 static int receive_message(int sock, void *buf, size_t buflen, int *fdp,
-                           int numfds)
+                           int *numfds)
 {
     struct msghdr msg;
     struct iovec iov;
     char ccmsg[CMSG_SPACE(sizeof(int)) * MAX_SEND_FDS];
     struct cmsghdr *cmsg;
     int res;
+    int i;
 
-    assert(numfds <= MAX_SEND_FDS);
+    assert(*numfds <= MAX_SEND_FDS);
     iov.iov_base = buf;
     iov.iov_len = buflen;
 
     memset(&msg, 0, sizeof(msg));
+    memset(ccmsg, -1, sizeof(ccmsg));
     msg.msg_iov = &iov;
     msg.msg_iovlen = 1;
     msg.msg_control = ccmsg;
@@ -90,7 +93,26 @@ static int receive_message(int sock, void *buf, size_t buflen, int *fdp,
                     cmsg->cmsg_type);
             return -1;
         }
-        memcpy(fdp, CMSG_DATA(cmsg), sizeof(int) * numfds);
+        memcpy(fdp, CMSG_DATA(cmsg), sizeof(int) * *numfds);
+        if (msg.msg_flags & MSG_CTRUNC) {
+            fprintf(stderr, "ulockmgr_server: control message truncated\n");
+            for (i = 0; i < *numfds; i++)
+                close(fdp[i]);
+            *numfds = 0;
+        }
+    } else {
+        if (msg.msg_flags & MSG_CTRUNC) {
+            fprintf(stderr, "ulockmgr_server: control message truncated(*)\n");
+
+            /* There's a bug in the Linux kernel, that if not all file
+               descriptors were allocated, then the cmsg header is not
+               filled in */
+            cmsg = (struct cmsghdr *) ccmsg;
+            memcpy(fdp, CMSG_DATA(cmsg), sizeof(int) * *numfds);
+            for (i = 0; i < *numfds; i++)
+                close(fdp[i]);
+        }
+        *numfds = 0;
     }
     return res;
 }
@@ -137,7 +159,7 @@ static void *process_request(void *d_)
     }
     d->msg.error = (res == -1) ? errno : 0;
     pthread_mutex_lock(&d->o->lock);
-    d->f->finished = 1;
+    d->f->inuse--;
     pthread_mutex_unlock(&d->o->lock);
     send_reply(d->cfd, &d->msg);
     close(d->cfd);
@@ -149,7 +171,9 @@ static void *process_request(void *d_)
 static void process_message(struct owner *o, struct message *msg, int cfd,
                             int fd)
 {
-    struct fd_store *f;
+    struct fd_store *f = NULL;
+    struct fd_store *newf = NULL;
+    struct fd_store **fp;
     struct req_data *d;
     pthread_t tid;
     int res;
@@ -162,18 +186,17 @@ static void process_message(struct owner *o, struct message *msg, int cfd,
 
     if (msg->cmd == F_SETLK  && msg->lock.l_type == F_UNLCK && 
         msg->lock.l_start == 0 && msg->lock.l_len == 0) {
-        struct fd_store **fp;
-
         for (fp = &o->fds; *fp;) {
-            struct fd_store *f = *fp;
-            if (f->origfd == msg->fd && f->finished) {
+            f = *fp;
+            if (f->origfd == msg->fd && !f->inuse) {
                 close(f->fd);
                 *fp = f->next;
                 free(f);
             } else
                 fp = &f->next;
         }
-        close(fd);
+        if (!msg->nofd)
+            close(fd);
 
         msg->error = 0;
         send_reply(cfd, msg);
@@ -181,16 +204,32 @@ static void process_message(struct owner *o, struct message *msg, int cfd,
         return;
     }
 
-    f = malloc(sizeof(struct fd_store));
-    if (!f) {
-        msg->error = ENOLCK;
-        send_reply(cfd, msg);
-        close(cfd);
-        return;
-    }
+    if (msg->nofd) {
+        for (fp = &o->fds; *fp; fp = &(*fp)->next) {
+            f = *fp;
+            if (f->origfd == msg->fd)
+                break;
+        }
+        if (!*fp) {
+            fprintf(stderr, "ulockmgr_server: fd %i not found\n", msg->fd);
+            msg->error = EIO;
+            send_reply(cfd, msg);
+            close(cfd);
+            return;
+        }
+    } else {
+        newf = f = malloc(sizeof(struct fd_store));
+        if (!f) {
+            msg->error = ENOLCK;
+            send_reply(cfd, msg);
+            close(cfd);
+            return;
+        }
 
-    f->fd = fd;
-    f->origfd = msg->fd;
+        f->fd = fd;
+        f->origfd = msg->fd;
+        f->inuse = 0;
+    }
 
     if (msg->cmd == F_GETLK || msg->cmd == F_SETLK ||
         msg->lock.l_type == F_UNLCK) {
@@ -198,9 +237,10 @@ static void process_message(struct owner *o, struct message *msg, int cfd,
         msg->error = (res == -1) ? errno : 0;
         send_reply(cfd, msg);
         close(cfd);
-        f->next = o->fds;
-        o->fds = f;
-        f->finished = 1;
+        if (newf) {
+            newf->next = o->fds;
+            o->fds = newf;
+        }
         return;
     }
 
@@ -209,10 +249,11 @@ static void process_message(struct owner *o, struct message *msg, int cfd,
         msg->error = ENOLCK;
         send_reply(cfd, msg);
         close(cfd);
-        free(f);
+        free(newf);
         return;
     }
 
+    f->inuse++;
     d->o = o;
     d->cfd = cfd;
     d->f = f;
@@ -223,12 +264,15 @@ static void process_message(struct owner *o, struct message *msg, int cfd,
         send_reply(cfd, msg);
         close(cfd);
         free(d);
-        free(f);
+        f->inuse--;
+        free(newf);
         return;
     }
 
-    f->next = o->fds;
-    o->fds = f;
+    if (newf) {
+        newf->next = o->fds;
+        o->fds = newf;
+    }
     pthread_detach(tid);
 }
 
@@ -258,16 +302,22 @@ static void process_owner(int cfd)
         struct message msg;
         int rfds[2];
         int res;
+        int numfds = 2;
 
-        res  = receive_message(cfd, &msg, sizeof(msg), rfds, 2);
+        res  = receive_message(cfd, &msg, sizeof(msg), rfds, &numfds);
         if (!res)
             break;
         if (res == -1)
             exit(1);
 
-        if (msg.intr)
+        if (msg.intr) {
+            if (numfds != 0)
+                fprintf(stderr, "ulockmgr_server: too many fds for intr\n");
             pthread_kill(msg.thr, SIGUSR1);
-        else {
+        } else {
+            if (numfds != 2)
+                continue;
+
             pthread_mutex_lock(&o.lock);
             process_message(&o, &msg, rfds[0], rfds[1]);
             pthread_mutex_unlock(&o.lock);
@@ -313,11 +363,13 @@ int main(int argc, char *argv[])
         char c;
         int sock;
         int pid;
-        int res = receive_message(cfd, &c, sizeof(c), &sock, 1);
+        int numfds = 1;
+        int res = receive_message(cfd, &c, sizeof(c), &sock, &numfds);
         if (!res)
             break;
         if (res == -1)
             exit(1);
+        assert(numfds == 1);
 
         pid = fork();
         if (pid == -1) {