summaryrefslogtreecommitdiff
path: root/fs/fuse/inode.c
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2005-09-09 13:10:27 -0700
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-09 14:03:44 -0700
commit334f485df85ac7736ebe14940bf0a059c5f26d7d (patch)
tree754e5528289048a7104f4c1b431cebc1df16e2ce /fs/fuse/inode.c
parentd8a5ba45457e4a22aa39c939121efd7bb6c76672 (diff)
[PATCH] FUSE - device functions
This adds the FUSE device handling functions. This contains the following files: o dev.c - fuse device operations (read, write, release, poll) - registers misc device - support for sending requests to userspace Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/fuse/inode.c')
-rw-r--r--fs/fuse/inode.c58
1 files changed, 53 insertions, 5 deletions
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index ea6339c2b6a1..33fad334ba70 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -151,6 +151,8 @@ static void fuse_put_super(struct super_block *sb)
mount_count --;
fc->sb = NULL;
fc->user_id = 0;
+ /* Flush all readers on this fs */
+ wake_up_all(&fc->waitq);
fuse_release_conn(fc);
*get_fuse_conn_super_p(sb) = NULL;
spin_unlock(&fuse_lock);
@@ -229,22 +231,51 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
return 0;
}
-void fuse_release_conn(struct fuse_conn *fc)
+static void free_conn(struct fuse_conn *fc)
{
+ while (!list_empty(&fc->unused_list)) {
+ struct fuse_req *req;
+ req = list_entry(fc->unused_list.next, struct fuse_req, list);
+ list_del(&req->list);
+ fuse_request_free(req);
+ }
kfree(fc);
}
+/* Must be called with the fuse lock held */
+void fuse_release_conn(struct fuse_conn *fc)
+{
+ if (!fc->sb && !fc->file)
+ free_conn(fc);
+}
+
static struct fuse_conn *new_conn(void)
{
struct fuse_conn *fc;
fc = kmalloc(sizeof(*fc), GFP_KERNEL);
if (fc != NULL) {
+ int i;
memset(fc, 0, sizeof(*fc));
fc->sb = NULL;
+ fc->file = NULL;
fc->user_id = 0;
+ init_waitqueue_head(&fc->waitq);
+ INIT_LIST_HEAD(&fc->pending);
+ INIT_LIST_HEAD(&fc->processing);
+ INIT_LIST_HEAD(&fc->unused_list);
+ sema_init(&fc->outstanding_sem, 0);
+ for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) {
+ struct fuse_req *req = fuse_request_alloc();
+ if (!req) {
+ free_conn(fc);
+ return NULL;
+ }
+ list_add(&req->list, &fc->unused_list);
+ }
fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
fc->bdi.unplug_io_fn = default_unplug_io_fn;
+ fc->reqctr = 0;
}
return fc;
}
@@ -253,11 +284,20 @@ static struct fuse_conn *get_conn(struct file *file, struct super_block *sb)
{
struct fuse_conn *fc;
+ if (file->f_op != &fuse_dev_operations)
+ return ERR_PTR(-EINVAL);
fc = new_conn();
if (fc == NULL)
- return NULL;
+ return ERR_PTR(-ENOMEM);
spin_lock(&fuse_lock);
- fc->sb = sb;
+ if (file->private_data) {
+ free_conn(fc);
+ fc = ERR_PTR(-EINVAL);
+ } else {
+ file->private_data = fc;
+ fc->sb = sb;
+ fc->file = file;
+ }
spin_unlock(&fuse_lock);
return fc;
}
@@ -315,8 +355,8 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
fc = get_conn(file, sb);
fput(file);
- if (fc == NULL)
- return -EINVAL;
+ if (IS_ERR(fc))
+ return PTR_ERR(fc);
fc->user_id = d.user_id;
@@ -336,6 +376,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
iput(root);
goto err;
}
+ fuse_send_init(fc);
return 0;
err:
@@ -411,8 +452,14 @@ static int __init fuse_init(void)
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;
}
@@ -422,6 +469,7 @@ static void __exit fuse_exit(void)
printk(KERN_DEBUG "fuse exit\n");
fuse_fs_cleanup();
+ fuse_dev_cleanup();
}
module_init(fuse_init);