Commit c34752bc authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'cuse' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse

* 'cuse' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
  CUSE: implement CUSE - Character device in Userspace
  fuse: export symbols to be used by CUSE
  fuse: update fuse_conn_init() and separate out fuse_conn_kill()
  fuse: don't use inode in fuse_file_poll
  fuse: don't use inode in fuse_do_ioctl() helper
  fuse: don't use inode in fuse_sync_release()
  fuse: create fuse_do_open() helper for CUSE
  fuse: clean up args in fuse_finish_open() and fuse_release_fill()
  fuse: don't use inode in helpers called by fuse_direct_io()
  fuse: add members to struct fuse_file
  fuse: prepare fuse_direct_io() for CUSE
  fuse: clean up fuse_write_fill()
  fuse: use struct path in release structure
  fuse: misc cleanups
parents 65d52cc9 151060ac
...@@ -62,6 +62,16 @@ source "fs/autofs/Kconfig" ...@@ -62,6 +62,16 @@ source "fs/autofs/Kconfig"
source "fs/autofs4/Kconfig" source "fs/autofs4/Kconfig"
source "fs/fuse/Kconfig" source "fs/fuse/Kconfig"
config CUSE
tristate "Character device in Userpace support"
depends on FUSE_FS
help
This FUSE extension allows character devices to be
implemented in userspace.
If you want to develop or use userspace character device
based on CUSE, answer Y or M.
config GENERIC_ACL config GENERIC_ACL
bool bool
select FS_POSIX_ACL select FS_POSIX_ACL
......
...@@ -3,5 +3,6 @@ ...@@ -3,5 +3,6 @@
# #
obj-$(CONFIG_FUSE_FS) += fuse.o obj-$(CONFIG_FUSE_FS) += fuse.o
obj-$(CONFIG_CUSE) += cuse.o
fuse-objs := dev.o dir.o file.o inode.o control.o fuse-objs := dev.o dir.o file.o inode.o control.o
This diff is collapsed.
...@@ -46,6 +46,7 @@ struct fuse_req *fuse_request_alloc(void) ...@@ -46,6 +46,7 @@ struct fuse_req *fuse_request_alloc(void)
fuse_request_init(req); fuse_request_init(req);
return req; return req;
} }
EXPORT_SYMBOL_GPL(fuse_request_alloc);
struct fuse_req *fuse_request_alloc_nofs(void) struct fuse_req *fuse_request_alloc_nofs(void)
{ {
...@@ -124,6 +125,7 @@ struct fuse_req *fuse_get_req(struct fuse_conn *fc) ...@@ -124,6 +125,7 @@ struct fuse_req *fuse_get_req(struct fuse_conn *fc)
atomic_dec(&fc->num_waiting); atomic_dec(&fc->num_waiting);
return ERR_PTR(err); return ERR_PTR(err);
} }
EXPORT_SYMBOL_GPL(fuse_get_req);
/* /*
* Return request in fuse_file->reserved_req. However that may * Return request in fuse_file->reserved_req. However that may
...@@ -208,6 +210,7 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req) ...@@ -208,6 +210,7 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
fuse_request_free(req); fuse_request_free(req);
} }
} }
EXPORT_SYMBOL_GPL(fuse_put_request);
static unsigned len_args(unsigned numargs, struct fuse_arg *args) static unsigned len_args(unsigned numargs, struct fuse_arg *args)
{ {
...@@ -282,7 +285,7 @@ __releases(&fc->lock) ...@@ -282,7 +285,7 @@ __releases(&fc->lock)
wake_up_all(&fc->blocked_waitq); wake_up_all(&fc->blocked_waitq);
} }
if (fc->num_background == FUSE_CONGESTION_THRESHOLD && if (fc->num_background == FUSE_CONGESTION_THRESHOLD &&
fc->connected) { fc->connected && fc->bdi_initialized) {
clear_bdi_congested(&fc->bdi, READ); clear_bdi_congested(&fc->bdi, READ);
clear_bdi_congested(&fc->bdi, WRITE); clear_bdi_congested(&fc->bdi, WRITE);
} }
...@@ -400,6 +403,7 @@ void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req) ...@@ -400,6 +403,7 @@ void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req)
} }
spin_unlock(&fc->lock); spin_unlock(&fc->lock);
} }
EXPORT_SYMBOL_GPL(fuse_request_send);
static void fuse_request_send_nowait_locked(struct fuse_conn *fc, static void fuse_request_send_nowait_locked(struct fuse_conn *fc,
struct fuse_req *req) struct fuse_req *req)
...@@ -408,7 +412,8 @@ static void fuse_request_send_nowait_locked(struct fuse_conn *fc, ...@@ -408,7 +412,8 @@ static void fuse_request_send_nowait_locked(struct fuse_conn *fc,
fc->num_background++; fc->num_background++;
if (fc->num_background == FUSE_MAX_BACKGROUND) if (fc->num_background == FUSE_MAX_BACKGROUND)
fc->blocked = 1; fc->blocked = 1;
if (fc->num_background == FUSE_CONGESTION_THRESHOLD) { if (fc->num_background == FUSE_CONGESTION_THRESHOLD &&
fc->bdi_initialized) {
set_bdi_congested(&fc->bdi, READ); set_bdi_congested(&fc->bdi, READ);
set_bdi_congested(&fc->bdi, WRITE); set_bdi_congested(&fc->bdi, WRITE);
} }
...@@ -439,6 +444,7 @@ void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req) ...@@ -439,6 +444,7 @@ void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req)
req->isreply = 1; req->isreply = 1;
fuse_request_send_nowait(fc, req); fuse_request_send_nowait(fc, req);
} }
EXPORT_SYMBOL_GPL(fuse_request_send_background);
/* /*
* Called under fc->lock * Called under fc->lock
...@@ -1105,8 +1111,9 @@ void fuse_abort_conn(struct fuse_conn *fc) ...@@ -1105,8 +1111,9 @@ void fuse_abort_conn(struct fuse_conn *fc)
} }
spin_unlock(&fc->lock); spin_unlock(&fc->lock);
} }
EXPORT_SYMBOL_GPL(fuse_abort_conn);
static int fuse_dev_release(struct inode *inode, struct file *file) int fuse_dev_release(struct inode *inode, struct file *file)
{ {
struct fuse_conn *fc = fuse_get_conn(file); struct fuse_conn *fc = fuse_get_conn(file);
if (fc) { if (fc) {
...@@ -1120,6 +1127,7 @@ static int fuse_dev_release(struct inode *inode, struct file *file) ...@@ -1120,6 +1127,7 @@ static int fuse_dev_release(struct inode *inode, struct file *file)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(fuse_dev_release);
static int fuse_dev_fasync(int fd, struct file *file, int on) static int fuse_dev_fasync(int fd, struct file *file, int on)
{ {
...@@ -1142,6 +1150,7 @@ const struct file_operations fuse_dev_operations = { ...@@ -1142,6 +1150,7 @@ const struct file_operations fuse_dev_operations = {
.release = fuse_dev_release, .release = fuse_dev_release,
.fasync = fuse_dev_fasync, .fasync = fuse_dev_fasync,
}; };
EXPORT_SYMBOL_GPL(fuse_dev_operations);
static struct miscdevice fuse_miscdevice = { static struct miscdevice fuse_miscdevice = {
.minor = FUSE_MINOR, .minor = FUSE_MINOR,
......
...@@ -361,19 +361,6 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, ...@@ -361,19 +361,6 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
return ERR_PTR(err); return ERR_PTR(err);
} }
/*
* Synchronous release for the case when something goes wrong in CREATE_OPEN
*/
static void fuse_sync_release(struct fuse_conn *fc, struct fuse_file *ff,
u64 nodeid, int flags)
{
fuse_release_fill(ff, nodeid, flags, FUSE_RELEASE);
ff->reserved_req->force = 1;
fuse_request_send(fc, ff->reserved_req);
fuse_put_request(fc, ff->reserved_req);
kfree(ff);
}
/* /*
* Atomic create+open operation * Atomic create+open operation
* *
...@@ -445,12 +432,14 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, ...@@ -445,12 +432,14 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
goto out_free_ff; goto out_free_ff;
fuse_put_request(fc, req); fuse_put_request(fc, req);
ff->fh = outopen.fh;
ff->nodeid = outentry.nodeid;
ff->open_flags = outopen.open_flags;
inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation, inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
&outentry.attr, entry_attr_timeout(&outentry), 0); &outentry.attr, entry_attr_timeout(&outentry), 0);
if (!inode) { if (!inode) {
flags &= ~(O_CREAT | O_EXCL | O_TRUNC); flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
ff->fh = outopen.fh; fuse_sync_release(ff, flags);
fuse_sync_release(fc, ff, outentry.nodeid, flags);
fuse_send_forget(fc, forget_req, outentry.nodeid, 1); fuse_send_forget(fc, forget_req, outentry.nodeid, 1);
return -ENOMEM; return -ENOMEM;
} }
...@@ -460,11 +449,11 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, ...@@ -460,11 +449,11 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
fuse_invalidate_attr(dir); fuse_invalidate_attr(dir);
file = lookup_instantiate_filp(nd, entry, generic_file_open); file = lookup_instantiate_filp(nd, entry, generic_file_open);
if (IS_ERR(file)) { if (IS_ERR(file)) {
ff->fh = outopen.fh; fuse_sync_release(ff, flags);
fuse_sync_release(fc, ff, outentry.nodeid, flags);
return PTR_ERR(file); return PTR_ERR(file);
} }
fuse_finish_open(inode, file, ff, &outopen); file->private_data = fuse_file_get(ff);
fuse_finish_open(inode, file);
return 0; return 0;
out_free_ff: out_free_ff:
...@@ -1035,7 +1024,7 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) ...@@ -1035,7 +1024,7 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
req->out.argpages = 1; req->out.argpages = 1;
req->num_pages = 1; req->num_pages = 1;
req->pages[0] = page; req->pages[0] = page;
fuse_read_fill(req, file, inode, file->f_pos, PAGE_SIZE, FUSE_READDIR); fuse_read_fill(req, file, file->f_pos, PAGE_SIZE, FUSE_READDIR);
fuse_request_send(fc, req); fuse_request_send(fc, req);
nbytes = req->out.args[0].size; nbytes = req->out.args[0].size;
err = req->out.h.error; err = req->out.h.error;
...@@ -1101,12 +1090,14 @@ static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c) ...@@ -1101,12 +1090,14 @@ static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
static int fuse_dir_open(struct inode *inode, struct file *file) static int fuse_dir_open(struct inode *inode, struct file *file)
{ {
return fuse_open_common(inode, file, 1); return fuse_open_common(inode, file, true);
} }
static int fuse_dir_release(struct inode *inode, struct file *file) static int fuse_dir_release(struct inode *inode, struct file *file)
{ {
return fuse_release_common(inode, file, 1); fuse_release_common(file, FUSE_RELEASEDIR);
return 0;
} }
static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync) static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
......
This diff is collapsed.
...@@ -97,8 +97,13 @@ struct fuse_inode { ...@@ -97,8 +97,13 @@ struct fuse_inode {
struct list_head writepages; struct list_head writepages;
}; };
struct fuse_conn;
/** FUSE specific file data */ /** FUSE specific file data */
struct fuse_file { struct fuse_file {
/** Fuse connection for this file */
struct fuse_conn *fc;
/** Request reserved for flush and release */ /** Request reserved for flush and release */
struct fuse_req *reserved_req; struct fuse_req *reserved_req;
...@@ -108,9 +113,15 @@ struct fuse_file { ...@@ -108,9 +113,15 @@ struct fuse_file {
/** File handle used by userspace */ /** File handle used by userspace */
u64 fh; u64 fh;
/** Node id of this file */
u64 nodeid;
/** Refcount */ /** Refcount */
atomic_t count; atomic_t count;
/** FOPEN_* flags returned by open */
u32 open_flags;
/** Entry on inode's write_files list */ /** Entry on inode's write_files list */
struct list_head write_entry; struct list_head write_entry;
...@@ -185,8 +196,6 @@ enum fuse_req_state { ...@@ -185,8 +196,6 @@ enum fuse_req_state {
FUSE_REQ_FINISHED FUSE_REQ_FINISHED
}; };
struct fuse_conn;
/** /**
* A request to the client * A request to the client
*/ */
...@@ -248,11 +257,12 @@ struct fuse_req { ...@@ -248,11 +257,12 @@ struct fuse_req {
struct fuse_forget_in forget_in; struct fuse_forget_in forget_in;
struct { struct {
struct fuse_release_in in; struct fuse_release_in in;
struct vfsmount *vfsmount; struct path path;
struct dentry *dentry;
} release; } release;
struct fuse_init_in init_in; struct fuse_init_in init_in;
struct fuse_init_out init_out; struct fuse_init_out init_out;
struct cuse_init_in cuse_init_in;
struct cuse_init_out cuse_init_out;
struct { struct {
struct fuse_read_in in; struct fuse_read_in in;
u64 attr_ver; u64 attr_ver;
...@@ -386,6 +396,9 @@ struct fuse_conn { ...@@ -386,6 +396,9 @@ struct fuse_conn {
/** Filesystem supports NFS exporting. Only set in INIT */ /** Filesystem supports NFS exporting. Only set in INIT */
unsigned export_support:1; unsigned export_support:1;
/** Set if bdi is valid */
unsigned bdi_initialized:1;
/* /*
* The following bitfields are only for optimization purposes * The following bitfields are only for optimization purposes
* and hence races in setting them will not cause malfunction * and hence races in setting them will not cause malfunction
...@@ -515,25 +528,24 @@ void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, ...@@ -515,25 +528,24 @@ void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
* Initialize READ or READDIR request * Initialize READ or READDIR request
*/ */
void fuse_read_fill(struct fuse_req *req, struct file *file, void fuse_read_fill(struct fuse_req *req, struct file *file,
struct inode *inode, loff_t pos, size_t count, int opcode); loff_t pos, size_t count, int opcode);
/** /**
* Send OPEN or OPENDIR request * Send OPEN or OPENDIR request
*/ */
int fuse_open_common(struct inode *inode, struct file *file, int isdir); int fuse_open_common(struct inode *inode, struct file *file, bool isdir);
struct fuse_file *fuse_file_alloc(struct fuse_conn *fc); struct fuse_file *fuse_file_alloc(struct fuse_conn *fc);
struct fuse_file *fuse_file_get(struct fuse_file *ff);
void fuse_file_free(struct fuse_file *ff); void fuse_file_free(struct fuse_file *ff);
void fuse_finish_open(struct inode *inode, struct file *file, void fuse_finish_open(struct inode *inode, struct file *file);
struct fuse_file *ff, struct fuse_open_out *outarg);
/** Fill in ff->reserved_req with a RELEASE request */ void fuse_sync_release(struct fuse_file *ff, int flags);
void fuse_release_fill(struct fuse_file *ff, u64 nodeid, int flags, int opcode);
/** /**
* Send RELEASE or RELEASEDIR request * Send RELEASE or RELEASEDIR request
*/ */
int fuse_release_common(struct inode *inode, struct file *file, int isdir); void fuse_release_common(struct file *file, int opcode);
/** /**
* Send FSYNC or FSYNCDIR request * Send FSYNC or FSYNCDIR request
...@@ -652,10 +664,12 @@ void fuse_invalidate_entry_cache(struct dentry *entry); ...@@ -652,10 +664,12 @@ void fuse_invalidate_entry_cache(struct dentry *entry);
*/ */
struct fuse_conn *fuse_conn_get(struct fuse_conn *fc); struct fuse_conn *fuse_conn_get(struct fuse_conn *fc);
void fuse_conn_kill(struct fuse_conn *fc);
/** /**
* Initialize fuse_conn * Initialize fuse_conn
*/ */
int fuse_conn_init(struct fuse_conn *fc, struct super_block *sb); void fuse_conn_init(struct fuse_conn *fc);
/** /**
* Release reference to fuse_conn * Release reference to fuse_conn
...@@ -694,4 +708,13 @@ void fuse_release_nowrite(struct inode *inode); ...@@ -694,4 +708,13 @@ void fuse_release_nowrite(struct inode *inode);
u64 fuse_get_attr_version(struct fuse_conn *fc); u64 fuse_get_attr_version(struct fuse_conn *fc);
int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file,
bool isdir);
ssize_t fuse_direct_io(struct file *file, const char __user *buf,
size_t count, loff_t *ppos, int write);
long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
unsigned int flags);
unsigned fuse_file_poll(struct file *file, poll_table *wait);
int fuse_dev_release(struct inode *inode, struct file *file);
#endif /* _FS_FUSE_I_H */ #endif /* _FS_FUSE_I_H */
...@@ -277,11 +277,14 @@ static void fuse_send_destroy(struct fuse_conn *fc) ...@@ -277,11 +277,14 @@ static void fuse_send_destroy(struct fuse_conn *fc)
} }
} }
static void fuse_put_super(struct super_block *sb) static void fuse_bdi_destroy(struct fuse_conn *fc)
{ {
struct fuse_conn *fc = get_fuse_conn_super(sb); if (fc->bdi_initialized)
bdi_destroy(&fc->bdi);
}
fuse_send_destroy(fc); void fuse_conn_kill(struct fuse_conn *fc)
{
spin_lock(&fc->lock); spin_lock(&fc->lock);
fc->connected = 0; fc->connected = 0;
fc->blocked = 0; fc->blocked = 0;
...@@ -295,7 +298,16 @@ static void fuse_put_super(struct super_block *sb) ...@@ -295,7 +298,16 @@ static void fuse_put_super(struct super_block *sb)
list_del(&fc->entry); list_del(&fc->entry);
fuse_ctl_remove_conn(fc); fuse_ctl_remove_conn(fc);
mutex_unlock(&fuse_mutex); mutex_unlock(&fuse_mutex);
bdi_destroy(&fc->bdi); fuse_bdi_destroy(fc);
}
EXPORT_SYMBOL_GPL(fuse_conn_kill);
static void fuse_put_super(struct super_block *sb)
{
struct fuse_conn *fc = get_fuse_conn_super(sb);
fuse_send_destroy(fc);
fuse_conn_kill(fc);
fuse_conn_put(fc); fuse_conn_put(fc);
} }
...@@ -466,10 +478,8 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt) ...@@ -466,10 +478,8 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
return 0; return 0;
} }
int fuse_conn_init(struct fuse_conn *fc, struct super_block *sb) void fuse_conn_init(struct fuse_conn *fc)
{ {
int err;
memset(fc, 0, sizeof(*fc)); memset(fc, 0, sizeof(*fc));
spin_lock_init(&fc->lock); spin_lock_init(&fc->lock);
mutex_init(&fc->inst_mutex); mutex_init(&fc->inst_mutex);
...@@ -484,49 +494,12 @@ int fuse_conn_init(struct fuse_conn *fc, struct super_block *sb) ...@@ -484,49 +494,12 @@ int fuse_conn_init(struct fuse_conn *fc, struct super_block *sb)
INIT_LIST_HEAD(&fc->bg_queue); INIT_LIST_HEAD(&fc->bg_queue);
INIT_LIST_HEAD(&fc->entry); INIT_LIST_HEAD(&fc->entry);
atomic_set(&fc->num_waiting, 0); atomic_set(&fc->num_waiting, 0);
fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
fc->bdi.unplug_io_fn = default_unplug_io_fn;
/* fuse does it's own writeback accounting */
fc->bdi.capabilities = BDI_CAP_NO_ACCT_WB;
fc->khctr = 0; fc->khctr = 0;
fc->polled_files = RB_ROOT; fc->polled_files = RB_ROOT;
fc->dev = sb->s_dev;
err = bdi_init(&fc->bdi);
if (err)
goto error_mutex_destroy;
if (sb->s_bdev) {
err = bdi_register(&fc->bdi, NULL, "%u:%u-fuseblk",
MAJOR(fc->dev), MINOR(fc->dev));
} else {
err = bdi_register_dev(&fc->bdi, fc->dev);
}
if (err)
goto error_bdi_destroy;
/*
* For a single fuse filesystem use max 1% of dirty +
* writeback threshold.
*
* This gives about 1M of write buffer for memory maps on a
* machine with 1G and 10% dirty_ratio, which should be more
* than enough.
*
* Privileged users can raise it by writing to
*
* /sys/class/bdi/<bdi>/max_ratio
*/
bdi_set_max_ratio(&fc->bdi, 1);
fc->reqctr = 0; fc->reqctr = 0;
fc->blocked = 1; fc->blocked = 1;
fc->attr_version = 1; fc->attr_version = 1;
get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key)); get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key));
return 0;
error_bdi_destroy:
bdi_destroy(&fc->bdi);
error_mutex_destroy:
mutex_destroy(&fc->inst_mutex);
return err;
} }
EXPORT_SYMBOL_GPL(fuse_conn_init); EXPORT_SYMBOL_GPL(fuse_conn_init);
...@@ -539,12 +512,14 @@ void fuse_conn_put(struct fuse_conn *fc) ...@@ -539,12 +512,14 @@ void fuse_conn_put(struct fuse_conn *fc)
fc->release(fc); fc->release(fc);
} }
} }
EXPORT_SYMBOL_GPL(fuse_conn_put);
struct fuse_conn *fuse_conn_get(struct fuse_conn *fc) struct fuse_conn *fuse_conn_get(struct fuse_conn *fc)
{ {
atomic_inc(&fc->count); atomic_inc(&fc->count);
return fc; return fc;
} }
EXPORT_SYMBOL_GPL(fuse_conn_get);
static struct inode *fuse_get_root_inode(struct super_block *sb, unsigned mode) static struct inode *fuse_get_root_inode(struct super_block *sb, unsigned mode)
{ {
...@@ -797,6 +772,48 @@ static void fuse_free_conn(struct fuse_conn *fc) ...@@ -797,6 +772,48 @@ static void fuse_free_conn(struct fuse_conn *fc)
kfree(fc); kfree(fc);
} }
static int fuse_bdi_init(struct fuse_conn *fc, struct super_block *sb)
{
int err;
fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
fc->bdi.unplug_io_fn = default_unplug_io_fn;
/* fuse does it's own writeback accounting */
fc->bdi.capabilities = BDI_CAP_NO_ACCT_WB;
err = bdi_init(&fc->bdi);
if (err)
return err;
fc->bdi_initialized = 1;
if (sb->s_bdev) {
err = bdi_register(&fc->bdi, NULL, "%u:%u-fuseblk",
MAJOR(fc->dev), MINOR(fc->dev));
} else {
err = bdi_register_dev(&fc->bdi, fc->dev);
}
if (err)
return err;
/*
* For a single fuse filesystem use max 1% of dirty +
* writeback threshold.
*
* This gives about 1M of write buffer for memory maps on a
* machine with 1G and 10% dirty_ratio, which should be more
* than enough.
*
* Privileged users can raise it by writing to
*
* /sys/class/bdi/<bdi>/max_ratio
*/
bdi_set_max_ratio(&fc->bdi, 1);
return 0;
}
static int fuse_fill_super(struct super_block *sb, void *data, int silent) static int fuse_fill_super(struct super_block *sb, void *data, int silent)
{ {
struct fuse_conn *fc; struct fuse_conn *fc;
...@@ -843,11 +860,12 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) ...@@ -843,11 +860,12 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
if (!fc) if (!fc)
goto err_fput; goto err_fput;
err = fuse_conn_init(fc, sb); fuse_conn_init(fc);
if (err) {
kfree(fc); fc->dev = sb->s_dev;
goto err_fput; err = fuse_bdi_init(fc, sb);
} if (err)
goto err_put_conn;
fc->release = fuse_free_conn; fc->release = fuse_free_conn;
fc->flags = d.flags; fc->flags = d.flags;
...@@ -911,7 +929,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) ...@@ -911,7 +929,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
err_put_root: err_put_root:
dput(root_dentry); dput(root_dentry);
err_put_conn: err_put_conn:
bdi_destroy(&fc->bdi); fuse_bdi_destroy(fc);
fuse_conn_put(fc); fuse_conn_put(fc);
err_fput: err_fput:
fput(file); fput(file);
......
...@@ -120,6 +120,13 @@ struct fuse_file_lock { ...@@ -120,6 +120,13 @@ struct fuse_file_lock {
#define FUSE_EXPORT_SUPPORT (1 << 4) #define FUSE_EXPORT_SUPPORT (1 << 4)
#define FUSE_BIG_WRITES (1 << 5) #define FUSE_BIG_WRITES (1 << 5)
/**
* CUSE INIT request/reply flags
*
* CUSE_UNRESTRICTED_IOCTL: use unrestricted ioctl
*/
#define CUSE_UNRESTRICTED_IOCTL (1 << 0)
/** /**
* Release flags * Release flags
*/ */
...@@ -210,6 +217,9 @@ enum fuse_opcode { ...@@ -210,6 +217,9 @@ enum fuse_opcode {
FUSE_DESTROY = 38, FUSE_DESTROY = 38,
FUSE_IOCTL = 39, FUSE_IOCTL = 39,
FUSE_POLL = 40, FUSE_POLL = 40,
/* CUSE specific operations */
CUSE_INIT = 4096,
}; };
enum fuse_notify_code { enum fuse_notify_code {
...@@ -401,6 +411,27 @@ struct fuse_init_out { ...@@ -401,6 +411,27 @@ struct fuse_init_out {
__u32 max_write; __u32 max_write;
}; };
#define CUSE_INIT_INFO_MAX 4096
struct cuse_init_in {
__u32 major;
__u32 minor;
__u32 unused;
__u32 flags;
};
struct cuse_init_out {
__u32 major;
__u32 minor;
__u32 unused;
__u32 flags;
__u32 max_read;
__u32 max_write;
__u32 dev_major; /* chardev major */
__u32 dev_minor; /* chardev minor */
__u32 spare[10];
};
struct fuse_interrupt_in { struct fuse_interrupt_in {
__u64 unique; __u64 unique;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment