-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
yaml --- r: 29775 b: refs/heads/master c: bafa965 h: refs/heads/master i: 29773: ca780c9 29771: 3816649 29767: 0eb21dd 29759: 606f610 v: v3
- Loading branch information
Miklos Szeredi
authored and
Linus Torvalds
committed
Jun 25, 2006
1 parent
1c818fa
commit 3ea8cca
Showing
7 changed files
with
332 additions
and
116 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
--- | ||
refs/heads/master: 51eb01e73599efb88c6c20b1c226d20309a75450 | ||
refs/heads/master: bafa96541b250a7051e3fbc5de6e8369daf8ffec |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,218 @@ | ||
/* | ||
FUSE: Filesystem in Userspace | ||
Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu> | ||
This program can be distributed under the terms of the GNU GPL. | ||
See the file COPYING. | ||
*/ | ||
|
||
#include "fuse_i.h" | ||
|
||
#include <linux/init.h> | ||
#include <linux/module.h> | ||
|
||
#define FUSE_CTL_SUPER_MAGIC 0x65735543 | ||
|
||
/* | ||
* This is non-NULL when the single instance of the control filesystem | ||
* exists. Protected by fuse_mutex | ||
*/ | ||
static struct super_block *fuse_control_sb; | ||
|
||
static struct fuse_conn *fuse_ctl_file_conn_get(struct file *file) | ||
{ | ||
struct fuse_conn *fc; | ||
mutex_lock(&fuse_mutex); | ||
fc = file->f_dentry->d_inode->u.generic_ip; | ||
if (fc) | ||
fc = fuse_conn_get(fc); | ||
mutex_unlock(&fuse_mutex); | ||
return fc; | ||
} | ||
|
||
static ssize_t fuse_conn_abort_write(struct file *file, const char __user *buf, | ||
size_t count, loff_t *ppos) | ||
{ | ||
struct fuse_conn *fc = fuse_ctl_file_conn_get(file); | ||
if (fc) { | ||
fuse_abort_conn(fc); | ||
fuse_conn_put(fc); | ||
} | ||
return count; | ||
} | ||
|
||
static ssize_t fuse_conn_waiting_read(struct file *file, char __user *buf, | ||
size_t len, loff_t *ppos) | ||
{ | ||
char tmp[32]; | ||
size_t size; | ||
|
||
if (!*ppos) { | ||
struct fuse_conn *fc = fuse_ctl_file_conn_get(file); | ||
if (!fc) | ||
return 0; | ||
|
||
file->private_data=(void *)(long)atomic_read(&fc->num_waiting); | ||
fuse_conn_put(fc); | ||
} | ||
size = sprintf(tmp, "%ld\n", (long)file->private_data); | ||
return simple_read_from_buffer(buf, len, ppos, tmp, size); | ||
} | ||
|
||
static const struct file_operations fuse_ctl_abort_ops = { | ||
.open = nonseekable_open, | ||
.write = fuse_conn_abort_write, | ||
}; | ||
|
||
static const struct file_operations fuse_ctl_waiting_ops = { | ||
.open = nonseekable_open, | ||
.read = fuse_conn_waiting_read, | ||
}; | ||
|
||
static struct dentry *fuse_ctl_add_dentry(struct dentry *parent, | ||
struct fuse_conn *fc, | ||
const char *name, | ||
int mode, int nlink, | ||
struct inode_operations *iop, | ||
const struct file_operations *fop) | ||
{ | ||
struct dentry *dentry; | ||
struct inode *inode; | ||
|
||
BUG_ON(fc->ctl_ndents >= FUSE_CTL_NUM_DENTRIES); | ||
dentry = d_alloc_name(parent, name); | ||
if (!dentry) | ||
return NULL; | ||
|
||
fc->ctl_dentry[fc->ctl_ndents++] = dentry; | ||
inode = new_inode(fuse_control_sb); | ||
if (!inode) | ||
return NULL; | ||
|
||
inode->i_mode = mode; | ||
inode->i_uid = fc->user_id; | ||
inode->i_gid = fc->group_id; | ||
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | ||
/* setting ->i_op to NULL is not allowed */ | ||
if (iop) | ||
inode->i_op = iop; | ||
inode->i_fop = fop; | ||
inode->i_nlink = nlink; | ||
inode->u.generic_ip = fc; | ||
d_add(dentry, inode); | ||
return dentry; | ||
} | ||
|
||
/* | ||
* Add a connection to the control filesystem (if it exists). Caller | ||
* must host fuse_mutex | ||
*/ | ||
int fuse_ctl_add_conn(struct fuse_conn *fc) | ||
{ | ||
struct dentry *parent; | ||
char name[32]; | ||
|
||
if (!fuse_control_sb) | ||
return 0; | ||
|
||
parent = fuse_control_sb->s_root; | ||
parent->d_inode->i_nlink++; | ||
sprintf(name, "%llu", (unsigned long long) fc->id); | ||
parent = fuse_ctl_add_dentry(parent, fc, name, S_IFDIR | 0500, 2, | ||
&simple_dir_inode_operations, | ||
&simple_dir_operations); | ||
if (!parent) | ||
goto err; | ||
|
||
if (!fuse_ctl_add_dentry(parent, fc, "waiting", S_IFREG | 0400, 1, | ||
NULL, &fuse_ctl_waiting_ops) || | ||
!fuse_ctl_add_dentry(parent, fc, "abort", S_IFREG | 0200, 1, | ||
NULL, &fuse_ctl_abort_ops)) | ||
goto err; | ||
|
||
return 0; | ||
|
||
err: | ||
fuse_ctl_remove_conn(fc); | ||
return -ENOMEM; | ||
} | ||
|
||
/* | ||
* Remove a connection from the control filesystem (if it exists). | ||
* Caller must host fuse_mutex | ||
*/ | ||
void fuse_ctl_remove_conn(struct fuse_conn *fc) | ||
{ | ||
int i; | ||
|
||
if (!fuse_control_sb) | ||
return; | ||
|
||
for (i = fc->ctl_ndents - 1; i >= 0; i--) { | ||
struct dentry *dentry = fc->ctl_dentry[i]; | ||
dentry->d_inode->u.generic_ip = NULL; | ||
d_drop(dentry); | ||
dput(dentry); | ||
} | ||
fuse_control_sb->s_root->d_inode->i_nlink--; | ||
} | ||
|
||
static int fuse_ctl_fill_super(struct super_block *sb, void *data, int silent) | ||
{ | ||
struct tree_descr empty_descr = {""}; | ||
struct fuse_conn *fc; | ||
int err; | ||
|
||
err = simple_fill_super(sb, FUSE_CTL_SUPER_MAGIC, &empty_descr); | ||
if (err) | ||
return err; | ||
|
||
mutex_lock(&fuse_mutex); | ||
BUG_ON(fuse_control_sb); | ||
fuse_control_sb = sb; | ||
list_for_each_entry(fc, &fuse_conn_list, entry) { | ||
err = fuse_ctl_add_conn(fc); | ||
if (err) { | ||
fuse_control_sb = NULL; | ||
mutex_unlock(&fuse_mutex); | ||
return err; | ||
} | ||
} | ||
mutex_unlock(&fuse_mutex); | ||
|
||
return 0; | ||
} | ||
|
||
static int fuse_ctl_get_sb(struct file_system_type *fs_type, int flags, | ||
const char *dev_name, void *raw_data, | ||
struct vfsmount *mnt) | ||
{ | ||
return get_sb_single(fs_type, flags, raw_data, | ||
fuse_ctl_fill_super, mnt); | ||
} | ||
|
||
static void fuse_ctl_kill_sb(struct super_block *sb) | ||
{ | ||
mutex_lock(&fuse_mutex); | ||
fuse_control_sb = NULL; | ||
mutex_unlock(&fuse_mutex); | ||
|
||
kill_litter_super(sb); | ||
} | ||
|
||
static struct file_system_type fuse_ctl_fs_type = { | ||
.owner = THIS_MODULE, | ||
.name = "fusectl", | ||
.get_sb = fuse_ctl_get_sb, | ||
.kill_sb = fuse_ctl_kill_sb, | ||
}; | ||
|
||
int __init fuse_ctl_init(void) | ||
{ | ||
return register_filesystem(&fuse_ctl_fs_type); | ||
} | ||
|
||
void fuse_ctl_cleanup(void) | ||
{ | ||
unregister_filesystem(&fuse_ctl_fs_type); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.