diff options
author | Miklos Szeredi <miklos@szeredi.hu> | 2004-06-19 22:42:38 +0000 |
---|---|---|
committer | Miklos Szeredi <miklos@szeredi.hu> | 2004-06-19 22:42:38 +0000 |
commit | 7eafccef7f5788e54efa5318d9f5af13a0cbd291 (patch) | |
tree | 0b813ada0adf19ae9971f15c347de85b34a69de6 /kernel | |
parent | 152f29edc452f36210c1a8e0e0d648ac08fbf1bc (diff) | |
download | libfuse-7eafccef7f5788e54efa5318d9f5af13a0cbd291.tar.gz |
pre-allocate request structures
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/.cvsignore | 1 | ||||
-rw-r--r-- | kernel/dev.c | 264 | ||||
-rw-r--r-- | kernel/dir.c | 613 | ||||
-rw-r--r-- | kernel/file.c | 284 | ||||
-rw-r--r-- | kernel/fuse_i.h | 164 | ||||
-rw-r--r-- | kernel/inode.c | 56 | ||||
-rw-r--r-- | kernel/util.c | 8 |
7 files changed, 751 insertions, 639 deletions
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; |