diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/Makefile | 2 | ||||
-rw-r--r-- | kernel/dev.c | 12 | ||||
-rw-r--r-- | kernel/dir.c | 121 | ||||
-rw-r--r-- | kernel/file.c | 88 | ||||
-rw-r--r-- | kernel/fuse_i.h | 14 | ||||
-rw-r--r-- | kernel/inode.c | 18 |
6 files changed, 199 insertions, 56 deletions
diff --git a/kernel/Makefile b/kernel/Makefile index f7769d5..4646162 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -5,7 +5,7 @@ CPPFLAGS = -I /lib/modules/`uname -r`/build/include/ -D__KERNEL__ -DMODULE -D_LO all: fuse.o -fuse_objs = dev.o inode.o dir.o util.o +fuse_objs = dev.o inode.o dir.o file.o util.o fuse.o: $(fuse_objs) ld -r -o fuse.o $(fuse_objs) diff --git a/kernel/dev.c b/kernel/dev.c index d32589d..6a8d373 100644 --- a/kernel/dev.c +++ b/kernel/dev.c @@ -87,7 +87,7 @@ static struct fuse_req *request_new(struct fuse_conn *fc, struct fuse_in *inp, { struct fuse_req *req; - req = kmalloc(sizeof(*req), GFP_KERNEL); + req = kmalloc(sizeof(*req), GFP_NOFS); if(!req) return NULL; @@ -98,7 +98,7 @@ static struct fuse_req *request_new(struct fuse_conn *fc, struct fuse_in *inp, req->out = NULL; req->insize = IHSIZE + inp->argsize; - req->in = kmalloc(req->insize, GFP_KERNEL); + req->in = kmalloc(req->insize, GFP_NOFS); if(!req->in) { request_free(req); return NULL; @@ -188,7 +188,7 @@ static ssize_t fuse_dev_read(struct file *file, char *buf, size_t nbytes, loff_t *off) { int ret; - struct fuse_conn *fc = file->private_data; + struct fuse_conn *fc = DEV_FC(file); struct fuse_req *req; char *tmpbuf; unsigned int size; @@ -249,7 +249,7 @@ static ssize_t fuse_dev_write(struct file *file, const char *buf, size_t nbytes, loff_t *off) { ssize_t ret; - struct fuse_conn *fc = file->private_data; + struct fuse_conn *fc = DEV_FC(file); struct fuse_req *req; char *tmpbuf; struct fuse_out_header *oh; @@ -302,7 +302,7 @@ 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; + struct fuse_conn *fc = DEV_FC(file); unsigned int mask = POLLOUT | POLLWRNORM; if(!fc->sb) @@ -370,7 +370,7 @@ static void end_requests(struct list_head *head) static int fuse_dev_release(struct inode *inode, struct file *file) { - struct fuse_conn *fc = file->private_data; + struct fuse_conn *fc = DEV_FC(file); spin_lock(&fuse_lock); fc->file = NULL; diff --git a/kernel/dir.c b/kernel/dir.c index b23def7..1dac0c8 100644 --- a/kernel/dir.c +++ b/kernel/dir.c @@ -10,9 +10,8 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/file.h> #include <linux/slab.h> +#include <linux/file.h> static struct inode_operations fuse_dir_inode_operations; static struct inode_operations fuse_file_inode_operations; @@ -20,13 +19,12 @@ static struct inode_operations fuse_symlink_inode_operations; static struct inode_operations fuse_special_inode_operations; static struct file_operations fuse_dir_operations; -static struct file_operations fuse_file_operations; static struct dentry_operations fuse_dentry_opertations; static void change_attributes(struct inode *inode, struct fuse_attr *attr) { - inode->i_mode = attr->mode; + inode->i_mode = (inode->i_mode & S_IFMT) + (attr->mode & 07777); inode->i_nlink = attr->nlink; inode->i_uid = attr->uid; inode->i_gid = attr->gid; @@ -38,29 +36,46 @@ static void change_attributes(struct inode *inode, struct fuse_attr *attr) inode->i_ctime = attr->ctime; } -void fuse_init_inode(struct inode *inode, struct fuse_attr *attr) +static void fuse_init_inode(struct inode *inode, int mode, int rdev) { - change_attributes(inode, attr); - + inode->i_mode = mode & S_IFMT; if(S_ISREG(inode->i_mode)) { inode->i_op = &fuse_file_inode_operations; - inode->i_fop = &fuse_file_operations; + fuse_init_file_inode(inode); } else if(S_ISDIR(inode->i_mode)) { inode->i_op = &fuse_dir_inode_operations; inode->i_fop = &fuse_dir_operations; } - else if(S_ISLNK(inode->i_mode)) + else if(S_ISLNK(inode->i_mode)) { inode->i_op = &fuse_symlink_inode_operations; + } else { inode->i_op = &fuse_special_inode_operations; - init_special_inode(inode, inode->i_mode, attr->rdev); + init_special_inode(inode, inode->i_mode, rdev); } + inode->u.generic_ip = inode; +} + +struct inode *fuse_iget(struct super_block *sb, ino_t ino, + struct fuse_attr *attr) +{ + struct inode *inode; + + inode = iget(sb, ino); + if(inode) { + if(!inode->u.generic_ip) + fuse_init_inode(inode, attr->mode, attr->rdev); + + change_attributes(inode, attr); + } + + return inode; } static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry) { - struct fuse_conn *fc = dir->i_sb->u.generic_sbp; + struct fuse_conn *fc = INO_FC(dir); struct fuse_in in = FUSE_IN_INIT; struct fuse_out out = FUSE_OUT_INIT; struct fuse_lookup_out arg; @@ -76,11 +91,9 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry) inode = NULL; if(!out.h.error) { - inode = iget(dir->i_sb, arg.ino); + inode = fuse_iget(dir->i_sb, arg.ino, &arg.attr); if(!inode) return ERR_PTR(-ENOMEM); - - fuse_init_inode(inode, &arg.attr); } else if(out.h.error != -ENOENT) return ERR_PTR(out.h.error); @@ -94,7 +107,7 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry) static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode, int rdev) { - struct fuse_conn *fc = dir->i_sb->u.generic_sbp; + struct fuse_conn *fc = INO_FC(dir); struct fuse_in in = FUSE_IN_INIT; struct fuse_out out = FUSE_OUT_INIT; struct fuse_mknod_in *inarg; @@ -123,11 +136,10 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode, if(out.h.error) return out.h.error; - inode = iget(dir->i_sb, outarg.ino); + inode = fuse_iget(dir->i_sb, outarg.ino, &outarg.attr); if(!inode) return -ENOMEM; - - fuse_init_inode(inode, &outarg.attr); + d_instantiate(entry, inode); return 0; @@ -141,7 +153,7 @@ static int fuse_create(struct inode *dir, struct dentry *entry, int mode) static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode) { - struct fuse_conn *fc = dir->i_sb->u.generic_sbp; + struct fuse_conn *fc = INO_FC(dir); struct fuse_in in = FUSE_IN_INIT; struct fuse_out out = FUSE_OUT_INIT; struct fuse_mkdir_in *inarg; @@ -168,7 +180,7 @@ static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode) static int fuse_symlink(struct inode *dir, struct dentry *entry, const char *link) { - struct fuse_conn *fc = dir->i_sb->u.generic_sbp; + struct fuse_conn *fc = INO_FC(dir); struct fuse_in in = FUSE_IN_INIT; struct fuse_out out = FUSE_OUT_INIT; char *inarg; @@ -195,7 +207,7 @@ static int fuse_symlink(struct inode *dir, struct dentry *entry, static int fuse_remove(struct inode *dir, struct dentry *entry, enum fuse_opcode op) { - struct fuse_conn *fc = dir->i_sb->u.generic_sbp; + struct fuse_conn *fc = INO_FC(dir); struct fuse_in in = FUSE_IN_INIT; struct fuse_out out = FUSE_OUT_INIT; @@ -220,7 +232,7 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry) static int fuse_rename(struct inode *olddir, struct dentry *oldent, struct inode *newdir, struct dentry *newent) { - struct fuse_conn *fc = olddir->i_sb->u.generic_sbp; + struct fuse_conn *fc = INO_FC(olddir); struct fuse_in in = FUSE_IN_INIT; struct fuse_out out = FUSE_OUT_INIT; struct fuse_rename_in *inarg; @@ -252,7 +264,7 @@ static int fuse_link(struct dentry *entry, struct inode *newdir, struct dentry *newent) { struct inode *inode = entry->d_inode; - struct fuse_conn *fc = inode->i_sb->u.generic_sbp; + struct fuse_conn *fc = INO_FC(inode); struct fuse_in in = FUSE_IN_INIT; struct fuse_out out = FUSE_OUT_INIT; struct fuse_link_in *inarg; @@ -286,7 +298,7 @@ static int fuse_permission(struct inode *inode, int mask) static int fuse_revalidate(struct dentry *dentry) { struct inode *inode = dentry->d_inode; - struct fuse_conn *fc = inode->i_sb->u.generic_sbp; + struct fuse_conn *fc = INO_FC(inode); struct fuse_in in = FUSE_IN_INIT; struct fuse_out out = FUSE_OUT_INIT; struct fuse_getattr_out arg; @@ -357,7 +369,7 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) static int read_link(struct dentry *dentry, char **bufp) { struct inode *inode = dentry->d_inode; - struct fuse_conn *fc = inode->i_sb->u.generic_sbp; + struct fuse_conn *fc = INO_FC(inode); struct fuse_in in = FUSE_IN_INIT; struct fuse_out out = FUSE_OUT_INIT; unsigned long page; @@ -417,7 +429,7 @@ static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd) static int fuse_dir_open(struct inode *inode, struct file *file) { - struct fuse_conn *fc = inode->i_sb->u.generic_sbp; + struct fuse_conn *fc = INO_FC(inode); struct fuse_in in = FUSE_IN_INIT; struct fuse_out out = FUSE_OUT_INIT; struct fuse_getdir_out outarg; @@ -453,15 +465,56 @@ static int fuse_dir_open(struct inode *inode, struct file *file) static int fuse_dir_release(struct inode *inode, struct file *file) { struct file *cfile = file->private_data; - - if(!cfile) - BUG(); - fput(cfile); return 0; } +static unsigned int iattr_to_fattr(struct iattr *iattr, + struct fuse_attr *fattr) +{ + unsigned int ivalid = iattr->ia_valid; + unsigned int fvalid = 0; + + memset(fattr, 0, sizeof(*fattr)); + + if(ivalid & ATTR_MODE) + fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode; + if(ivalid & ATTR_UID) + fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid; + if(ivalid & ATTR_GID) + fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid; + if(ivalid & ATTR_SIZE) + fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size; + /* You can only _set_ these together (they may change by themselves) */ + if((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) { + fvalid |= FATTR_UTIME; + fattr->atime = iattr->ia_atime; + fattr->mtime = iattr->ia_mtime; + } + + return fvalid; +} + +static int fuse_setattr(struct dentry *entry, struct iattr *attr) +{ + struct inode *inode = entry->d_inode; + struct fuse_conn *fc = INO_FC(inode); + struct fuse_in in = FUSE_IN_INIT; + struct fuse_out out = FUSE_OUT_INIT; + struct fuse_setattr_in arg; + + arg.valid = iattr_to_fattr(attr, &arg.attr); + + in.h.opcode = FUSE_SETATTR; + in.h.ino = inode->i_ino; + in.argsize = sizeof(arg); + in.arg = &arg; + request_send(fc, &in, &out); + + return out.h.error; +} + static int fuse_dentry_revalidate(struct dentry *entry, int flags) { if(!entry->d_inode || !(flags & LOOKUP_CONTINUE)) @@ -481,9 +534,7 @@ static struct inode_operations fuse_dir_inode_operations = rmdir: fuse_rmdir, rename: fuse_rename, link: fuse_link, -#if 0 setattr: fuse_setattr, -#endif permission: fuse_permission, revalidate: fuse_revalidate, }; @@ -496,20 +547,20 @@ static struct file_operations fuse_dir_operations = { }; static struct inode_operations fuse_file_inode_operations = { + setattr: fuse_setattr, permission: fuse_permission, revalidate: fuse_revalidate, }; static struct inode_operations fuse_special_inode_operations = { + setattr: fuse_setattr, permission: fuse_permission, revalidate: fuse_revalidate, }; -static struct file_operations fuse_file_operations = { -}; - static struct inode_operations fuse_symlink_inode_operations = { + setattr: fuse_setattr, readlink: fuse_readlink, follow_link: fuse_follow_link, revalidate: fuse_revalidate, diff --git a/kernel/file.c b/kernel/file.c new file mode 100644 index 0000000..df3a863 --- /dev/null +++ b/kernel/file.c @@ -0,0 +1,88 @@ +/* + 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/pagemap.h> + + +static int fuse_open(struct inode *inode, struct file *file) +{ + struct fuse_conn *fc = INO_FC(inode); + struct fuse_in in = FUSE_IN_INIT; + struct fuse_out out = FUSE_OUT_INIT; + struct fuse_open_in arg; + + arg.flags = file->f_flags & ~O_EXCL; + in.h.opcode = FUSE_OPEN; + in.h.ino = inode->i_ino; + in.argsize = sizeof(arg); + in.arg = &arg; + request_send(fc, &in, &out); + + return out.h.error; +} + +static int fuse_readpage(struct file *file, struct page *page) +{ + struct inode *inode = page->mapping->host; + struct fuse_conn *fc = INO_FC(inode); + struct fuse_in in = FUSE_IN_INIT; + struct fuse_out out = FUSE_OUT_INIT; + struct fuse_read_in arg; + char *buffer; + + buffer = kmap(page); + + arg.offset = page->index << PAGE_CACHE_SHIFT; + arg.size = PAGE_CACHE_SIZE; + + in.h.opcode = FUSE_READ; + in.h.ino = inode->i_ino; + in.argsize = sizeof(arg); + in.arg = &arg; + out.argsize = PAGE_CACHE_SIZE; + out.argvar = 1; + out.arg = buffer; + + request_send(fc, &in, &out); + if(!out.h.error) { + if(out.argsize < PAGE_CACHE_SIZE) + memset(buffer + out.argsize, 0, + PAGE_CACHE_SIZE - out.argsize); + SetPageUptodate(page); + } + + kunmap(page); + UnlockPage(page); + + return out.h.error; +} + +static struct file_operations fuse_file_operations = { + open: fuse_open, + read: generic_file_read, +}; + +static struct address_space_operations fuse_file_aops = { + readpage: fuse_readpage, +}; + +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 de0a9e6..aaa395d 100644 --- a/kernel/fuse_i.h +++ b/kernel/fuse_i.h @@ -82,6 +82,9 @@ struct fuse_req { }; +#define INO_FC(inode) ((struct fuse_conn *) (inode)->i_sb->u.generic_sbp) +#define DEV_FC(file) ((struct fuse_conn *) (file)->private_data) + struct fuse_in { struct fuse_in_header h; unsigned int argsize; @@ -111,9 +114,16 @@ extern spinlock_t fuse_lock; /** - * Initialize inode + * Get a filled in inode + */ +struct inode *fuse_iget(struct super_block *sb, ino_t ino, + struct fuse_attr *attr); + + +/** + * Initialise operations on regular file */ -void fuse_init_inode(struct inode *inode, struct fuse_attr *attr); +void fuse_init_file_inode(struct inode *inode); /** * Check if the connection can be released, and if yes, then free the diff --git a/kernel/inode.c b/kernel/inode.c index 702ef57..ed4f760 100644 --- a/kernel/inode.c +++ b/kernel/inode.c @@ -39,7 +39,7 @@ static int alloc_cleared(struct fuse_conn *fc) unsigned long *tmp; spin_unlock(&fuse_lock); - tmp = kmalloc(sizeof(unsigned long) * MAX_CLEARED, GFP_KERNEL); + tmp = kmalloc(sizeof(unsigned long) * MAX_CLEARED, GFP_NOFS); spin_lock(&fuse_lock); if(!fc->file || fc->cleared != NULL) @@ -72,7 +72,7 @@ static unsigned long *add_cleared(struct fuse_conn *fc, unsigned long ino) static void fuse_clear_inode(struct inode *inode) { - struct fuse_conn *fc = inode->i_sb->u.generic_sbp; + struct fuse_conn *fc = INO_FC(inode); unsigned long *forget; spin_lock(&fuse_lock); @@ -139,17 +139,11 @@ static struct fuse_conn *get_conn(struct fuse_mount_data *d) static struct inode *get_root_inode(struct super_block *sb) { - struct inode *root; - - root = iget(sb, 1); - if(root) { - struct fuse_attr attr; - memset(&attr, 0, sizeof(attr)); - attr.mode = S_IFDIR; - fuse_init_inode(root, &attr); - } + struct fuse_attr attr; + memset(&attr, 0, sizeof(attr)); - return root; + attr.mode = S_IFDIR; + return fuse_iget(sb, 1, &attr); } static struct super_block *fuse_read_super(struct super_block *sb, |