From d8ae7147bfe8f40e72ea640c6631a4b2c6f2c6c9 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Thu, 25 Oct 2001 14:16:17 +0000 Subject: [PATCH] improvements --- dev.c | 189 +++++++++++++++++++++++++++++++++++++++------------- dir.c | 14 +++- fuse.h | 41 +++++++++++- fuse_i.h | 27 ++++++-- fusemount.c | 28 +++++++- inode.c | 1 - request.c | 22 ++++++ 7 files changed, 265 insertions(+), 57 deletions(-) create mode 100644 request.c diff --git a/dev.c b/dev.c index 159d8d6..b6b9930 100644 --- a/dev.c +++ b/dev.c @@ -16,88 +16,176 @@ static struct proc_dir_entry *proc_fs_fuse; struct proc_dir_entry *proc_fuse_dev; -static struct fuse_req *request_wait(struct fuse_conn *fc) +static int request_wait_answer(struct fuse_req *req) { + int ret = 0; DECLARE_WAITQUEUE(wait, current); - struct fuse_req *req; - spin_lock(&fuse_lock); - add_wait_queue(&fc->waitq, &wait); - set_current_state(TASK_INTERRUPTIBLE); - while(list_empty(&fc->pending)) { - if(signal_pending(current)) + add_wait_queue(&req->waitq, &wait); + while(!req->done) { + set_current_state(TASK_INTERRUPTIBLE); + if(signal_pending(current)) { + ret = -EINTR; break; - + } spin_unlock(&fuse_lock); schedule(); spin_lock(&fuse_lock); } set_current_state(TASK_RUNNING); - remove_wait_queue(&fc->waitq, &wait); - - if(list_empty(&fc->pending)) - return NULL; - - req = list_entry(fc->pending.next, struct fuse_req, list); - list_del(&req->list); - spin_unlock(&fuse_lock); + remove_wait_queue(&req->waitq, &wait); - return req; + return ret; } -static void request_processing(struct fuse_conn *fc, struct fuse_req *req) +void request_send(struct fuse_conn *fc, struct fuse_inparam *in, + struct fuse_outparam *out, int valuret) { + int ret; + struct fuse_req *req; + + req = kmalloc(sizeof(*req), GFP_KERNEL); + if(req == NULL) { + out->result = -ENOMEM; + return; + } + + req->param.u.i = *in; + req->size = sizeof(req->param); + req->done = 0; + init_waitqueue_head(&req->waitq); + spin_lock(&fuse_lock); - list_add_tail(&req->list, &fc->processing); + req->param.unique = fc->reqctr ++; + list_add_tail(&req->list, &fc->pending); fc->outstanding ++; + /* FIXME: Wait until the number of outstanding requests drops + below a certain level */ + wake_up(&fc->waitq); + ret = request_wait_answer(req); + fc->outstanding --; + *out = req->param.u.o; + list_del(&req->list); + kfree(req); spin_unlock(&fuse_lock); + + if(ret) + out->result = ret; + else if (out->result < -512 || (out->result > 0 && !valuret)) { + printk("Bad result from client: %i\n", out->result); + out->result = -EIO; + } } -static void request_free(struct fuse_req *req) +static int request_wait(struct fuse_conn *fc) { - kfree(req); + int ret = 0; + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&fc->waitq, &wait); + while(list_empty(&fc->pending)) { + set_current_state(TASK_INTERRUPTIBLE); + if(signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + spin_unlock(&fuse_lock); + schedule(); + spin_lock(&fuse_lock); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&fc->waitq, &wait); + + return ret; } static ssize_t fuse_dev_read(struct file *file, char *buf, size_t nbytes, loff_t *off) { - ssize_t res; + ssize_t ret; struct fuse_conn *fc = file->private_data; struct fuse_req *req; + struct fuse_param param; + size_t size; + spin_lock(&fuse_lock); + ret = request_wait(fc); + if(ret) + goto err; + printk(KERN_DEBUG "fuse_dev_read[%i]\n", fc->id); - res = -ERESTARTSYS; - req = request_wait(fc); - if(req == NULL) - goto err; + req = list_entry(fc->pending.next, struct fuse_req, list); + param = req->param; + size = req->size; - res = -EIO; - if(nbytes < req->size) { - printk("fuse_dev_read: buffer too small (%i)\n", req->size); - goto err_free_req; + ret = -EIO; + if(nbytes < size) { + printk("fuse_dev_read: buffer too small (%i)\n", size); + goto err; } - res = -EFAULT; - if(copy_to_user(buf, req->data, req->size)) - goto err_free_req; + list_del(&req->list); + list_add_tail(&req->list, &fc->processing); + spin_unlock(&fuse_lock); - request_processing(fc, req); - return req->size; + if(copy_to_user(buf, ¶m, size)) + return -EFAULT; + + return size; - err_free_req: - request_free(req); err: - return res; + spin_unlock(&fuse_lock); + return ret; +} + +static struct fuse_req *request_find(struct fuse_conn *fc, unsigned int unique) +{ + struct list_head *entry; + struct fuse_req *req = NULL; + + list_for_each(entry, &fc->processing) { + struct fuse_req *tmp; + tmp = list_entry(entry, struct fuse_req, list); + if(tmp->param.unique == unique) { + req = tmp; + list_del_init(&req->list); + break; + } + } + + return req; } static ssize_t fuse_dev_write(struct file *file, const char *buf, - size_t nbytes, loff_t *off) + size_t nbytes, loff_t *off) { struct fuse_conn *fc = file->private_data; + struct fuse_param param; + struct fuse_req *req; + + printk(KERN_DEBUG "fuse_dev_write[%i]\n", fc->id); + + if(nbytes < sizeof(param.unique) || nbytes > sizeof(param)) { + printk("fuse_dev_write: write is short or long\n"); + return -EIO; + } + + if(copy_from_user(¶m, buf, nbytes)) + return -EFAULT; + + spin_lock(&fuse_lock); + req = request_find(fc, param.unique); + if(req == NULL) + printk("fuse_dev_write[%i]: unknown request: %i", fc->id, + param.unique); + else { + req->param = param; + req->done = 1; + wake_up(&req->waitq); + } + spin_unlock(&fuse_lock); - printk(KERN_DEBUG "fuse_dev_write[%i] <%.*s>\n", fc->id, (int) nbytes, - buf); return nbytes; } @@ -105,9 +193,16 @@ static ssize_t fuse_dev_write(struct file *file, const char *buf, static unsigned int fuse_dev_poll(struct file *file, poll_table *wait) { struct fuse_conn *fc = file->private_data; + unsigned int mask = POLLOUT | POLLWRNORM; - printk(KERN_DEBUG "fuse_dev_poll[%i]\n", fc->id); - return 0; + poll_wait(file, &fc->waitq, wait); + + spin_lock(&fuse_lock); + if (!list_empty(&fc->pending)) + mask |= POLLIN | POLLRDNORM; + spin_unlock(&fuse_lock); + + return mask; } static struct fuse_conn *new_conn(void) @@ -123,6 +218,7 @@ static struct fuse_conn *new_conn(void) INIT_LIST_HEAD(&fc->pending); INIT_LIST_HEAD(&fc->processing); fc->outstanding = 0; + fc->reqctr = 0; spin_lock(&fuse_lock); fc->id = connctr ++; @@ -173,12 +269,12 @@ static struct file_operations fuse_dev_operations = { int fuse_dev_init() { - int res; + int ret; proc_fs_fuse = NULL; proc_fuse_dev = NULL; - res = -EIO; + ret = -EIO; proc_fs_fuse = proc_mkdir("fuse", proc_root_fs); if(!proc_fs_fuse) { printk("fuse: failed to create directory in /proc/fs\n"); @@ -199,8 +295,7 @@ int fuse_dev_init() err: fuse_dev_cleanup(); - return res; - + return ret; } void fuse_dev_cleanup() diff --git a/dir.c b/dir.c index 150c401..6fa5959 100644 --- a/dir.c +++ b/dir.c @@ -43,9 +43,21 @@ static int fuse_readdir(struct file *file, void *dirent, filldir_t filldir) static int fuse_open(struct inode *inode, struct file *file) { + struct fuse_conn *fc = inode->i_sb->u.generic_sbp; + struct fuse_inparam in; + struct fuse_outparam out; + printk(KERN_DEBUG "fuse_open: %li\n", inode->i_ino); - return 0; + in.opcode = FUSE_OPEN; + in.u.open.ino = inode->i_ino; + in.u.open.flags = file->f_flags & ~O_EXCL; + + request_send(fc, &in, &out, 0); + + printk(KERN_DEBUG " fuse_open: <%i> %i\n", out.result, out.u.open.fd); + + return out.result; } static int fuse_release(struct inode *inode, struct file *file) diff --git a/fuse.h b/fuse.h index df71221..32c2609 100644 --- a/fuse.h +++ b/fuse.h @@ -1,4 +1,3 @@ -/* -*- indent-tabs-mode: t; c-basic-offset: 8; -*- */ /* FUSE: Filesystem in Userspace Copyright (C) 2001 Miklos Szeredi (mszeredi@inf.bme.hu) @@ -15,3 +14,43 @@ struct fuse_mount_data { int fd; }; +enum fuse_opcode { + FUSE_OPEN, + FUSE_RELEASE, +}; + +struct fuse_inparam { + enum fuse_opcode opcode; + union { + struct { + unsigned int ino; + int flags; + } open; + } u; +}; + +struct fuse_outparam { + int result; + union { + struct { + int fd; + } open; + } u; +}; + +struct fuse_param { + int unique; + int result; + union { + struct fuse_inparam i; + struct fuse_outparam o; + } u; +}; + + +/* + * Local Variables: + * indent-tabs-mode: t + * c-basic-offset: 8 + * End: + */ diff --git a/fuse_i.h b/fuse_i.h index 70e149c..a7a907f 100644 --- a/fuse_i.h +++ b/fuse_i.h @@ -6,6 +6,8 @@ See the file COPYING. */ +#include "fuse.h" + #include #include #include @@ -40,20 +42,29 @@ struct fuse_conn { /** Connnection number (for debuging) */ int id; + + /** The request id */ + int reqctr; }; /** - * A filesystem request + * A request to the client */ struct fuse_req { /** The request list */ struct list_head list; - /** The size of the data */ + /** The size of the parameters */ size_t size; - /** A pointer to the data */ - void *data; + /** The request parameters */ + struct fuse_param param; + + /** The request wait queue */ + wait_queue_head_t waitq; + + /** True if the request is finished */ + int done; }; /** @@ -97,6 +108,14 @@ int fuse_fs_init(void); */ void fuse_fs_cleanup(void); +/** + * Send a request + * + * @valuret: if true then the request can return a positive value + */ +void request_send(struct fuse_conn *fc, struct fuse_inparam *in, + struct fuse_outparam *out, int valuret); + /* * Local Variables: * indent-tabs-mode: t diff --git a/fusemount.c b/fusemount.c index b4d3bc0..3ae2932 100644 --- a/fusemount.c +++ b/fusemount.c @@ -17,8 +17,30 @@ #include #include +static void loop(int devfd) +{ + int res; + struct fuse_param param; + + while(1) { + res = read(devfd, ¶m, sizeof(param)); + if(res == -1) { + perror("read"); + exit(1); + } + + printf("unique: %i, opcode: %i\n", param.unique, param.u.i.opcode); + param.u.o.result = 0; + + res = write(devfd, ¶m, sizeof(param)); + if(res == -1) { + perror("write"); + exit(1); + } + } +} -int mount_fuse(const char *dev, const char *dir, int devfd) +static int mount_fuse(const char *dev, const char *dir, int devfd) { int res; const char *type; @@ -81,7 +103,7 @@ int main(int argc, char *argv[]) mount_fuse(dev, dir, devfd); - sleep(1000); - + loop(devfd); + return 0; } diff --git a/inode.c b/inode.c index da30cac..590a80d 100644 --- a/inode.c +++ b/inode.c @@ -6,7 +6,6 @@ See the file COPYING. */ -#include "fuse.h" #include "fuse_i.h" #include diff --git a/request.c b/request.c new file mode 100644 index 0000000..d12a4c8 --- /dev/null +++ b/request.c @@ -0,0 +1,22 @@ +/* + FUSE: Filesystem in Userspace + Copyright (C) 2001 Miklos Szeredi (mszeredi@inf.bme.hu) + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. +*/ + +#include "fuse_i.h" + +#include +#include +#include + + + +/* + * Local Variables: + * indent-tabs-mode: t + * c-basic-offset: 8 + * End: + */ -- 2.30.2