#FORMAT Plain /* * tyler@agat.net * * Nano DevFS (intended to Linux Kernel 2.6(.12)) * * This module implements the nano dev file system from Greg KH. * This code is included in the main tree but I've writtent this module * because it's a very simple file system. * * ndevfs is a simple ramfs based filesystem. It creates/deletes * nodes in the /dev directory dynamically in the format seen in devfs. */ #include #include #include #include #include #include #include #define DRIVER_AUTHOR "tyler@agat.net" #define DRIVER_DESC "Ram File System" #define MAGIC 0x64756d62 struct entry { struct list_head node; struct dentry *dentry; char name[BUS_ID_SIZE]; }; static LIST_HEAD(entries); static struct vfsmount *mount; static int mount_count; static struct file_operations file_ops = { read: generic_file_read, write: generic_file_write, mmap: generic_file_mmap, fsync: simple_sync_file, llseek: generic_file_llseek, }; static struct inode *get_inode(struct super_block *sb, int mode, dev_t dev) { struct inode *inode = new_inode(sb); if (inode) { inode->i_mode = mode; inode->i_uid = 0; inode->i_gid = 0; inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; switch (mode & S_IFMT) { case S_IFREG: inode->i_fop = &file_ops; break; case S_IFDIR: inode->i_op = &simple_dir_inode_operations; inode->i_fop = &simple_dir_operations; inode->i_nlink++; break; } } return inode; } static int mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) { struct inode *inode = get_inode(dir->i_sb, mode, dev); if (dentry->d_inode) { return -EEXIST; } if (! inode) { return -EPERM; } d_instantiate(dentry, inode); dget(dentry); return 0; } static inline int positive(struct dentry *dentry) { return dentry->d_inode && !d_unhashed(dentry); } static void remove(struct dentry *dentry) { struct dentry *parent; if (!dentry) { return; } parent = dentry->d_parent; if (!parent || !parent->d_inode) { return; } down(&parent->d_inode->i_sem); if (positive(dentry)) { if (dentry->d_inode) { if (S_ISDIR(dentry->d_inode->i_mode)) { simple_rmdir(parent->d_inode, dentry); } else { simple_unlink(parent->d_inode, dentry); } } } up(&parent->d_inode->i_sem); simple_release_fs(&mount, &mount_count); } void mfs_create(const char *name, dev_t dev) { struct dentry *dentry; struct dentry *parent; struct entry *entry; int err; int mode = S_IRUSR | S_IWUSR; mode |= S_IFREG; err = simple_pin_fs("mfs", &mount, &mount_count); if (err) { return; } if (mount && mount->mnt_sb) { parent = mount->mnt_sb->s_root; } else { pr_debug("%s: no parent?\n", __FUNCTION__); goto error; } down(&parent->d_inode->i_sem); dentry = lookup_one_len(name, parent, strlen(name)); if (!IS_ERR(dentry)) { err = mknod(parent->d_inode, dentry, mode, dev); } else { err = PTR_ERR(dentry); } up(&parent->d_inode->i_sem); if (err) { goto error; } entry = kmalloc(sizeof(struct entry), GFP_KERNEL); if (!entry) { remove(dentry); err = -ENOMEM; goto error; } entry->dentry = dentry; strcpy(&entry->name[0], name); list_add(&entry->node, &entries); return; error: pr_debug("%s failed with error %d\n", __FUNCTION__, err); simple_release_fs(&mount, &mount_count); } EXPORT_SYMBOL_GPL(mfs_create); void mfs_remove(const char *name) { struct entry *entry; struct dentry *dentry = NULL; list_for_each_entry(entry, &entries, node) { if (strcmp(&entry->name[0], name) == 0) { dentry = entry->dentry; break; } } if (!dentry) { pr_debug("%s: can't find %s\n", __FUNCTION__, name); return; } remove(dentry); } EXPORT_SYMBOL_GPL(mfs_remove); static int fill_super(struct super_block *sb, void *data, int silent) { static struct tree_descr files[] = {{""}}; return simple_fill_super(sb, MAGIC, files); } static struct super_block *get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { return get_sb_single(fs_type, flags, data, fill_super); } static struct file_system_type mfs = { owner: THIS_MODULE, name: "mfs", get_sb: get_sb, kill_sb: kill_litter_super, }; int __init loading(void) { return register_filesystem(&mfs); } void __exit unloading(void) { simple_release_fs(&mount, &mount_count); unregister_filesystem(&mfs); } module_init(loading); module_exit(unloading); MODULE_LICENSE("GPL"); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC);