improvements
authorMiklos Szeredi <miklos@szeredi.hu>
Wed, 24 Oct 2001 14:37:13 +0000 (14:37 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Wed, 24 Oct 2001 14:37:13 +0000 (14:37 +0000)
Makefile
dev.c
dir.c
fuse_i.h
inode.c
main.c [deleted file]
util.c [new file with mode: 0644]

index aedd26d7d25b12fc996378c4319ea98a32b20252..f8810fd2046992d07cb7d44f5ed4a926f0f2b94f 100644 (file)
--- 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 c7dd2478cddfa50f4cb13b80fc290388551893af..159d8d6148e33fa67d90cd8f78fc62d21c72dbdc 100644 (file)
--- a/dev.c
+++ b/dev.c
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/smp_lock.h>
 #include <linux/poll.h>
-#include <linux/file.h>
 #include <linux/proc_fs.h>
 
 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 afa610694b9867c2e4402b9e436410f2673fdc89..150c4014fa26b3eb830649c85b889a72c0ca420f 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -7,13 +7,10 @@
 */
 
 
-#include "fuse.h"
+#include "fuse_i.h"
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/smp_lock.h>
-#include <linux/sched.h>
-#include <linux/file.h>
 
 static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
 {
index 5e1cc1cd8575f7ae4f7b98c7a7d7202c00215253..70e149c2330bd4af1864123ac6880b9235e42689 100644 (file)
--- a/fuse_i.h
+++ b/fuse_i.h
@@ -7,6 +7,8 @@
 */
 
 #include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
 
 #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 77040fcfd040d25c23a16aebc5465573ee597459..da30cacc1ae57552062fa5ebaf4e100c650f73e1 100644 (file)
--- a/inode.c
+++ b/inode.c
@@ -11,7 +11,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/smp_lock.h>
 #include <linux/sched.h>
 #include <linux/file.h>
 
@@ -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 (file)
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 <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/smp_lock.h>
-#include <linux/slab.h>
-
-#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 (file)
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 <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/smp_lock.h>
+#include <linux/slab.h>
+
+#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
+ */