From 7e7fa1fb9429adf2061670c97ce30a39685daadd Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Sun, 8 Oct 2006 15:41:20 +0000 Subject: fixes --- ChangeLog | 21 +++++++++ lib/fuse.c | 5 ++- lib/ulockmgr.c | 56 ++++++++++++++++-------- test/test.c | 51 ++++++++++++++++++++++ util/Makefile.am | 6 ++- util/udev.rules | 2 +- util/ulockmgr_server.c | 116 +++++++++++++++++++++++++++++++++++-------------- 7 files changed, 202 insertions(+), 55 deletions(-) diff --git a/ChangeLog b/ChangeLog index 29bb805..c034ccf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +2006-10-08 Miklos Szeredi + + * 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 * Released 2.6.0-rc2 diff --git a/lib/fuse.c b/lib/fuse.c index c87bff3..8fc1bac 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -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; } diff --git a/lib/ulockmgr.c b/lib/ulockmgr.c index 012a450..9e9c2b6 100644 --- a/lib/ulockmgr.c +++ b/lib/ulockmgr.c @@ -22,7 +22,8 @@ #include 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 diff --git a/test/test.c b/test/test.c index bbe937e..c5ee786 100644 --- a/test/test.c +++ b/test/test.c @@ -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(); diff --git a/util/Makefile.am b/util/Makefile.am index d963e81..6572afe 100644 --- a/util/Makefile.am +++ b/util/Makefile.am @@ -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"; \ diff --git a/util/udev.rules b/util/udev.rules index e378073..9585111 100644 --- a/util/udev.rules +++ b/util/udev.rules @@ -1 +1 @@ -KERNEL=="fuse", NAME="%k", MODE="0666" +KERNEL=="fuse", MODE="0666" diff --git a/util/ulockmgr_server.c b/util/ulockmgr_server.c index a2d6863..0d00975 100644 --- a/util/ulockmgr_server.c +++ b/util/ulockmgr_server.c @@ -23,7 +23,8 @@ #include 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) { -- cgit v1.2.3