improvements
authorMiklos Szeredi <miklos@szeredi.hu>
Thu, 25 Oct 2001 14:16:17 +0000 (14:16 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Thu, 25 Oct 2001 14:16:17 +0000 (14:16 +0000)
dev.c
dir.c
fuse.h
fuse_i.h
fusemount.c
inode.c
request.c [new file with mode: 0644]

diff --git a/dev.c b/dev.c
index 159d8d6148e33fa67d90cd8f78fc62d21c72dbdc..b6b99300300c2e0b4df65102ad9b12ba8c843ac2 100644 (file)
--- a/dev.c
+++ b/dev.c
 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, &param, 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(&param, 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 150c4014fa26b3eb830649c85b889a72c0ca420f..6fa5959bf3ec5b643d31085b9917bdb40435a507 100644 (file)
--- 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 df71221399a985f8518eb84e556eea6bb7537ac9..32c2609336893fe97b2a925d5493c539f1a5fa6f 100644 (file)
--- 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:
+ */
index 70e149c2330bd4af1864123ac6880b9235e42689..a7a907feddfb6f0bd983dcd4dcce84f21acf0b3f 100644 (file)
--- a/fuse_i.h
+++ b/fuse_i.h
@@ -6,6 +6,8 @@
     See the file COPYING.
 */
 
+#include "fuse.h"
+
 #include <linux/fs.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
@@ -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
index b4d3bc0939086cf5a125ec69042c6fbec7072956..3ae293221d4d0484937a38e49c634dfe40456552 100644 (file)
 #include <sys/mount.h>
 #include <mntent.h>
 
+static void loop(int devfd)
+{
+    int res;
+    struct fuse_param param;
+    
+    while(1) {
+        res = read(devfd, &param, 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, &param, 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 da30cacc1ae57552062fa5ebaf4e100c650f73e1..590a80db5b2aa5e365bebbae78d7b50b2c2204f6 100644 (file)
--- a/inode.c
+++ b/inode.c
@@ -6,7 +6,6 @@
     See the file COPYING.
 */
 
-#include "fuse.h"
 #include "fuse_i.h"
 
 #include <linux/module.h>
diff --git a/request.c b/request.c
new file mode 100644 (file)
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 <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+
+
+/* 
+ * Local Variables:
+ * indent-tabs-mode: t
+ * c-basic-offset: 8
+ * End:
+ */