diff options
Diffstat (limited to 'fs/proc/base.c')
| -rw-r--r-- | fs/proc/base.c | 46 | 
1 files changed, 38 insertions, 8 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index 8dfa36a99c74..93f7e3d971e4 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1885,7 +1885,7 @@ void proc_pid_evict_inode(struct proc_inode *ei)  	put_pid(pid);  } -struct inode *proc_pid_make_inode(struct super_block * sb, +struct inode *proc_pid_make_inode(struct super_block *sb,  				  struct task_struct *task, umode_t mode)  {  	struct inode * inode; @@ -1914,11 +1914,6 @@ struct inode *proc_pid_make_inode(struct super_block * sb,  	/* Let the pid remember us for quick removal */  	ei->pid = pid; -	if (S_ISDIR(mode)) { -		spin_lock(&pid->lock); -		hlist_add_head_rcu(&ei->sibling_inodes, &pid->inodes); -		spin_unlock(&pid->lock); -	}  	task_dump_owner(task, 0, &inode->i_uid, &inode->i_gid);  	security_task_to_inode(task, inode); @@ -1931,6 +1926,39 @@ out_unlock:  	return NULL;  } +/* + * Generating an inode and adding it into @pid->inodes, so that task will + * invalidate inode's dentry before being released. + * + * This helper is used for creating dir-type entries under '/proc' and + * '/proc/<tgid>/task'. Other entries(eg. fd, stat) under '/proc/<tgid>' + * can be released by invalidating '/proc/<tgid>' dentry. + * In theory, dentries under '/proc/<tgid>/task' can also be released by + * invalidating '/proc/<tgid>' dentry, we reserve it to handle single + * thread exiting situation: Any one of threads should invalidate its + * '/proc/<tgid>/task/<pid>' dentry before released. + */ +static struct inode *proc_pid_make_base_inode(struct super_block *sb, +				struct task_struct *task, umode_t mode) +{ +	struct inode *inode; +	struct proc_inode *ei; +	struct pid *pid; + +	inode = proc_pid_make_inode(sb, task, mode); +	if (!inode) +		return NULL; + +	/* Let proc_flush_pid find this directory inode */ +	ei = PROC_I(inode); +	pid = ei->pid; +	spin_lock(&pid->lock); +	hlist_add_head_rcu(&ei->sibling_inodes, &pid->inodes); +	spin_unlock(&pid->lock); + +	return inode; +} +  int pid_getattr(struct user_namespace *mnt_userns, const struct path *path,  		struct kstat *stat, u32 request_mask, unsigned int query_flags)  { @@ -3369,7 +3397,8 @@ static struct dentry *proc_pid_instantiate(struct dentry * dentry,  {  	struct inode *inode; -	inode = proc_pid_make_inode(dentry->d_sb, task, S_IFDIR | S_IRUGO | S_IXUGO); +	inode = proc_pid_make_base_inode(dentry->d_sb, task, +					 S_IFDIR | S_IRUGO | S_IXUGO);  	if (!inode)  		return ERR_PTR(-ENOENT); @@ -3671,7 +3700,8 @@ static struct dentry *proc_task_instantiate(struct dentry *dentry,  	struct task_struct *task, const void *ptr)  {  	struct inode *inode; -	inode = proc_pid_make_inode(dentry->d_sb, task, S_IFDIR | S_IRUGO | S_IXUGO); +	inode = proc_pid_make_base_inode(dentry->d_sb, task, +					 S_IFDIR | S_IRUGO | S_IXUGO);  	if (!inode)  		return ERR_PTR(-ENOENT);  |