diff options
Diffstat (limited to 'fs/libfs.c')
-rw-r--r-- | fs/libfs.c | 83 |
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 | ||
138 | int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir) | 139 | int 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 | ||