#include #include #include #define V4ROOT_SUPER_MAGIC 0x9696 #define V4ROOT_ROOT_INO 0x1 #define V4ROOT_FIRST_DIR_INO 0x2 struct v4root_sb_info { unsigned long max_blocks; /* How many blocks are allowed */ unsigned long free_blocks; /* How many are left for allocation */ unsigned long max_inodes; /* How many inodes are allowed */ unsigned long free_inodes; /* How many are left for allocation */ spinlock_t stat_lock; /* Serialize shmem_sb_info changes */ uid_t uid; /* Mount uid for root directory */ gid_t gid; /* Mount gid for root directory */ mode_t mode; /* Mount mode for root directory */ }; static inline struct v4root_sb_info *v4root_sbinfo(struct super_block *sb) { return (struct v4root_sb_info *)(sb->s_fs_info); } static int v4root_mkdir(struct inode *dir, struct dentry *dentry, int mode); static int v4root_unlink(struct inode *dir, struct dentry *dentry); static int v4root_rmdir(struct inode *dir, struct dentry *dentry); const struct file_operations v4root_root_operations = { .open = dcache_dir_open, .release = dcache_dir_close, .read = generic_read_dir, .readdir = dcache_readdir, }; const struct inode_operations v4root_root_inode_operations = { .lookup = simple_lookup, .unlink = v4root_unlink, .mkdir = v4root_mkdir, .rmdir = v4root_rmdir, }; const struct file_operations v4root_dir_operations = { .open = dcache_dir_open, .release = dcache_dir_close, .llseek = dcache_dir_lseek, .read = generic_read_dir, .readdir = dcache_readdir, .fsync = simple_sync_file, }; const struct inode_operations v4root_dir_inode_operations = { .lookup = simple_lookup, .unlink = v4root_unlink, .mkdir = v4root_mkdir, .rmdir = v4root_rmdir, }; static const struct super_operations v4root_sops = { .statfs = simple_statfs, .show_options = generic_show_options, }; static struct inode * v4root_iget(struct super_block *sb, int mode, unsigned long ino) { struct inode *inode; /* * Only hand out directory inodes */ if (!S_ISDIR(mode)) return NULL; inode = iget_locked(sb, ino); if (!inode) return NULL; if (!(inode->i_state & I_NEW)) return inode; inode->i_mode = mode; inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; inode->i_blocks = 0; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; inc_nlink(inode); inode->i_op = &v4root_dir_inode_operations; inode->i_fop = &v4root_dir_operations; if (ino == V4ROOT_ROOT_INO) { inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR; inode->i_op = &v4root_root_inode_operations; inode->i_fop = &v4root_root_operations; } unlock_new_inode(inode); return inode; } static inline void v4root_put_super(struct super_block *sb) { kfree(sb->s_fs_info); sb->s_fs_info = NULL; } static int v4root_fill_super(struct super_block *sb, void *data, int silent) { struct inode *inode; struct dentry *root; struct v4root_sb_info *sbinfo; int err = -ENOMEM; sbinfo = kmalloc(sizeof(struct v4root_sb_info), GFP_KERNEL); if (!sbinfo) return -ENOMEM; sbinfo->max_blocks = 0; sbinfo->max_inodes = 0; sbinfo->mode = S_IFDIR | S_IRUGO | S_IXUGO; sbinfo->uid = current->fsuid; sbinfo->gid = current->fsgid; sb->s_fs_info = sbinfo; sb->s_blocksize = 1024; sb->s_blocksize_bits = 10; sb->s_magic = V4ROOT_SUPER_MAGIC; sb->s_op = &v4root_sops; inode = v4root_iget(sb, sbinfo->mode, 0); if (!inode) goto failed; inode->i_uid = sbinfo->uid; inode->i_gid = sbinfo->gid; root = d_alloc_root(inode); if (!root) goto failed_iput; sb->s_root = root; return 0; failed_iput: iput(inode); failed: v4root_put_super(sb); return err; } unsigned long ino_cnt = 3; static int v4root_mkdir(struct inode *dir, struct dentry *dentry, int mode) { struct inode *inode; inode = v4root_iget(dir->i_sb, mode | S_IFDIR, ++ino_cnt); if (!inode) return -ENOSPC; dir->i_ctime = dir->i_mtime = CURRENT_TIME; d_instantiate(dentry, inode); dget(dentry); return 0; } static int v4root_unlink(struct inode *dir, struct dentry *dentry) { struct inode *inode = dentry->d_inode; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; drop_nlink(inode); dput(dentry); return 0; } static int v4root_rmdir(struct inode *dir, struct dentry *dentry) { int error; if (!simple_empty(dentry)) return -ENOTEMPTY; drop_nlink(dentry->d_inode); drop_nlink(dir); error = v4root_unlink(dir, dentry); return error; } static int v4root_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct vfsmount *mnt) { return get_sb_nodev(fs_type, flags, data, v4root_fill_super, mnt); } void v4root_kill_sb(struct super_block *sb) { v4root_put_super(sb); kill_anon_super(sb); } static struct file_system_type v4root_fs_type = { .owner = THIS_MODULE, .name = "v4root", .get_sb = v4root_get_sb, .kill_sb = v4root_kill_sb, }; int v4root_init(void); void v4root_shutdown(void); int v4root_init() { return register_filesystem(&v4root_fs_type); } void v4root_shutdown() { unregister_filesystem(&v4root_fs_type); }