nfsd4: don't do lookup within readdir in recovery code
[safe/jmp/linux-2.6] / fs / nfsd / nfs4recover.c
index 74f7b67..b11cf8d 100644 (file)
@@ -182,36 +182,26 @@ out_unlock:
 
 typedef int (recdir_func)(struct dentry *, struct dentry *);
 
-struct dentry_list {
-       struct dentry *dentry;
+struct name_list {
+       char name[HEXDIR_LEN];
        struct list_head list;
 };
 
-struct dentry_list_arg {
-       struct list_head dentries;
-       struct dentry *parent;
-};
-
 static int
-nfsd4_build_dentrylist(void *arg, const char *name, int namlen,
+nfsd4_build_namelist(void *arg, const char *name, int namlen,
                loff_t offset, u64 ino, unsigned int d_type)
 {
-       struct dentry_list_arg *dla = arg;
-       struct list_head *dentries = &dla->dentries;
-       struct dentry *parent = dla->parent;
-       struct dentry *dentry;
-       struct dentry_list *child;
+       struct list_head *names = arg;
+       struct name_list *entry;
 
-       if (name && isdotent(name, namlen))
+       if (namlen != HEXDIR_LEN - 1)
                return 0;
-       dentry = lookup_one_len(name, parent, namlen);
-       if (IS_ERR(dentry))
-               return PTR_ERR(dentry);
-       child = kmalloc(sizeof(*child), GFP_KERNEL);
-       if (child == NULL)
+       entry = kmalloc(sizeof(struct name_list), GFP_KERNEL);
+       if (entry == NULL)
                return -ENOMEM;
-       child->dentry = dentry;
-       list_add(&child->list, dentries);
+       memcpy(entry->name, name, HEXDIR_LEN - 1);
+       entry->name[HEXDIR_LEN - 1] = '\0';
+       list_add(&entry->list, names);
        return 0;
 }
 
@@ -220,11 +210,9 @@ nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f)
 {
        const struct cred *original_cred;
        struct file *filp;
-       struct dentry_list_arg dla = {
-               .parent = dir,
-       };
-       struct list_head *dentries = &dla.dentries;
-       struct dentry_list *child;
+       LIST_HEAD(names);
+       struct name_list *entry;
+       struct dentry *dentry;
        int status;
 
        if (!rec_dir_init)
@@ -233,31 +221,34 @@ nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f)
        status = nfs4_save_creds(&original_cred);
        if (status < 0)
                return status;
-       INIT_LIST_HEAD(dentries);
 
        filp = dentry_open(dget(dir), mntget(rec_dir.mnt), O_RDONLY,
                           current_cred());
        status = PTR_ERR(filp);
        if (IS_ERR(filp))
                goto out;
-       INIT_LIST_HEAD(dentries);
-       status = vfs_readdir(filp, nfsd4_build_dentrylist, &dla);
+       status = vfs_readdir(filp, nfsd4_build_namelist, &names);
        fput(filp);
-       while (!list_empty(dentries)) {
-               child = list_entry(dentries->next, struct dentry_list, list);
-               status = f(dir, child->dentry);
+       while (!list_empty(&names)) {
+               entry = list_entry(names.next, struct name_list, list);
+
+               dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1);
+               if (IS_ERR(dentry)) {
+                       status = PTR_ERR(dentry);
+                       goto out;
+               }
+               status = f(dir, dentry);
+               dput(dentry);
                if (status)
                        goto out;
-               list_del(&child->list);
-               dput(child->dentry);
-               kfree(child);
+               list_del(&entry->list);
+               kfree(entry);
        }
 out:
-       while (!list_empty(dentries)) {
-               child = list_entry(dentries->next, struct dentry_list, list);
-               list_del(&child->list);
-               dput(child->dentry);
-               kfree(child);
+       while (!list_empty(&names)) {
+               entry = list_entry(names.next, struct name_list, list);
+               list_del(&entry->list);
+               kfree(entry);
        }
        nfs4_reset_creds(original_cred);
        return status;