diff options
author | Miklos Szeredi <miklos@szeredi.hu> | 2006-09-30 16:02:25 +0000 |
---|---|---|
committer | Miklos Szeredi <miklos@szeredi.hu> | 2006-09-30 16:02:25 +0000 |
commit | 708b4818f2d0b9a1e277de85a00a0355745a5cd0 (patch) | |
tree | 0e35c2d3906473f9b471eb4029a32e91e32d2480 /kernel | |
parent | ff5fa7f8de978d56e8c334e746e08195ed25730d (diff) |
bmap support
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/file.c | 37 | ||||
-rw-r--r-- | kernel/fuse_i.h | 3 | ||||
-rw-r--r-- | kernel/fuse_kernel.h | 11 | ||||
-rw-r--r-- | kernel/inode.c | 80 |
4 files changed, 116 insertions, 15 deletions
diff --git a/kernel/file.c b/kernel/file.c index 9e50109..fb381da 100644 --- a/kernel/file.c +++ b/kernel/file.c @@ -805,6 +805,42 @@ static int fuse_file_lock(struct file *file, int cmd, struct file_lock *fl) return err; } +static sector_t fuse_bmap(struct address_space *mapping, sector_t block) +{ + struct inode *inode = mapping->host; + struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_req *req; + struct fuse_bmap_in inarg; + struct fuse_bmap_out outarg; + int err; + + if (!inode->i_sb->s_bdev || fc->no_bmap) + return 0; + + req = fuse_get_req(fc); + if (IS_ERR(req)) + return 0; + + memset(&inarg, 0, sizeof(inarg)); + inarg.block = block; + inarg.blocksize = inode->i_sb->s_blocksize; + req->in.h.opcode = FUSE_BMAP; + req->in.h.nodeid = get_node_id(inode); + req->in.numargs = 1; + req->in.args[0].size = sizeof(inarg); + req->in.args[0].value = &inarg; + req->out.numargs = 1; + req->out.args[0].size = sizeof(outarg); + req->out.args[0].value = &outarg; + request_send(fc, req); + err = req->out.h.error; + fuse_put_request(fc, req); + if (err == -ENOSYS) + fc->no_bmap = 1; + + return err ? 0 : outarg.block; +} + static struct file_operations fuse_file_operations = { .llseek = generic_file_llseek, .read = generic_file_read, @@ -836,6 +872,7 @@ static struct address_space_operations fuse_file_aops = { .commit_write = fuse_commit_write, .readpages = fuse_readpages, .set_page_dirty = fuse_set_page_dirty, + .bmap = fuse_bmap, }; void fuse_init_file_inode(struct inode *inode) diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h index e44dd9a..0841e44 100644 --- a/kernel/fuse_i.h +++ b/kernel/fuse_i.h @@ -398,6 +398,9 @@ struct fuse_conn { /** Is interrupt not implemented by fs? */ unsigned no_interrupt : 1; + /** Is bmap not implemented by fs? */ + unsigned no_bmap : 1; + /** The number of requests waiting for completion */ atomic_t num_waiting; diff --git a/kernel/fuse_kernel.h b/kernel/fuse_kernel.h index 179c7eb..936ea95 100644 --- a/kernel/fuse_kernel.h +++ b/kernel/fuse_kernel.h @@ -162,6 +162,7 @@ enum fuse_opcode { FUSE_ACCESS = 34, FUSE_CREATE = 35, FUSE_INTERRUPT = 36, + FUSE_BMAP = 37, }; /* The read buffer is required to be at least 8k, but may be much larger */ @@ -331,6 +332,16 @@ struct fuse_interrupt_in { __u64 unique; }; +struct fuse_bmap_in { + __u64 block; + __u32 blocksize; + __u32 padding; +}; + +struct fuse_bmap_out { + __u64 block; +}; + struct fuse_in_header { __u32 len; __u32 opcode; diff --git a/kernel/inode.c b/kernel/inode.c index 2d4749e..7800892 100644 --- a/kernel/inode.c +++ b/kernel/inode.c @@ -44,6 +44,7 @@ struct fuse_mount_data { unsigned group_id_present : 1; unsigned flags; unsigned max_read; + unsigned blksize; }; static struct inode *fuse_alloc_inode(struct super_block *sb) @@ -302,6 +303,7 @@ enum { OPT_DEFAULT_PERMISSIONS, OPT_ALLOW_OTHER, OPT_MAX_READ, + OPT_BLKSIZE, OPT_ERR }; @@ -313,14 +315,16 @@ static match_table_t tokens = { {OPT_DEFAULT_PERMISSIONS, "default_permissions"}, {OPT_ALLOW_OTHER, "allow_other"}, {OPT_MAX_READ, "max_read=%u"}, + {OPT_BLKSIZE, "blksize=%u"}, {OPT_ERR, NULL} }; -static int parse_fuse_opt(char *opt, struct fuse_mount_data *d) +static int parse_fuse_opt(char *opt, struct fuse_mount_data *d, int is_bdev) { char *p; memset(d, 0, sizeof(struct fuse_mount_data)); d->max_read = ~0; + d->blksize = 512; while ((p = strsep(&opt, ",")) != NULL) { int token; @@ -373,6 +377,12 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d) d->max_read = value; break; + case OPT_BLKSIZE: + if (!is_bdev || match_int(&args[0], &value)) + return 0; + d->blksize = value; + break; + default: return 0; } @@ -599,15 +609,21 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) struct dentry *root_dentry; struct fuse_req *init_req; int err; + int is_bdev = sb->s_bdev != NULL; if (sb->s_flags & MS_MANDLOCK) return -EINVAL; - if (!parse_fuse_opt((char *) data, &d)) + if (!parse_fuse_opt((char *) data, &d, is_bdev)) return -EINVAL; - sb->s_blocksize = PAGE_CACHE_SIZE; - sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + if (is_bdev) { + if (!sb_set_blocksize(sb, d.blksize)) + return -EINVAL; + } else { + sb->s_blocksize = PAGE_CACHE_SIZE; + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + } sb->s_magic = FUSE_SUPER_MAGIC; sb->s_op = &fuse_super_operations; sb->s_maxbytes = MAX_LFS_FILESIZE; @@ -693,6 +709,14 @@ static int fuse_get_sb(struct file_system_type *fs_type, { return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super, mnt); } + +static int fuse_get_sb_blk(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *raw_data, struct vfsmount *mnt) +{ + return get_sb_bdev(fs_type, flags, dev_name, raw_data, fuse_fill_super, + mnt); +} #else static struct super_block *fuse_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, @@ -700,6 +724,14 @@ static struct super_block *fuse_get_sb(struct file_system_type *fs_type, { return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super); } + +static struct super_block *fuse_get_sb_blk(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *raw_data) +{ + return get_sb_bdev(fs_type, flags, dev_name, raw_data, + fuse_fill_super); +} #endif static struct file_system_type fuse_fs_type = { @@ -709,6 +741,14 @@ static struct file_system_type fuse_fs_type = { .kill_sb = kill_anon_super, }; +static struct file_system_type fuseblk_fs_type = { + .owner = THIS_MODULE, + .name = "fuseblk", + .get_sb = fuse_get_sb_blk, + .kill_sb = kill_block_super, + .fs_flags = FS_REQUIRES_DEV, +}; + #ifndef HAVE_FS_SUBSYS static decl_subsys(fs, NULL, NULL); #endif @@ -731,24 +771,34 @@ static int __init fuse_fs_init(void) err = register_filesystem(&fuse_fs_type); if (err) - printk("fuse: failed to register filesystem\n"); - else { - fuse_inode_cachep = kmem_cache_create("fuse_inode", - sizeof(struct fuse_inode), - 0, SLAB_HWCACHE_ALIGN, - fuse_inode_init_once, NULL); - if (!fuse_inode_cachep) { - unregister_filesystem(&fuse_fs_type); - err = -ENOMEM; - } - } + goto out; + + err = register_filesystem(&fuseblk_fs_type); + if (err) + goto out_unreg; + fuse_inode_cachep = kmem_cache_create("fuse_inode", + sizeof(struct fuse_inode), + 0, SLAB_HWCACHE_ALIGN, + fuse_inode_init_once, NULL); + err = -ENOMEM; + if (!fuse_inode_cachep) + goto out_unreg2; + + return 0; + + out_unreg2: + unregister_filesystem(&fuseblk_fs_type); + out_unreg: + unregister_filesystem(&fuse_fs_type); + out: return err; } static void fuse_fs_cleanup(void) { unregister_filesystem(&fuse_fs_type); + unregister_filesystem(&fuseblk_fs_type); kmem_cache_destroy(fuse_inode_cachep); } |