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 | ||
