From 13ed482774a87185fb4753d84444741b1eb93780 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Sat, 20 Nov 2004 11:12:21 +0000 Subject: [PATCH] fix --- ChangeLog | 15 ++ kernel/cleanup.sh | 16 ++ kernel/dev.c | 275 ++++++++++++++++++--------------- kernel/dir.c | 137 +++++++---------- kernel/file.c | 368 ++++++++++++++++++++++++++------------------ kernel/fuse_i.h | 63 ++++---- kernel/inode.c | 150 ++++++++++-------- kernel/linux/fuse.h | 6 +- kernel/util.c | 15 +- 9 files changed, 585 insertions(+), 460 deletions(-) create mode 100755 kernel/cleanup.sh diff --git a/ChangeLog b/ChangeLog index 1f905b1..f50741c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2004-11-19 Miklos Szeredi + + * Cleaned up kernel in preparation for merge into mainline: + + * Use /sys/fs/fuse/version instead of /proc/fs/fuse/version + + * Use real device (/dev/fuse) instead of /proc/fs/fuse/dev + + * __user annotations for sparse + + * allocate individual pages instead of kmalloc in fuse_readdir, + fuse_read and fuse_write. + + * Fix NFS export in case "use_ino" mount option is given + 2004-11-14 Miklos Szeredi * Released 2.1-pre1 diff --git a/kernel/cleanup.sh b/kernel/cleanup.sh new file mode 100755 index 0000000..6255cb2 --- /dev/null +++ b/kernel/cleanup.sh @@ -0,0 +1,16 @@ +#! /bin/sh + +destdir=$1 + +if test ! -d "$destdir"; then + printf "Usage: %s destination_directory\n" $0 + exit 1 +fi +if test "$destdir" = "."; then + echo "Not overwriting contents of original directory" + exit 1 +fi + +for f in dev.c dir.c file.c inode.c util.c fuse_i.h; do + unifdef -DKERNEL_2_6 -DKERNEL_2_6_6_PLUS -DKERNEL_2_6_10_PLUS -DHAVE_KERNEL_XATTR -DFS_SAFE -DMAX_LFS_FILESIZE -DFUSE_MAINLINE -DBUG_ON -D__user -DMODULE_LICENSE $f > $destdir/$f +done 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 #include +#ifdef KERNEL_2_6 +#include +#include +#else #include +#endif #include -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); +} diff --git a/kernel/dir.c b/kernel/dir.c index e322544..124bf86 100644 --- a/kernel/dir.c +++ b/kernel/dir.c @@ -9,22 +9,24 @@ #include "fuse_i.h" #include -#include #include +#ifdef KERNEL_2_6 +#include +#else +#include +#endif +#include static struct inode_operations fuse_dir_inode_operations; static struct inode_operations fuse_file_inode_operations; static struct inode_operations fuse_symlink_inode_operations; - static struct file_operations fuse_dir_operations; - static struct dentry_operations fuse_dentry_operations; #ifndef KERNEL_2_6 #define new_decode_dev(x) (x) #define new_encode_dev(x) (x) #endif - static void change_attributes(struct inode *inode, struct fuse_attr *attr) { if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size) { @@ -126,9 +128,9 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, return inode; } -struct inode *fuse_ilookup(struct fuse_conn *fc, ino_t ino, unsigned long nodeid) +struct inode *fuse_ilookup(struct super_block *sb, unsigned long nodeid) { - return ilookup5(fc->sb, nodeid, fuse_inode_eq, &nodeid); + return ilookup5(sb, nodeid, fuse_inode_eq, &nodeid); } #else static int fuse_inode_eq(struct inode *inode, unsigned long ino, void *_nodeidp){ @@ -163,16 +165,15 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, return inode; } -struct inode *fuse_ilookup(struct fuse_conn *fc, ino_t ino, unsigned long nodeid) +struct inode *fuse_ilookup(struct super_block *sb, ino_t ino, unsigned long nodeid) { - struct inode *inode = iget4(fc->sb, ino, fuse_inode_eq, &nodeid); + struct inode *inode = iget4(sb, ino, fuse_inode_eq, &nodeid); if (inode && !inode->u.generic_ip) { iput(inode); inode = NULL; } return inode; } - #endif static int fuse_send_lookup(struct fuse_conn *fc, struct fuse_req *req, @@ -303,8 +304,7 @@ static int lookup_new_entry(struct fuse_conn *fc, struct fuse_req *req, return 0; } - -static int _fuse_mknod(struct inode *dir, struct dentry *entry, int mode, +static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode, dev_t rdev) { struct fuse_conn *fc = INO_FC(dir); @@ -340,12 +340,12 @@ static int _fuse_mknod(struct inode *dir, struct dentry *entry, int mode, return err; } -static int _fuse_create(struct inode *dir, struct dentry *entry, int mode) +static int fuse_create(struct inode *dir, struct dentry *entry, int mode, + struct nameidata *nd) { - return _fuse_mknod(dir, entry, mode, 0); + return fuse_mknod(dir, entry, mode, 0); } - static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode) { struct fuse_conn *fc = INO_FC(dir); @@ -592,7 +592,7 @@ static int fuse_revalidate(struct dentry *entry) return fuse_do_getattr(inode); } -static int _fuse_permission(struct inode *inode, int mask) +static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) { struct fuse_conn *fc = INO_FC(inode); @@ -601,10 +601,10 @@ static int _fuse_permission(struct inode *inode, int mask) return -EACCES; else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { int err; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) - err = vfs_permission(inode, mask); -#else +#ifdef KERNEL_2_6_10_PLUS err = generic_permission(inode, mask, NULL); +#else + err = vfs_permission(inode, mask); #endif /* If permission is denied, try to refresh file @@ -613,13 +613,12 @@ static int _fuse_permission(struct inode *inode, int mask) if (err == -EACCES) { err = fuse_do_getattr(inode); - if (!err) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) - err = vfs_permission(inode, mask); -#else + if (!err) +#ifdef KERNEL_2_6_10_PLUS err = generic_permission(inode, mask, NULL); +#else + err = vfs_permission(inode, mask); #endif - } } /* FIXME: Need some mechanism to revoke permissions: @@ -706,7 +705,6 @@ static int fuse_getdir(struct file *file) return err; } -#define DIR_BUFSIZE 2048 static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) { struct file *cfile = file->private_data; @@ -721,17 +719,17 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) cfile = file->private_data; } - buf = kmalloc(DIR_BUFSIZE, GFP_KERNEL); + buf = (char *) __get_free_page(GFP_KERNEL); if (!buf) return -ENOMEM; - ret = kernel_read(cfile, file->f_pos, buf, DIR_BUFSIZE); + ret = kernel_read(cfile, file->f_pos, buf, PAGE_SIZE); if (ret < 0) printk("fuse_readdir: failed to read container file\n"); else ret = parse_dirfile(buf, ret, file, dstbuf, filldir); - kfree(buf); + free_page((unsigned long) buf); return ret; } @@ -774,7 +772,8 @@ static void free_link(char *link) free_page((unsigned long) link); } -static int fuse_readlink(struct dentry *dentry, char *buffer, int buflen) +static int fuse_readlink(struct dentry *dentry, char __user *buffer, + int buflen) { int ret; char *link; @@ -863,10 +862,10 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr) if (attr->ia_valid & ATTR_SIZE) { unsigned long limit; is_truncate = 1; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) - limit = current->rlim[RLIMIT_FSIZE].rlim_cur; -#else +#ifdef KERNEL_2_6_10_PLUS limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; +#else + limit = current->rlim[RLIMIT_FSIZE].rlim_cur; #endif if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) { send_sig(SIGXFSZ, current, 0); @@ -912,7 +911,7 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr) return err; } -static int _fuse_dentry_revalidate(struct dentry *entry) +static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) { if (!entry->d_inode) return 0; @@ -942,9 +941,6 @@ static int _fuse_dentry_revalidate(struct dentry *entry) } #ifdef KERNEL_2_6 - -#define fuse_mknod _fuse_mknod - static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry, struct kstat *stat) { @@ -965,29 +961,7 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, return ERR_PTR(err); return d_splice_alias(inode, entry); } - -static int fuse_create(struct inode *dir, struct dentry *entry, int mode, - struct nameidata *nd) -{ - return _fuse_create(dir, entry, mode); -} - -static int fuse_permission(struct inode *inode, int mask, - struct nameidata *nd) -{ - return _fuse_permission(inode, mask); -} - -static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) -{ - return _fuse_dentry_revalidate(entry); -} - #else /* KERNEL_2_6 */ - -#define fuse_create _fuse_create -#define fuse_permission _fuse_permission - static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry) { struct inode *inode; @@ -1009,20 +983,29 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry) return NULL; } -static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode, +static int fuse_mknod_2_4(struct inode *dir, struct dentry *entry, int mode, int rdev) { - return _fuse_mknod(dir, entry, mode, rdev); + return fuse_mknod(dir, entry, mode, rdev); +} + +static int fuse_dentry_revalidate_2_4(struct dentry *entry, int flags) +{ + return fuse_dentry_revalidate(entry, NULL); +} + +static int fuse_create_2_4(struct inode *dir, struct dentry *entry, int mode) +{ + return fuse_create(dir, entry, mode, NULL); } -static int fuse_dentry_revalidate(struct dentry *entry, int flags) +static int fuse_permission_2_4(struct inode *inode, int mask) { - return _fuse_dentry_revalidate(entry); + return fuse_permission(inode, mask, NULL); } #endif /* KERNEL_2_6 */ #ifdef HAVE_KERNEL_XATTR - #ifdef KERNEL_2_6 static int fuse_setxattr(struct dentry *entry, const char *name, const void *value, size_t size, int flags) @@ -1198,14 +1181,10 @@ static int fuse_removexattr(struct dentry *entry, const char *name) fuse_put_request(fc, req); return err; } - #endif -static struct inode_operations fuse_dir_inode_operations = -{ +static struct inode_operations fuse_dir_inode_operations = { .lookup = fuse_lookup, - .create = fuse_create, - .mknod = fuse_mknod, .mkdir = fuse_mkdir, .symlink = fuse_symlink, .unlink = fuse_unlink, @@ -1213,10 +1192,15 @@ static struct inode_operations fuse_dir_inode_operations = .rename = fuse_rename, .link = fuse_link, .setattr = fuse_setattr, - .permission = fuse_permission, #ifdef KERNEL_2_6 + .create = fuse_create, + .mknod = fuse_mknod, + .permission = fuse_permission, .getattr = fuse_getattr, #else + .create = fuse_create_2_4, + .mknod = fuse_mknod_2_4, + .permission = fuse_permission_2_4, .revalidate = fuse_revalidate, #endif #ifdef HAVE_KERNEL_XATTR @@ -1236,10 +1220,11 @@ static struct file_operations fuse_dir_operations = { static struct inode_operations fuse_file_inode_operations = { .setattr = fuse_setattr, - .permission = fuse_permission, #ifdef KERNEL_2_6 + .permission = fuse_permission, .getattr = fuse_getattr, #else + .permission = fuse_permission_2_4, .revalidate = fuse_revalidate, #endif #ifdef HAVE_KERNEL_XATTR @@ -1250,8 +1235,7 @@ static struct inode_operations fuse_file_inode_operations = { #endif }; -static struct inode_operations fuse_symlink_inode_operations = -{ +static struct inode_operations fuse_symlink_inode_operations = { .setattr = fuse_setattr, .readlink = fuse_readlink, .follow_link = fuse_follow_link, @@ -1269,12 +1253,9 @@ static struct inode_operations fuse_symlink_inode_operations = }; static struct dentry_operations fuse_dentry_operations = { +#ifdef KERNEL_2_6 .d_revalidate = fuse_dentry_revalidate, +#else + .d_revalidate = fuse_dentry_revalidate_2_4, +#endif }; - -/* - * Local Variables: - * indent-tabs-mode: t - * c-basic-offset: 8 - * End: - */ diff --git a/kernel/file.c b/kernel/file.c index f89bfb7..03e870b 100644 --- a/kernel/file.c +++ b/kernel/file.c @@ -9,27 +9,23 @@ #include #include -#include +#include +#include #ifdef KERNEL_2_6 -#include #include +#include #endif - -#ifndef KERNEL_2_6 -#define PageUptodate(page) Page_Uptodate(page) -#endif +#include static int user_mmap; #ifdef KERNEL_2_6 -#include -module_param(user_mmap, int, 0); +module_param(user_mmap, int, 0644); #else MODULE_PARM(user_mmap, "i"); +#define PageUptodate(page) Page_Uptodate(page) #endif - MODULE_PARM_DESC(user_mmap, "Allow non root user to create a shared writable mapping"); - static int fuse_open(struct inode *inode, struct file *file) { struct fuse_conn *fc = INO_FC(inode); @@ -144,7 +140,7 @@ static int fuse_release(struct inode *inode, struct file *file) req->in.numargs = 1; req->in.args[0].size = sizeof(struct fuse_release_in); req->in.args[0].value = inarg; - request_send_nonint(fc, req); + request_send(fc, req); fuse_put_request(fc, req); kfree(ff); up(&inode->i_sem); @@ -174,7 +170,7 @@ static int fuse_flush(struct file *file) req->in.numargs = 1; req->in.args[0].size = sizeof(inarg); req->in.args[0].value = &inarg; - request_send_nonint(fc, req); + request_send(fc, req); err = req->out.h.error; fuse_reset_request(req); up(&inode->i_sem); @@ -260,7 +256,6 @@ static ssize_t fuse_send_read(struct file *file, struct inode *inode, return res; } - static int fuse_readpage(struct file *file, struct page *page) { struct inode *inode = page->mapping->host; @@ -284,8 +279,7 @@ static int fuse_readpage(struct file *file, struct page *page) } #ifdef KERNEL_2_6 - -static int read_pages_copyout(struct fuse_req *req, const char *buf, +static int read_pages_copyout(struct fuse_req *req, const char __user *buf, size_t nbytes) { unsigned i; @@ -356,7 +350,7 @@ static void fuse_send_readpages(struct fuse_req *req, struct file *file, req->in.args[0].size = sizeof(struct fuse_read_in); req->in.args[0].value = inarg; req->copy_out = read_pages_copyout; - request_send_nonblock(fc, req, read_pages_end, NULL); + request_send_async(fc, req, read_pages_end, NULL); } struct fuse_readpages_data { @@ -404,9 +398,7 @@ static int fuse_readpages(struct file *file, struct address_space *mapping, return 0; } -#endif - -#ifndef KERNEL_2_6 +#else /* KERNEL_2_6 */ static int fuse_is_block_uptodate(struct inode *inode, size_t bl_index) { size_t index = bl_index << FUSE_BLOCK_PAGE_SHIFT; @@ -512,58 +504,119 @@ static void fuse_file_bigread(struct file *file, struct inode *inode, bl_index++; } } -#endif +#endif /* KERNEL_2_6 */ -static ssize_t fuse_read(struct file *file, char *buf, size_t count, +static int fuse_read_copyout(struct fuse_req *req, const char __user *buf, + size_t nbytes) +{ + struct fuse_read_in *inarg = &req->misc.read_in; + unsigned i; + if (nbytes > inarg->size) { + printk("fuse: long read\n"); + return -EPROTO; + } + req->out.args[0].size = nbytes; + for (i = 0; i < req->num_pages && nbytes; i++) { + struct page *page = req->pages[i]; + unsigned long offset = i * PAGE_CACHE_SIZE; + unsigned count = min((unsigned) PAGE_CACHE_SIZE, nbytes); + if (copy_from_user(page_address(page), buf + offset, count)) + return -EFAULT; + nbytes -= count; + } + return 0; +} + +static int fuse_send_read_multi(struct file *file, struct fuse_req *req, + size_t size, off_t pos) +{ + struct inode *inode = file->f_dentry->d_inode; + struct fuse_conn *fc = INO_FC(inode); + struct fuse_inode *fi = INO_FI(inode); + struct fuse_file *ff = file->private_data; + struct fuse_read_in *inarg; + + inarg = &req->misc.read_in; + inarg->fh = ff->fh; + inarg->offset = pos; + inarg->size = size; + req->in.h.opcode = FUSE_READ; + req->in.h.nodeid = fi->nodeid; + req->in.numargs = 1; + req->in.args[0].size = sizeof(struct fuse_read_in); + req->in.args[0].value = inarg; + req->copy_out = fuse_read_copyout; + request_send(fc, req); + return req->out.h.error; +} + +static ssize_t fuse_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct inode *inode = file->f_dentry->d_inode; struct fuse_conn *fc = INO_FC(inode); - char *tmpbuf; - ssize_t res = 0; + ssize_t res; loff_t pos = *ppos; - unsigned int max_read = count < fc->max_read ? count : fc->max_read; + struct fuse_req *req; + unsigned npages; + int i; - do { - tmpbuf = kmalloc(max_read, GFP_KERNEL); - if (tmpbuf) - break; - - max_read /= 2; - } while (max_read > PAGE_CACHE_SIZE / 4); - if (!tmpbuf) - return -ENOMEM; + npages = (min(fc->max_read, count) + PAGE_SIZE - 1) >> PAGE_SHIFT; + npages = min(npages, (unsigned) FUSE_MAX_PAGES_PER_REQ); + + req = fuse_get_request(fc); + if (!req) + return -ERESTARTSYS; + + res = -ENOMEM; + for (req->num_pages = 0; req->num_pages < npages; req->num_pages++) { + req->pages[req->num_pages] = alloc_page(GFP_KERNEL); + if (!req->pages[req->num_pages]) + goto out; + } + res = 0; while (count) { - size_t nbytes = count < max_read ? count : max_read; - ssize_t res1; - res1 = fuse_send_read(file, inode, tmpbuf, pos, nbytes); - if (res1 < 0) { + size_t nbytes; + size_t nbytes_req = min(req->num_pages * (unsigned) PAGE_SIZE, + count); + int err = fuse_send_read_multi(file, req, nbytes_req, pos); + if (err) { if (!res) - res = res1; + res = err; break; } - res += res1; - if (copy_to_user(buf, tmpbuf, res1)) { - res = -EFAULT; - break; + nbytes = req->out.args[0].size; + for (i = 0; i < req->num_pages && nbytes; i++) { + struct page *page = req->pages[i]; + unsigned n = min((unsigned) PAGE_SIZE, nbytes); + if (copy_to_user(buf, page_address(page), n)) { + res = -EFAULT; + break; + } + nbytes -= n; + buf += n; } - count -= res1; - buf += res1; - pos += res1; - if (res1 < nbytes) + nbytes = req->out.args[0].size; + count -= nbytes; + res += nbytes; + pos += nbytes; + + if (res < 0 || nbytes != nbytes_req) break; } - kfree(tmpbuf); - + out: + for (i = 0; i < req->num_pages; i++) + __free_page(req->pages[i]); + fuse_put_request(fc, req); if (res > 0) *ppos += res; return res; } -static ssize_t fuse_file_read(struct file *file, char *buf, - size_t count, loff_t * ppos) +static ssize_t fuse_file_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) { struct inode *inode = file->f_dentry->d_inode; struct fuse_conn *fc = INO_FC(inode); @@ -586,9 +639,9 @@ static ssize_t fuse_file_read(struct file *file, char *buf, return res; } -static ssize_t fuse_send_write(struct fuse_req *req, int writepage, - struct fuse_file *ff, struct inode *inode, - const char *buf, loff_t pos, size_t count) +static ssize_t fuse_send_write(struct fuse_req *req, struct fuse_file *ff, + struct inode *inode, const char *buf, + loff_t pos, size_t count) { struct fuse_conn *fc = INO_FC(inode); struct fuse_inode *fi = INO_FI(inode); @@ -597,17 +650,12 @@ static ssize_t fuse_send_write(struct fuse_req *req, int writepage, ssize_t res; memset(&inarg, 0, sizeof(inarg)); - inarg.writepage = writepage; + inarg.writepage = 0; inarg.fh = ff->fh; inarg.offset = pos; inarg.size = count; req->in.h.opcode = FUSE_WRITE; req->in.h.nodeid = fi->nodeid; - if (writepage) { - req->in.h.uid = 0; - req->in.h.gid = 0; - req->in.h.pid = 0; - } req->in.numargs = 2; req->in.args[0].size = sizeof(inarg); req->in.args[0].value = &inarg; @@ -644,7 +692,7 @@ static int write_buffer(struct inode *inode, struct file *file, pos = ((loff_t) page->index << PAGE_CACHE_SHIFT) + offset; buffer = kmap(page); - res = fuse_send_write(req, 0, ff, inode, buffer + offset, pos, count); + res = fuse_send_write(req, ff, inode, buffer + offset, pos, count); fuse_put_request(fc, req); if (res >= 0) { if (res < count) { @@ -676,54 +724,10 @@ static int get_write_count(struct inode *inode, struct page *page) return count; } - -static int write_page_block(struct inode *inode, struct page *page) -{ - struct fuse_conn *fc = INO_FC(inode); - struct fuse_inode *fi = INO_FI(inode); - char *buffer; - ssize_t res; - loff_t pos; - unsigned count; - struct fuse_req *req; - - req = fuse_get_request(fc); - if (!req) - return -ERESTARTSYS; - - down_read(&fi->write_sem); - count = get_write_count(inode, page); - res = 0; - if (count) { - struct fuse_file *ff; - BUG_ON(list_empty(&fi->write_files)); - ff = list_entry(fi->write_files.next, struct fuse_file, ff_list); - pos = ((loff_t) page->index << PAGE_CACHE_SHIFT); - buffer = kmap(page); - res = fuse_send_write(req, 1, ff, inode, buffer, pos, count); - if (res >= 0) { - if (res < count) { - printk("fuse: short write\n"); - res = -EPROTO; - } else - res = 0; - } - } - up_read(&fi->write_sem); - fuse_put_request(fc, req); - kunmap(page); - if (res) - SetPageError(page); - return res; -} - - #ifdef KERNEL_2_6 - - -static void write_page_nonblock_end(struct fuse_conn *fc, struct fuse_req *req) +static void write_page_end(struct fuse_conn *fc, struct fuse_req *req) { - struct page *page = (struct page *) req->data; + struct page *page = req->data; struct inode *inode = page->mapping->host; struct fuse_inode *fi = INO_FI(inode); struct fuse_write_out *outarg = req->out.args[0].value; @@ -746,8 +750,8 @@ static void write_page_nonblock_end(struct fuse_conn *fc, struct fuse_req *req) fuse_put_request(fc, req); } -static void send_write_nonblock(struct fuse_req *req, struct inode *inode, - struct page *page, unsigned count) +static void fuse_send_writepage(struct fuse_req *req, struct inode *inode, + struct page *page, unsigned count) { struct fuse_conn *fc = INO_FC(inode); struct fuse_inode *fi = INO_FI(inode); @@ -777,57 +781,134 @@ static void send_write_nonblock(struct fuse_req *req, struct inode *inode, req->out.numargs = 1; req->out.args[0].size = sizeof(struct fuse_write_out); req->out.args[0].value = &req->misc.write.out; - request_send_nonblock(fc, req, write_page_nonblock_end, page); + request_send_async(fc, req, write_page_end, page); } -static int write_page_nonblock(struct inode *inode, struct page *page) +static int fuse_writepage(struct page *page, struct writeback_control *wbc) { + struct inode *inode = page->mapping->host; struct fuse_conn *fc = INO_FC(inode); struct fuse_inode *fi = INO_FI(inode); struct fuse_req *req; int err; err = -EWOULDBLOCK; - req = fuse_get_request_nonblock(fc); + if (wbc->nonblocking) + req = fuse_get_request_nonblock(fc); + else + req = fuse_get_request_nonint(fc); if (req) { - if (down_read_trylock(&fi->write_sem)) { + int locked = 1; + if (wbc->nonblocking) + locked = down_read_trylock(&fi->write_sem); + else + down_read(&fi->write_sem); + if (locked) { unsigned count; err = 0; count = get_write_count(inode, page); if (count) { SetPageWriteback(page); - send_write_nonblock(req, inode, page, count); - return 0; + fuse_send_writepage(req, inode, page, count); + goto out; } up_read(&fi->write_sem); } fuse_put_request(fc, req); } + if (err == -EWOULDBLOCK) { +#ifdef KERNEL_2_6_6_PLUS + redirty_page_for_writepage(wbc, page); +#else + __set_page_dirty_nobuffers(page); +#endif + err = 0; + } + out: + unlock_page(page); return err; } +#else +static ssize_t fuse_send_writepage(struct fuse_req *req, struct fuse_file *ff, + struct inode *inode, const char *buf, + loff_t pos, size_t count) +{ + struct fuse_conn *fc = INO_FC(inode); + struct fuse_inode *fi = INO_FI(inode); + struct fuse_write_in inarg; + struct fuse_write_out outarg; + ssize_t res; + + memset(&inarg, 0, sizeof(inarg)); + inarg.writepage = 1; + inarg.fh = ff->fh; + inarg.offset = pos; + inarg.size = count; + req->in.h.opcode = FUSE_WRITE; + req->in.h.nodeid = fi->nodeid; + req->in.h.uid = 0; + req->in.h.gid = 0; + req->in.h.pid = 0; + req->in.numargs = 2; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + req->in.args[1].size = count; + req->in.args[1].value = buf; + req->out.numargs = 1; + req->out.args[0].size = sizeof(outarg); + req->out.args[0].value = &outarg; + request_send(fc, req); + res = req->out.h.error; + if (!res) { + if (outarg.size > count) + return -EPROTO; + else + return outarg.size; + } + else + return res; +} -static int fuse_writepage(struct page *page, struct writeback_control *wbc) +static int write_page_block(struct inode *inode, struct page *page) { - int err; - struct inode *inode = page->mapping->host; + struct fuse_conn *fc = INO_FC(inode); + struct fuse_inode *fi = INO_FI(inode); + char *buffer; + ssize_t res; + loff_t pos; + unsigned count; + struct fuse_req *req; - if (wbc->nonblocking) { - err = write_page_nonblock(inode, page); - if (err == -EWOULDBLOCK) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,6) - redirty_page_for_writepage(wbc, page); -#else - __set_page_dirty_nobuffers(page); -#endif - err = 0; + req = fuse_get_request(fc); + if (!req) + return -ERESTARTSYS; + + down_read(&fi->write_sem); + count = get_write_count(inode, page); + res = 0; + if (count) { + struct fuse_file *ff; + BUG_ON(list_empty(&fi->write_files)); + ff = list_entry(fi->write_files.next, struct fuse_file, ff_list); + pos = ((loff_t) page->index << PAGE_CACHE_SHIFT); + buffer = kmap(page); + res = fuse_send_writepage(req, ff, inode, buffer, pos, count); + if (res >= 0) { + if (res < count) { + printk("fuse: short write\n"); + res = -EPROTO; + } else + res = 0; } - } else - err = write_page_block(inode, page); - - unlock_page(page); - return err; + } + up_read(&fi->write_sem); + fuse_put_request(fc, req); + kunmap(page); + if (res) + SetPageError(page); + return res; } -#else + static int fuse_writepage(struct page *page) { int err = write_page_block(page->mapping->host, page); @@ -868,8 +949,8 @@ static int fuse_commit_write(struct file *file, struct page *page, return err; } -static ssize_t fuse_write(struct file *file, const char *buf, size_t count, - loff_t *ppos) +static ssize_t fuse_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) { struct inode *inode = file->f_dentry->d_inode; struct fuse_conn *fc = INO_FC(inode); @@ -878,26 +959,26 @@ static ssize_t fuse_write(struct file *file, const char *buf, size_t count, ssize_t res = 0; loff_t pos = *ppos; struct fuse_req *req; + size_t max_write = min(fc->max_write, (unsigned) PAGE_SIZE); req = fuse_get_request(fc); if (!req) return -ERESTARTSYS; - tmpbuf = kmalloc(count < fc->max_write ? count : fc->max_write, - GFP_KERNEL); + tmpbuf = (char *) __get_free_page(GFP_KERNEL); if (!tmpbuf) { fuse_put_request(fc, req); return -ENOMEM; } while (count) { - size_t nbytes = count < fc->max_write ? count : fc->max_write; + size_t nbytes = min(max_write, count); ssize_t res1; if (copy_from_user(tmpbuf, buf, nbytes)) { res = -EFAULT; break; } - res1 = fuse_send_write(req, 0, ff, inode, tmpbuf, pos, nbytes); + res1 = fuse_send_write(req, ff, inode, tmpbuf, pos, nbytes); if (res1 < 0) { res = res1; break; @@ -912,7 +993,7 @@ static ssize_t fuse_write(struct file *file, const char *buf, size_t count, if (count) fuse_reset_request(req); } - kfree(tmpbuf); + free_page((unsigned long) tmpbuf); fuse_put_request(fc, req); if (res > 0) { @@ -924,7 +1005,7 @@ static ssize_t fuse_write(struct file *file, const char *buf, size_t count, return res; } -static ssize_t fuse_file_write(struct file *file, const char *buf, +static ssize_t fuse_file_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct inode *inode = file->f_dentry->d_inode; @@ -995,10 +1076,3 @@ void fuse_init_file_inode(struct inode *inode) inode->i_fop = &fuse_file_operations; inode->i_data.a_ops = &fuse_file_aops; } - -/* - * Local Variables: - * indent-tabs-mode: t - * c-basic-offset: 8 - * End: - */ diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h index 58d6466..ce35ee4 100644 --- a/kernel/fuse_i.h +++ b/kernel/fuse_i.h @@ -8,6 +8,7 @@ #include +#ifndef FUSE_MAINLINE #include #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) @@ -15,7 +16,13 @@ #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) -#define KERNEL_2_6 +# define KERNEL_2_6 +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,6) +# define KERNEL_2_6_6_PLUS +# endif +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10) +# define KERNEL_2_6_10_PLUS +# endif #endif #include @@ -30,23 +37,27 @@ # define i_size_write(inode, size) do { (inode)->i_size = size; } while(0) # endif #endif -#include -#include +#endif /* FUSE_MAINLINE */ #include +#include #include #include +#include #ifndef BUG_ON #define BUG_ON(x) #endif - +#ifndef __user +#define __user +#endif +#ifndef KERNEL_2_6 /** Read combining parameters */ #define FUSE_BLOCK_SHIFT 16 #define FUSE_BLOCK_SIZE 65536 #define FUSE_BLOCK_MASK 0xffff0000 - #define FUSE_BLOCK_PAGE_SHIFT (FUSE_BLOCK_SHIFT - PAGE_CACHE_SHIFT) - +#endif +/* Max number of pages that can be used in a single read request */ #define FUSE_MAX_PAGES_PER_REQ 32 /* If more requests are outstanding, then the operation will block */ @@ -73,7 +84,6 @@ permission checking is done in the kernel */ than for small. */ #define FUSE_LARGE_READ (1 << 31) #endif - /** Bypass the page cache for read and write operations */ #define FUSE_DIRECT_IO (1 << 3) @@ -130,7 +140,7 @@ struct fuse_req; struct fuse_conn; typedef void (*fuse_reqend_t)(struct fuse_conn *, struct fuse_req *); -typedef int (*fuse_copyout_t)(struct fuse_req *, const char *, size_t); +typedef int (*fuse_copyout_t)(struct fuse_req *, const char __user *, size_t); /** * A request to the client @@ -139,8 +149,8 @@ struct fuse_req { /** The request list */ struct list_head list; - /** True if the request is synchronous */ - unsigned int issync:1; + /** True if the request has reply */ + unsigned int isreply:1; /** The request is locked */ unsigned int locked:1; @@ -270,26 +280,25 @@ struct fuse_getdir_out_i { #define INO_FC(inode) SB_FC((inode)->i_sb) #define INO_FI(i) ((struct fuse_inode *) (((struct inode *)(i))+1)) - -/** - * The proc entry for the client device ("/proc/fs/fuse/dev") - */ -extern struct proc_dir_entry *proc_fuse_dev; +/** Device operations */ +extern struct file_operations fuse_dev_operations; /** * The lock to protect fuses structures */ extern spinlock_t fuse_lock; - /** * Get a filled in inode */ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, int generation, struct fuse_attr *attr, int version); - -struct inode *fuse_ilookup(struct fuse_conn *fc, ino_t ino, unsigned long nodeid); +#ifdef KERNEL_2_6 +struct inode *fuse_ilookup(struct super_block *sb, unsigned long nodeid); +#else +struct inode *fuse_ilookup(struct super_block *sb, ino_t ino, unsigned long nodeid); +#endif /** * Send FORGET command @@ -369,21 +378,16 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req); */ void request_send(struct fuse_conn *fc, struct fuse_req *req); -/** - * Send a non-interruptible request - */ -void request_send_nonint(struct fuse_conn *fc, struct fuse_req *req); - /** * Send a request for which a reply is not expected */ void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req); /** - * Send a synchronous request without blocking + * Send asynchronous request */ -void request_send_nonblock(struct fuse_conn *fc, struct fuse_req *req, - fuse_reqend_t end, void *data); +void request_send_async(struct fuse_conn *fc, struct fuse_req *req, + fuse_reqend_t end, void *data); /** * Get the attributes of a file @@ -394,10 +398,3 @@ int fuse_do_getattr(struct inode *inode); * Write dirty pages */ void fuse_sync_inode(struct inode *inode); - -/* - * Local Variables: - * indent-tabs-mode: t - * c-basic-offset: 8 - * End: - */ diff --git a/kernel/inode.c b/kernel/inode.c index 641d03a..3775733 100644 --- a/kernel/inode.c +++ b/kernel/inode.c @@ -9,47 +9,41 @@ #include "fuse_i.h" #include -#include #include #include #include -#include #include +#include #ifdef KERNEL_2_6 +#include #include #include #else +#include #include "compat/parser.h" #endif - -static int user_allow_other; static kmem_cache_t *fuse_inode_cachep; +static int user_allow_other; #ifdef KERNEL_2_6 -#include -module_param(user_allow_other, int, 0); +module_param(user_allow_other, int, 0644); #else MODULE_PARM(user_allow_other, "i"); #endif - MODULE_PARM_DESC(user_allow_other, "Allow non root user to specify the \"allow_other\" or \"allow_root\" mount options"); - #define FUSE_SUPER_MAGIC 0x65735546 #ifndef KERNEL_2_6 #define kstatfs statfs #endif - #ifndef FS_SAFE #define FS_SAFE 0 #endif - #ifndef MAX_LFS_FILESIZE #define MAX_LFS_FILESIZE (((u64)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1) #endif - struct fuse_mount_data { int fd; unsigned int rootmode; @@ -176,30 +170,32 @@ static int fuse_statfs(struct super_block *sb, struct kstatfs *buf) return err; } -enum { opt_fd, - opt_rootmode, - opt_uid, - opt_default_permissions, - opt_allow_other, - opt_allow_root, - opt_kernel_cache, - opt_large_read, - opt_direct_io, - opt_max_read, - opt_err }; +enum { + OPT_FD, + OPT_ROOTMODE, + OPT_UID, + OPT_DEFAULT_PERMISSIONS, + OPT_ALLOW_OTHER, + OPT_ALLOW_ROOT, + OPT_KERNEL_CACHE, + OPT_LARGE_READ, + OPT_DIRECT_IO, + OPT_MAX_READ, + OPT_ERR +}; static match_table_t tokens = { - {opt_fd, "fd=%u"}, - {opt_rootmode, "rootmode=%o"}, - {opt_uid, "uid=%u"}, - {opt_default_permissions, "default_permissions"}, - {opt_allow_other, "allow_other"}, - {opt_allow_root, "allow_root"}, - {opt_kernel_cache, "kernel_cache"}, - {opt_large_read, "large_read"}, - {opt_direct_io, "direct_io"}, - {opt_max_read, "max_read=%u" }, - {opt_err, NULL} + {OPT_FD, "fd=%u"}, + {OPT_ROOTMODE, "rootmode=%o"}, + {OPT_UID, "uid=%u"}, + {OPT_DEFAULT_PERMISSIONS, "default_permissions"}, + {OPT_ALLOW_OTHER, "allow_other"}, + {OPT_ALLOW_ROOT, "allow_root"}, + {OPT_KERNEL_CACHE, "kernel_cache"}, + {OPT_LARGE_READ, "large_read"}, + {OPT_DIRECT_IO, "direct_io"}, + {OPT_MAX_READ, "max_read=%u"}, + {OPT_ERR, NULL} }; static int parse_fuse_opt(char *opt, struct fuse_mount_data *d) @@ -218,41 +214,41 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d) token = match_token(p, tokens, args); switch (token) { - case opt_fd: + case OPT_FD: if (match_int(&args[0], &value)) return 0; d->fd = value; break; - case opt_rootmode: + case OPT_ROOTMODE: if (match_octal(&args[0], &value)) return 0; d->rootmode = value; break; - case opt_uid: + case OPT_UID: if (match_int(&args[0], &value)) return 0; d->uid = value; break; - case opt_default_permissions: + case OPT_DEFAULT_PERMISSIONS: d->flags |= FUSE_DEFAULT_PERMISSIONS; break; - case opt_allow_other: + case OPT_ALLOW_OTHER: d->flags |= FUSE_ALLOW_OTHER; break; - case opt_allow_root: + case OPT_ALLOW_ROOT: d->flags |= FUSE_ALLOW_ROOT; break; - case opt_kernel_cache: + case OPT_KERNEL_CACHE: d->flags |= FUSE_KERNEL_CACHE; break; - case opt_large_read: + case OPT_LARGE_READ: #ifndef KERNEL_2_6 d->flags |= FUSE_LARGE_READ; #else @@ -266,11 +262,11 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d) #endif break; - case opt_direct_io: + case OPT_DIRECT_IO: d->flags |= FUSE_DIRECT_IO; break; - case opt_max_read: + case OPT_MAX_READ: if (match_int(&args[0], &value)) return 0; d->max_read = value; @@ -328,7 +324,6 @@ void fuse_release_conn(struct fuse_conn *fc) free_conn(fc); } - static struct fuse_conn *new_conn(void) { struct fuse_conn *fc; @@ -367,12 +362,12 @@ static struct fuse_conn *get_conn(struct file *file, struct super_block *sb) struct inode *ino; ino = file->f_dentry->d_inode; - if (!ino || !proc_fuse_dev || - strcmp(ino->i_sb->s_type->name, "proc") != 0 || - proc_fuse_dev->low_ino != ino->i_ino) { + if (file->f_op != &fuse_dev_operations) { printk("FUSE: bad communication file descriptor\n"); + printk("fuse_dev_operations: %p file->f_op: %p\n", + &fuse_dev_operations, file->f_op); return NULL; - } + } fc = new_conn(); if (fc == NULL) { printk("FUSE: failed to allocate connection data\n"); @@ -402,21 +397,19 @@ static struct inode *get_root_inode(struct super_block *sb, unsigned int mode) return fuse_iget(sb, 1, 0, &attr, 0); } - #ifdef KERNEL_2_6 - static struct dentry *fuse_get_dentry(struct super_block *sb, void *vobjp) { __u32 *objp = vobjp; - unsigned long ino = objp[0]; + unsigned long nodeid = objp[0]; __u32 generation = objp[1]; struct inode *inode; struct dentry *entry; - if (ino == 0) + if (nodeid == 0) return ERR_PTR(-ESTALE); - inode = ilookup(sb, ino); + inode = fuse_ilookup(sb, nodeid); if (!inode || inode->i_generation != generation) return ERR_PTR(-ESTALE); @@ -429,8 +422,41 @@ static struct dentry *fuse_get_dentry(struct super_block *sb, void *vobjp) return entry; } +static int fuse_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len, + int connectable) +{ + struct inode *inode = dentry->d_inode; + struct fuse_inode *fi = INO_FI(inode); + int len = *max_len; + int type = 1; + + if (len < 2 || (connectable && len < 4)) + return 255; + + len = 2; + fh[0] = fi->nodeid; + fh[1] = inode->i_generation; + if (connectable && !S_ISDIR(inode->i_mode)) { + struct inode *parent; + struct fuse_inode *parent_fi; + + spin_lock(&dentry->d_lock); + parent = dentry->d_parent->d_inode; + parent_fi = INO_FI(parent); + fh[2] = parent_fi->nodeid; + fh[3] = parent->i_generation; + spin_unlock(&dentry->d_lock); + len = 4; + type = 2; + } + *max_len = len; + return type; +} + + static struct export_operations fuse_export_operations = { .get_dentry = fuse_get_dentry, + .encode_fh = fuse_encode_fh, }; #endif @@ -482,8 +508,6 @@ static int fuse_read_super(struct super_block *sb, void *data, int silent) fc->max_read = d.max_read; fc->max_write = FUSE_MAX_IN / 2; - /* fc is needed in fuse_init_file_inode which could be called - from get_root_inode */ SB_FC(sb) = fc; root = get_root_inode(sb, d.rootmode); @@ -524,7 +548,9 @@ static struct file_system_type fuse_fs_type = { .name = "fuse", .get_sb = fuse_get_sb, .kill_sb = kill_anon_super, +#ifndef FUSE_MAINLINE .fs_flags = FS_SAFE, +#endif }; #else static struct super_block *fuse_read_super_compat(struct super_block *sb, @@ -543,15 +569,14 @@ static DECLARE_FSTYPE(fuse_fs_type, "fuse", fuse_read_super_compat, 0); static void fuse_inode_init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) { - struct inode * inode = (struct inode *) foo; + struct inode * inode = foo; if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR) inode_init_once(inode); } - -int fuse_fs_init() +int fuse_fs_init(void) { int err; @@ -572,15 +597,8 @@ int fuse_fs_init() return err; } -void fuse_fs_cleanup() +void fuse_fs_cleanup(void) { unregister_filesystem(&fuse_fs_type); kmem_cache_destroy(fuse_inode_cachep); } - -/* - * Local Variables: - * indent-tabs-mode: t - * c-basic-offset: 8 - * End: - */ diff --git a/kernel/linux/fuse.h b/kernel/linux/fuse.h index 55af4d9..8e62f9f 100644 --- a/kernel/linux/fuse.h +++ b/kernel/linux/fuse.h @@ -12,16 +12,16 @@ #define FUSE_KERNEL_VERSION 4 /** Minor version number of this interface */ -#define FUSE_KERNEL_MINOR_VERSION 1 +#define FUSE_KERNEL_MINOR_VERSION 2 /** The node ID of the root inode */ #define FUSE_ROOT_ID 1 /** Opening this will yield a new control file */ -#define FUSE_DEV "/proc/fs/fuse/dev" +#define FUSE_DEV "/dev/fuse" /** The file containing the version in the form MAJOR.MINOR */ -#define FUSE_VERSION_FILE "/proc/fs/fuse/version" +#define FUSE_VERSION_FILE "/sys/fs/fuse/version" struct fuse_attr { unsigned long ino; diff --git a/kernel/util.c b/kernel/util.c index ac6455d..fa5b082 100644 --- a/kernel/util.c +++ b/kernel/util.c @@ -9,7 +9,7 @@ #include "fuse_i.h" #include -#include +#include MODULE_AUTHOR("Miklos Szeredi "); MODULE_DESCRIPTION("Filesystem in Userspace"); @@ -23,9 +23,11 @@ int __init fuse_init(void) { int res; - printk(KERN_DEBUG "fuse init %s (API version %i.%i)\n", - FUSE_VERSION, + printk("fuse init (API version %i.%i)\n", FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); +#ifndef FUSE_MAINLINE + printk("fuse distribution version: %s\n", FUSE_VERSION); +#endif spin_lock_init(&fuse_lock); res = fuse_fs_init(); @@ -54,10 +56,3 @@ void __exit fuse_exit(void) module_init(fuse_init); module_exit(fuse_exit); - -/* - * Local Variables: - * indent-tabs-mode: t - * c-basic-offset: 8 - * End: - */ -- 2.30.2