📄 control.c
字号:
/* 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#ifndef HAVE_I_PRIVATE#define i_private u.generic_ip#endif/* * 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->i_private; 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 struct file_operations fuse_ctl_abort_ops = { .open = nonseekable_open, .write = fuse_conn_abort_write,};static struct file_operations fuse_ctl_waiting_ops = { .open = nonseekable_open, .read = fuse_conn_waiting_read,};#ifndef KERNEL_2_6_10_PLUSstruct dentry *d_alloc_name(struct dentry *parent, const char *name){ struct qstr q; q.name = name; q.len = strlen(name); q.hash = full_name_hash(q.name, q.len); return d_alloc(parent, &q);}#endifstatic struct dentry *fuse_ctl_add_dentry(struct dentry *parent, struct fuse_conn *fc, const char *name, int mode, int nlink, struct inode_operations *iop,#ifdef KERNEL_2_6_17_PLUS const struct file_operations *fop#else struct file_operations *fop#endif){ 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->i_private = fc; d_add(dentry, inode); return dentry;}/* * Add a connection to the control filesystem (if it exists). Caller * must hold 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; inc_nlink(parent->d_inode); 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 hold 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->i_private = 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;}#ifdef KERNEL_2_6_18_PLUSstatic 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);}#elsestatic struct super_block *fuse_ctl_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *raw_data){ return get_sb_single(fs_type, flags, raw_data, fuse_ctl_fill_super);}#endifstatic void fuse_ctl_kill_sb(struct super_block *sb){ struct fuse_conn *fc; mutex_lock(&fuse_mutex); fuse_control_sb = NULL; list_for_each_entry(fc, &fuse_conn_list, entry) fc->ctl_ndents = 0; 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);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -