From 7eafccef7f5788e54efa5318d9f5af13a0cbd291 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Sat, 19 Jun 2004 22:42:38 +0000 Subject: [PATCH] pre-allocate request structures --- ChangeLog | 4 + kernel/.cvsignore | 1 + kernel/dev.c | 264 +++++++++++--------- kernel/dir.c | 613 +++++++++++++++++++++++++--------------------- kernel/file.c | 284 ++++++++++----------- kernel/fuse_i.h | 164 +++++++------ kernel/inode.c | 56 ++--- kernel/util.c | 8 - lib/fuse.c | 278 ++++++++++----------- lib/fuse_mt.c | 16 +- lufis/lufis.c | 10 +- 11 files changed, 906 insertions(+), 792 deletions(-) diff --git a/ChangeLog b/ChangeLog index afbdd65..4126df2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2004-06-19 Miklos Szeredi + + * Requests are allocated at open time + 2004-06-03 Miklos Szeredi * Build shared library as well as static (using libtool) diff --git a/kernel/.cvsignore b/kernel/.cvsignore index 2852fde..9722e6c 100644 --- a/kernel/.cvsignore +++ b/kernel/.cvsignore @@ -4,3 +4,4 @@ Makefile *.mod.c *.ko *.s +.tmp_versions diff --git a/kernel/dev.c b/kernel/dev.c index af20de8..84d4d99 100644 --- a/kernel/dev.c +++ b/kernel/dev.c @@ -19,27 +19,21 @@ static struct proc_dir_entry *proc_fs_fuse; struct proc_dir_entry *proc_fuse_dev; static kmem_cache_t *fuse_req_cachep; -static struct fuse_req *request_new(void) +struct fuse_req *fuse_request_alloc(void) { struct fuse_req *req; - req = (struct fuse_req *) kmem_cache_alloc(fuse_req_cachep, SLAB_NOFS); + req = (struct fuse_req *) kmem_cache_alloc(fuse_req_cachep, SLAB_KERNEL); if (req) { + memset(req, 0, sizeof(*req)); INIT_LIST_HEAD(&req->list); - req->issync = 0; - req->locked = 0; - req->interrupted = 0; - req->sent = 0; - req->finished = 0; - req->in = NULL; - req->out = NULL; init_waitqueue_head(&req->waitq); } return req; } -static void request_free(struct fuse_req *req) +void fuse_request_free(struct fuse_req *req) { kmem_cache_free(fuse_req_cachep, req); } @@ -49,11 +43,17 @@ static int request_restartable(enum fuse_opcode opcode) switch (opcode) { case FUSE_LOOKUP: case FUSE_GETATTR: + case FUSE_SETATTR: case FUSE_READLINK: case FUSE_GETDIR: case FUSE_OPEN: case FUSE_READ: case FUSE_WRITE: + case FUSE_STATFS: + case FUSE_FSYNC: + case FUSE_GETXATTR: + case FUSE_SETXATTR: + case FUSE_LISTXATTR: return 1; default: @@ -83,10 +83,10 @@ static void request_wait_answer(struct fuse_req *req) /* Operations which modify the filesystem cannot safely be restarted, because it is uncertain whether the operation has completed or not... */ - if (req->sent && !request_restartable(req->in->h.opcode)) - req->out->h.error = -EINTR; + if (req->sent && !request_restartable(req->in.h.opcode)) + req->out.h.error = -EINTR; else - req->out->h.error = -ERESTARTSYS; + req->out.h.error = -ERESTARTSYS; } static int get_unique(struct fuse_conn *fc) @@ -96,125 +96,126 @@ static int get_unique(struct fuse_conn *fc) return fc->reqctr; } -/* Must be called with fuse_lock held, and unlocks it */ -static void request_end(struct fuse_conn *fc, struct fuse_req *req) +static struct fuse_req *do_get_request(struct fuse_conn *fc) { - fuse_reqend_t endfunc = req->end; + struct fuse_req *req; - if (!endfunc) { - wake_up(&req->waitq); - spin_unlock(&fuse_lock); - } else { - spin_unlock(&fuse_lock); - endfunc(fc, req->in, req->out, req->data); - request_free(req); - up(&fc->outstanding); - } + spin_lock(&fuse_lock); + BUG_ON(list_empty(&fc->unused_list)); + req = list_entry(fc->unused_list.next, struct fuse_req, list); + list_del_init(&req->list); + spin_unlock(&fuse_lock); + + memset(req, 0, sizeof(*req)); + INIT_LIST_HEAD(&req->list); + init_waitqueue_head(&req->waitq); + + return req; } -void request_send(struct fuse_conn *fc, struct fuse_in *in, - struct fuse_out *out) +struct fuse_req *fuse_get_request(struct fuse_conn *fc) { struct fuse_req *req; + + if (down_interruptible(&fc->unused_sem)) + return NULL; - out->h.error = -ERESTARTSYS; - if (down_interruptible(&fc->outstanding)) - return; + req = do_get_request(fc); + req->in.h.uid = current->fsuid; + req->in.h.gid = current->fsgid; + return req; +} - out->h.error = -ENOMEM; - req = request_new(); - if (req) { - req->in = in; - req->out = out; - req->issync = 1; - req->end = NULL; - - spin_lock(&fuse_lock); - out->h.error = -ENOTCONN; - if (fc->file) { - in->h.unique = get_unique(fc); - list_add_tail(&req->list, &fc->pending); - wake_up(&fc->waitq); - request_wait_answer(req); - list_del(&req->list); - } - spin_unlock(&fuse_lock); - request_free(req); - } +struct fuse_req *fuse_get_request_nonblock(struct fuse_conn *fc) +{ + struct fuse_req *req; - up(&fc->outstanding); + if (down_trylock(&fc->unused_sem)) + return NULL; + + req = do_get_request(fc); + req->in.h.uid = current->fsuid; + req->in.h.gid = current->fsgid; + return req; } - -static inline void destroy_request(struct fuse_req *req) +struct fuse_req *fuse_get_request_nonint(struct fuse_conn *fc) { - if (req) { - kfree(req->in); - request_free(req); - } + down(&fc->unused_sem); + + return do_get_request(fc); } -/* This one is currently only used for sending FORGET and RELEASE, - which are kernel initiated request. So the outstanding semaphore - is not used. */ -int request_send_noreply(struct fuse_conn *fc, struct fuse_in *in) -{ - struct fuse_req *req; - req = request_new(); - if (!req) - return -ENOMEM; +void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req) +{ + spin_lock(&fuse_lock); + list_add(&req->list, &fc->unused_list); + spin_unlock(&fuse_lock); + up(&fc->unused_sem); +} - req->in = in; - req->issync = 0; +/* Must be called with fuse_lock held, and unlocks it */ +static void request_end(struct fuse_conn *fc, struct fuse_req *req) +{ + fuse_reqend_t endfunc = req->end; - spin_lock(&fuse_lock); - if (!fc->file) { + if (!endfunc) { + wake_up(&req->waitq); spin_unlock(&fuse_lock); - request_free(req); - return -ENOTCONN; + } else { + spin_unlock(&fuse_lock); + endfunc(fc, req); } +} - list_add_tail(&req->list, &fc->pending); - wake_up(&fc->waitq); +void request_send(struct fuse_conn *fc, struct fuse_req *req) +{ + req->issync = 1; + req->end = NULL; + + spin_lock(&fuse_lock); + req->out.h.error = -ENOTCONN; + if (fc->file) { + req->in.h.unique = get_unique(fc); + list_add_tail(&req->list, &fc->pending); + wake_up(&fc->waitq); + request_wait_answer(req); + list_del(&req->list); + } spin_unlock(&fuse_lock); - return 0; } -int request_send_nonblock(struct fuse_conn *fc, struct fuse_in *in, - struct fuse_out *out, fuse_reqend_t end, void *data) +void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req) { - int err; - struct fuse_req *req; - - BUG_ON(!end); - - if (down_trylock(&fc->outstanding)) - return -EWOULDBLOCK; + req->issync = 0; - err = -ENOMEM; - req = request_new(); - if (req) { - req->in = in; - req->out = out; - req->issync = 1; - req->end = end; - req->data = data; + spin_lock(&fuse_lock); + if (fc->file) { + list_add_tail(&req->list, &fc->pending); + wake_up(&fc->waitq); + } else + fuse_put_request(fc, req); + spin_unlock(&fuse_lock); +} - spin_lock(&fuse_lock); - err = -ENOTCONN; - if (fc->file) { - in->h.unique = get_unique(fc); - list_add_tail(&req->list, &fc->pending); - wake_up(&fc->waitq); - spin_unlock(&fuse_lock); - return 0; - } +void request_send_nonblock(struct fuse_conn *fc, struct fuse_req *req, + fuse_reqend_t end, void *data) +{ + req->end = end; + req->data = data; + req->issync = 1; + + spin_lock(&fuse_lock); + if (fc->file) { + req->in.h.unique = get_unique(fc); + list_add_tail(&req->list, &fc->pending); + wake_up(&fc->waitq); spin_unlock(&fuse_lock); - request_free(req); + } else { + req->out.h.error = -ENOTCONN; + request_end(fc, req); } - up(&fc->outstanding); - return err; } static void request_wait(struct fuse_conn *fc) @@ -292,11 +293,11 @@ static ssize_t fuse_dev_read(struct file *file, char *buf, size_t nbytes, if (req == NULL) return -EINTR; - ret = copy_in_args(req->in, buf, nbytes); + ret = copy_in_args(&req->in, buf, nbytes); spin_lock(&fuse_lock); if (req->issync) { if (ret < 0) { - req->out->h.error = -EPROTO; + req->out.h.error = -EPROTO; req->finished = 1; } else { list_add_tail(&req->list, &fc->processing); @@ -310,7 +311,7 @@ static ssize_t fuse_dev_read(struct file *file, char *buf, size_t nbytes, spin_unlock(&fuse_lock); } else { spin_unlock(&fuse_lock); - destroy_request(req); + fuse_put_request(fc, req); } return ret; } @@ -323,7 +324,7 @@ static struct fuse_req *request_find(struct fuse_conn *fc, unsigned int unique) list_for_each(entry, &fc->processing) { struct fuse_req *tmp; tmp = list_entry(entry, struct fuse_req, list); - if (tmp->in->h.unique == unique) { + if (tmp->in.h.unique == unique) { req = tmp; break; } @@ -335,7 +336,7 @@ static struct fuse_req *request_find(struct fuse_conn *fc, unsigned int unique) static void process_getdir(struct fuse_req *req) { struct fuse_getdir_out_i *arg; - arg = (struct fuse_getdir_out_i *) req->out->args[0].value; + arg = (struct fuse_getdir_out_i *) req->out.args[0].value; arg->file = fget(arg->fd); } @@ -495,15 +496,15 @@ static ssize_t fuse_dev_write(struct file *file, const char *buf, if (!req) return -ENOENT; - req->out->h = oh; - err = copy_out_args(req->out, buf, nbytes); + req->out.h = oh; + err = copy_out_args(&req->out, buf, nbytes); spin_lock(&fuse_lock); if (err) - req->out->h.error = -EPROTO; + req->out.h.error = -EPROTO; else { /* fget() needs to be done in this context */ - if (req->in->h.opcode == FUSE_GETDIR && !oh.error) + if (req->in.h.opcode == FUSE_GETDIR && !oh.error) process_getdir(req); } req->finished = 1; @@ -537,12 +538,32 @@ static unsigned int fuse_dev_poll(struct file *file, poll_table *wait) return mask; } +static void free_conn(struct fuse_conn *fc) +{ + while (!list_empty(&fc->unused_list)) { + struct fuse_req *req; + req = list_entry(fc->unused_list.next, struct fuse_req, list); + list_del(&req->list); + fuse_request_free(req); + } + kfree(fc); +} + +/* Must be called with the fuse lock held */ +void fuse_release_conn(struct fuse_conn *fc) +{ + if (fc->sb == NULL && fc->file == NULL) { + free_conn(fc); + } +} + static struct fuse_conn *new_conn(void) { struct fuse_conn *fc; fc = kmalloc(sizeof(*fc), GFP_KERNEL); if (fc != NULL) { + int i; memset(fc, 0, sizeof(*fc)); fc->sb = NULL; fc->file = NULL; @@ -551,7 +572,16 @@ static struct fuse_conn *new_conn(void) init_waitqueue_head(&fc->waitq); INIT_LIST_HEAD(&fc->pending); INIT_LIST_HEAD(&fc->processing); - sema_init(&fc->outstanding, MAX_OUTSTANDING); + INIT_LIST_HEAD(&fc->unused_list); + sema_init(&fc->unused_sem, MAX_OUTSTANDING); + for (i = 0; i < MAX_OUTSTANDING; i++) { + struct fuse_req *req = fuse_request_alloc(); + if (!req) { + free_conn(fc); + return NULL; + } + list_add(&req->list, &fc->unused_list); + } fc->reqctr = 1; } return fc; @@ -578,13 +608,13 @@ static void end_requests(struct fuse_conn *fc, struct list_head *head) req = list_entry(head->next, struct fuse_req, list); list_del_init(&req->list); if (req->issync) { - req->out->h.error = -ECONNABORTED; + req->out.h.error = -ECONNABORTED; req->finished = 1; /* Unlocks fuse_lock: */ request_end(fc, req); spin_lock(&fuse_lock); } else - destroy_request(req); + fuse_put_request(fc, req); } } @@ -657,7 +687,7 @@ void fuse_dev_cleanup() remove_proc_entry("version", proc_fs_fuse); remove_proc_entry("fuse", proc_root_fs); } - + kmem_cache_destroy(fuse_req_cachep); } diff --git a/kernel/dir.c b/kernel/dir.c index 9e2ac33..2cf0676 100644 --- a/kernel/dir.c +++ b/kernel/dir.c @@ -106,25 +106,27 @@ static int fuse_do_lookup(struct inode *dir, struct dentry *entry, struct fuse_entry_out *outarg, int *version) { struct fuse_conn *fc = INO_FC(dir); - struct fuse_in in = FUSE_IN_INIT; - struct fuse_out out = FUSE_OUT_INIT; - + struct fuse_req *req; + int err; if (entry->d_name.len > FUSE_NAME_MAX) return -ENAMETOOLONG; - - in.h.opcode = FUSE_LOOKUP; - in.h.ino = dir->i_ino; - in.numargs = 1; - in.args[0].size = entry->d_name.len + 1; - in.args[0].value = entry->d_name.name; - out.numargs = 1; - out.args[0].size = sizeof(struct fuse_entry_out); - out.args[0].value = outarg; - request_send(fc, &in, &out); - - *version = out.h.unique; - return out.h.error; + req = fuse_get_request(fc); + if (!req) + return -ERESTARTSYS; + req->in.h.opcode = FUSE_LOOKUP; + req->in.h.ino = dir->i_ino; + req->in.numargs = 1; + req->in.args[0].size = entry->d_name.len + 1; + req->in.args[0].value = entry->d_name.name; + req->out.numargs = 1; + req->out.args[0].size = sizeof(struct fuse_entry_out); + req->out.args[0].value = outarg; + request_send(fc, req); + *version = req->out.h.unique; + err = req->out.h.error; + fuse_put_request(fc, req); + return err; } static inline unsigned long time_to_jiffies(unsigned long sec, @@ -187,31 +189,34 @@ static int _fuse_mknod(struct inode *dir, struct dentry *entry, int mode, dev_t rdev) { struct fuse_conn *fc = INO_FC(dir); - struct fuse_in in = FUSE_IN_INIT; - struct fuse_out out = FUSE_OUT_INIT; + struct fuse_req *req = fuse_get_request(fc); struct fuse_mknod_in inarg; struct fuse_entry_out outarg; + int err; + + if (!req) + return -ERESTARTSYS; memset(&inarg, 0, sizeof(inarg)); inarg.mode = mode; inarg.rdev = new_encode_dev(rdev); - - in.h.opcode = FUSE_MKNOD; - in.h.ino = dir->i_ino; - in.numargs = 2; - in.args[0].size = sizeof(inarg); - in.args[0].value = &inarg; - in.args[1].size = entry->d_name.len + 1; - in.args[1].value = entry->d_name.name; - out.numargs = 1; - out.args[0].size = sizeof(outarg); - out.args[0].value = &outarg; - request_send(fc, &in, &out); - - if (out.h.error) - return out.h.error; - - return lookup_new_entry(dir, entry, &outarg, out.h.unique, mode); + req->in.h.opcode = FUSE_MKNOD; + req->in.h.ino = dir->i_ino; + req->in.numargs = 2; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + req->in.args[1].size = entry->d_name.len + 1; + req->in.args[1].value = entry->d_name.name; + req->out.numargs = 1; + req->out.args[0].size = sizeof(outarg); + req->out.args[0].value = &outarg; + request_send(fc, req); + err = req->out.h.error; + if (!err) + err = lookup_new_entry(dir, entry, &outarg, req->out.h.unique, + mode); + fuse_put_request(fc, req); + return err; } static int _fuse_create(struct inode *dir, struct dentry *entry, int mode) @@ -223,125 +228,145 @@ static int _fuse_create(struct inode *dir, struct dentry *entry, int mode) static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode) { struct fuse_conn *fc = INO_FC(dir); - struct fuse_in in = FUSE_IN_INIT; - struct fuse_out out = FUSE_OUT_INIT; + struct fuse_req *req = fuse_get_request(fc); struct fuse_mkdir_in inarg; struct fuse_entry_out outarg; + int err; + + if (!req) + return -ERESTARTSYS; memset(&inarg, 0, sizeof(inarg)); inarg.mode = mode; - - in.h.opcode = FUSE_MKDIR; - in.h.ino = dir->i_ino; - in.numargs = 2; - in.args[0].size = sizeof(inarg); - in.args[0].value = &inarg; - in.args[1].size = entry->d_name.len + 1; - in.args[1].value = entry->d_name.name; - out.numargs = 1; - out.args[0].size = sizeof(outarg); - out.args[0].value = &outarg; - request_send(fc, &in, &out); - if (out.h.error) - return out.h.error; - - return lookup_new_entry(dir, entry, &outarg, out.h.unique, S_IFDIR); + req->in.h.opcode = FUSE_MKDIR; + req->in.h.ino = dir->i_ino; + req->in.numargs = 2; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + req->in.args[1].size = entry->d_name.len + 1; + req->in.args[1].value = entry->d_name.name; + req->out.numargs = 1; + req->out.args[0].size = sizeof(outarg); + req->out.args[0].value = &outarg; + request_send(fc, req); + err = req->out.h.error; + if (!err) + err = lookup_new_entry(dir, entry, &outarg, req->out.h.unique, + S_IFDIR); + fuse_put_request(fc, req); + return err; } static int fuse_symlink(struct inode *dir, struct dentry *entry, const char *link) { struct fuse_conn *fc = INO_FC(dir); - struct fuse_in in = FUSE_IN_INIT; - struct fuse_out out = FUSE_OUT_INIT; + struct fuse_req *req; struct fuse_entry_out outarg; unsigned int len = strlen(link) + 1; + int err; if (len > FUSE_SYMLINK_MAX) return -ENAMETOOLONG; - in.h.opcode = FUSE_SYMLINK; - in.h.ino = dir->i_ino; - in.numargs = 2; - in.args[0].size = entry->d_name.len + 1; - in.args[0].value = entry->d_name.name; - in.args[1].size = len; - in.args[1].value = link; - out.numargs = 1; - out.args[0].size = sizeof(outarg); - out.args[0].value = &outarg; - request_send(fc, &in, &out); - if (out.h.error) - return out.h.error; - - return lookup_new_entry(dir, entry, &outarg, out.h.unique, S_IFLNK); + req = fuse_get_request(fc); + if (!req) + return -ERESTARTSYS; + + req->in.h.opcode = FUSE_SYMLINK; + req->in.h.ino = dir->i_ino; + req->in.numargs = 2; + req->in.args[0].size = entry->d_name.len + 1; + req->in.args[0].value = entry->d_name.name; + req->in.args[1].size = len; + req->in.args[1].value = link; + req->out.numargs = 1; + req->out.args[0].size = sizeof(outarg); + req->out.args[0].value = &outarg; + request_send(fc, req); + err = req->out.h.error; + if (!err) + err = lookup_new_entry(dir, entry, &outarg, req->out.h.unique, + S_IFLNK); + fuse_put_request(fc, req); + return err; } static int fuse_unlink(struct inode *dir, struct dentry *entry) { struct fuse_conn *fc = INO_FC(dir); - struct fuse_in in = FUSE_IN_INIT; - struct fuse_out out = FUSE_OUT_INIT; - - in.h.opcode = FUSE_UNLINK; - in.h.ino = dir->i_ino; - in.numargs = 1; - in.args[0].size = entry->d_name.len + 1; - in.args[0].value = entry->d_name.name; - request_send(fc, &in, &out); - - if (!out.h.error) { + struct fuse_req *req = fuse_get_request(fc); + int err; + + if (!req) + return -ERESTARTSYS; + + req->in.h.opcode = FUSE_UNLINK; + req->in.h.ino = dir->i_ino; + req->in.numargs = 1; + req->in.args[0].size = entry->d_name.len + 1; + req->in.args[0].value = entry->d_name.name; + request_send(fc, req); + err = req->out.h.error; + if (!err) { /* Set nlink to zero so the inode can be cleared, if the inode does have more links this will be discovered at the next lookup/getattr */ /* FIXME: mark inode "not uptodate" */ entry->d_inode->i_nlink = 0; } - - return out.h.error; + fuse_put_request(fc, req); + return err; } static int fuse_rmdir(struct inode *dir, struct dentry *entry) { struct fuse_conn *fc = INO_FC(dir); - struct fuse_in in = FUSE_IN_INIT; - struct fuse_out out = FUSE_OUT_INIT; - - in.h.opcode = FUSE_RMDIR; - in.h.ino = dir->i_ino; - in.numargs = 1; - in.args[0].size = entry->d_name.len + 1; - in.args[0].value = entry->d_name.name; - request_send(fc, &in, &out); - if (!out.h.error) + struct fuse_req *req = fuse_get_request(fc); + int err; + + if (!req) + return -ERESTARTSYS; + + req->in.h.opcode = FUSE_RMDIR; + req->in.h.ino = dir->i_ino; + req->in.numargs = 1; + req->in.args[0].size = entry->d_name.len + 1; + req->in.args[0].value = entry->d_name.name; + request_send(fc, req); + err = req->out.h.error; + if (!err) entry->d_inode->i_nlink = 0; - - return out.h.error; + fuse_put_request(fc, req); + return err; } static int fuse_rename(struct inode *olddir, struct dentry *oldent, struct inode *newdir, struct dentry *newent) { struct fuse_conn *fc = INO_FC(olddir); - struct fuse_in in = FUSE_IN_INIT; - struct fuse_out out = FUSE_OUT_INIT; + struct fuse_req *req = fuse_get_request(fc); struct fuse_rename_in inarg; - - memset(&inarg, 0, sizeof(inarg)); - inarg.newdir = newdir->i_ino; + int err; - in.h.opcode = FUSE_RENAME; - in.h.ino = olddir->i_ino; - in.numargs = 3; - in.args[0].size = sizeof(inarg); - in.args[0].value = &inarg; - in.args[1].size = oldent->d_name.len + 1; - in.args[1].value = oldent->d_name.name; - in.args[2].size = newent->d_name.len + 1; - in.args[2].value = newent->d_name.name; - request_send(fc, &in, &out); + if (!req) + return -ERESTARTSYS; - return out.h.error; + memset(&inarg, 0, sizeof(inarg)); + inarg.newdir = newdir->i_ino; + req->in.h.opcode = FUSE_RENAME; + req->in.h.ino = olddir->i_ino; + req->in.numargs = 3; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + req->in.args[1].size = oldent->d_name.len + 1; + req->in.args[1].value = oldent->d_name.name; + req->in.args[2].size = newent->d_name.len + 1; + req->in.args[2].value = newent->d_name.name; + request_send(fc, req); + err = req->out.h.error; + fuse_put_request(fc, req); + return err; } static int fuse_link(struct dentry *entry, struct inode *newdir, @@ -349,52 +374,59 @@ static int fuse_link(struct dentry *entry, struct inode *newdir, { struct inode *inode = entry->d_inode; struct fuse_conn *fc = INO_FC(inode); - struct fuse_in in = FUSE_IN_INIT; - struct fuse_out out = FUSE_OUT_INIT; + struct fuse_req *req = fuse_get_request(fc); struct fuse_link_in inarg; struct fuse_entry_out outarg; - + int err; + + if (!req) + return -ERESTARTSYS; + memset(&inarg, 0, sizeof(inarg)); inarg.newdir = newdir->i_ino; - - in.h.opcode = FUSE_LINK; - in.h.ino = inode->i_ino; - in.numargs = 2; - in.args[0].size = sizeof(inarg); - in.args[0].value = &inarg; - in.args[1].size = newent->d_name.len + 1; - in.args[1].value = newent->d_name.name; - out.numargs = 1; - out.args[0].size = sizeof(outarg); - out.args[0].value = &outarg; - request_send(fc, &in, &out); - if (out.h.error) - return out.h.error; - - /* Invalidate old entry, so attributes are refreshed */ - d_invalidate(entry); - return lookup_new_entry(newdir, newent, &outarg, out.h.unique, - inode->i_mode); + req->in.h.opcode = FUSE_LINK; + req->in.h.ino = inode->i_ino; + req->in.numargs = 2; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + req->in.args[1].size = newent->d_name.len + 1; + req->in.args[1].value = newent->d_name.name; + req->out.numargs = 1; + req->out.args[0].size = sizeof(outarg); + req->out.args[0].value = &outarg; + request_send(fc, req); + err = req->out.h.error; + if (!err) { + /* Invalidate old entry, so attributes are refreshed */ + d_invalidate(entry); + err = lookup_new_entry(newdir, newent, &outarg, + req->out.h.unique, inode->i_mode); + } + fuse_put_request(fc, req); + return err; } int fuse_do_getattr(struct inode *inode) { struct fuse_conn *fc = INO_FC(inode); - struct fuse_in in = FUSE_IN_INIT; - struct fuse_out out = FUSE_OUT_INIT; + struct fuse_req *req = fuse_get_request(fc); struct fuse_attr_out arg; - - in.h.opcode = FUSE_GETATTR; - in.h.ino = inode->i_ino; - out.numargs = 1; - out.args[0].size = sizeof(arg); - out.args[0].value = &arg; - request_send(fc, &in, &out); - - if (!out.h.error) + int err; + + if (!req) + return -ERESTARTSYS; + + req->in.h.opcode = FUSE_GETATTR; + req->in.h.ino = inode->i_ino; + req->out.numargs = 1; + req->out.args[0].size = sizeof(arg); + req->out.args[0].value = &arg; + request_send(fc, req); + err = req->out.h.error; + if (!err) change_attributes(inode, &arg.attr); - - return out.h.error; + fuse_put_request(fc, req); + return err; } static int fuse_revalidate(struct dentry *entry) @@ -472,38 +504,46 @@ static int parse_dirfile(char *buf, size_t nbytes, struct file *file, return 0; } +static int fuse_checkdir(struct file *cfile, struct file *file) +{ + struct inode *inode; + if (!cfile) { + printk("fuse_getdir: invalid file\n"); + return -EPROTO; + } + inode = cfile->f_dentry->d_inode; + if (!S_ISREG(inode->i_mode)) { + printk("fuse_getdir: not a regular file\n"); + fput(cfile); + return -EPROTO; + } + + file->private_data = cfile; + return 0; +} + static int fuse_getdir(struct file *file) { struct inode *inode = file->f_dentry->d_inode; struct fuse_conn *fc = INO_FC(inode); - struct fuse_in in = FUSE_IN_INIT; - struct fuse_out out = FUSE_OUT_INIT; + struct fuse_req *req = fuse_get_request(fc); struct fuse_getdir_out_i outarg; + int err; - in.h.opcode = FUSE_GETDIR; - in.h.ino = inode->i_ino; - out.numargs = 1; - out.args[0].size = sizeof(struct fuse_getdir_out); - out.args[0].value = &outarg; - request_send(fc, &in, &out); - if (!out.h.error) { - struct file *cfile = outarg.file; - struct inode *inode; - if (!cfile) { - printk("fuse_getdir: invalid file\n"); - return -EPROTO; - } - inode = cfile->f_dentry->d_inode; - if (!S_ISREG(inode->i_mode)) { - printk("fuse_getdir: not a regular file\n"); - fput(cfile); - return -EPROTO; - } - - file->private_data = cfile; - } + if (!req) + return -ERESTARTSYS; - return out.h.error; + req->in.h.opcode = FUSE_GETDIR; + req->in.h.ino = inode->i_ino; + req->out.numargs = 1; + req->out.args[0].size = sizeof(struct fuse_getdir_out); + req->out.args[0].value = &outarg; + request_send(fc, req); + err = req->out.h.error; + if (!err) + err = fuse_checkdir(outarg.file, file); + fuse_put_request(fc, req); + return err; } #define DIR_BUFSIZE 2048 @@ -539,27 +579,31 @@ static char *read_link(struct dentry *dentry) { struct inode *inode = dentry->d_inode; struct fuse_conn *fc = INO_FC(inode); - struct fuse_in in = FUSE_IN_INIT; - struct fuse_out out = FUSE_OUT_INIT; + struct fuse_req *req = fuse_get_request(fc); char *link; + if (!req) + return ERR_PTR(-ERESTARTSYS); + link = (char *) __get_free_page(GFP_KERNEL); - if (!link) - return ERR_PTR(-ENOMEM); - - in.h.opcode = FUSE_READLINK; - in.h.ino = inode->i_ino; - out.argvar = 1; - out.numargs = 1; - out.args[0].size = PAGE_SIZE - 1; - out.args[0].value = link; - request_send(fc, &in, &out); - if (out.h.error) { - free_page((unsigned long) link); - return ERR_PTR(out.h.error); + if (!link) { + link = ERR_PTR(-ENOMEM); + goto out; } - - link[out.args[0].size] = '\0'; + req->in.h.opcode = FUSE_READLINK; + req->in.h.ino = inode->i_ino; + req->out.argvar = 1; + req->out.numargs = 1; + req->out.args[0].size = PAGE_SIZE - 1; + req->out.args[0].value = link; + request_send(fc, req); + if (req->out.h.error) { + free_page((unsigned long) link); + link = ERR_PTR(req->out.h.error); + } else + link[req->out.args[0].size] = '\0'; + out: + fuse_put_request(fc, req); return link; } @@ -642,32 +686,35 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr) { struct inode *inode = entry->d_inode; struct fuse_conn *fc = INO_FC(inode); - struct fuse_in in = FUSE_IN_INIT; - struct fuse_out out = FUSE_OUT_INIT; + struct fuse_req *req = fuse_get_request(fc); struct fuse_setattr_in inarg; struct fuse_attr_out outarg; + int err; + + if (!req) + return -ERESTARTSYS; memset(&inarg, 0, sizeof(inarg)); inarg.valid = iattr_to_fattr(attr, &inarg.attr); - - in.h.opcode = FUSE_SETATTR; - in.h.ino = inode->i_ino; - in.numargs = 1; - in.args[0].size = sizeof(inarg); - in.args[0].value = &inarg; - out.numargs = 1; - out.args[0].size = sizeof(outarg); - out.args[0].value = &outarg; - request_send(fc, &in, &out); - - if (!out.h.error) { + req->in.h.opcode = FUSE_SETATTR; + req->in.h.ino = inode->i_ino; + req->in.numargs = 1; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + req->out.numargs = 1; + req->out.args[0].size = sizeof(outarg); + req->out.args[0].value = &outarg; + request_send(fc, req); + err = req->out.h.error; + if (!err) { if (attr->ia_valid & ATTR_SIZE && outarg.attr.size < i_size_read(inode)) vmtruncate(inode, outarg.attr.size); change_attributes(inode, &outarg.attr); } - return out.h.error; + fuse_put_request(fc, req); + return err; } static int _fuse_dentry_revalidate(struct dentry *entry) @@ -788,9 +835,9 @@ static int fuse_setxattr(struct dentry *entry, const char *name, { struct inode *inode = entry->d_inode; struct fuse_conn *fc = INO_FC(inode); - struct fuse_in in = FUSE_IN_INIT; - struct fuse_out out = FUSE_OUT_INIT; + struct fuse_req *req; struct fuse_setxattr_in inarg; + int err; if (size > FUSE_XATTR_SIZE_MAX) return -E2BIG; @@ -798,25 +845,30 @@ static int fuse_setxattr(struct dentry *entry, const char *name, if (fc->no_setxattr) return -EOPNOTSUPP; + req = fuse_get_request(fc); + if (!req) + return -ERESTARTSYS; + memset(&inarg, 0, sizeof(inarg)); inarg.size = size; inarg.flags = flags; - - in.h.opcode = FUSE_SETXATTR; - in.h.ino = inode->i_ino; - in.numargs = 3; - in.args[0].size = sizeof(inarg); - in.args[0].value = &inarg; - in.args[1].size = strlen(name) + 1; - in.args[1].value = name; - in.args[2].size = size; - in.args[2].value = value; - request_send(fc, &in, &out); - if (out.h.error == -ENOSYS) { + req->in.h.opcode = FUSE_SETXATTR; + req->in.h.ino = inode->i_ino; + req->in.numargs = 3; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + req->in.args[1].size = strlen(name) + 1; + req->in.args[1].value = name; + req->in.args[2].size = size; + req->in.args[2].value = value; + request_send(fc, req); + err = req->out.h.error; + if (err == -ENOSYS) { fc->no_setxattr = 1; - return -EOPNOTSUPP; + err = -EOPNOTSUPP; } - return out.h.error; + fuse_put_request(fc, req); + return err; } static ssize_t fuse_getxattr(struct dentry *entry, const char *name, @@ -824,110 +876,125 @@ static ssize_t fuse_getxattr(struct dentry *entry, const char *name, { struct inode *inode = entry->d_inode; struct fuse_conn *fc = INO_FC(inode); - struct fuse_in in = FUSE_IN_INIT; - struct fuse_out out = FUSE_OUT_INIT; + struct fuse_req *req; struct fuse_getxattr_in inarg; struct fuse_getxattr_out outarg; + ssize_t ret; if (fc->no_getxattr) return -EOPNOTSUPP; + req = fuse_get_request(fc); + if (!req) + return -ERESTARTSYS; + memset(&inarg, 0, sizeof(inarg)); inarg.size = size; - - in.h.opcode = FUSE_GETXATTR; - in.h.ino = inode->i_ino; - in.numargs = 2; - in.args[0].size = sizeof(inarg); - in.args[0].value = &inarg; - in.args[1].size = strlen(name) + 1; - in.args[1].value = name; + req->in.h.opcode = FUSE_GETXATTR; + req->in.h.ino = inode->i_ino; + req->in.numargs = 2; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + req->in.args[1].size = strlen(name) + 1; + req->in.args[1].value = name; /* This is really two different operations rolled into one */ - out.numargs = 1; + req->out.numargs = 1; if (size) { - out.argvar = 1; - out.args[0].size = size; - out.args[0].value = value; + req->out.argvar = 1; + req->out.args[0].size = size; + req->out.args[0].value = value; } else { - out.args[0].size = sizeof(outarg); - out.args[0].value = &outarg; + req->out.args[0].size = sizeof(outarg); + req->out.args[0].value = &outarg; } - request_send(fc, &in, &out); - if (!out.h.error) - return size ? out.args[0].size : outarg.size; + request_send(fc, req); + ret = req->out.h.error; + if (!ret) + ret = size ? req->out.args[0].size : outarg.size; else { - if (out.h.error == -ENOSYS) { + if (ret == -ENOSYS) { fc->no_getxattr = 1; - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; } - return out.h.error; } + fuse_put_request(fc, req); + return ret; } static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size) { struct inode *inode = entry->d_inode; struct fuse_conn *fc = INO_FC(inode); - struct fuse_in in = FUSE_IN_INIT; - struct fuse_out out = FUSE_OUT_INIT; + struct fuse_req *req; struct fuse_getxattr_in inarg; struct fuse_getxattr_out outarg; + ssize_t ret; if (fc->no_listxattr) return -EOPNOTSUPP; + req = fuse_get_request(fc); + if (!req) + return -ERESTARTSYS; + memset(&inarg, 0, sizeof(inarg)); inarg.size = size; - - in.h.opcode = FUSE_LISTXATTR; - in.h.ino = inode->i_ino; - in.numargs = 1; - in.args[0].size = sizeof(inarg); - in.args[0].value = &inarg; + req->in.h.opcode = FUSE_LISTXATTR; + req->in.h.ino = inode->i_ino; + req->in.numargs = 1; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; /* This is really two different operations rolled into one */ - out.numargs = 1; + req->out.numargs = 1; if (size) { - out.argvar = 1; - out.args[0].size = size; - out.args[0].value = list; + req->out.argvar = 1; + req->out.args[0].size = size; + req->out.args[0].value = list; } else { - out.args[0].size = sizeof(outarg); - out.args[0].value = &outarg; + req->out.args[0].size = sizeof(outarg); + req->out.args[0].value = &outarg; } - request_send(fc, &in, &out); - if (!out.h.error) - return size ? out.args[0].size : outarg.size; + request_send(fc, req); + ret = req->out.h.error; + if (!ret) + ret = size ? req->out.args[0].size : outarg.size; else { - if (out.h.error == -ENOSYS) { + if (ret == -ENOSYS) { fc->no_listxattr = 1; - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; } - return out.h.error; } + fuse_put_request(fc, req); + return ret; } static int fuse_removexattr(struct dentry *entry, const char *name) { struct inode *inode = entry->d_inode; struct fuse_conn *fc = INO_FC(inode); - struct fuse_in in = FUSE_IN_INIT; - struct fuse_out out = FUSE_OUT_INIT; + struct fuse_req *req; + int err; if (fc->no_removexattr) return -EOPNOTSUPP; - in.h.opcode = FUSE_REMOVEXATTR; - in.h.ino = inode->i_ino; - in.numargs = 1; - in.args[0].size = strlen(name) + 1; - in.args[0].value = name; - request_send(fc, &in, &out); - if (out.h.error == -ENOSYS) { + req = fuse_get_request(fc); + if (!req) + return -ERESTARTSYS; + + req->in.h.opcode = FUSE_REMOVEXATTR; + req->in.h.ino = inode->i_ino; + req->in.numargs = 1; + req->in.args[0].size = strlen(name) + 1; + req->in.args[0].value = name; + request_send(fc, req); + err = req->out.h.error; + if (err == -ENOSYS) { fc->no_removexattr = 1; - return -EOPNOTSUPP; + err = -EOPNOTSUPP; } - return out.h.error; - + fuse_put_request(fc, req); + return err; } #endif diff --git a/kernel/file.c b/kernel/file.c index 2067bd7..128c1b8 100644 --- a/kernel/file.c +++ b/kernel/file.c @@ -17,7 +17,9 @@ #ifndef KERNEL_2_6 #define PageUptodate(page) Page_Uptodate(page) #ifndef NO_MM +#ifndef filemap_fdatawrite #define filemap_fdatawrite filemap_fdatasync +#endif #else #define filemap_fdatawrite do {} while (0) #endif @@ -26,8 +28,7 @@ static int fuse_open(struct inode *inode, struct file *file) { struct fuse_conn *fc = INO_FC(inode); - struct fuse_in in = FUSE_IN_INIT; - struct fuse_out out = FUSE_OUT_INIT; + struct fuse_req *req; struct fuse_open_in inarg; int err; @@ -43,52 +44,50 @@ static int fuse_open(struct inode *inode, struct file *file) return err; } + req = fuse_get_request(fc); + if (!req) + return -ERESTARTSYS; + memset(&inarg, 0, sizeof(inarg)); inarg.flags = file->f_flags & ~O_EXCL; - - in.h.opcode = FUSE_OPEN; - in.h.ino = inode->i_ino; - in.numargs = 1; - in.args[0].size = sizeof(inarg); - in.args[0].value = &inarg; - request_send(fc, &in, &out); - if (!out.h.error && !(fc->flags & FUSE_KERNEL_CACHE)) { + req->in.h.opcode = FUSE_OPEN; + req->in.h.ino = inode->i_ino; + req->in.numargs = 1; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + request_send(fc, req); + err = req->out.h.error; + if (!err && !(fc->flags & FUSE_KERNEL_CACHE)) { #ifdef KERNEL_2_6 invalidate_inode_pages(inode->i_mapping); #else invalidate_inode_pages(inode); #endif } - - return out.h.error; + fuse_put_request(fc, req); + return err; } static int fuse_release(struct inode *inode, struct file *file) { struct fuse_conn *fc = INO_FC(inode); - struct fuse_in *in = NULL; - struct fuse_open_in *inarg = NULL; - unsigned int s = sizeof(struct fuse_in) + sizeof(struct fuse_open_in); - + struct fuse_open_in *inarg; + struct fuse_req *req; + if (file->f_mode & FMODE_WRITE) filemap_fdatawrite(inode->i_mapping); - in = kmalloc(s, GFP_NOFS); - if (!in) - return -ENOMEM; - memset(in, 0, s); - inarg = (struct fuse_open_in *) (in + 1); + req = fuse_get_request_nonint(fc); + inarg = &req->misc.open_in; inarg->flags = file->f_flags & ~O_EXCL; - - in->h.opcode = FUSE_RELEASE; - in->h.ino = inode->i_ino; - in->numargs = 1; - in->args[0].size = sizeof(struct fuse_open_in); - in->args[0].value = inarg; - if (!request_send_noreply(fc, in)) - return 0; - - kfree(in); + req->in.h.opcode = FUSE_RELEASE; + req->in.h.ino = inode->i_ino; + req->in.numargs = 1; + req->in.args[0].size = sizeof(struct fuse_open_in); + req->in.args[0].value = inarg; + request_send_noreply(fc, req); + + /* Return value is ignored by VFS */ return 0; } @@ -96,49 +95,58 @@ static int fuse_flush(struct file *file) { struct inode *inode = file->f_dentry->d_inode; struct fuse_conn *fc = INO_FC(inode); - struct fuse_in in = FUSE_IN_INIT; - struct fuse_out out = FUSE_OUT_INIT; + struct fuse_req *req; + int err; if (fc->no_flush) return 0; - in.h.opcode = FUSE_FLUSH; - in.h.ino = inode->i_ino; - request_send(fc, &in, &out); - if (out.h.error == -ENOSYS) { + req = fuse_get_request(fc); + if (!req) + return -EINTR; + + req->in.h.opcode = FUSE_FLUSH; + req->in.h.ino = inode->i_ino; + request_send(fc, req); + err = req->out.h.error; + if (err == -ENOSYS) { fc->no_flush = 1; - return 0; + err = 0; } - else - return out.h.error; + fuse_put_request(fc, req); + return err; } static int fuse_fsync(struct file *file, struct dentry *de, int datasync) { struct inode *inode = de->d_inode; struct fuse_conn *fc = INO_FC(inode); - struct fuse_in in = FUSE_IN_INIT; - struct fuse_out out = FUSE_OUT_INIT; + struct fuse_req *req; struct fuse_fsync_in inarg; + int err; if (fc->no_fsync) return 0; + req = fuse_get_request(fc); + if (!req) + return -ERESTARTSYS; + memset(&inarg, 0, sizeof(inarg)); inarg.datasync = datasync; - - in.h.opcode = FUSE_FSYNC; - in.h.ino = inode->i_ino; - in.numargs = 1; - in.args[0].size = sizeof(inarg); - in.args[0].value = &inarg; - request_send(fc, &in, &out); - - if (out.h.error == -ENOSYS) { + req->in.h.opcode = FUSE_FSYNC; + req->in.h.ino = inode->i_ino; + req->in.numargs = 1; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + request_send(fc, req); + err = req->out.h.error; + if (err == -ENOSYS) { fc->no_fsync = 1; - return 0; + err = 0; } - return out.h.error; + fuse_put_request(fc, req); + return err; /* FIXME: need to ensure, that all write requests issued before this request are completed. Should userspace take @@ -149,40 +157,42 @@ static int fuse_readpage(struct file *file, struct page *page) { struct inode *inode = page->mapping->host; struct fuse_conn *fc = INO_FC(inode); - struct fuse_in in = FUSE_IN_INIT; - struct fuse_out out = FUSE_OUT_INIT; + struct fuse_req *req; struct fuse_read_in inarg; char *buffer; + int err; buffer = kmap(page); + req = fuse_get_request(fc); + if (!req) + return -ERESTARTSYS; + memset(&inarg, 0, sizeof(inarg)); inarg.offset = (unsigned long long) page->index << PAGE_CACHE_SHIFT; inarg.size = PAGE_CACHE_SIZE; - - in.h.opcode = FUSE_READ; - in.h.ino = inode->i_ino; - in.numargs = 1; - in.args[0].size = sizeof(inarg); - in.args[0].value = &inarg; - out.argvar = 1; - out.numargs = 1; - out.args[0].size = PAGE_CACHE_SIZE; - out.args[0].value = buffer; - - request_send(fc, &in, &out); - if (!out.h.error) { - size_t outsize = out.args[0].size; + req->in.h.opcode = FUSE_READ; + req->in.h.ino = inode->i_ino; + req->in.numargs = 1; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + req->out.argvar = 1; + req->out.numargs = 1; + req->out.args[0].size = PAGE_CACHE_SIZE; + req->out.args[0].value = buffer; + request_send(fc, req); + err = req->out.h.error; + if (!err) { + size_t outsize = req->out.args[0].size; if (outsize < PAGE_CACHE_SIZE) memset(buffer + outsize, 0, PAGE_CACHE_SIZE - outsize); flush_dcache_page(page); SetPageUptodate(page); } - + fuse_put_request(fc, req); kunmap(page); unlock_page(page); - - return out.h.error; + return err; } static int fuse_is_block_uptodate(struct address_space *mapping, @@ -255,33 +265,34 @@ static int fuse_file_read_block(struct inode *inode, char *bl_buf, size_t bl_index) { struct fuse_conn *fc = INO_FC(inode); - struct fuse_in in = FUSE_IN_INIT; - struct fuse_out out = FUSE_OUT_INIT; + struct fuse_req *req = fuse_get_request(fc); struct fuse_read_in inarg; + int err; + + if (!req) + return -ERESTARTSYS; memset(&inarg, 0, sizeof(inarg)); inarg.offset = bl_index << FUSE_BLOCK_SHIFT; inarg.size = FUSE_BLOCK_SIZE; - - in.h.opcode = FUSE_READ; - in.h.ino = inode->i_ino; - in.numargs = 1; - in.args[0].size = sizeof(inarg); - in.args[0].value = &inarg; - out.argvar = 1; - out.numargs = 1; - out.args[0].size = FUSE_BLOCK_SIZE; - out.args[0].value = bl_buf; - - request_send(fc, &in, &out); - - if (!out.h.error) { - size_t outsize = out.args[0].size; + req->in.h.opcode = FUSE_READ; + req->in.h.ino = inode->i_ino; + req->in.numargs = 1; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + req->out.argvar = 1; + req->out.numargs = 1; + req->out.args[0].size = FUSE_BLOCK_SIZE; + req->out.args[0].value = bl_buf; + request_send(fc, req); + err = req->out.h.error; + if (!err) { + size_t outsize = req->out.args[0].size; if (outsize < FUSE_BLOCK_SIZE) memset(bl_buf + outsize, 0, FUSE_BLOCK_SIZE - outsize); } - - return out.h.error; + fuse_put_request(fc, req); + return err; } static void fuse_file_bigread(struct address_space *mapping, @@ -296,7 +307,7 @@ static void fuse_file_bigread(struct address_space *mapping, while (bl_index <= bl_end_index) { int res; - char *bl_buf = kmalloc(FUSE_BLOCK_SIZE, GFP_NOFS); + char *bl_buf = kmalloc(FUSE_BLOCK_SIZE, GFP_KERNEL); if (!bl_buf) break; res = fuse_is_block_uptodate(mapping, inode, bl_index); @@ -326,31 +337,35 @@ static int write_buffer(struct inode *inode, struct page *page, unsigned offset, size_t count) { struct fuse_conn *fc = INO_FC(inode); - struct fuse_in in = FUSE_IN_INIT; - struct fuse_out out = FUSE_OUT_INIT; + struct fuse_req *req; struct fuse_write_in inarg; char *buffer; + int err; buffer = kmap(page); + req = fuse_get_request(fc); + if (!req) + return -ERESTARTSYS; + memset(&inarg, 0, sizeof(inarg)); inarg.offset = ((unsigned long long) page->index << PAGE_CACHE_SHIFT) + offset; inarg.size = count; - - in.h.opcode = FUSE_WRITE; - in.h.ino = inode->i_ino; - in.numargs = 2; - in.args[0].size = sizeof(inarg); - in.args[0].value = &inarg; - in.args[1].size = count; - in.args[1].value = buffer + offset; - request_send(fc, &in, &out); + req->in.h.opcode = FUSE_WRITE; + req->in.h.ino = inode->i_ino; + req->in.numargs = 2; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + req->in.args[1].size = count; + req->in.args[1].value = buffer + offset; + request_send(fc, req); + err = req->out.h.error; + fuse_put_request(fc, req); kunmap(page); - if (out.h.error) + if (err) SetPageError(page); - - return out.h.error; + return err; } static int get_write_count(struct inode *inode, struct page *page) @@ -372,15 +387,14 @@ static int get_write_count(struct inode *inode, struct page *page) #ifdef KERNEL_2_6 -static void write_buffer_end(struct fuse_conn *fc, struct fuse_in *in, - struct fuse_out *out, void *_page) +static void write_buffer_end(struct fuse_conn *fc, struct fuse_req *req) { - struct page *page = (struct page *) _page; + struct page *page = (struct page *) req->data; lock_page(page); - if (out->h.error) { + if (req->out.h.error) { SetPageError(page); - if (out->h.error == -ENOSPC) + if (req->out.h.error == -ENOSPC) set_bit(AS_ENOSPC, &page->mapping->flags); else set_bit(AS_EIO, &page->mapping->flags); @@ -388,48 +402,34 @@ static void write_buffer_end(struct fuse_conn *fc, struct fuse_in *in, end_page_writeback(page); kunmap(page); unlock_page(page); - kfree(in); + fuse_put_request(fc, req); } static int write_buffer_nonblock(struct inode *inode, struct page *page, unsigned offset, size_t count) { - int err; struct fuse_conn *fc = INO_FC(inode); - struct fuse_in *in = NULL; - struct fuse_out *out = NULL; + struct fuse_req *req; struct fuse_write_in *inarg = NULL; char *buffer; - unsigned int s = sizeof(struct fuse_in) + sizeof(struct fuse_out) + - sizeof(struct fuse_write_in); - - in = kmalloc(s, GFP_NOFS); - if (!in) - return -ENOMEM; - memset(in, 0, s); - out = (struct fuse_out *)(in + 1); - inarg = (struct fuse_write_in *)(out + 1); - - buffer = kmap(page); + req = fuse_get_request_nonblock(fc); + if (!req) + return -EWOULDBLOCK; + + inarg = &req->misc.write_in; + buffer = kmap(page); inarg->offset = ((unsigned long long) page->index << PAGE_CACHE_SHIFT) + offset; inarg->size = count; - - in->h.opcode = FUSE_WRITE; - in->h.ino = inode->i_ino; - in->numargs = 2; - in->args[0].size = sizeof(struct fuse_write_in); - in->args[0].value = inarg; - in->args[1].size = count; - in->args[1].value = buffer + offset; - err = request_send_nonblock(fc, in, out, write_buffer_end, page); - if (err) { - if (err != -EWOULDBLOCK) - SetPageError(page); - kunmap(page); - kfree(in); - } - return err; + req->in.h.opcode = FUSE_WRITE; + req->in.h.ino = inode->i_ino; + req->in.numargs = 2; + req->in.args[0].size = sizeof(struct fuse_write_in); + req->in.args[0].value = inarg; + req->in.args[1].size = count; + req->in.args[1].value = buffer + offset; + request_send_nonblock(fc, req, write_buffer_end, page); + return 0; } static int fuse_writepage(struct page *page, struct writeback_control *wbc) diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h index d5943a9..f9daa7e 100644 --- a/kernel/fuse_i.h +++ b/kernel/fuse_i.h @@ -62,60 +62,6 @@ permission checking is done in the kernel */ than for small. */ #define FUSE_LARGE_READ (1 << 3) -/** - * A Fuse connection. - * - * This structure is created, when the client device is opened, and is - * destroyed, when the client device is closed _and_ the filesystem is - * unmounted. - */ -struct fuse_conn { - /** The superblock of the mounted filesystem */ - struct super_block *sb; - - /** The opened client device */ - struct file *file; - - /** The user id for this mount */ - uid_t uid; - - /** The fuse mount flags for this mount */ - unsigned int flags; - - /** Readers of the connection are waiting on this */ - wait_queue_head_t waitq; - - /** The list of pending requests */ - struct list_head pending; - - /** The list of requests being processed */ - struct list_head processing; - - /** Controls the maximum number of outstanding requests */ - struct semaphore outstanding; - - /** The next unique request id */ - int reqctr; - - /** Is fsync not implemented by fs? */ - unsigned int no_fsync : 1; - - /** Is flush not implemented by fs? */ - unsigned int no_flush : 1; - - /** Is setxattr not implemented by fs? */ - unsigned int no_setxattr : 1; - - /** Is getxattr not implemented by fs? */ - unsigned int no_getxattr : 1; - - /** Is listxattr not implemented by fs? */ - unsigned int no_listxattr : 1; - - /** Is removexattr not implemented by fs? */ - unsigned int no_removexattr : 1; -}; - /** One input argument of a request */ struct fuse_in_arg { unsigned int size; @@ -143,12 +89,10 @@ struct fuse_out { struct fuse_out_arg args[3]; }; -#define FUSE_IN_INIT { {0, 0, 0, current->fsuid, current->fsgid}, 0} -#define FUSE_OUT_INIT { {0, 0}, 0, 0} - struct fuse_req; -typedef void (*fuse_reqend_t)(struct fuse_conn *, struct fuse_in *, - struct fuse_out *, void *data); +struct fuse_conn; + +typedef void (*fuse_reqend_t)(struct fuse_conn *, struct fuse_req *); /** * A request to the client @@ -170,13 +114,13 @@ struct fuse_req { unsigned int sent:1; /* The request is finished */ - unsigned int finished:1; + unsigned int finished; /** The request input */ - struct fuse_in *in; + struct fuse_in in; /** The request output */ - struct fuse_out *out; + struct fuse_out out; /** Used to wake up the task waiting for completion of request*/ wait_queue_head_t waitq; @@ -186,6 +130,70 @@ struct fuse_req { /** User data */ void *data; + + /** Data for asynchronous requests */ + union { + struct fuse_write_in write_in; + struct fuse_open_in open_in; + struct fuse_forget_in forget_in; + } misc; +}; + +/** + * A Fuse connection. + * + * This structure is created, when the client device is opened, and is + * destroyed, when the client device is closed _and_ the filesystem is + * unmounted. + */ +struct fuse_conn { + /** The superblock of the mounted filesystem */ + struct super_block *sb; + + /** The opened client device */ + struct file *file; + + /** The user id for this mount */ + uid_t uid; + + /** The fuse mount flags for this mount */ + unsigned int flags; + + /** Readers of the connection are waiting on this */ + wait_queue_head_t waitq; + + /** The list of pending requests */ + struct list_head pending; + + /** The list of requests being processed */ + struct list_head processing; + + /** Controls the maximum number of outstanding requests */ + struct semaphore unused_sem; + + /** The list of unused requests */ + struct list_head unused_list; + + /** The next unique request id */ + int reqctr; + + /** Is fsync not implemented by fs? */ + unsigned int no_fsync : 1; + + /** Is flush not implemented by fs? */ + unsigned int no_flush : 1; + + /** Is setxattr not implemented by fs? */ + unsigned int no_setxattr : 1; + + /** Is getxattr not implemented by fs? */ + unsigned int no_getxattr : 1; + + /** Is listxattr not implemented by fs? */ + unsigned int no_listxattr : 1; + + /** Is removexattr not implemented by fs? */ + unsigned int no_removexattr : 1; }; struct fuse_getdir_out_i { @@ -251,24 +259,42 @@ int fuse_fs_init(void); */ void fuse_fs_cleanup(void); + +/** + * Reserve a request + */ +struct fuse_req *fuse_get_request(struct fuse_conn *fc); + +/** + * Reserve a request, non-iterruptable + */ +struct fuse_req *fuse_get_request_nonint(struct fuse_conn *fc); + +/** + * Reserve a request, non-blocking + */ +struct fuse_req *fuse_get_request_nonblock(struct fuse_conn *fc); + +/** + * Free a request + */ +void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req); + /** * Send a request - * */ -void request_send(struct fuse_conn *fc, struct fuse_in *in, - struct fuse_out *out); +void request_send(struct fuse_conn *fc, struct fuse_req *req); /** * Send a request for which a reply is not expected */ -int request_send_noreply(struct fuse_conn *fc, struct fuse_in *in); - +void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req); /** * Send a synchronous request without blocking */ -int request_send_nonblock(struct fuse_conn *fc, struct fuse_in *in, - struct fuse_out *out, fuse_reqend_t end, void *data); +void request_send_nonblock(struct fuse_conn *fc, struct fuse_req *req, + fuse_reqend_t end, void *data); /** * Get the attributes of a file diff --git a/kernel/inode.c b/kernel/inode.c index fb02569..89b6da6 100644 --- a/kernel/inode.c +++ b/kernel/inode.c @@ -47,30 +47,21 @@ static void fuse_read_inode(struct inode *inode) static void fuse_clear_inode(struct inode *inode) { struct fuse_conn *fc = INO_FC(inode); - struct fuse_in *in = NULL; + struct fuse_req *req; struct fuse_forget_in *inarg = NULL; - unsigned int s = sizeof(struct fuse_in) + sizeof(struct fuse_forget_in); if (fc == NULL) return; - in = kmalloc(s, GFP_NOFS); - if (!in) - return; - memset(in, 0, s); - inarg = (struct fuse_forget_in *) (in + 1); + req = fuse_get_request_nonint(fc); + inarg = &req->misc.forget_in; inarg->version = inode->i_version; - - in->h.opcode = FUSE_FORGET; - in->h.ino = inode->i_ino; - in->numargs = 1; - in->args[0].size = sizeof(struct fuse_forget_in); - in->args[0].value = inarg; - - if (!request_send_noreply(fc, in)) - return; - - kfree(in); + req->in.h.opcode = FUSE_FORGET; + req->in.h.ino = inode->i_ino; + req->in.numargs = 1; + req->in.args[0].size = sizeof(struct fuse_forget_in); + req->in.args[0].value = inarg; + request_send_noreply(fc, req); } static void fuse_put_super(struct super_block *sb) @@ -104,20 +95,25 @@ static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr static int fuse_statfs(struct super_block *sb, struct kstatfs *buf) { struct fuse_conn *fc = SB_FC(sb); - struct fuse_in in = FUSE_IN_INIT; - struct fuse_out out = FUSE_OUT_INIT; + struct fuse_req *req; struct fuse_statfs_out outarg; - - in.numargs = 0; - in.h.opcode = FUSE_STATFS; - out.numargs = 1; - out.args[0].size = sizeof(outarg); - out.args[0].value = &outarg; - request_send(fc, &in, &out); - if (!out.h.error) + int err; + + req = fuse_get_request(fc); + if (!req) + return -ERESTARTSYS; + + req->in.numargs = 0; + req->in.h.opcode = FUSE_STATFS; + req->out.numargs = 1; + req->out.args[0].size = sizeof(outarg); + req->out.args[0].value = &outarg; + request_send(fc, req); + err = req->out.h.error; + if (!err) convert_fuse_statfs(buf, &outarg.st); - - return out.h.error; + fuse_put_request(fc, req); + return err; } enum { opt_fd, opt_rootmode, opt_uid, opt_default_permissions, diff --git a/kernel/util.c b/kernel/util.c index faffb08..3e7b6ef 100644 --- a/kernel/util.c +++ b/kernel/util.c @@ -19,14 +19,6 @@ MODULE_LICENSE("GPL"); spinlock_t fuse_lock = SPIN_LOCK_UNLOCKED; -/* Must be called with the fuse lock held */ -void fuse_release_conn(struct fuse_conn *fc) -{ - if (fc->sb == NULL && fc->file == NULL) { - kfree(fc); - } -} - int __init fuse_init(void) { int res; diff --git a/lib/fuse.c b/lib/fuse.c index 05d9713..4015d82 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -24,7 +24,7 @@ static const char *opname(enum fuse_opcode opcode) { - switch(opcode) { + switch (opcode) { case FUSE_LOOKUP: return "LOOKUP"; case FUSE_FORGET: return "FORGET"; case FUSE_GETATTR: return "GETATTR"; @@ -72,8 +72,8 @@ static struct node *__get_node(struct fuse *f, fino_t ino) size_t hash = ino % f->ino_table_size; struct node *node; - for(node = f->ino_table[hash]; node != NULL; node = node->ino_next) - if(node->ino == ino) + for (node = f->ino_table[hash]; node != NULL; node = node->ino_next) + if (node->ino == ino) return node; return NULL; @@ -82,7 +82,7 @@ static struct node *__get_node(struct fuse *f, fino_t ino) static struct node *get_node(struct fuse *f, fino_t ino) { struct node *node = __get_node(f, ino); - if(node != NULL) + if (node != NULL) return node; fprintf(stderr, "fuse internal error: inode %lu not found\n", ino); @@ -101,8 +101,8 @@ static void unhash_ino(struct fuse *f, struct node *node) size_t hash = node->ino % f->ino_table_size; struct node **nodep = &f->ino_table[hash]; - for(; *nodep != NULL; nodep = &(*nodep)->ino_next) - if(*nodep == node) { + for (; *nodep != NULL; nodep = &(*nodep)->ino_next) + if (*nodep == node) { *nodep = node->ino_next; return; } @@ -112,9 +112,9 @@ static fino_t next_ino(struct fuse *f) { do { f->ctr++; - if(!f->ctr) + if (!f->ctr) f->generation ++; - } while(f->ctr == 0 || __get_node(f, f->ctr) != NULL); + } while (f->ctr == 0 || __get_node(f, f->ctr) != NULL); return f->ctr; } @@ -128,8 +128,8 @@ static unsigned int name_hash(struct fuse *f, fino_t parent, const char *name) { unsigned int hash = *name; - if(hash) - for(name += 1; *name != '\0'; name++) + if (hash) + for (name += 1; *name != '\0'; name++) hash = (hash << 5) - hash + *name; return (hash + parent) % f->name_table_size; @@ -141,8 +141,8 @@ static struct node *lookup_node(struct fuse *f, fino_t parent, size_t hash = name_hash(f, parent, name); struct node *node; - for(node = f->name_table[hash]; node != NULL; node = node->name_next) - if(node->parent == parent && strcmp(node->name, name) == 0) + for (node = f->name_table[hash]; node != NULL; node = node->name_next) + if (node->parent == parent && strcmp(node->name, name) == 0) return node; return NULL; @@ -160,12 +160,12 @@ static void hash_name(struct fuse *f, struct node *node, fino_t parent, static void unhash_name(struct fuse *f, struct node *node) { - if(node->name != NULL) { + if (node->name != NULL) { size_t hash = name_hash(f, node->parent, node->name); struct node **nodep = &f->name_table[hash]; - for(; *nodep != NULL; nodep = &(*nodep)->name_next) - if(*nodep == node) { + for (; *nodep != NULL; nodep = &(*nodep)->name_next) + if (*nodep == node) { *nodep = node->name_next; node->name_next = NULL; free(node->name); @@ -186,13 +186,13 @@ static struct node *find_node(struct fuse *f, fino_t parent, char *name, int mode = attr->mode & S_IFMT; int rdev = 0; - if(S_ISCHR(mode) || S_ISBLK(mode)) + if (S_ISCHR(mode) || S_ISBLK(mode)) rdev = attr->rdev; pthread_mutex_lock(&f->lock); node = lookup_node(f, parent, name); - if(node != NULL) { - if(node->mode == mode && node->rdev == rdev) + if (node != NULL) { + if (node->mode == mode && node->rdev == rdev) goto out; unhash_name(f, node); @@ -216,7 +216,7 @@ static char *add_name(char *buf, char *s, const char *name) { size_t len = strlen(name); s -= len; - if(s <= buf) { + if (s <= buf) { fprintf(stderr, "fuse: path too long: ...%s\n", s + len); return NULL; } @@ -235,29 +235,29 @@ static char *get_path_name(struct fuse *f, fino_t ino, const char *name) *s = '\0'; - if(name != NULL) { + if (name != NULL) { s = add_name(buf, s, name); - if(s == NULL) + if (s == NULL) return NULL; } pthread_mutex_lock(&f->lock); - for(node = get_node(f, ino); node->ino != FUSE_ROOT_INO; + for (node = get_node(f, ino); node->ino != FUSE_ROOT_INO; node = get_node(f, node->parent)) { - if(node->name == NULL) { + if (node->name == NULL) { s = NULL; break; } s = add_name(buf, s, node->name); - if(s == NULL) + if (s == NULL) break; } pthread_mutex_unlock(&f->lock); - if(s == NULL) + if (s == NULL) return NULL; - else if(*s == '\0') + else if (*s == '\0') return strdup("/"); else return strdup(s); @@ -274,7 +274,7 @@ static void destroy_node(struct fuse *f, fino_t ino, int version) pthread_mutex_lock(&f->lock); node = get_node(f, ino); - if(node->version == version && ino != FUSE_ROOT_INO) { + if (node->version == version && ino != FUSE_ROOT_INO) { unhash_name(f, node); unhash_ino(f, node); free_node(node); @@ -289,7 +289,7 @@ static void remove_node(struct fuse *f, fino_t dir, const char *name) pthread_mutex_lock(&f->lock); node = lookup_node(f, dir, name); - if(node == NULL) { + if (node == NULL) { fprintf(stderr, "fuse internal error: unable to remove node %lu/%s\n", dir, name); abort(); @@ -307,13 +307,13 @@ static void rename_node(struct fuse *f, fino_t olddir, const char *oldname, pthread_mutex_lock(&f->lock); node = lookup_node(f, olddir, oldname); newnode = lookup_node(f, newdir, newname); - if(node == NULL) { + if (node == NULL) { fprintf(stderr, "fuse internal error: unable to rename node %lu/%s\n", olddir, oldname); abort(); } - if(newnode != NULL) + if (newnode != NULL) unhash_name(f, newnode); unhash_name(f, node); @@ -350,7 +350,7 @@ static int fill_dir(struct fuse_dirhandle *dh, char *name, int type) dirent.type = type; reclen = FUSE_DIRENT_SIZE(&dirent); res = fwrite(&dirent, reclen, 1, dh->fp); - if(res == 0) { + if (res == 0) { perror("fuse: writing directory file"); return -EIO; } @@ -361,7 +361,7 @@ static int send_reply_raw(struct fuse *f, char *outbuf, size_t outsize) { int res; - if((f->flags & FUSE_DEBUG)) { + if ((f->flags & FUSE_DEBUG)) { struct fuse_out_header *out = (struct fuse_out_header *) outbuf; printf(" unique: %i, error: %i (%s), outsize: %i\n", out->unique, out->error, strerror(-out->error), outsize); @@ -374,9 +374,9 @@ static int send_reply_raw(struct fuse *f, char *outbuf, size_t outsize) inc_avail(f); res = write(f->fd, outbuf, outsize); - if(res == -1) { + if (res == -1) { /* ENOENT means the operation was interrupted */ - if(!f->exited && errno != ENOENT) + if (!f->exited && errno != ENOENT) perror("fuse: writing device"); return -errno; } @@ -391,12 +391,12 @@ static int send_reply(struct fuse *f, struct fuse_in_header *in, int error, size_t outsize; struct fuse_out_header *out; - if(error <= -1000 || error > 0) { + if (error <= -1000 || error > 0) { fprintf(stderr, "fuse: bad error value: %i\n", error); error = -ERANGE; } - if(error) + if (error) argsize = 0; outsize = sizeof(struct fuse_out_header) + argsize; @@ -405,7 +405,7 @@ static int send_reply(struct fuse *f, struct fuse_in_header *in, int error, memset(out, 0, sizeof(struct fuse_out_header)); out->unique = in->unique; out->error = error; - if(argsize != 0) + if (argsize != 0) memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize); res = send_reply_raw(f, outbuf, outsize); @@ -421,7 +421,7 @@ static int lookup_path(struct fuse *f, fino_t ino, int version, char *name, struct stat buf; res = f->op.getattr(path, &buf); - if(res == 0) { + if (res == 0) { struct node *node; memset(arg, 0, sizeof(struct fuse_entry_out)); @@ -433,7 +433,7 @@ static int lookup_path(struct fuse *f, fino_t ino, int version, char *name, arg->entry_valid_nsec = 0; arg->attr_valid = ATTR_REVALIDATE_TIME; arg->attr_valid_nsec = 0; - if(f->flags & FUSE_DEBUG) { + if (f->flags & FUSE_DEBUG) { printf(" INO: %li\n", arg->ino); fflush(stdout); } @@ -449,13 +449,13 @@ static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name) res = -ENOENT; path = get_path_name(f, in->ino, name); - if(path != NULL) { - if(f->flags & FUSE_DEBUG) { + if (path != NULL) { + if (f->flags & FUSE_DEBUG) { printf("LOOKUP %s\n", path); fflush(stdout); } res = -ENOSYS; - if(f->op.getattr) + if (f->op.getattr) res = lookup_path(f, in->ino, in->unique, name, path, &arg); free(path); } @@ -465,7 +465,7 @@ static void do_lookup(struct fuse *f, struct fuse_in_header *in, char *name) static void do_forget(struct fuse *f, struct fuse_in_header *in, struct fuse_forget_in *arg) { - if(f->flags & FUSE_DEBUG) { + if (f->flags & FUSE_DEBUG) { printf("FORGET %li/%i\n", in->ino, arg->version); fflush(stdout); } @@ -481,14 +481,14 @@ static void do_getattr(struct fuse *f, struct fuse_in_header *in) res = -ENOENT; path = get_path(f, in->ino); - if(path != NULL) { + if (path != NULL) { res = -ENOSYS; - if(f->op.getattr) + if (f->op.getattr) res = f->op.getattr(path, &buf); free(path); } - if(res == 0) { + if (res == 0) { memset(&arg, 0, sizeof(struct fuse_attr_out)); arg.attr_valid = ATTR_REVALIDATE_TIME; arg.attr_valid_nsec = 0; @@ -503,7 +503,7 @@ static int do_chmod(struct fuse *f, const char *path, struct fuse_attr *attr) int res; res = -ENOSYS; - if(f->op.chmod) + if (f->op.chmod) res = f->op.chmod(path, attr->mode); return res; @@ -517,7 +517,7 @@ static int do_chown(struct fuse *f, const char *path, struct fuse_attr *attr, gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1; res = -ENOSYS; - if(f->op.chown) + if (f->op.chown) res = f->op.chown(path, uid, gid); return res; @@ -529,7 +529,7 @@ static int do_truncate(struct fuse *f, const char *path, int res; res = -ENOSYS; - if(f->op.truncate) + if (f->op.truncate) res = f->op.truncate(path, attr->size); return res; @@ -542,7 +542,7 @@ static int do_utime(struct fuse *f, const char *path, struct fuse_attr *attr) buf.actime = attr->atime; buf.modtime = attr->mtime; res = -ENOSYS; - if(f->op.utime) + if (f->op.utime) res = f->op.utime(path, &buf); return res; @@ -559,23 +559,23 @@ static void do_setattr(struct fuse *f, struct fuse_in_header *in, res = -ENOENT; path = get_path(f, in->ino); - if(path != NULL) { + if (path != NULL) { res = -ENOSYS; - if(f->op.getattr) { + if (f->op.getattr) { res = 0; - if(!res && (valid & FATTR_MODE)) + if (!res && (valid & FATTR_MODE)) res = do_chmod(f, path, attr); - if(!res && (valid & (FATTR_UID | FATTR_GID))) + if (!res && (valid & (FATTR_UID | FATTR_GID))) res = do_chown(f, path, attr, valid); - if(!res && (valid & FATTR_SIZE)) + if (!res && (valid & FATTR_SIZE)) res = do_truncate(f, path, attr); - if(!res && (valid & (FATTR_ATIME | FATTR_MTIME)) == + if (!res && (valid & (FATTR_ATIME | FATTR_MTIME)) == (FATTR_ATIME | FATTR_MTIME)) res = do_utime(f, path, attr); - if(!res) { + if (!res) { struct stat buf; res = f->op.getattr(path, &buf); - if(!res) { + if (!res) { memset(&outarg, 0, sizeof(struct fuse_attr_out)); outarg.attr_valid = ATTR_REVALIDATE_TIME; outarg.attr_valid_nsec = 0; @@ -596,9 +596,9 @@ static void do_readlink(struct fuse *f, struct fuse_in_header *in) res = -ENOENT; path = get_path(f, in->ino); - if(path != NULL) { + if (path != NULL) { res = -ENOSYS; - if(f->op.readlink) + if (f->op.readlink) res = f->op.readlink(path, link, sizeof(link)); free(path); } @@ -618,9 +618,9 @@ static void do_getdir(struct fuse *f, struct fuse_in_header *in) dh.dir = in->ino; res = -ENOENT; path = get_path(f, in->ino); - if(path != NULL) { + if (path != NULL) { res = -ENOSYS; - if(f->op.getdir) + if (f->op.getdir) res = f->op.getdir(path, &dh, (fuse_dirfil_t) fill_dir); free(path); } @@ -642,15 +642,15 @@ static void do_mknod(struct fuse *f, struct fuse_in_header *in, res = -ENOENT; path = get_path_name(f, in->ino, name); - if(path != NULL) { - if(f->flags & FUSE_DEBUG) { + if (path != NULL) { + if (f->flags & FUSE_DEBUG) { printf("MKNOD %s\n", path); fflush(stdout); } res = -ENOSYS; - if(f->op.mknod && f->op.getattr) { + if (f->op.mknod && f->op.getattr) { res = f->op.mknod(path, inarg->mode, inarg->rdev); - if(res == 0) + if (res == 0) res = lookup_path(f, in->ino, in->unique, name, path, &outarg); } free(path); @@ -668,15 +668,15 @@ static void do_mkdir(struct fuse *f, struct fuse_in_header *in, res = -ENOENT; path = get_path_name(f, in->ino, name); - if(path != NULL) { - if(f->flags & FUSE_DEBUG) { + if (path != NULL) { + if (f->flags & FUSE_DEBUG) { printf("MKDIR %s\n", path); fflush(stdout); } res = -ENOSYS; - if(f->op.mkdir && f->op.getattr) { + if (f->op.mkdir && f->op.getattr) { res = f->op.mkdir(path, inarg->mode); - if(res == 0) + if (res == 0) res = lookup_path(f, in->ino, in->unique, name, path, &outarg); } free(path); @@ -691,11 +691,11 @@ static void do_unlink(struct fuse *f, struct fuse_in_header *in, char *name) res = -ENOENT; path = get_path_name(f, in->ino, name); - if(path != NULL) { + if (path != NULL) { res = -ENOSYS; - if(f->op.unlink) { + if (f->op.unlink) { res = f->op.unlink(path); - if(res == 0) + if (res == 0) remove_node(f, in->ino, name); } free(path); @@ -710,11 +710,11 @@ static void do_rmdir(struct fuse *f, struct fuse_in_header *in, char *name) res = -ENOENT; path = get_path_name(f, in->ino, name); - if(path != NULL) { + if (path != NULL) { res = -ENOSYS; - if(f->op.rmdir) { + if (f->op.rmdir) { res = f->op.rmdir(path); - if(res == 0) + if (res == 0) remove_node(f, in->ino, name); } free(path); @@ -731,15 +731,15 @@ static void do_symlink(struct fuse *f, struct fuse_in_header *in, char *name, res = -ENOENT; path = get_path_name(f, in->ino, name); - if(path != NULL) { - if(f->flags & FUSE_DEBUG) { + if (path != NULL) { + if (f->flags & FUSE_DEBUG) { printf("SYMLINK %s\n", path); fflush(stdout); } res = -ENOSYS; - if(f->op.symlink && f->op.getattr) { + if (f->op.symlink && f->op.getattr) { res = f->op.symlink(link, path); - if(res == 0) + if (res == 0) res = lookup_path(f, in->ino, in->unique, name, path, &outarg); } free(path); @@ -760,13 +760,13 @@ static void do_rename(struct fuse *f, struct fuse_in_header *in, res = -ENOENT; oldpath = get_path_name(f, olddir, oldname); - if(oldpath != NULL) { + if (oldpath != NULL) { newpath = get_path_name(f, newdir, newname); - if(newpath != NULL) { + if (newpath != NULL) { res = -ENOSYS; - if(f->op.rename) + if (f->op.rename) res = f->op.rename(oldpath, newpath); - if(res == 0) + if (res == 0) rename_node(f, olddir, oldname, newdir, newname); free(newpath); } @@ -786,17 +786,17 @@ static void do_link(struct fuse *f, struct fuse_in_header *in, res = -ENOENT; oldpath = get_path(f, in->ino); - if(oldpath != NULL) { + if (oldpath != NULL) { newpath = get_path_name(f, arg->newdir, name); - if(newpath != NULL) { - if(f->flags & FUSE_DEBUG) { + if (newpath != NULL) { + if (f->flags & FUSE_DEBUG) { printf("LINK %s\n", newpath); fflush(stdout); } res = -ENOSYS; - if(f->op.link && f->op.getattr) { + if (f->op.link && f->op.getattr) { res = f->op.link(oldpath, newpath); - if(res == 0) + if (res == 0) res = lookup_path(f, arg->newdir, in->unique, name, newpath, &outarg); } @@ -816,15 +816,15 @@ static void do_open(struct fuse *f, struct fuse_in_header *in, res = -ENOENT; path = get_path(f, in->ino); - if(path != NULL) { + if (path != NULL) { res = -ENOSYS; - if(f->op.open) + if (f->op.open) res = f->op.open(path, arg->flags); } res2 = send_reply(f, in, res, NULL, 0); - if(path != NULL) { + if (path != NULL) { /* The open syscall was interrupted, so it must be cancelled */ - if(res == 0 && res2 == -ENOENT && f->op.release) + if (res == 0 && res2 == -ENOENT && f->op.release) f->op.release(path, arg->flags); free(path); } @@ -837,9 +837,9 @@ static void do_flush(struct fuse *f, struct fuse_in_header *in) res = -ENOENT; path = get_path(f, in->ino); - if(path != NULL) { + if (path != NULL) { res = -ENOSYS; - if(f->op.flush) + if (f->op.flush) res = f->op.flush(path); free(path); } @@ -851,10 +851,14 @@ static void do_release(struct fuse *f, struct fuse_in_header *in, { char *path; + if (!f->op.release) { + send_reply(f, in, -ENOSYS, NULL, 0); + return; + } + path = get_path(f, in->ino); - if(path != NULL) { - if(f->op.release) - f->op.release(path, arg->flags); + if (path != NULL) { + f->op.release(path, arg->flags); free(path); } } @@ -872,23 +876,23 @@ static void do_read(struct fuse *f, struct fuse_in_header *in, res = -ENOENT; path = get_path(f, in->ino); - if(path != NULL) { - if(f->flags & FUSE_DEBUG) { + if (path != NULL) { + if (f->flags & FUSE_DEBUG) { printf("READ %u bytes from %llu\n", arg->size, arg->offset); fflush(stdout); } res = -ENOSYS; - if(f->op.read) + if (f->op.read) res = f->op.read(path, buf, arg->size, arg->offset); free(path); } size = 0; - if(res > 0) { + if (res > 0) { size = res; res = 0; - if(f->flags & FUSE_DEBUG) { + if (f->flags & FUSE_DEBUG) { printf(" READ %u bytes\n", size); fflush(stdout); } @@ -910,20 +914,20 @@ static void do_write(struct fuse *f, struct fuse_in_header *in, res = -ENOENT; path = get_path(f, in->ino); - if(path != NULL) { - if(f->flags & FUSE_DEBUG) { + if (path != NULL) { + if (f->flags & FUSE_DEBUG) { printf("WRITE %u bytes to %llu\n", arg->size, arg->offset); fflush(stdout); } res = -ENOSYS; - if(f->op.write) + if (f->op.write) res = f->op.write(path, PARAM(arg), arg->size, arg->offset); free(path); } - if(res > 0) { - if((size_t) res != arg->size) { + if (res > 0) { + if ((size_t) res != arg->size) { fprintf(stderr, "short write: %u (should be %u)\n", res, arg->size); res = -EINVAL; @@ -960,12 +964,12 @@ static void do_statfs(struct fuse *f, struct fuse_in_header *in) struct statfs buf; memset(&buf, 0, sizeof(struct statfs)); - if(f->op.statfs) + if (f->op.statfs) res = f->op.statfs("/", &buf); else res = default_statfs(&buf); - if(res == 0) + if (res == 0) convert_statfs(&buf, &arg.st); send_reply(f, in, res, &arg, sizeof(arg)); @@ -979,9 +983,9 @@ static void do_fsync(struct fuse *f, struct fuse_in_header *in, res = -ENOENT; path = get_path(f, in->ino); - if(path != NULL) { + if (path != NULL) { res = -ENOSYS; - if(f->op.fsync) + if (f->op.fsync) res = f->op.fsync(path, inarg->datasync); free(path); } @@ -1034,7 +1038,7 @@ static void do_getxattr_read(struct fuse *f, struct fuse_in_header *in, res = common_getxattr(f, in, name, value, size); size = 0; - if(res > 0) { + if (res > 0) { size = res; res = 0; } @@ -1053,7 +1057,7 @@ static void do_getxattr_size(struct fuse *f, struct fuse_in_header *in, struct fuse_getxattr_out arg; res = common_getxattr(f, in, name, NULL, 0); - if(res >= 0) { + if (res >= 0) { arg.size = res; res = 0; } @@ -1065,7 +1069,7 @@ static void do_getxattr(struct fuse *f, struct fuse_in_header *in, { char *name = PARAM(arg); - if(arg->size) + if (arg->size) do_getxattr_read(f, in, name, arg->size); else do_getxattr_size(f, in, name); @@ -1098,7 +1102,7 @@ static void do_listxattr_read(struct fuse *f, struct fuse_in_header *in, res = common_listxattr(f, in, list, size); size = 0; - if(res > 0) { + if (res > 0) { size = res; res = 0; } @@ -1126,7 +1130,7 @@ static void do_listxattr_size(struct fuse *f, struct fuse_in_header *in) static void do_listxattr(struct fuse *f, struct fuse_in_header *in, struct fuse_getxattr_in *arg) { - if(arg->size) + if (arg->size) do_listxattr_read(f, in, arg->size); else do_listxattr_size(f, in); @@ -1165,7 +1169,7 @@ void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd) dec_avail(f); - if((f->flags & FUSE_DEBUG)) { + if ((f->flags & FUSE_DEBUG)) { printf("unique: %i, opcode: %s (%i), ino: %li, insize: %i\n", in->unique, opname(in->opcode), in->opcode, in->ino, cmd->buflen); @@ -1177,7 +1181,7 @@ void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd) argsize = cmd->buflen - sizeof(struct fuse_in_header); - switch(in->opcode) { + switch (in->opcode) { case FUSE_LOOKUP: do_lookup(f, in, (char *) inarg); break; @@ -1292,13 +1296,13 @@ struct fuse_cmd *__fuse_read_cmd(struct fuse *f) do { res = read(f->fd, cmd->buf, FUSE_MAX_IN); - if(res == -1) { + if (res == -1) { free_cmd(cmd); - if(f->exited || errno == EINTR) + if (f->exited || errno == EINTR) return NULL; /* ENODEV means we got unmounted, so we silenty return failure */ - if(errno != ENODEV) { + if (errno != ENODEV) { /* BAD... This will happen again */ perror("fuse: reading device"); } @@ -1306,7 +1310,7 @@ struct fuse_cmd *__fuse_read_cmd(struct fuse *f) fuse_exit(f); return NULL; } - if((size_t) res < sizeof(struct fuse_in_header)) { + if ((size_t) res < sizeof(struct fuse_in_header)) { free_cmd(cmd); /* Cannot happen */ fprintf(stderr, "short read on fuse device\n"); @@ -1316,27 +1320,27 @@ struct fuse_cmd *__fuse_read_cmd(struct fuse *f) cmd->buflen = res; /* Forget is special, it can be done without messing with threads. */ - if(in->opcode == FUSE_FORGET) + if (in->opcode == FUSE_FORGET) do_forget(f, in, (struct fuse_forget_in *) inarg); - } while(in->opcode == FUSE_FORGET); + } while (in->opcode == FUSE_FORGET); return cmd; } void fuse_loop(struct fuse *f) { - if(f == NULL) + if (f == NULL) return; - while(1) { + while (1) { struct fuse_cmd *cmd; - if(f->exited) + if (f->exited) return; cmd = __fuse_read_cmd(f); - if(cmd == NULL) + if (cmd == NULL) continue; __fuse_process_cmd(f, cmd); @@ -1350,7 +1354,7 @@ void fuse_exit(struct fuse *f) struct fuse_context *fuse_get_context(struct fuse *f) { - if(f->getcontext) + if (f->getcontext) return f->getcontext(f); else return &f->context; @@ -1360,23 +1364,23 @@ static int check_version(struct fuse *f) { int res; FILE *vf = fopen(FUSE_VERSION_FILE, "r"); - if(vf == NULL) { + if (vf == NULL) { fprintf(stderr, "fuse: kernel interface too old, need >= %i.%i\n", FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); return -1; } res = fscanf(vf, "%i.%i", &f->majorver, &f->minorver); fclose(vf); - if(res != 2) { + if (res != 2) { fprintf(stderr, "fuse: error reading %s\n", FUSE_VERSION_FILE); return -1; } - if(f->majorver != FUSE_KERNEL_VERSION) { + if (f->majorver != FUSE_KERNEL_VERSION) { fprintf(stderr, "fuse: bad kernel interface major version: needs %i\n", FUSE_KERNEL_VERSION); return -1; } - if(f->minorver < FUSE_KERNEL_MINOR_VERSION) { + if (f->minorver < FUSE_KERNEL_MINOR_VERSION) { fprintf(stderr, "fuse: kernel interface too old: need >= %i.%i", FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); return -1; @@ -1392,7 +1396,7 @@ struct fuse *fuse_new(int fd, int flags, const struct fuse_operations *op) f = (struct fuse *) calloc(1, sizeof(struct fuse)); - if(check_version(f) == -1) { + if (check_version(f) == -1) { free(f); return NULL; } @@ -1432,10 +1436,10 @@ struct fuse *fuse_new(int fd, int flags, const struct fuse_operations *op) void fuse_destroy(struct fuse *f) { size_t i; - for(i = 0; i < f->ino_table_size; i++) { + for (i = 0; i < f->ino_table_size; i++) { struct node *node; struct node *next; - for(node = f->ino_table[i]; node != NULL; node = next) { + for (node = f->ino_table[i]; node != NULL; node = next) { next = node->ino_next; free_node(node); } diff --git a/lib/fuse_mt.c b/lib/fuse_mt.c index 40da6ed..aa9dc7e 100644 --- a/lib/fuse_mt.c +++ b/lib/fuse_mt.c @@ -31,17 +31,17 @@ static void *do_work(void *data) struct fuse_worker *w = (struct fuse_worker *) data; struct fuse *f = w->f; - while(1) { + while (1) { struct fuse_cmd *cmd; - if(f->exited) + if (f->exited) break; cmd = __fuse_read_cmd(w->f); - if(cmd == NULL) + if (cmd == NULL) continue; - if(f->numavail == 0 && f->numworker < FUSE_MAX_WORKERS) { + if (f->numavail == 0 && f->numworker < FUSE_MAX_WORKERS) { pthread_mutex_lock(&f->lock); f->numavail ++; f->numworker ++; @@ -67,7 +67,7 @@ static void start_thread(struct fuse_worker *w) pthread_sigmask(SIG_SETMASK, &newset, &oldset); res = pthread_create(&thrid, NULL, do_work, w); pthread_sigmask(SIG_SETMASK, &oldset, NULL); - if(res != 0) { + if (res != 0) { fprintf(stderr, "Error creating thread: %s\n", strerror(res)); exit(1); } @@ -79,7 +79,7 @@ static struct fuse_context *mt_getcontext(struct fuse *f) struct fuse_context *ctx; ctx = (struct fuse_context *) pthread_getspecific(f->context_key); - if(ctx == NULL) { + if (ctx == NULL) { ctx = (struct fuse_context *) malloc(sizeof(struct fuse_context)); pthread_setspecific(f->context_key, ctx); } @@ -104,7 +104,7 @@ void __fuse_loop_mt(struct fuse *f, fuse_processor_t proc, void *data) f->numworker = 1; res = pthread_key_create(&f->context_key, mt_freecontext); - if(res != 0) { + if (res != 0) { fprintf(stderr, "Failed to create thread specific key\n"); exit(1); } @@ -114,7 +114,7 @@ void __fuse_loop_mt(struct fuse *f, fuse_processor_t proc, void *data) void fuse_loop_mt(struct fuse *f) { - if(f == NULL) + if (f == NULL) return; __fuse_loop_mt(f, (fuse_processor_t) __fuse_process_cmd, NULL); diff --git a/lufis/lufis.c b/lufis/lufis.c index f91c1e0..a8b17c9 100644 --- a/lufis/lufis.c +++ b/lufis/lufis.c @@ -793,19 +793,13 @@ static struct fuse_operations lu_oper = { int main(int argc, char *argv[]) { int res; - int pid; res = lufis_init(&argc, &argv); if(res == -1) exit(1); - pid = fork(); - if(pid == -1) - exit(1); - if(pid == 0) { - fuse_main(argc, argv, &lu_oper); - lufis_cleanup(); - } + fuse_main(argc, argv, &lu_oper); + lufis_cleanup(); return 0; } -- 2.30.2