diff options
-rw-r--r-- | fs/fs_struct.c | 27 |
1 files changed, 15 insertions, 12 deletions
diff --git a/fs/fs_struct.c b/fs/fs_struct.c index 27114b413622..6324c4274959 100644 --- a/fs/fs_struct.c +++ b/fs/fs_struct.c | |||
@@ -26,11 +26,11 @@ void set_fs_root(struct fs_struct *fs, struct path *path) | |||
26 | { | 26 | { |
27 | struct path old_root; | 27 | struct path old_root; |
28 | 28 | ||
29 | path_get_longterm(path); | ||
29 | spin_lock(&fs->lock); | 30 | spin_lock(&fs->lock); |
30 | write_seqcount_begin(&fs->seq); | 31 | write_seqcount_begin(&fs->seq); |
31 | old_root = fs->root; | 32 | old_root = fs->root; |
32 | fs->root = *path; | 33 | fs->root = *path; |
33 | path_get_longterm(path); | ||
34 | write_seqcount_end(&fs->seq); | 34 | write_seqcount_end(&fs->seq); |
35 | spin_unlock(&fs->lock); | 35 | spin_unlock(&fs->lock); |
36 | if (old_root.dentry) | 36 | if (old_root.dentry) |
@@ -45,11 +45,11 @@ void set_fs_pwd(struct fs_struct *fs, struct path *path) | |||
45 | { | 45 | { |
46 | struct path old_pwd; | 46 | struct path old_pwd; |
47 | 47 | ||
48 | path_get_longterm(path); | ||
48 | spin_lock(&fs->lock); | 49 | spin_lock(&fs->lock); |
49 | write_seqcount_begin(&fs->seq); | 50 | write_seqcount_begin(&fs->seq); |
50 | old_pwd = fs->pwd; | 51 | old_pwd = fs->pwd; |
51 | fs->pwd = *path; | 52 | fs->pwd = *path; |
52 | path_get_longterm(path); | ||
53 | write_seqcount_end(&fs->seq); | 53 | write_seqcount_end(&fs->seq); |
54 | spin_unlock(&fs->lock); | 54 | spin_unlock(&fs->lock); |
55 | 55 | ||
@@ -57,6 +57,14 @@ void set_fs_pwd(struct fs_struct *fs, struct path *path) | |||
57 | path_put_longterm(&old_pwd); | 57 | path_put_longterm(&old_pwd); |
58 | } | 58 | } |
59 | 59 | ||
60 | static inline int replace_path(struct path *p, const struct path *old, const struct path *new) | ||
61 | { | ||
62 | if (likely(p->dentry != old->dentry || p->mnt != old->mnt)) | ||
63 | return 0; | ||
64 | *p = *new; | ||
65 | return 1; | ||
66 | } | ||
67 | |||
60 | void chroot_fs_refs(struct path *old_root, struct path *new_root) | 68 | void chroot_fs_refs(struct path *old_root, struct path *new_root) |
61 | { | 69 | { |
62 | struct task_struct *g, *p; | 70 | struct task_struct *g, *p; |
@@ -68,21 +76,16 @@ void chroot_fs_refs(struct path *old_root, struct path *new_root) | |||
68 | task_lock(p); | 76 | task_lock(p); |
69 | fs = p->fs; | 77 | fs = p->fs; |
70 | if (fs) { | 78 | if (fs) { |
79 | int hits = 0; | ||
71 | spin_lock(&fs->lock); | 80 | spin_lock(&fs->lock); |
72 | write_seqcount_begin(&fs->seq); | 81 | write_seqcount_begin(&fs->seq); |
73 | if (fs->root.dentry == old_root->dentry | 82 | hits += replace_path(&fs->root, old_root, new_root); |
74 | && fs->root.mnt == old_root->mnt) { | 83 | hits += replace_path(&fs->pwd, old_root, new_root); |
75 | path_get_longterm(new_root); | 84 | write_seqcount_end(&fs->seq); |
76 | fs->root = *new_root; | 85 | while (hits--) { |
77 | count++; | 86 | count++; |
78 | } | ||
79 | if (fs->pwd.dentry == old_root->dentry | ||
80 | && fs->pwd.mnt == old_root->mnt) { | ||
81 | path_get_longterm(new_root); | 87 | path_get_longterm(new_root); |
82 | fs->pwd = *new_root; | ||
83 | count++; | ||
84 | } | 88 | } |
85 | write_seqcount_end(&fs->seq); | ||
86 | spin_unlock(&fs->lock); | 89 | spin_unlock(&fs->lock); |
87 | } | 90 | } |
88 | task_unlock(p); | 91 | task_unlock(p); |