int devpts_new_index(struct inode *ptmx_inode) { struct super_block *sb = pts_sb_from_inode(ptmx_inode); struct pts_fs_info *fsi = DEVPTS_SB(sb); int index; int ida_ret; retry: if (!ida_pre_get(&fsi->allocated_ptys, GFP_KERNEL)) return -ENOMEM; mutex_lock(&allocated_ptys_lock); if (pty_count >= pty_limit - (fsi->mount_opts.newinstance ? pty_reserve : 0)) { mutex_unlock(&allocated_ptys_lock); return -ENOSPC; } ida_ret = ida_get_new(&fsi->allocated_ptys, &index); if (ida_ret < 0) { mutex_unlock(&allocated_ptys_lock); if (ida_ret == -EAGAIN) goto retry; return -EIO; } if (index >= fsi->mount_opts.max) { ida_remove(&fsi->allocated_ptys, index); mutex_unlock(&allocated_ptys_lock); return -ENOSPC; } pty_count++; mutex_unlock(&allocated_ptys_lock); return index; }
int devpts_new_index(struct inode *ptmx_inode) { struct super_block *sb = pts_sb_from_inode(ptmx_inode); struct pts_fs_info *fsi = DEVPTS_SB(sb); int index; int ida_ret; retry: if (!ida_pre_get(&fsi->allocated_ptys, GFP_KERNEL)) return -ENOMEM; mutex_lock(&allocated_ptys_lock); ida_ret = ida_get_new(&fsi->allocated_ptys, &index); if (ida_ret < 0) { mutex_unlock(&allocated_ptys_lock); if (ida_ret == -EAGAIN) goto retry; return -EIO; } if (index >= pty_limit) { ida_remove(&fsi->allocated_ptys, index); mutex_unlock(&allocated_ptys_lock); return -EIO; } mutex_unlock(&allocated_ptys_lock); return index; }
void devpts_pty_kill(struct tty_struct *tty) { struct inode *inode = tty->driver_data; struct super_block *sb = pts_sb_from_inode(inode); struct dentry *root = sb->s_root; struct dentry *dentry; BUG_ON(inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR)); mutex_lock(&root->d_inode->i_mutex); dentry = d_find_alias(inode); if (IS_ERR(dentry)) goto out; if (dentry) { inode->i_nlink--; d_delete(dentry); dput(dentry); /* d_alloc_name() in devpts_pty_new() */ } dput(dentry); /* d_find_alias above */ out: mutex_unlock(&root->d_inode->i_mutex); }
void devpts_kill_index(struct inode *ptmx_inode, int idx) { struct super_block *sb = pts_sb_from_inode(ptmx_inode); struct pts_fs_info *fsi = DEVPTS_SB(sb); mutex_lock(&allocated_ptys_lock); ida_remove(&fsi->allocated_ptys, idx); mutex_unlock(&allocated_ptys_lock); }
int devpts_pty_new(struct inode *ptmx_inode, struct tty_struct *tty) { int number = tty->index; struct tty_driver *driver = tty->driver; dev_t device = MKDEV(driver->major, driver->minor_start+number); struct dentry *dentry; struct super_block *sb = pts_sb_from_inode(ptmx_inode); struct inode *inode = new_inode(sb); struct dentry *root = sb->s_root; struct pts_fs_info *fsi = DEVPTS_SB(sb); struct pts_mount_opts *opts = &fsi->mount_opts; int ret = 0; char s[12]; BUG_ON(driver->type != TTY_DRIVER_TYPE_PTY); BUG_ON(driver->subtype != PTY_TYPE_SLAVE); if (!inode) return -ENOMEM; inode->i_ino = number + 3; inode->i_uid = opts->setuid ? opts->uid : current_fsuid(); inode->i_gid = opts->setgid ? opts->gid : current_fsgid(); inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; init_special_inode(inode, S_IFCHR|opts->mode, device); inode->i_private = tty; tty->driver_data = inode; sprintf(s, "%d", number); mutex_lock(&root->d_inode->i_mutex); dentry = d_alloc_name(root, s); if (dentry) { d_add(dentry, inode); fsnotify_create(root->d_inode, dentry); } else { iput(inode); ret = -ENOMEM; } mutex_unlock(&root->d_inode->i_mutex); return ret; }
/** * devpts_pty_kill -- remove inode form /dev/pts/ * @inode: inode of the slave to be removed * * This is an inverse operation of devpts_pty_new. */ void devpts_pty_kill(struct inode *inode) { struct super_block *sb = pts_sb_from_inode(inode); struct dentry *root = sb->s_root; struct dentry *dentry; BUG_ON(inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR)); mutex_lock(&root->d_inode->i_mutex); dentry = d_find_alias(inode); drop_nlink(inode); d_delete(dentry); dput(dentry); /* d_alloc_name() in devpts_pty_new() */ dput(dentry); /* d_find_alias above */ mutex_unlock(&root->d_inode->i_mutex); }
void devpts_pty_kill(struct tty_struct *tty) { struct inode *inode = tty->driver_data; struct super_block *sb = pts_sb_from_inode(inode); struct dentry *root = sb->s_root; struct dentry *dentry; BUG_ON(inode->i_rdev == MKDEV(TTYAUX_MAJOR, PTMX_MINOR)); mutex_lock(&root->d_inode->i_mutex); dentry = d_find_alias(inode); drop_nlink(inode); d_delete(dentry); dput(dentry); dput(dentry); mutex_unlock(&root->d_inode->i_mutex); }
/** * devpts_pty_new -- create a new inode in /dev/pts/ * @ptmx_inode: inode of the master * @device: major+minor of the node to be created * @index: used as a name of the node * @priv: what's given back by devpts_get_priv * * The created inode is returned. Remove it from /dev/pts/ by devpts_pty_kill. */ struct inode *devpts_pty_new(struct inode *ptmx_inode, dev_t device, int index, void *priv) { struct dentry *dentry; struct super_block *sb = pts_sb_from_inode(ptmx_inode); struct inode *inode; struct dentry *root = sb->s_root; struct pts_fs_info *fsi = DEVPTS_SB(sb); struct pts_mount_opts *opts = &fsi->mount_opts; char s[12]; inode = new_inode(sb); if (!inode) return ERR_PTR(-ENOMEM); inode->i_ino = index + 3; inode->i_uid = opts->setuid ? opts->uid : current_fsuid(); inode->i_gid = opts->setgid ? opts->gid : current_fsgid(); inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; init_special_inode(inode, S_IFCHR|opts->mode, device); inode->i_private = priv; sprintf(s, "%d", index); mutex_lock(&root->d_inode->i_mutex); dentry = d_alloc_name(root, s); if (dentry) { d_add(dentry, inode); fsnotify_create(root->d_inode, dentry); } else { iput(inode); inode = ERR_PTR(-ENOMEM); } mutex_unlock(&root->d_inode->i_mutex); return inode; }