diff options
Diffstat (limited to 'fs/proc/base.c')
-rw-r--r-- | fs/proc/base.c | 73 |
1 files changed, 27 insertions, 46 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index 0c9de19a1633..f71559784bfb 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -80,6 +80,7 @@ | |||
80 | #include <linux/oom.h> | 80 | #include <linux/oom.h> |
81 | #include <linux/elf.h> | 81 | #include <linux/elf.h> |
82 | #include <linux/pid_namespace.h> | 82 | #include <linux/pid_namespace.h> |
83 | #include <linux/fs_struct.h> | ||
83 | #include "internal.h" | 84 | #include "internal.h" |
84 | 85 | ||
85 | /* NOTE: | 86 | /* NOTE: |
@@ -146,15 +147,22 @@ static unsigned int pid_entry_count_dirs(const struct pid_entry *entries, | |||
146 | return count; | 147 | return count; |
147 | } | 148 | } |
148 | 149 | ||
149 | static struct fs_struct *get_fs_struct(struct task_struct *task) | 150 | static int get_fs_path(struct task_struct *task, struct path *path, bool root) |
150 | { | 151 | { |
151 | struct fs_struct *fs; | 152 | struct fs_struct *fs; |
153 | int result = -ENOENT; | ||
154 | |||
152 | task_lock(task); | 155 | task_lock(task); |
153 | fs = task->fs; | 156 | fs = task->fs; |
154 | if(fs) | 157 | if (fs) { |
155 | atomic_inc(&fs->count); | 158 | read_lock(&fs->lock); |
159 | *path = root ? fs->root : fs->pwd; | ||
160 | path_get(path); | ||
161 | read_unlock(&fs->lock); | ||
162 | result = 0; | ||
163 | } | ||
156 | task_unlock(task); | 164 | task_unlock(task); |
157 | return fs; | 165 | return result; |
158 | } | 166 | } |
159 | 167 | ||
160 | static int get_nr_threads(struct task_struct *tsk) | 168 | static int get_nr_threads(struct task_struct *tsk) |
@@ -172,42 +180,24 @@ static int get_nr_threads(struct task_struct *tsk) | |||
172 | static int proc_cwd_link(struct inode *inode, struct path *path) | 180 | static int proc_cwd_link(struct inode *inode, struct path *path) |
173 | { | 181 | { |
174 | struct task_struct *task = get_proc_task(inode); | 182 | struct task_struct *task = get_proc_task(inode); |
175 | struct fs_struct *fs = NULL; | ||
176 | int result = -ENOENT; | 183 | int result = -ENOENT; |
177 | 184 | ||
178 | if (task) { | 185 | if (task) { |
179 | fs = get_fs_struct(task); | 186 | result = get_fs_path(task, path, 0); |
180 | put_task_struct(task); | 187 | put_task_struct(task); |
181 | } | 188 | } |
182 | if (fs) { | ||
183 | read_lock(&fs->lock); | ||
184 | *path = fs->pwd; | ||
185 | path_get(&fs->pwd); | ||
186 | read_unlock(&fs->lock); | ||
187 | result = 0; | ||
188 | put_fs_struct(fs); | ||
189 | } | ||
190 | return result; | 189 | return result; |
191 | } | 190 | } |
192 | 191 | ||
193 | static int proc_root_link(struct inode *inode, struct path *path) | 192 | static int proc_root_link(struct inode *inode, struct path *path) |
194 | { | 193 | { |
195 | struct task_struct *task = get_proc_task(inode); | 194 | struct task_struct *task = get_proc_task(inode); |
196 | struct fs_struct *fs = NULL; | ||
197 | int result = -ENOENT; | 195 | int result = -ENOENT; |
198 | 196 | ||
199 | if (task) { | 197 | if (task) { |
200 | fs = get_fs_struct(task); | 198 | result = get_fs_path(task, path, 1); |
201 | put_task_struct(task); | 199 | put_task_struct(task); |
202 | } | 200 | } |
203 | if (fs) { | ||
204 | read_lock(&fs->lock); | ||
205 | *path = fs->root; | ||
206 | path_get(&fs->root); | ||
207 | read_unlock(&fs->lock); | ||
208 | result = 0; | ||
209 | put_fs_struct(fs); | ||
210 | } | ||
211 | return result; | 201 | return result; |
212 | } | 202 | } |
213 | 203 | ||
@@ -596,7 +586,6 @@ static int mounts_open_common(struct inode *inode, struct file *file, | |||
596 | struct task_struct *task = get_proc_task(inode); | 586 | struct task_struct *task = get_proc_task(inode); |
597 | struct nsproxy *nsp; | 587 | struct nsproxy *nsp; |
598 | struct mnt_namespace *ns = NULL; | 588 | struct mnt_namespace *ns = NULL; |
599 | struct fs_struct *fs = NULL; | ||
600 | struct path root; | 589 | struct path root; |
601 | struct proc_mounts *p; | 590 | struct proc_mounts *p; |
602 | int ret = -EINVAL; | 591 | int ret = -EINVAL; |
@@ -610,22 +599,16 @@ static int mounts_open_common(struct inode *inode, struct file *file, | |||
610 | get_mnt_ns(ns); | 599 | get_mnt_ns(ns); |
611 | } | 600 | } |
612 | rcu_read_unlock(); | 601 | rcu_read_unlock(); |
613 | if (ns) | 602 | if (ns && get_fs_path(task, &root, 1) == 0) |
614 | fs = get_fs_struct(task); | 603 | ret = 0; |
615 | put_task_struct(task); | 604 | put_task_struct(task); |
616 | } | 605 | } |
617 | 606 | ||
618 | if (!ns) | 607 | if (!ns) |
619 | goto err; | 608 | goto err; |
620 | if (!fs) | 609 | if (ret) |
621 | goto err_put_ns; | 610 | goto err_put_ns; |
622 | 611 | ||
623 | read_lock(&fs->lock); | ||
624 | root = fs->root; | ||
625 | path_get(&root); | ||
626 | read_unlock(&fs->lock); | ||
627 | put_fs_struct(fs); | ||
628 | |||
629 | ret = -ENOMEM; | 612 | ret = -ENOMEM; |
630 | p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL); | 613 | p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL); |
631 | if (!p) | 614 | if (!p) |
@@ -1545,7 +1528,7 @@ static int pid_delete_dentry(struct dentry * dentry) | |||
1545 | return !proc_pid(dentry->d_inode)->tasks[PIDTYPE_PID].first; | 1528 | return !proc_pid(dentry->d_inode)->tasks[PIDTYPE_PID].first; |
1546 | } | 1529 | } |
1547 | 1530 | ||
1548 | static struct dentry_operations pid_dentry_operations = | 1531 | static const struct dentry_operations pid_dentry_operations = |
1549 | { | 1532 | { |
1550 | .d_revalidate = pid_revalidate, | 1533 | .d_revalidate = pid_revalidate, |
1551 | .d_delete = pid_delete_dentry, | 1534 | .d_delete = pid_delete_dentry, |
@@ -1717,7 +1700,7 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
1717 | return 0; | 1700 | return 0; |
1718 | } | 1701 | } |
1719 | 1702 | ||
1720 | static struct dentry_operations tid_fd_dentry_operations = | 1703 | static const struct dentry_operations tid_fd_dentry_operations = |
1721 | { | 1704 | { |
1722 | .d_revalidate = tid_fd_revalidate, | 1705 | .d_revalidate = tid_fd_revalidate, |
1723 | .d_delete = pid_delete_dentry, | 1706 | .d_delete = pid_delete_dentry, |
@@ -2339,7 +2322,7 @@ static int proc_base_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
2339 | return 0; | 2322 | return 0; |
2340 | } | 2323 | } |
2341 | 2324 | ||
2342 | static struct dentry_operations proc_base_dentry_operations = | 2325 | static const struct dentry_operations proc_base_dentry_operations = |
2343 | { | 2326 | { |
2344 | .d_revalidate = proc_base_revalidate, | 2327 | .d_revalidate = proc_base_revalidate, |
2345 | .d_delete = pid_delete_dentry, | 2328 | .d_delete = pid_delete_dentry, |
@@ -3066,7 +3049,6 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi | |||
3066 | int retval = -ENOENT; | 3049 | int retval = -ENOENT; |
3067 | ino_t ino; | 3050 | ino_t ino; |
3068 | int tid; | 3051 | int tid; |
3069 | unsigned long pos = filp->f_pos; /* avoiding "long long" filp->f_pos */ | ||
3070 | struct pid_namespace *ns; | 3052 | struct pid_namespace *ns; |
3071 | 3053 | ||
3072 | task = get_proc_task(inode); | 3054 | task = get_proc_task(inode); |
@@ -3083,18 +3065,18 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi | |||
3083 | goto out_no_task; | 3065 | goto out_no_task; |
3084 | retval = 0; | 3066 | retval = 0; |
3085 | 3067 | ||
3086 | switch (pos) { | 3068 | switch ((unsigned long)filp->f_pos) { |
3087 | case 0: | 3069 | case 0: |
3088 | ino = inode->i_ino; | 3070 | ino = inode->i_ino; |
3089 | if (filldir(dirent, ".", 1, pos, ino, DT_DIR) < 0) | 3071 | if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) < 0) |
3090 | goto out; | 3072 | goto out; |
3091 | pos++; | 3073 | filp->f_pos++; |
3092 | /* fall through */ | 3074 | /* fall through */ |
3093 | case 1: | 3075 | case 1: |
3094 | ino = parent_ino(dentry); | 3076 | ino = parent_ino(dentry); |
3095 | if (filldir(dirent, "..", 2, pos, ino, DT_DIR) < 0) | 3077 | if (filldir(dirent, "..", 2, filp->f_pos, ino, DT_DIR) < 0) |
3096 | goto out; | 3078 | goto out; |
3097 | pos++; | 3079 | filp->f_pos++; |
3098 | /* fall through */ | 3080 | /* fall through */ |
3099 | } | 3081 | } |
3100 | 3082 | ||
@@ -3104,9 +3086,9 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi | |||
3104 | ns = filp->f_dentry->d_sb->s_fs_info; | 3086 | ns = filp->f_dentry->d_sb->s_fs_info; |
3105 | tid = (int)filp->f_version; | 3087 | tid = (int)filp->f_version; |
3106 | filp->f_version = 0; | 3088 | filp->f_version = 0; |
3107 | for (task = first_tid(leader, tid, pos - 2, ns); | 3089 | for (task = first_tid(leader, tid, filp->f_pos - 2, ns); |
3108 | task; | 3090 | task; |
3109 | task = next_tid(task), pos++) { | 3091 | task = next_tid(task), filp->f_pos++) { |
3110 | tid = task_pid_nr_ns(task, ns); | 3092 | tid = task_pid_nr_ns(task, ns); |
3111 | if (proc_task_fill_cache(filp, dirent, filldir, task, tid) < 0) { | 3093 | if (proc_task_fill_cache(filp, dirent, filldir, task, tid) < 0) { |
3112 | /* returning this tgid failed, save it as the first | 3094 | /* returning this tgid failed, save it as the first |
@@ -3117,7 +3099,6 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi | |||
3117 | } | 3099 | } |
3118 | } | 3100 | } |
3119 | out: | 3101 | out: |
3120 | filp->f_pos = pos; | ||
3121 | put_task_struct(leader); | 3102 | put_task_struct(leader); |
3122 | out_no_task: | 3103 | out_no_task: |
3123 | return retval; | 3104 | return retval; |