aboutsummaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorGravatar Miklos Szeredi <miklos@szeredi.hu>2006-09-30 16:02:25 +0000
committerGravatar Miklos Szeredi <miklos@szeredi.hu>2006-09-30 16:02:25 +0000
commit708b4818f2d0b9a1e277de85a00a0355745a5cd0 (patch)
tree0e35c2d3906473f9b471eb4029a32e91e32d2480 /kernel
parentff5fa7f8de978d56e8c334e746e08195ed25730d (diff)
bmap support
Diffstat (limited to 'kernel')
-rw-r--r--kernel/file.c37
-rw-r--r--kernel/fuse_i.h3
-rw-r--r--kernel/fuse_kernel.h11
-rw-r--r--kernel/inode.c80
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);
}