diff options
Diffstat (limited to 'fs/nfsd/nfs4recover.c')
-rw-r--r-- | fs/nfsd/nfs4recover.c | 71 |
1 files changed, 31 insertions, 40 deletions
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 74f7b67567fd..b11cf8d34280 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c | |||
@@ -182,36 +182,26 @@ out_unlock: | |||
182 | 182 | ||
183 | typedef int (recdir_func)(struct dentry *, struct dentry *); | 183 | typedef int (recdir_func)(struct dentry *, struct dentry *); |
184 | 184 | ||
185 | struct dentry_list { | 185 | struct name_list { |
186 | struct dentry *dentry; | 186 | char name[HEXDIR_LEN]; |
187 | struct list_head list; | 187 | struct list_head list; |
188 | }; | 188 | }; |
189 | 189 | ||
190 | struct dentry_list_arg { | ||
191 | struct list_head dentries; | ||
192 | struct dentry *parent; | ||
193 | }; | ||
194 | |||
195 | static int | 190 | static int |
196 | nfsd4_build_dentrylist(void *arg, const char *name, int namlen, | 191 | nfsd4_build_namelist(void *arg, const char *name, int namlen, |
197 | loff_t offset, u64 ino, unsigned int d_type) | 192 | loff_t offset, u64 ino, unsigned int d_type) |
198 | { | 193 | { |
199 | struct dentry_list_arg *dla = arg; | 194 | struct list_head *names = arg; |
200 | struct list_head *dentries = &dla->dentries; | 195 | struct name_list *entry; |
201 | struct dentry *parent = dla->parent; | ||
202 | struct dentry *dentry; | ||
203 | struct dentry_list *child; | ||
204 | 196 | ||
205 | if (name && isdotent(name, namlen)) | 197 | if (namlen != HEXDIR_LEN - 1) |
206 | return 0; | 198 | return 0; |
207 | dentry = lookup_one_len(name, parent, namlen); | 199 | entry = kmalloc(sizeof(struct name_list), GFP_KERNEL); |
208 | if (IS_ERR(dentry)) | 200 | if (entry == NULL) |
209 | return PTR_ERR(dentry); | ||
210 | child = kmalloc(sizeof(*child), GFP_KERNEL); | ||
211 | if (child == NULL) | ||
212 | return -ENOMEM; | 201 | return -ENOMEM; |
213 | child->dentry = dentry; | 202 | memcpy(entry->name, name, HEXDIR_LEN - 1); |
214 | list_add(&child->list, dentries); | 203 | entry->name[HEXDIR_LEN - 1] = '\0'; |
204 | list_add(&entry->list, names); | ||
215 | return 0; | 205 | return 0; |
216 | } | 206 | } |
217 | 207 | ||
@@ -220,11 +210,9 @@ nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f) | |||
220 | { | 210 | { |
221 | const struct cred *original_cred; | 211 | const struct cred *original_cred; |
222 | struct file *filp; | 212 | struct file *filp; |
223 | struct dentry_list_arg dla = { | 213 | LIST_HEAD(names); |
224 | .parent = dir, | 214 | struct name_list *entry; |
225 | }; | 215 | struct dentry *dentry; |
226 | struct list_head *dentries = &dla.dentries; | ||
227 | struct dentry_list *child; | ||
228 | int status; | 216 | int status; |
229 | 217 | ||
230 | if (!rec_dir_init) | 218 | if (!rec_dir_init) |
@@ -233,31 +221,34 @@ nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f) | |||
233 | status = nfs4_save_creds(&original_cred); | 221 | status = nfs4_save_creds(&original_cred); |
234 | if (status < 0) | 222 | if (status < 0) |
235 | return status; | 223 | return status; |
236 | INIT_LIST_HEAD(dentries); | ||
237 | 224 | ||
238 | filp = dentry_open(dget(dir), mntget(rec_dir.mnt), O_RDONLY, | 225 | filp = dentry_open(dget(dir), mntget(rec_dir.mnt), O_RDONLY, |
239 | current_cred()); | 226 | current_cred()); |
240 | status = PTR_ERR(filp); | 227 | status = PTR_ERR(filp); |
241 | if (IS_ERR(filp)) | 228 | if (IS_ERR(filp)) |
242 | goto out; | 229 | goto out; |
243 | INIT_LIST_HEAD(dentries); | 230 | status = vfs_readdir(filp, nfsd4_build_namelist, &names); |
244 | status = vfs_readdir(filp, nfsd4_build_dentrylist, &dla); | ||
245 | fput(filp); | 231 | fput(filp); |
246 | while (!list_empty(dentries)) { | 232 | while (!list_empty(&names)) { |
247 | child = list_entry(dentries->next, struct dentry_list, list); | 233 | entry = list_entry(names.next, struct name_list, list); |
248 | status = f(dir, child->dentry); | 234 | |
235 | dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1); | ||
236 | if (IS_ERR(dentry)) { | ||
237 | status = PTR_ERR(dentry); | ||
238 | goto out; | ||
239 | } | ||
240 | status = f(dir, dentry); | ||
241 | dput(dentry); | ||
249 | if (status) | 242 | if (status) |
250 | goto out; | 243 | goto out; |
251 | list_del(&child->list); | 244 | list_del(&entry->list); |
252 | dput(child->dentry); | 245 | kfree(entry); |
253 | kfree(child); | ||
254 | } | 246 | } |
255 | out: | 247 | out: |
256 | while (!list_empty(dentries)) { | 248 | while (!list_empty(&names)) { |
257 | child = list_entry(dentries->next, struct dentry_list, list); | 249 | entry = list_entry(names.next, struct name_list, list); |
258 | list_del(&child->list); | 250 | list_del(&entry->list); |
259 | dput(child->dentry); | 251 | kfree(entry); |
260 | kfree(child); | ||
261 | } | 252 | } |
262 | nfs4_reset_creds(original_cred); | 253 | nfs4_reset_creds(original_cred); |
263 | return status; | 254 | return status; |