diff options
Diffstat (limited to 'fs/devpts/inode.c')
-rw-r--r-- | fs/devpts/inode.c | 240 |
1 files changed, 83 insertions, 157 deletions
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index 67cc1c7b1..c3667b208 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c @@ -27,7 +27,7 @@ #include "devpts_i.h" -static struct super_block *mounts = NULL; +static struct vfsmount *devpts_mnt; static void devpts_put_super(struct super_block *sb) { @@ -37,29 +37,24 @@ static void devpts_put_super(struct super_block *sb) for ( i = 0 ; i < sbi->max_ptys ; i++ ) { if ( (inode = sbi->inodes[i]) ) { - if ( inode->i_count != 1 ) + if ( atomic_read(&inode->i_count) != 1 ) printk("devpts_put_super: badness: entry %d count %d\n", - i, inode->i_count); + i, atomic_read(&inode->i_count)); inode->i_nlink--; iput(inode); } } - - *sbi->back = sbi->next; - if ( sbi->next ) - SBI(sbi->next)->back = sbi->back; - kfree(sbi->inodes); kfree(sbi); } static int devpts_statfs(struct super_block *sb, struct statfs *buf); -static void devpts_read_inode(struct inode *inode); +static int devpts_remount (struct super_block * sb, int * flags, char * data); static struct super_operations devpts_sops = { - read_inode: devpts_read_inode, put_super: devpts_put_super, statfs: devpts_statfs, + remount_fs: devpts_remount, }; static int devpts_parse_options(char *options, struct devpts_sb_info *sbi) @@ -112,108 +107,69 @@ static int devpts_parse_options(char *options, struct devpts_sb_info *sbi) return 0; } +static int devpts_remount(struct super_block * sb, int * flags, char * data) +{ + struct devpts_sb_info *sbi = sb->u.generic_sbp; + int res = devpts_parse_options(data,sbi); + if (res) { + printk("devpts: called with bogus options\n"); + return -EINVAL; + } + return 0; +} + struct super_block *devpts_read_super(struct super_block *s, void *data, int silent) { - struct inode * root_inode; - struct dentry * root; + struct inode * inode; struct devpts_sb_info *sbi; - /* Super block already completed? */ - if (s->s_root) - goto out_unlock; - sbi = (struct devpts_sb_info *) kmalloc(sizeof(struct devpts_sb_info), GFP_KERNEL); if ( !sbi ) - goto fail_unlock; + goto fail; sbi->magic = DEVPTS_SBI_MAGIC; sbi->max_ptys = unix98_max_ptys; sbi->inodes = kmalloc(sizeof(struct inode *) * sbi->max_ptys, GFP_KERNEL); - if ( !sbi->inodes ) { - kfree(sbi); - goto fail_unlock; - } + if ( !sbi->inodes ) + goto fail_free; memset(sbi->inodes, 0, sizeof(struct inode *) * sbi->max_ptys); + if ( devpts_parse_options(data,sbi) && !silent) { + printk("devpts: called with bogus options\n"); + goto fail_free; + } + + inode = get_empty_inode(); + if (!inode) + goto fail_free; + inode->i_sb = s; + inode->i_dev = s->s_dev; + inode->i_ino = 1; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->i_size = 0; + inode->i_blocks = 0; + inode->i_blksize = 1024; + inode->i_uid = inode->i_gid = 0; + inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR; + inode->i_op = &devpts_root_inode_operations; + inode->i_fop = &devpts_root_operations; + inode->i_nlink = 2; + s->u.generic_sbp = (void *) sbi; s->s_blocksize = 1024; s->s_blocksize_bits = 10; s->s_magic = DEVPTS_SUPER_MAGIC; s->s_op = &devpts_sops; - s->s_root = NULL; - - /* - * Get the root inode and dentry, but defer checking for errors. - */ - root_inode = iget(s, 1); /* inode 1 == root directory */ - root = d_alloc_root(root_inode); - - /* - * Check whether somebody else completed the super block. - */ + s->s_root = d_alloc_root(inode); if (s->s_root) - goto out_dput; - - if (!root) - goto fail_iput; - - /* Can this call block? (It shouldn't) */ - if ( devpts_parse_options(data,sbi) ) { - printk("devpts: called with bogus options\n"); - goto fail_dput; - } - - /* - * Check whether somebody else completed the super block. - */ - if (s->s_root) - goto out_dec; - - /* - * Success! Install the root dentry now to indicate completion. - */ - s->s_root = root; - - sbi->next = mounts; - if ( sbi->next ) - SBI(sbi->next)->back = &(sbi->next); - sbi->back = &mounts; - mounts = s; - - return s; - - /* - * Success ... somebody else completed the super block for us. - */ -out_unlock: - goto out_dec; -out_dput: - if (root) - dput(root); - else - iput(root_inode); -out_dec: - return s; + return s; - /* - * Failure ... clear the s_dev slot and clean up. - */ -fail_dput: - /* - * dput() can block, so we clear the super block first. - */ - dput(root); - goto fail_free; -fail_iput: printk("devpts: get root dentry failed\n"); - /* - * iput() can block, so we clear the super block first. - */ - iput(root_inode); + iput(inode); fail_free: kfree(sbi); -fail_unlock: +fail: return NULL; } @@ -221,95 +177,64 @@ static int devpts_statfs(struct super_block *sb, struct statfs *buf) { buf->f_type = DEVPTS_SUPER_MAGIC; buf->f_bsize = 1024; - buf->f_bfree = 0; - buf->f_bavail = 0; - buf->f_ffree = 0; buf->f_namelen = NAME_MAX; return 0; } -static void devpts_read_inode(struct inode *inode) -{ - ino_t ino = inode->i_ino; - struct devpts_sb_info *sbi = SBI(inode->i_sb); - - inode->i_mode = 0; - inode->i_nlink = 0; - 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_uid = inode->i_gid = 0; - - if ( ino == 1 ) { - inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR; - inode->i_op = &devpts_root_inode_operations; - inode->i_fop = &devpts_root_operations; - inode->i_nlink = 2; - return; - } - - ino -= 2; - if ( ino >= sbi->max_ptys ) - return; /* Bogus */ - - /* Gets filled in by devpts_pty_new() */ - init_special_inode(inode,S_IFCHR,0); - - return; -} - -static DECLARE_FSTYPE(devpts_fs_type, "devpts", devpts_read_super, 0); +static DECLARE_FSTYPE(devpts_fs_type, "devpts", devpts_read_super, FS_SINGLE); void devpts_pty_new(int number, kdev_t device) { - struct super_block *sb; - struct devpts_sb_info *sbi; + struct super_block *sb = devpts_mnt->mnt_sb; + struct devpts_sb_info *sbi = SBI(sb); struct inode *inode; - for ( sb = mounts ; sb ; sb = sbi->next ) { - sbi = SBI(sb); - - if ( sbi->inodes[number] ) { - continue; /* Already registered, this does happen */ - } + if ( sbi->inodes[number] ) + return; /* Already registered, this does happen */ - /* Yes, this looks backwards, but it is correct */ - inode = iget(sb, number+2); - if ( inode ) { - inode->i_uid = sbi->setuid ? sbi->uid : current->fsuid; - inode->i_gid = sbi->setgid ? sbi->gid : current->fsgid; - inode->i_mode = sbi->mode | S_IFCHR; - inode->i_rdev = device; - inode->i_nlink++; - sbi->inodes[number] = inode; - } + inode = get_empty_inode(); + if (!inode) + return; + inode->i_sb = sb; + inode->i_dev = sb->s_dev; + inode->i_ino = number+2; + inode->i_blocks = 0; + inode->i_blksize = 1024; + inode->i_uid = sbi->setuid ? sbi->uid : current->fsuid; + inode->i_gid = sbi->setgid ? sbi->gid : current->fsgid; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + init_special_inode(inode, S_IFCHR|sbi->mode, kdev_t_to_nr(device)); + + if ( sbi->inodes[number] ) { + iput(inode); + return; } + sbi->inodes[number] = inode; } void devpts_pty_kill(int number) { - struct super_block *sb; - struct devpts_sb_info *sbi; - struct inode *inode; - - for ( sb = mounts ; sb ; sb = sbi->next ) { - sbi = SBI(sb); - - inode = sbi->inodes[number]; + struct super_block *sb = devpts_mnt->mnt_sb; + struct devpts_sb_info *sbi = SBI(sb); + struct inode *inode = sbi->inodes[number]; - if ( inode ) { - sbi->inodes[number] = NULL; - inode->i_nlink--; - iput(inode); - } + if ( inode ) { + sbi->inodes[number] = NULL; + inode->i_nlink--; + iput(inode); } } int __init init_devpts_fs(void) { - return register_filesystem(&devpts_fs_type); - + int err = register_filesystem(&devpts_fs_type); + if (!err) { + devpts_mnt = kern_mount(&devpts_fs_type); + err = PTR_ERR(devpts_mnt); + if (!IS_ERR(devpts_mnt)) + err = 0; + } + return err; } #ifdef MODULE @@ -329,6 +254,7 @@ void cleanup_module(void) devpts_upcall_new = NULL; devpts_upcall_kill = NULL; unregister_filesystem(&devpts_fs_type); + kern_umount(devpts_mnt); } #endif |