unsigned group_id_present : 1;
unsigned flags;
unsigned max_read;
+ unsigned blksize;
};
static struct inode *fuse_alloc_inode(struct super_block *sb)
{
struct fuse_conn *fc = get_fuse_conn(inode);
if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size)
- invalidate_inode_pages(inode->i_mapping);
+ invalidate_mapping_pages(inode->i_mapping, 0, -1);
inode->i_ino = attr->ino;
inode->i_mode = (inode->i_mode & S_IFMT) + (attr->mode & 07777);
fuse_abort_conn(get_fuse_conn_super(vfsmnt->mnt_sb));
}
+static void fuse_send_destroy(struct fuse_conn *fc)
+{
+ struct fuse_req *req = fc->destroy_req;
+ if (req && fc->conn_init) {
+ fc->destroy_req = NULL;
+ req->in.h.opcode = FUSE_DESTROY;
+ req->force = 1;
+ request_send(fc, req);
+ fuse_put_request(fc, req);
+ }
+}
+
static void fuse_put_super(struct super_block *sb)
{
struct fuse_conn *fc = get_fuse_conn_super(sb);
+ fuse_send_destroy(fc);
spin_lock(&fc->lock);
fc->connected = 0;
fc->blocked = 0;
OPT_DEFAULT_PERMISSIONS,
OPT_ALLOW_OTHER,
OPT_MAX_READ,
+ OPT_BLKSIZE,
OPT_ERR
};
{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;
case OPT_ROOTMODE:
if (match_octal(&args[0], &value))
return 0;
+ if (!fuse_valid_type(value))
+ return 0;
d->rootmode = value;
d->rootmode_present = 1;
break;
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;
}
void fuse_conn_put(struct fuse_conn *fc)
{
if (atomic_dec_and_test(&fc->count)) {
+ if (fc->destroy_req)
+ fuse_request_free(fc->destroy_req);
mutex_destroy(&fc->inst_mutex);
kfree(fc);
}
return fuse_iget(sb, 1, 0, &attr);
}
-static struct super_operations fuse_super_operations = {
+static const struct super_operations fuse_super_operations = {
.alloc_inode = fuse_alloc_inode,
.destroy_inode = fuse_destroy_inode,
.read_inode = fuse_read_inode,
fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages);
fc->minor = arg->minor;
fc->max_write = arg->minor < 5 ? 4096 : arg->max_write;
+ fc->conn_init = 1;
}
fuse_put_request(fc, req);
fc->blocked = 0;
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) {
+#ifdef CONFIG_BLOCK
+ if (!sb_set_blocksize(sb, d.blksize))
+ return -EINVAL;
+#endif
+ } 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;
if (!init_req)
goto err_put_root;
+ if (is_bdev) {
+ fc->destroy_req = fuse_request_alloc();
+ if (!fc->destroy_req)
+ goto err_put_root;
+ }
+
mutex_lock(&fuse_mutex);
err = -EINVAL;
if (file->private_data)
return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super, mnt);
}
+static struct file_system_type fuse_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "fuse",
+ .get_sb = fuse_get_sb,
+ .kill_sb = kill_anon_super,
+};
+
+#ifdef CONFIG_BLOCK
static int fuse_get_sb_blk(struct file_system_type *fs_type,
int flags, const char *dev_name,
void *raw_data, struct vfsmount *mnt)
mnt);
}
-static struct file_system_type fuse_fs_type = {
- .owner = THIS_MODULE,
- .name = "fuse",
- .get_sb = fuse_get_sb,
- .kill_sb = kill_anon_super,
-};
-
static struct file_system_type fuseblk_fs_type = {
.owner = THIS_MODULE,
.name = "fuseblk",
.fs_flags = FS_REQUIRES_DEV,
};
+static inline int register_fuseblk(void)
+{
+ return register_filesystem(&fuseblk_fs_type);
+}
+
+static inline void unregister_fuseblk(void)
+{
+ unregister_filesystem(&fuseblk_fs_type);
+}
+#else
+static inline int register_fuseblk(void)
+{
+ return 0;
+}
+
+static inline void unregister_fuseblk(void)
+{
+}
+#endif
+
static decl_subsys(fuse, NULL, NULL);
static decl_subsys(connections, NULL, NULL);
if (err)
goto out;
- err = register_filesystem(&fuseblk_fs_type);
+ err = register_fuseblk();
if (err)
goto out_unreg;
return 0;
out_unreg2:
- unregister_filesystem(&fuseblk_fs_type);
+ unregister_fuseblk();
out_unreg:
unregister_filesystem(&fuse_fs_type);
out:
static void fuse_fs_cleanup(void)
{
unregister_filesystem(&fuse_fs_type);
- unregister_filesystem(&fuseblk_fs_type);
+ unregister_fuseblk();
kmem_cache_destroy(fuse_inode_cachep);
}