aboutsummaryrefslogtreecommitdiffstats
path: root/fs/libfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/libfs.c')
-rw-r--r--fs/libfs.c24
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
82loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin) 82loff_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;
288out: 299out:
300 spin_unlock(&dentry->d_lock);
289 spin_unlock(&dcache_lock); 301 spin_unlock(&dcache_lock);
290 return ret; 302 return ret;
291} 303}