diff options
author | Miklos Szeredi <miklos@szeredi.hu> | 2004-11-20 11:12:21 +0000 |
---|---|---|
committer | Miklos Szeredi <miklos@szeredi.hu> | 2004-11-20 11:12:21 +0000 |
commit | 13ed482774a87185fb4753d84444741b1eb93780 (patch) | |
tree | e5f7d851ca6445bad3d6820a9202ae87bd7a7e2b /kernel/dev.c | |
parent | 08ddb8e5e0af8c1326607f4d06c0dbc85733e483 (diff) | |
download | libfuse-13ed482774a87185fb4753d84444741b1eb93780.tar.gz |
fix
Diffstat (limited to 'kernel/dev.c')
-rw-r--r-- | kernel/dev.c | 275 |
1 files changed, 152 insertions, 123 deletions
diff --git a/kernel/dev.c b/kernel/dev.c index d353c7f..7261770 100644 --- a/kernel/dev.c +++ b/kernel/dev.c @@ -8,19 +8,23 @@ #include "fuse_i.h" +#include <linux/module.h> #include <linux/poll.h> +#ifdef KERNEL_2_6 +#include <linux/kobject.h> +#include <linux/miscdevice.h> +#else #include <linux/proc_fs.h> +#endif #include <linux/file.h> -static struct proc_dir_entry *proc_fs_fuse; -struct proc_dir_entry *proc_fuse_dev; static kmem_cache_t *fuse_req_cachep; static inline struct fuse_conn *fuse_get_conn(struct file *file) { struct fuse_conn *fc; spin_lock(&fuse_lock); - fc = (struct fuse_conn *) file->private_data; + fc = file->private_data; if (fc && !fc->sb) fc = NULL; spin_unlock(&fuse_lock); @@ -29,15 +33,12 @@ static inline struct fuse_conn *fuse_get_conn(struct file *file) struct fuse_req *fuse_request_alloc(void) { - struct fuse_req *req; - - req = (struct fuse_req *) kmem_cache_alloc(fuse_req_cachep, SLAB_KERNEL); + struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, SLAB_KERNEL); if (req) { memset(req, 0, sizeof(*req)); INIT_LIST_HEAD(&req->list); init_waitqueue_head(&req->waitq); } - return req; } @@ -46,68 +47,19 @@ void fuse_request_free(struct fuse_req *req) kmem_cache_free(fuse_req_cachep, req); } -static int request_restartable(enum fuse_opcode opcode) -{ - switch (opcode) { - case FUSE_LOOKUP: - case FUSE_GETATTR: - case FUSE_SETATTR: - case FUSE_READLINK: - case FUSE_GETDIR: - case FUSE_OPEN: - case FUSE_READ: - case FUSE_WRITE: - case FUSE_STATFS: - case FUSE_FSYNC: - case FUSE_GETXATTR: - case FUSE_SETXATTR: - case FUSE_LISTXATTR: - return 1; - - default: - return 0; - } -} - /* Called with fuse_lock held. Releases, and then reaquires it. */ -static void request_wait_answer(struct fuse_req *req, int interruptible) +static void request_wait_answer(struct fuse_req *req) { - int intr; - spin_unlock(&fuse_lock); - if (interruptible) - intr = wait_event_interruptible(req->waitq, req->finished); - else { - wait_event(req->waitq, req->finished); - intr = 0; - } + wait_event(req->waitq, req->finished); spin_lock(&fuse_lock); - if (!intr) - return; - - /* Request interrupted... Wait for it to be unlocked */ - while (req->locked) { - req->interrupted = 1; - spin_unlock(&fuse_lock); - wait_event(req->waitq, !req->locked); - spin_lock(&fuse_lock); - } - if (req->finished) - return; - - /* Operations which modify the filesystem cannot safely be - restarted, because it is uncertain whether the operation has - completed or not... */ - if (req->sent && !request_restartable(req->in.h.opcode)) - req->out.h.error = -EINTR; - else - req->out.h.error = -ERESTARTSYS; } static int get_unique(struct fuse_conn *fc) { - do fc->reqctr++; - while (!fc->reqctr); + fc->reqctr++; + if (fc->reqctr == 0) + fc->reqctr = 1; return fc->reqctr; } @@ -183,10 +135,9 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req) } } -static void __request_send(struct fuse_conn *fc, struct fuse_req *req, - int interruptible) +void request_send(struct fuse_conn *fc, struct fuse_req *req) { - req->issync = 1; + req->isreply = 1; req->end = NULL; spin_lock(&fuse_lock); @@ -195,27 +146,15 @@ static void __request_send(struct fuse_conn *fc, struct fuse_req *req, req->in.h.unique = get_unique(fc); list_add_tail(&req->list, &fc->pending); wake_up(&fc->waitq); - request_wait_answer(req, interruptible); + request_wait_answer(req); list_del(&req->list); } spin_unlock(&fuse_lock); } -void request_send(struct fuse_conn *fc, struct fuse_req *req) -{ - /* There are problems with interrupted requests so it's - disabled for now */ - __request_send(fc, req, 0); -} - -void request_send_nonint(struct fuse_conn *fc, struct fuse_req *req) -{ - __request_send(fc, req, 0); -} - void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req) { - req->issync = 0; + req->isreply = 0; spin_lock(&fuse_lock); if (fc->file) { @@ -228,12 +167,12 @@ void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req) } } -void request_send_nonblock(struct fuse_conn *fc, struct fuse_req *req, +void request_send_async(struct fuse_conn *fc, struct fuse_req *req, fuse_reqend_t end, void *data) { req->end = end; req->data = data; - req->issync = 1; + req->isreply = 1; spin_lock(&fuse_lock); if (fc->file) { @@ -265,8 +204,8 @@ static void request_wait(struct fuse_conn *fc) remove_wait_queue(&fc->waitq, &wait); } -static inline int copy_in_one(const void *src, size_t srclen, char **dstp, - size_t *dstlenp) +static inline int copy_in_one(const void *src, size_t srclen, + char __user **dstp, size_t *dstlenp) { if (*dstlenp < srclen) { printk("fuse_dev_read: buffer too small\n"); @@ -282,7 +221,8 @@ static inline int copy_in_one(const void *src, size_t srclen, char **dstp, return 0; } -static inline int copy_in_args(struct fuse_in *in, char *buf, size_t nbytes) +static inline int copy_in_args(struct fuse_in *in, char __user *buf, + size_t nbytes) { int err; int i; @@ -302,15 +242,15 @@ static inline int copy_in_args(struct fuse_in *in, char *buf, size_t nbytes) return orignbytes - nbytes; } -static ssize_t fuse_dev_read(struct file *file, char *buf, size_t nbytes, - loff_t *off) +static ssize_t fuse_dev_read(struct file *file, char __user *buf, + size_t nbytes, loff_t *off) { ssize_t ret; struct fuse_conn *fc; struct fuse_req *req = NULL; spin_lock(&fuse_lock); - fc = (struct fuse_conn *) file->private_data; + fc = file->private_data; if (!fc) { spin_unlock(&fuse_lock); return -EPERM; @@ -331,7 +271,7 @@ static ssize_t fuse_dev_read(struct file *file, char *buf, size_t nbytes, ret = copy_in_args(&req->in, buf, nbytes); spin_lock(&fuse_lock); - if (req->issync) { + if (req->isreply) { if (ret < 0) { req->out.h.error = -EPROTO; req->finished = 1; @@ -371,12 +311,12 @@ static struct fuse_req *request_find(struct fuse_conn *fc, unsigned int unique) static void process_getdir(struct fuse_req *req) { - struct fuse_getdir_out_i *arg; - arg = (struct fuse_getdir_out_i *) req->out.args[0].value; + struct fuse_getdir_out_i *arg = req->out.args[0].value; arg->file = fget(arg->fd); } -static inline int copy_out_one(struct fuse_out_arg *arg, const char **srcp, +static inline int copy_out_one(struct fuse_out_arg *arg, + const char __user **srcp, size_t *srclenp, int allowvar) { size_t dstlen = arg->size; @@ -398,7 +338,7 @@ static inline int copy_out_one(struct fuse_out_arg *arg, const char **srcp, return 0; } -static inline int copy_out_args(struct fuse_req *req, const char *buf, +static inline int copy_out_args(struct fuse_req *req, const char __user *buf, size_t nbytes) { struct fuse_out *out = &req->out; @@ -436,8 +376,8 @@ static inline int copy_out_args(struct fuse_req *req, const char *buf, return 0; } -static inline int copy_out_header(struct fuse_out_header *oh, const char *buf, - size_t nbytes) +static inline int copy_out_header(struct fuse_out_header *oh, + const char __user *buf, size_t nbytes) { if (nbytes < sizeof(struct fuse_out_header)) { printk("fuse_dev_write: write is short\n"); @@ -456,7 +396,12 @@ static int fuse_invalidate(struct fuse_conn *fc, struct fuse_user_header *uh) down(&fc->sb_sem); err = -ENODEV; if (fc->sb) { - struct inode *inode = fuse_ilookup(fc, uh->ino, uh->nodeid); + struct inode *inode; +#ifdef KERNEL_2_6 + inode = fuse_ilookup(fc->sb, uh->nodeid); +#else + inode = fuse_ilookup(fc->sb, uh->ino, uh->nodeid); +#endif err = -ENOENT; if (inode) { fuse_sync_inode(inode); @@ -474,7 +419,7 @@ static int fuse_invalidate(struct fuse_conn *fc, struct fuse_user_header *uh) return err; } -static int fuse_user_request(struct fuse_conn *fc, const char *buf, +static int fuse_user_request(struct fuse_conn *fc, const char __user *buf, size_t nbytes) { struct fuse_user_header uh; @@ -499,8 +444,7 @@ static int fuse_user_request(struct fuse_conn *fc, const char *buf, return err; } - -static ssize_t fuse_dev_write(struct file *file, const char *buf, +static ssize_t fuse_dev_write(struct file *file, const char __user *buf, size_t nbytes, loff_t *off) { int err; @@ -558,7 +502,6 @@ static ssize_t fuse_dev_write(struct file *file, const char *buf, return err; } - static unsigned int fuse_dev_poll(struct file *file, poll_table *wait) { struct fuse_conn *fc = fuse_get_conn(file); @@ -583,7 +526,7 @@ static void end_requests(struct fuse_conn *fc, struct list_head *head) struct fuse_req *req; req = list_entry(head->next, struct fuse_req, list); list_del_init(&req->list); - if (req->issync) { + if (req->isreply) { req->out.h.error = -ECONNABORTED; req->finished = 1; /* Unlocks fuse_lock: */ @@ -602,7 +545,7 @@ static int fuse_dev_release(struct inode *inode, struct file *file) struct fuse_conn *fc; spin_lock(&fuse_lock); - fc = (struct fuse_conn *) file->private_data; + fc = file->private_data; if (fc) { fc->file = NULL; end_requests(fc, &fc->pending); @@ -613,7 +556,7 @@ static int fuse_dev_release(struct inode *inode, struct file *file) return 0; } -static struct file_operations fuse_dev_operations = { +struct file_operations fuse_dev_operations = { .owner = THIS_MODULE, .read = fuse_dev_read, .write = fuse_dev_write, @@ -621,6 +564,81 @@ static struct file_operations fuse_dev_operations = { .release = fuse_dev_release, }; +#ifdef KERNEL_2_6 +#define FUSE_MINOR MISC_DYNAMIC_MINOR + +#ifndef FUSE_MAINLINE +static decl_subsys(fs, NULL, NULL); +#endif +static decl_subsys(fuse, NULL, NULL); + +static ssize_t version_show(struct subsystem *subsys, char *buf) +{ + return sprintf(buf, "%i.%i\n", FUSE_KERNEL_VERSION, + FUSE_KERNEL_MINOR_VERSION); +} +static struct subsys_attribute fuse_attr_version = __ATTR_RO(version); + +static struct miscdevice fuse_miscdevice = { + .minor = FUSE_MINOR, + .name = "fuse", + .fops = &fuse_dev_operations, +}; + +static int __init fuse_sysfs_init(void) +{ + int err; +#ifdef FUSE_MAINLINE + err = fs_subsys_register(&fuse_subsys); +#else + subsystem_register(&fs_subsys); + kset_set_kset_s(&fuse_subsys, fs_subsys); + err = subsystem_register(&fuse_subsys); +#endif + if (err) + return err; + err = subsys_create_file(&fuse_subsys, &fuse_attr_version); + if (err) { + subsystem_unregister(&fuse_subsys); +#ifndef FUSE_MAINLINE + subsystem_unregister(&fs_subsys); +#endif + return err; + } + return 0; +} + +static void fuse_sysfs_clean(void) +{ + subsys_remove_file(&fuse_subsys, &fuse_attr_version); + subsystem_unregister(&fuse_subsys); +#ifndef FUSE_MAINLINE + subsystem_unregister(&fs_subsys); +#endif +} + +static int __init fuse_device_init(void) +{ + int err = fuse_sysfs_init(); + if (err) + return err; + + err = misc_register(&fuse_miscdevice); + if (err) { + fuse_sysfs_clean(); + return err; + } + return 0; +} + +static void fuse_device_clean(void) +{ + misc_deregister(&fuse_miscdevice); + fuse_sysfs_clean(); +} +#else +static struct proc_dir_entry *proc_fs_fuse; + static int read_version(char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -630,27 +648,18 @@ static int read_version(char *page, char **start, off_t off, int count, return s - page; } -int fuse_dev_init() +static int fuse_device_init(void) { - proc_fs_fuse = NULL; - proc_fuse_dev = NULL; - - fuse_req_cachep = kmem_cache_create("fuser_request", - sizeof(struct fuse_req), - 0, 0, NULL, NULL); - if (!fuse_req_cachep) - return -ENOMEM; - proc_fs_fuse = proc_mkdir("fuse", proc_root_fs); if (proc_fs_fuse) { struct proc_dir_entry *de; proc_fs_fuse->owner = THIS_MODULE; - proc_fuse_dev = create_proc_entry("dev", S_IFSOCK | 0666, + de = create_proc_entry("dev", S_IFSOCK | 0666, proc_fs_fuse); - if (proc_fuse_dev) { - proc_fuse_dev->owner = THIS_MODULE; - proc_fuse_dev->proc_fops = &fuse_dev_operations; + if (de) { + de->owner = THIS_MODULE; + de->proc_fops = &fuse_dev_operations; } de = create_proc_entry("version", S_IFREG | 0444, proc_fs_fuse); if (de) { @@ -661,20 +670,40 @@ int fuse_dev_init() return 0; } -void fuse_dev_cleanup() +static void fuse_device_clean(void) { if (proc_fs_fuse) { remove_proc_entry("dev", proc_fs_fuse); remove_proc_entry("version", proc_fs_fuse); remove_proc_entry("fuse", proc_root_fs); } +} +#endif - kmem_cache_destroy(fuse_req_cachep); +int __init fuse_dev_init(void) +{ + int err; + err = fuse_device_init(); + if (err) + goto out; + + err = -ENOMEM; + fuse_req_cachep = kmem_cache_create("fuser_request", + sizeof(struct fuse_req), + 0, 0, NULL, NULL); + if (!fuse_req_cachep) + goto out_device_clean; + + return 0; + + out_device_clean: + fuse_device_clean(); + out: + return err; } -/* - * Local Variables: - * indent-tabs-mode: t - * c-basic-offset: 8 - * End: - */ +void fuse_dev_cleanup(void) +{ + fuse_device_clean(); + kmem_cache_destroy(fuse_req_cachep); +} |