aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/dev.c')
-rw-r--r--kernel/dev.c275
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);
+}