diff options
Diffstat (limited to 'fs/libfs.c')
-rw-r--r-- | fs/libfs.c | 63 |
1 files changed, 39 insertions, 24 deletions
diff --git a/fs/libfs.c b/fs/libfs.c index a3accdf528ad..889311e3d06b 100644 --- a/fs/libfs.c +++ b/fs/libfs.c | |||
@@ -16,6 +16,11 @@ | |||
16 | 16 | ||
17 | #include <asm/uaccess.h> | 17 | #include <asm/uaccess.h> |
18 | 18 | ||
19 | static inline int simple_positive(struct dentry *dentry) | ||
20 | { | ||
21 | return dentry->d_inode && !d_unhashed(dentry); | ||
22 | } | ||
23 | |||
19 | int simple_getattr(struct vfsmount *mnt, struct dentry *dentry, | 24 | int simple_getattr(struct vfsmount *mnt, struct dentry *dentry, |
20 | struct kstat *stat) | 25 | struct kstat *stat) |
21 | { | 26 | { |
@@ -37,7 +42,7 @@ int simple_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
37 | * Retaining negative dentries for an in-memory filesystem just wastes | 42 | * Retaining negative dentries for an in-memory filesystem just wastes |
38 | * memory and lookup time: arrange for them to be deleted immediately. | 43 | * memory and lookup time: arrange for them to be deleted immediately. |
39 | */ | 44 | */ |
40 | static int simple_delete_dentry(struct dentry *dentry) | 45 | static int simple_delete_dentry(const struct dentry *dentry) |
41 | { | 46 | { |
42 | return 1; | 47 | return 1; |
43 | } | 48 | } |
@@ -54,7 +59,7 @@ struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, struct na | |||
54 | 59 | ||
55 | if (dentry->d_name.len > NAME_MAX) | 60 | if (dentry->d_name.len > NAME_MAX) |
56 | return ERR_PTR(-ENAMETOOLONG); | 61 | return ERR_PTR(-ENAMETOOLONG); |
57 | dentry->d_op = &simple_dentry_operations; | 62 | d_set_d_op(dentry, &simple_dentry_operations); |
58 | d_add(dentry, NULL); | 63 | d_add(dentry, NULL); |
59 | return NULL; | 64 | return NULL; |
60 | } | 65 | } |
@@ -76,7 +81,8 @@ int dcache_dir_close(struct inode *inode, struct file *file) | |||
76 | 81 | ||
77 | 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) |
78 | { | 83 | { |
79 | 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); | ||
80 | switch (origin) { | 86 | switch (origin) { |
81 | case 1: | 87 | case 1: |
82 | offset += file->f_pos; | 88 | offset += file->f_pos; |
@@ -84,7 +90,7 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin) | |||
84 | if (offset >= 0) | 90 | if (offset >= 0) |
85 | break; | 91 | break; |
86 | default: | 92 | default: |
87 | mutex_unlock(&file->f_path.dentry->d_inode->i_mutex); | 93 | mutex_unlock(&dentry->d_inode->i_mutex); |
88 | return -EINVAL; | 94 | return -EINVAL; |
89 | } | 95 | } |
90 | if (offset != file->f_pos) { | 96 | if (offset != file->f_pos) { |
@@ -94,21 +100,24 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin) | |||
94 | struct dentry *cursor = file->private_data; | 100 | struct dentry *cursor = file->private_data; |
95 | loff_t n = file->f_pos - 2; | 101 | loff_t n = file->f_pos - 2; |
96 | 102 | ||
97 | spin_lock(&dcache_lock); | 103 | spin_lock(&dentry->d_lock); |
104 | /* d_lock not required for cursor */ | ||
98 | list_del(&cursor->d_u.d_child); | 105 | list_del(&cursor->d_u.d_child); |
99 | p = file->f_path.dentry->d_subdirs.next; | 106 | p = dentry->d_subdirs.next; |
100 | while (n && p != &file->f_path.dentry->d_subdirs) { | 107 | while (n && p != &dentry->d_subdirs) { |
101 | struct dentry *next; | 108 | struct dentry *next; |
102 | next = list_entry(p, struct dentry, d_u.d_child); | 109 | next = list_entry(p, struct dentry, d_u.d_child); |
103 | if (!d_unhashed(next) && next->d_inode) | 110 | spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED); |
111 | if (simple_positive(next)) | ||
104 | n--; | 112 | n--; |
113 | spin_unlock(&next->d_lock); | ||
105 | p = p->next; | 114 | p = p->next; |
106 | } | 115 | } |
107 | list_add_tail(&cursor->d_u.d_child, p); | 116 | list_add_tail(&cursor->d_u.d_child, p); |
108 | spin_unlock(&dcache_lock); | 117 | spin_unlock(&dentry->d_lock); |
109 | } | 118 | } |
110 | } | 119 | } |
111 | mutex_unlock(&file->f_path.dentry->d_inode->i_mutex); | 120 | mutex_unlock(&dentry->d_inode->i_mutex); |
112 | return offset; | 121 | return offset; |
113 | } | 122 | } |
114 | 123 | ||
@@ -148,29 +157,35 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
148 | i++; | 157 | i++; |
149 | /* fallthrough */ | 158 | /* fallthrough */ |
150 | default: | 159 | default: |
151 | spin_lock(&dcache_lock); | 160 | spin_lock(&dentry->d_lock); |
152 | if (filp->f_pos == 2) | 161 | if (filp->f_pos == 2) |
153 | list_move(q, &dentry->d_subdirs); | 162 | list_move(q, &dentry->d_subdirs); |
154 | 163 | ||
155 | for (p=q->next; p != &dentry->d_subdirs; p=p->next) { | 164 | for (p=q->next; p != &dentry->d_subdirs; p=p->next) { |
156 | struct dentry *next; | 165 | struct dentry *next; |
157 | next = list_entry(p, struct dentry, d_u.d_child); | 166 | next = list_entry(p, struct dentry, d_u.d_child); |
158 | if (d_unhashed(next) || !next->d_inode) | 167 | spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED); |
168 | if (!simple_positive(next)) { | ||
169 | spin_unlock(&next->d_lock); | ||
159 | continue; | 170 | continue; |
171 | } | ||
160 | 172 | ||
161 | spin_unlock(&dcache_lock); | 173 | spin_unlock(&next->d_lock); |
174 | spin_unlock(&dentry->d_lock); | ||
162 | if (filldir(dirent, next->d_name.name, | 175 | if (filldir(dirent, next->d_name.name, |
163 | next->d_name.len, filp->f_pos, | 176 | next->d_name.len, filp->f_pos, |
164 | next->d_inode->i_ino, | 177 | next->d_inode->i_ino, |
165 | dt_type(next->d_inode)) < 0) | 178 | dt_type(next->d_inode)) < 0) |
166 | return 0; | 179 | return 0; |
167 | spin_lock(&dcache_lock); | 180 | spin_lock(&dentry->d_lock); |
181 | spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED); | ||
168 | /* next is still alive */ | 182 | /* next is still alive */ |
169 | list_move(q, p); | 183 | list_move(q, p); |
184 | spin_unlock(&next->d_lock); | ||
170 | p = q; | 185 | p = q; |
171 | filp->f_pos++; | 186 | filp->f_pos++; |
172 | } | 187 | } |
173 | spin_unlock(&dcache_lock); | 188 | spin_unlock(&dentry->d_lock); |
174 | } | 189 | } |
175 | return 0; | 190 | return 0; |
176 | } | 191 | } |
@@ -259,23 +274,23 @@ int simple_link(struct dentry *old_dentry, struct inode *dir, struct dentry *den | |||
259 | return 0; | 274 | return 0; |
260 | } | 275 | } |
261 | 276 | ||
262 | static inline int simple_positive(struct dentry *dentry) | ||
263 | { | ||
264 | return dentry->d_inode && !d_unhashed(dentry); | ||
265 | } | ||
266 | |||
267 | int simple_empty(struct dentry *dentry) | 277 | int simple_empty(struct dentry *dentry) |
268 | { | 278 | { |
269 | struct dentry *child; | 279 | struct dentry *child; |
270 | int ret = 0; | 280 | int ret = 0; |
271 | 281 | ||
272 | spin_lock(&dcache_lock); | 282 | spin_lock(&dentry->d_lock); |
273 | list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) | 283 | list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) { |
274 | if (simple_positive(child)) | 284 | spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED); |
285 | if (simple_positive(child)) { | ||
286 | spin_unlock(&child->d_lock); | ||
275 | goto out; | 287 | goto out; |
288 | } | ||
289 | spin_unlock(&child->d_lock); | ||
290 | } | ||
276 | ret = 1; | 291 | ret = 1; |
277 | out: | 292 | out: |
278 | spin_unlock(&dcache_lock); | 293 | spin_unlock(&dentry->d_lock); |
279 | return ret; | 294 | return ret; |
280 | } | 295 | } |
281 | 296 | ||