From: Miklos Szeredi Date: Wed, 24 Oct 2001 14:37:13 +0000 (+0000) Subject: improvements X-Git-Tag: fuse_0_9~17 X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=79b52f63303c15d4545a7464775f4b1beab8d2c9;p=qemu-gpiodev%2Flibfuse.git improvements --- diff --git a/Makefile b/Makefile index aedd26d..f8810fd 100644 --- a/Makefile +++ b/Makefile @@ -17,10 +17,10 @@ inode.o: inode.c dir.o: dir.c $(CC) $(KCFLAGS) $(KCPPFLAGS) -c dir.c -main.o: main.c - $(CC) $(KCFLAGS) $(KCPPFLAGS) -c main.c +util.o: util.c + $(CC) $(KCFLAGS) $(KCPPFLAGS) -c util.c -fuse_objs = dev.o inode.o dir.o main.o +fuse_objs = dev.o inode.o dir.o util.o fuse.o: $(fuse_objs) ld -r -o fuse.o $(fuse_objs) diff --git a/dev.c b/dev.c index c7dd247..159d8d6 100644 --- a/dev.c +++ b/dev.c @@ -10,69 +10,155 @@ #include #include -#include #include -#include #include 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) +{ + 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)) + 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); + + return req; +} + +static void request_processing(struct fuse_conn *fc, struct fuse_req *req) +{ + spin_lock(&fuse_lock); + list_add_tail(&req->list, &fc->processing); + fc->outstanding ++; + spin_unlock(&fuse_lock); +} + +static void request_free(struct fuse_req *req) +{ + kfree(req); +} + static ssize_t fuse_dev_read(struct file *file, char *buf, size_t nbytes, loff_t *off) { - printk(KERN_DEBUG "fuse_dev_read\n"); - return 0; + ssize_t res; + struct fuse_conn *fc = file->private_data; + struct fuse_req *req; + + printk(KERN_DEBUG "fuse_dev_read[%i]\n", fc->id); + + res = -ERESTARTSYS; + req = request_wait(fc); + if(req == NULL) + goto err; + + res = -EIO; + if(nbytes < req->size) { + printk("fuse_dev_read: buffer too small (%i)\n", req->size); + goto err_free_req; + } + + res = -EFAULT; + if(copy_to_user(buf, req->data, req->size)) + goto err_free_req; + + request_processing(fc, req); + return req->size; + + err_free_req: + request_free(req); + err: + return res; } static ssize_t fuse_dev_write(struct file *file, const char *buf, size_t nbytes, loff_t *off) { - printk(KERN_DEBUG "fuse_dev_write <%.*s>\n", (int) nbytes, buf); + struct fuse_conn *fc = file->private_data; + + printk(KERN_DEBUG "fuse_dev_write[%i] <%.*s>\n", fc->id, (int) nbytes, + buf); return nbytes; } static unsigned int fuse_dev_poll(struct file *file, poll_table *wait) { - printk(KERN_DEBUG "fuse_dev_poll\n"); + struct fuse_conn *fc = file->private_data; + + printk(KERN_DEBUG "fuse_dev_poll[%i]\n", fc->id); return 0; } +static struct fuse_conn *new_conn(void) +{ + static int connctr = 1; + struct fuse_conn *fc; + + fc = kmalloc(sizeof(*fc), GFP_KERNEL); + if(fc != NULL) { + fc->sb = NULL; + fc->file = NULL; + init_waitqueue_head(&fc->waitq); + INIT_LIST_HEAD(&fc->pending); + INIT_LIST_HEAD(&fc->processing); + fc->outstanding = 0; + + spin_lock(&fuse_lock); + fc->id = connctr ++; + spin_unlock(&fuse_lock); + } + return fc; +} + static int fuse_dev_open(struct inode *inode, struct file *file) { - int res; struct fuse_conn *fc; printk(KERN_DEBUG "fuse_dev_open\n"); - res = -ENOMEM; - fc = kmalloc(sizeof(*fc), GFP_KERNEL); + fc = new_conn(); if(!fc) - goto out; - - fc->sb = NULL; + return -ENOMEM; + fc->file = file; - - lock_kernel(); file->private_data = fc; - unlock_kernel(); - res = 0; - - out: - return res; + + printk(KERN_DEBUG "new connection: %i\n", fc->id); + + return 0; } static int fuse_dev_release(struct inode *inode, struct file *file) { struct fuse_conn *fc = file->private_data; - printk(KERN_DEBUG "fuse_dev_release\n"); + printk(KERN_DEBUG "fuse_dev_release[%i]\n", fc->id); - lock_kernel(); + spin_lock(&fuse_lock); fc->file = NULL; fuse_release_conn(fc); - unlock_kernel(); + spin_unlock(&fuse_lock); return 0; } diff --git a/dir.c b/dir.c index afa6106..150c401 100644 --- a/dir.c +++ b/dir.c @@ -7,13 +7,10 @@ */ -#include "fuse.h" +#include "fuse_i.h" #include #include -#include -#include -#include static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry) { diff --git a/fuse_i.h b/fuse_i.h index 5e1cc1c..70e149c 100644 --- a/fuse_i.h +++ b/fuse_i.h @@ -7,6 +7,8 @@ */ #include +#include +#include #define FUSE_VERSION "0.1" @@ -23,6 +25,35 @@ struct fuse_conn { /** The opened client device */ struct file *file; + + /** The client wait queue */ + wait_queue_head_t waitq; + + /** The list of pending requests */ + struct list_head pending; + + /** The list of requests being processed */ + struct list_head processing; + + /** The number of outstanding requests */ + int outstanding; + + /** Connnection number (for debuging) */ + int id; +}; + +/** + * A filesystem request + */ +struct fuse_req { + /** The request list */ + struct list_head list; + + /** The size of the data */ + size_t size; + + /** A pointer to the data */ + void *data; }; /** @@ -30,12 +61,16 @@ struct fuse_conn { */ extern struct proc_dir_entry *proc_fuse_dev; +/** + * The lock to protect fuses structures + */ +extern spinlock_t fuse_lock; + /** * Fill in the directory operations */ void fuse_dir_init(struct inode *inode); - /** * Check if the connection can be released, and if yes, then free the * connection structure diff --git a/inode.c b/inode.c index 77040fc..da30cac 100644 --- a/inode.c +++ b/inode.c @@ -11,7 +11,6 @@ #include #include -#include #include #include @@ -28,10 +27,13 @@ static void fuse_put_super(struct super_block *sb) { struct fuse_conn *fc = sb->u.generic_sbp; - printk(KERN_DEBUG "fuse_put_super\n"); + printk(KERN_DEBUG "fuse_put_super[%i]\n", fc->id); + spin_lock(&fuse_lock); fc->sb = NULL; fuse_release_conn(fc); + spin_unlock(&fuse_lock); + } static struct super_operations fuse_super_operations = { @@ -76,60 +78,68 @@ static struct fuse_conn *get_conn(struct fuse_mount_data *d) } +static struct inode *get_root_inode(struct super_block *sb) +{ + struct inode *root ; + + root = iget(sb, 1); + if(root) { + root->i_mode = S_IFDIR; + root->i_uid = 0; + root->i_gid = 0; + root->i_nlink = 2; + root->i_size = 0; + root->i_blksize = 1024; + root->i_blocks = 0; + root->i_atime = CURRENT_TIME; + root->i_mtime = CURRENT_TIME; + root->i_ctime = CURRENT_TIME; + fuse_dir_init(root); + } + + return root; +} + static struct super_block *fuse_read_super(struct super_block *sb, void *data, int silent) { struct fuse_conn *fc; struct inode *root; - fc = get_conn(data); - if(fc == NULL) - goto err; - - if(fc->sb != NULL) { - printk("fuse_read_super: file already mounted\n"); - goto err; - } - - sb->u.generic_sbp = fc; sb->s_blocksize = 1024; sb->s_blocksize_bits = 10; sb->s_magic = FUSE_SUPER_MAGIC; sb->s_op = &fuse_super_operations; - root = iget(sb, 1); - if(!root) { + root = get_root_inode(sb); + if(root == NULL) { printk("fuse_read_super: failed to get root inode\n"); - goto err; + return NULL; } printk(KERN_DEBUG "root inode: %ld/%d\n", root->i_ino, root->i_dev); - root->i_mode = S_IFDIR; - root->i_uid = 0; - root->i_gid = 0; - root->i_nlink = 2; - root->i_size = 0; - root->i_blksize = 1024; - root->i_blocks = 0; - root->i_atime = CURRENT_TIME; - root->i_mtime = CURRENT_TIME; - root->i_ctime = CURRENT_TIME; - fuse_dir_init(root); + spin_lock(&fuse_lock); + fc = get_conn(data); + if(fc == NULL) + goto err; - sb->s_root = d_alloc_root(root); - if(!sb->s_root) { - printk("fuse_read_super: failed to allocate root dentry\n"); - goto err_iput; + if(fc->sb != NULL) { + printk("fuse_read_super: connection %i already mounted\n", + fc->id); + goto err; } + sb->u.generic_sbp = fc; + sb->s_root = d_alloc_root(root); fc->sb = sb; - + spin_unlock(&fuse_lock); + return sb; - err_iput: - iput(root); err: + spin_unlock(&fuse_lock); + iput(root); return NULL; } diff --git a/main.c b/main.c deleted file mode 100644 index fa4ca8c..0000000 --- a/main.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - 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 -#include - -#define FUSE_VERSION "0.1" - - -void fuse_release_conn(struct fuse_conn *fc) -{ - if(fc->sb == NULL && fc->file == NULL) { - printk(KERN_DEBUG "fuse: release connection\n"); - kfree(fc); - } -} - -int init_module(void) -{ - int res; - - printk(KERN_DEBUG "fuse init (version %s)\n", FUSE_VERSION); - - res = fuse_fs_init(); - if(res) - goto err; - - res = fuse_dev_init(); - if(res) - goto err_fs_cleanup; - - return 0; - - err_fs_cleanup: - fuse_fs_cleanup(); - err: - return res; -} - -void cleanup_module(void) -{ - printk(KERN_DEBUG "fuse cleanup\n"); - - fuse_fs_cleanup(); - fuse_dev_cleanup(); -} - -/* - * Local Variables: - * indent-tabs-mode: t - * c-basic-offset: 8 - */ diff --git a/util.c b/util.c new file mode 100644 index 0000000..281725c --- /dev/null +++ b/util.c @@ -0,0 +1,63 @@ +/* + 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 +#include + +#define FUSE_VERSION "0.1" + +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) { + printk(KERN_DEBUG "fuse: release connection: %i\n", fc->id); + kfree(fc); + } +} + +int init_module(void) +{ + int res; + + printk(KERN_DEBUG "fuse init (version %s)\n", FUSE_VERSION); + + res = fuse_fs_init(); + if(res) + goto err; + + res = fuse_dev_init(); + if(res) + goto err_fs_cleanup; + + return 0; + + err_fs_cleanup: + fuse_fs_cleanup(); + err: + return res; +} + +void cleanup_module(void) +{ + printk(KERN_DEBUG "fuse cleanup\n"); + + fuse_fs_cleanup(); + fuse_dev_cleanup(); +} + +/* + * Local Variables: + * indent-tabs-mode: t + * c-basic-offset: 8 + */