diff options
Diffstat (limited to 'fs/libfs.c')
-rw-r--r-- | fs/libfs.c | 24 |
1 files changed, 18 insertions, 6 deletions
diff --git a/fs/libfs.c b/fs/libfs.c index 433e7139c23a..cc4794914b52 100644 --- a/fs/libfs.c +++ b/fs/libfs.c | |||
@@ -81,7 +81,8 @@ int dcache_dir_close(struct inode *inode, struct file *file) | |||
81 | 81 | ||
82 | loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin) | 82 | loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin) |
83 | { | 83 | { |
84 | mutex_lock(&file->f_path.dentry->d_inode->i_mutex); | 84 | struct dentry *dentry = file->f_path.dentry; |
85 | mutex_lock(&dentry->d_inode->i_mutex); | ||
85 | switch (origin) { | 86 | switch (origin) { |
86 | case 1: | 87 | case 1: |
87 | offset += file->f_pos; | 88 | offset += file->f_pos; |
@@ -89,7 +90,7 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin) | |||
89 | if (offset >= 0) | 90 | if (offset >= 0) |
90 | break; | 91 | break; |
91 | default: | 92 | default: |
92 | mutex_unlock(&file->f_path.dentry->d_inode->i_mutex); | 93 | mutex_unlock(&dentry->d_inode->i_mutex); |
93 | return -EINVAL; | 94 | return -EINVAL; |
94 | } | 95 | } |
95 | if (offset != file->f_pos) { | 96 | if (offset != file->f_pos) { |
@@ -100,22 +101,25 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin) | |||
100 | loff_t n = file->f_pos - 2; | 101 | loff_t n = file->f_pos - 2; |
101 | 102 | ||
102 | spin_lock(&dcache_lock); | 103 | spin_lock(&dcache_lock); |
104 | spin_lock(&dentry->d_lock); | ||
105 | /* d_lock not required for cursor */ | ||
103 | list_del(&cursor->d_u.d_child); | 106 | list_del(&cursor->d_u.d_child); |
104 | p = file->f_path.dentry->d_subdirs.next; | 107 | p = dentry->d_subdirs.next; |
105 | while (n && p != &file->f_path.dentry->d_subdirs) { | 108 | while (n && p != &dentry->d_subdirs) { |
106 | struct dentry *next; | 109 | struct dentry *next; |
107 | next = list_entry(p, struct dentry, d_u.d_child); | 110 | next = list_entry(p, struct dentry, d_u.d_child); |
108 | spin_lock(&next->d_lock); | 111 | spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED); |
109 | if (simple_positive(next)) | 112 | if (simple_positive(next)) |
110 | n--; | 113 | n--; |
111 | spin_unlock(&next->d_lock); | 114 | spin_unlock(&next->d_lock); |
112 | p = p->next; | 115 | p = p->next; |
113 | } | 116 | } |
114 | list_add_tail(&cursor->d_u.d_child, p); | 117 | list_add_tail(&cursor->d_u.d_child, p); |
118 | spin_unlock(&dentry->d_lock); | ||
115 | spin_unlock(&dcache_lock); | 119 | spin_unlock(&dcache_lock); |
116 | } | 120 | } |
117 | } | 121 | } |
118 | mutex_unlock(&file->f_path.dentry->d_inode->i_mutex); | 122 | mutex_unlock(&dentry->d_inode->i_mutex); |
119 | return offset; | 123 | return offset; |
120 | } | 124 | } |
121 | 125 | ||
@@ -156,6 +160,7 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
156 | /* fallthrough */ | 160 | /* fallthrough */ |
157 | default: | 161 | default: |
158 | spin_lock(&dcache_lock); | 162 | spin_lock(&dcache_lock); |
163 | spin_lock(&dentry->d_lock); | ||
159 | if (filp->f_pos == 2) | 164 | if (filp->f_pos == 2) |
160 | list_move(q, &dentry->d_subdirs); | 165 | list_move(q, &dentry->d_subdirs); |
161 | 166 | ||
@@ -169,6 +174,7 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
169 | } | 174 | } |
170 | 175 | ||
171 | spin_unlock(&next->d_lock); | 176 | spin_unlock(&next->d_lock); |
177 | spin_unlock(&dentry->d_lock); | ||
172 | spin_unlock(&dcache_lock); | 178 | spin_unlock(&dcache_lock); |
173 | if (filldir(dirent, next->d_name.name, | 179 | if (filldir(dirent, next->d_name.name, |
174 | next->d_name.len, filp->f_pos, | 180 | next->d_name.len, filp->f_pos, |
@@ -176,11 +182,15 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
176 | dt_type(next->d_inode)) < 0) | 182 | dt_type(next->d_inode)) < 0) |
177 | return 0; | 183 | return 0; |
178 | spin_lock(&dcache_lock); | 184 | spin_lock(&dcache_lock); |
185 | spin_lock(&dentry->d_lock); | ||
186 | spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED); | ||
179 | /* next is still alive */ | 187 | /* next is still alive */ |
180 | list_move(q, p); | 188 | list_move(q, p); |
189 | spin_unlock(&next->d_lock); | ||
181 | p = q; | 190 | p = q; |
182 | filp->f_pos++; | 191 | filp->f_pos++; |
183 | } | 192 | } |
193 | spin_unlock(&dentry->d_lock); | ||
184 | spin_unlock(&dcache_lock); | 194 | spin_unlock(&dcache_lock); |
185 | } | 195 | } |
186 | return 0; | 196 | return 0; |
@@ -276,6 +286,7 @@ int simple_empty(struct dentry *dentry) | |||
276 | int ret = 0; | 286 | int ret = 0; |
277 | 287 | ||
278 | spin_lock(&dcache_lock); | 288 | spin_lock(&dcache_lock); |
289 | spin_lock(&dentry->d_lock); | ||
279 | list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) { | 290 | list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) { |
280 | spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED); | 291 | spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED); |
281 | if (simple_positive(child)) { | 292 | if (simple_positive(child)) { |
@@ -286,6 +297,7 @@ int simple_empty(struct dentry *dentry) | |||
286 | } | 297 | } |
287 | ret = 1; | 298 | ret = 1; |
288 | out: | 299 | out: |
300 | spin_unlock(&dentry->d_lock); | ||
289 | spin_unlock(&dcache_lock); | 301 | spin_unlock(&dcache_lock); |
290 | return ret; | 302 | return ret; |
291 | } | 303 | } |