aboutsummaryrefslogtreecommitdiffstats
path: root/fs/libfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/libfs.c')
-rw-r--r--fs/libfs.c83
1 files changed, 32 insertions, 51 deletions
diff --git a/fs/libfs.c b/fs/libfs.c
index 916da8c4158b..3a3a9b53bf5a 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -61,7 +61,8 @@ struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, unsigned
61 61
62 if (dentry->d_name.len > NAME_MAX) 62 if (dentry->d_name.len > NAME_MAX)
63 return ERR_PTR(-ENAMETOOLONG); 63 return ERR_PTR(-ENAMETOOLONG);
64 d_set_d_op(dentry, &simple_dentry_operations); 64 if (!dentry->d_sb->s_d_op)
65 d_set_d_op(dentry, &simple_dentry_operations);
65 d_add(dentry, NULL); 66 d_add(dentry, NULL);
66 return NULL; 67 return NULL;
67} 68}
@@ -135,60 +136,40 @@ static inline unsigned char dt_type(struct inode *inode)
135 * both impossible due to the lock on directory. 136 * both impossible due to the lock on directory.
136 */ 137 */
137 138
138int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir) 139int dcache_readdir(struct file *file, struct dir_context *ctx)
139{ 140{
140 struct dentry *dentry = filp->f_path.dentry; 141 struct dentry *dentry = file->f_path.dentry;
141 struct dentry *cursor = filp->private_data; 142 struct dentry *cursor = file->private_data;
142 struct list_head *p, *q = &cursor->d_u.d_child; 143 struct list_head *p, *q = &cursor->d_u.d_child;
143 ino_t ino;
144 int i = filp->f_pos;
145 144
146 switch (i) { 145 if (!dir_emit_dots(file, ctx))
147 case 0: 146 return 0;
148 ino = dentry->d_inode->i_ino; 147 spin_lock(&dentry->d_lock);
149 if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0) 148 if (ctx->pos == 2)
150 break; 149 list_move(q, &dentry->d_subdirs);
151 filp->f_pos++; 150
152 i++; 151 for (p = q->next; p != &dentry->d_subdirs; p = p->next) {
153 /* fallthrough */ 152 struct dentry *next = list_entry(p, struct dentry, d_u.d_child);
154 case 1: 153 spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED);
155 ino = parent_ino(dentry); 154 if (!simple_positive(next)) {
156 if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0) 155 spin_unlock(&next->d_lock);
157 break; 156 continue;
158 filp->f_pos++; 157 }
159 i++;
160 /* fallthrough */
161 default:
162 spin_lock(&dentry->d_lock);
163 if (filp->f_pos == 2)
164 list_move(q, &dentry->d_subdirs);
165
166 for (p=q->next; p != &dentry->d_subdirs; p=p->next) {
167 struct dentry *next;
168 next = list_entry(p, struct dentry, d_u.d_child);
169 spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED);
170 if (!simple_positive(next)) {
171 spin_unlock(&next->d_lock);
172 continue;
173 }
174 158
175 spin_unlock(&next->d_lock); 159 spin_unlock(&next->d_lock);
176 spin_unlock(&dentry->d_lock); 160 spin_unlock(&dentry->d_lock);
177 if (filldir(dirent, next->d_name.name, 161 if (!dir_emit(ctx, next->d_name.name, next->d_name.len,
178 next->d_name.len, filp->f_pos, 162 next->d_inode->i_ino, dt_type(next->d_inode)))
179 next->d_inode->i_ino, 163 return 0;
180 dt_type(next->d_inode)) < 0) 164 spin_lock(&dentry->d_lock);
181 return 0; 165 spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED);
182 spin_lock(&dentry->d_lock); 166 /* next is still alive */
183 spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED); 167 list_move(q, p);
184 /* next is still alive */ 168 spin_unlock(&next->d_lock);
185 list_move(q, p); 169 p = q;
186 spin_unlock(&next->d_lock); 170 ctx->pos++;
187 p = q;
188 filp->f_pos++;
189 }
190 spin_unlock(&dentry->d_lock);
191 } 171 }
172 spin_unlock(&dentry->d_lock);
192 return 0; 173 return 0;
193} 174}
194 175
@@ -202,7 +183,7 @@ const struct file_operations simple_dir_operations = {
202 .release = dcache_dir_close, 183 .release = dcache_dir_close,
203 .llseek = dcache_dir_lseek, 184 .llseek = dcache_dir_lseek,
204 .read = generic_read_dir, 185 .read = generic_read_dir,
205 .readdir = dcache_readdir, 186 .iterate = dcache_readdir,
206 .fsync = noop_fsync, 187 .fsync = noop_fsync,
207}; 188};
208 189