Messages in this thread | | | Subject | Minimal fs module won't unmount | Date | Tue, 30 Nov 1999 13:00:44 +0000 (GMT) | From | Malcolm Beattie <> |
| |
I'm writing a little "fake" filesystem module which, when mounted on a mountpoint, makes the root of the new filesystem be a "magic" symlink. It all works fine except that the filesystem won't unmount. strace shows that oldumount is returning EINVAL. What the "magic symlink" does isn't important here and the following cut-down version displays the same problem. Is it something to do with the fact that the core fs code expects the root of the new filesystem to be an ordinary directory or am I missing something else? Here's the cut-down module which simply makes follow_link appear to be your cwd. You can compile (under 2.2 or 2.3, though 2.3 is untested) by
cc -c -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -m486 -DCPU=486 -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h -I/usr/src/linux/include nullfs.c
(modifying arch-specific options as necessary) and then doing # insmod ./nullfs.o # mkdir /tmp/nullcwd # mount -t null none /tmp/nullcwd # ls -l /tmp/nullcwd lrwxrwxrwx 1 root root 0 Nov 30 12:21 /tmp/nullcwd -> foo # ls -l /tmp/nullcwd/ ...listing of your current working directory... # umount /tmp/nullcwd umount: none: not found umount: /tmp/foo: not mounted How can I get it to umount properly?
------------------------------ nullfs.c ------------------------------ #define NULL_ROOT_INO 1 #define NULL_SUPER_MAGIC 0x04ab
#include <linux/fs.h> #include <linux/kernel.h> #include <linux/stat.h> #include <linux/malloc.h> #include <linux/locks.h> #include <linux/module.h> #include <linux/errno.h> #include <asm/uaccess.h>
static struct dentry * null_follow_link(struct dentry *dentry, struct dentry *base, unsigned int follow) { return dget(current->fs->pwd); }
static int null_readlink(struct dentry *dentry, char *buffer, int buflen) { if (buflen > 4) buflen = 4; copy_to_user(buffer, "foo", buflen); return buflen; }
static struct file_operations null_file_operations = { 0 /* all of them */ };
static struct inode_operations null_inode_operations = { &null_file_operations, /* fops */ 0, /* create */ 0, /* lookup */ 0, /* link */ 0, /* unlink */ 0, /* symlink */ 0, /* mkdir */ 0, /* rmdir */ 0, /* mknod */ 0, /* rename */ null_readlink, /* readlink */ null_follow_link, /* follow_link */ 0 /* and all the rest are zero */ };
static void null_put_inode(struct inode *inode) { if (inode->i_count == 1) inode->i_nlink = 0; }
static int null_statfs(struct super_block *sb, struct statfs *buf, int bufsiz) { struct statfs tmp;
tmp.f_type = NULL_SUPER_MAGIC; tmp.f_bsize = PAGE_SIZE/sizeof(long); tmp.f_blocks = 0; tmp.f_bfree = 0; tmp.f_bavail = 0; tmp.f_files = 0; tmp.f_ffree = 0; tmp.f_namelen = NAME_MAX; return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0; }
static void null_read_inode(struct inode * inode) { if (inode->i_ino != NULL_ROOT_INO) printk("nullfs: bad inode number %lu\n", inode->i_ino);
inode->i_mode = S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO; inode->i_uid = 0; inode->i_gid = 0; inode->i_nlink = 1; inode->i_size = 0; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; inode->i_blocks = 0; inode->i_blksize = 1024; inode->i_op = &null_inode_operations; }
static void null_put_super(struct super_block *sb) { MOD_DEC_USE_COUNT; }
static struct super_operations null_sops = { null_read_inode, 0, /* write_inode */ null_put_inode, 0, /* delete_inode */ 0, /* notify_change */ null_put_super, 0, /* write_super */ null_statfs, 0, /* remount_fs */ 0, /* clear_inode */ 0 /* umount_begin */ };
static struct super_block *null_read_super(struct super_block *sb, void *data, int silent) { struct inode *inode;
MOD_INC_USE_COUNT; lock_super(sb); sb->s_blocksize = 1024; sb->s_blocksize_bits = 10; sb->s_magic = NULL_SUPER_MAGIC; sb->s_op = &null_sops;
inode = iget(sb, 1); if (!inode) goto out_no_root; #if LINUX_VERSION_CODE < 0x020300 sb->s_root = d_alloc_root(inode, 0); #else sb->s_root = d_alloc_root(inode); #endif if (!sb->s_root) goto out_no_root; unlock_super(sb); return sb;
out_no_root: printk("null_read_super: get root inode failed\n"); if (inode) iput(inode); sb->s_dev = 0; unlock_super(sb); MOD_DEC_USE_COUNT; return 0; }
static struct file_system_type null_fs_type = { "null", 0, null_read_super, 0 };
int init_null_fs(void) { return register_filesystem(&null_fs_type); }
#ifdef MODULE int init_module(void) { return init_null_fs(); }
void cleanup_module(void) { unregister_filesystem(&null_fs_type); } #endif ------------------------------ nullfs.c ------------------------------
--Malcolm
-- Malcolm Beattie <mbeattie@sable.ox.ac.uk> Unix Systems Programmer Oxford University Computing Services
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/
| |