diff options
Diffstat (limited to 'fs/proc/base.c')
| -rw-r--r-- | fs/proc/base.c | 121 | 
1 files changed, 41 insertions, 80 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index c7c64272b0fa..74f948a6b621 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -405,11 +405,11 @@ print0:  static int lock_trace(struct task_struct *task)  { -	int err = mutex_lock_killable(&task->signal->cred_guard_mutex); +	int err = mutex_lock_killable(&task->signal->exec_update_mutex);  	if (err)  		return err;  	if (!ptrace_may_access(task, PTRACE_MODE_ATTACH_FSCREDS)) { -		mutex_unlock(&task->signal->cred_guard_mutex); +		mutex_unlock(&task->signal->exec_update_mutex);  		return -EPERM;  	}  	return 0; @@ -417,7 +417,7 @@ static int lock_trace(struct task_struct *task)  static void unlock_trace(struct task_struct *task)  { -	mutex_unlock(&task->signal->cred_guard_mutex); +	mutex_unlock(&task->signal->exec_update_mutex);  }  #ifdef CONFIG_STACKTRACE @@ -1834,11 +1834,25 @@ void task_dump_owner(struct task_struct *task, umode_t mode,  	*rgid = gid;  } +void proc_pid_evict_inode(struct proc_inode *ei) +{ +	struct pid *pid = ei->pid; + +	if (S_ISDIR(ei->vfs_inode.i_mode)) { +		spin_lock(&pid->wait_pidfd.lock); +		hlist_del_init_rcu(&ei->sibling_inodes); +		spin_unlock(&pid->wait_pidfd.lock); +	} + +	put_pid(pid); +} +  struct inode *proc_pid_make_inode(struct super_block * sb,  				  struct task_struct *task, umode_t mode)  {  	struct inode * inode;  	struct proc_inode *ei; +	struct pid *pid;  	/* We need a new inode */ @@ -1856,10 +1870,18 @@ struct inode *proc_pid_make_inode(struct super_block * sb,  	/*  	 * grab the reference to task.  	 */ -	ei->pid = get_task_pid(task, PIDTYPE_PID); -	if (!ei->pid) +	pid = get_task_pid(task, PIDTYPE_PID); +	if (!pid)  		goto out_unlock; +	/* Let the pid remember us for quick removal */ +	ei->pid = pid; +	if (S_ISDIR(mode)) { +		spin_lock(&pid->wait_pidfd.lock); +		hlist_add_head_rcu(&ei->sibling_inodes, &pid->inodes); +		spin_unlock(&pid->wait_pidfd.lock); +	} +  	task_dump_owner(task, 0, &inode->i_uid, &inode->i_gid);  	security_task_to_inode(task, inode); @@ -2861,7 +2883,7 @@ static int do_io_accounting(struct task_struct *task, struct seq_file *m, int wh  	unsigned long flags;  	int result; -	result = mutex_lock_killable(&task->signal->cred_guard_mutex); +	result = mutex_lock_killable(&task->signal->exec_update_mutex);  	if (result)  		return result; @@ -2897,7 +2919,7 @@ static int do_io_accounting(struct task_struct *task, struct seq_file *m, int wh  	result = 0;  out_unlock: -	mutex_unlock(&task->signal->cred_guard_mutex); +	mutex_unlock(&task->signal->exec_update_mutex);  	return result;  } @@ -3230,90 +3252,29 @@ static const struct inode_operations proc_tgid_base_inode_operations = {  	.permission	= proc_pid_permission,  }; -static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid) -{ -	struct dentry *dentry, *leader, *dir; -	char buf[10 + 1]; -	struct qstr name; - -	name.name = buf; -	name.len = snprintf(buf, sizeof(buf), "%u", pid); -	/* no ->d_hash() rejects on procfs */ -	dentry = d_hash_and_lookup(mnt->mnt_root, &name); -	if (dentry) { -		d_invalidate(dentry); -		dput(dentry); -	} - -	if (pid == tgid) -		return; - -	name.name = buf; -	name.len = snprintf(buf, sizeof(buf), "%u", tgid); -	leader = d_hash_and_lookup(mnt->mnt_root, &name); -	if (!leader) -		goto out; - -	name.name = "task"; -	name.len = strlen(name.name); -	dir = d_hash_and_lookup(leader, &name); -	if (!dir) -		goto out_put_leader; - -	name.name = buf; -	name.len = snprintf(buf, sizeof(buf), "%u", pid); -	dentry = d_hash_and_lookup(dir, &name); -	if (dentry) { -		d_invalidate(dentry); -		dput(dentry); -	} - -	dput(dir); -out_put_leader: -	dput(leader); -out: -	return; -} -  /** - * proc_flush_task -  Remove dcache entries for @task from the /proc dcache. - * @task: task that should be flushed. + * proc_flush_pid -  Remove dcache entries for @pid from the /proc dcache. + * @pid: pid that should be flushed.   * - * When flushing dentries from proc, one needs to flush them from global - * proc (proc_mnt) and from all the namespaces' procs this task was seen - * in. This call is supposed to do all of this job. - * - * Looks in the dcache for - * /proc/@pid - * /proc/@tgid/task/@pid - * if either directory is present flushes it and all of it'ts children - * from the dcache. + * This function walks a list of inodes (that belong to any proc + * filesystem) that are attached to the pid and flushes them from + * the dentry cache.   *   * It is safe and reasonable to cache /proc entries for a task until   * that task exits.  After that they just clog up the dcache with   * useless entries, possibly causing useful dcache entries to be - * flushed instead.  This routine is proved to flush those useless - * dcache entries at process exit time. + * flushed instead.  This routine is provided to flush those useless + * dcache entries when a process is reaped.   *   * NOTE: This routine is just an optimization so it does not guarantee - *       that no dcache entries will exist at process exit time it - *       just makes it very unlikely that any will persist. + *       that no dcache entries will exist after a process is reaped + *       it just makes it very unlikely that any will persist.   */ -void proc_flush_task(struct task_struct *task) +void proc_flush_pid(struct pid *pid)  { -	int i; -	struct pid *pid, *tgid; -	struct upid *upid; - -	pid = task_pid(task); -	tgid = task_tgid(task); - -	for (i = 0; i <= pid->level; i++) { -		upid = &pid->numbers[i]; -		proc_flush_task_mnt(upid->ns->proc_mnt, upid->nr, -					tgid->numbers[i].nr); -	} +	proc_invalidate_siblings_dcache(&pid->inodes, &pid->wait_pidfd.lock); +	put_pid(pid);  }  static struct dentry *proc_pid_instantiate(struct dentry * dentry,  |