aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2001-10-25 14:16:17 +0000
committerMiklos Szeredi <miklos@szeredi.hu>2001-10-25 14:16:17 +0000
commitd8ae7147bfe8f40e72ea640c6631a4b2c6f2c6c9 (patch)
treeb9cc8c9342ebf54a45184b0345a798106466a3a8
parent79b52f63303c15d4545a7464775f4b1beab8d2c9 (diff)
downloadlibfuse-d8ae7147bfe8f40e72ea640c6631a4b2c6f2c6c9.tar.gz
improvements
-rw-r--r--dev.c189
-rw-r--r--dir.c14
-rw-r--r--fuse.h41
-rw-r--r--fuse_i.h27
-rw-r--r--fusemount.c28
-rw-r--r--inode.c1
-rw-r--r--request.c22
7 files changed, 265 insertions, 57 deletions
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, &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 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 <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
diff --git a/fusemount.c b/fusemount.c
index b4d3bc0..3ae2932 100644
--- a/fusemount.c
+++ b/fusemount.c
@@ -17,8 +17,30 @@
#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 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 <linux/module.h>
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 <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+
+
+/*
+ * Local Variables:
+ * indent-tabs-mode: t
+ * c-basic-offset: 8
+ * End:
+ */