[PATCH] autofs4: use libfs routines for readdir
authorIan Kent <raven@themaw.net>
Mon, 27 Mar 2006 09:14:43 +0000 (01:14 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Mon, 27 Mar 2006 16:44:39 +0000 (08:44 -0800)
Change readdir routines to use the cursor based routines in libfs.c.  This
removes reliance on old readdir code from 2.4 and should improve efficiency of
readdir in autofs4.

Signed-off-by: Ian Kent <raven@themaw.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
fs/autofs4/root.c

index 2c676bd44acdcc910a721b2bf75154fd43b2c450..af9a4c6bbadfdece89b194b5f2801ff099613eda 100644 (file)
@@ -30,7 +30,6 @@ static int autofs4_dir_close(struct inode *inode, struct file *file);
 static int autofs4_dir_readdir(struct file * filp, void * dirent, filldir_t filldir);
 static int autofs4_root_readdir(struct file * filp, void * dirent, filldir_t filldir);
 static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *);
-static int autofs4_dcache_readdir(struct file *, void *, filldir_t);
 
 struct file_operations autofs4_root_operations = {
        .open           = dcache_dir_open,
@@ -82,7 +81,7 @@ static int autofs4_root_readdir(struct file *file, void *dirent,
 
        DPRINTK("needs_reghost = %d", sbi->needs_reghost);
 
-       return autofs4_dcache_readdir(file, dirent, filldir);
+       return dcache_readdir(file, dirent, filldir);
 }
 
 /* Update usage from here to top of tree, so that scan of
@@ -103,75 +102,21 @@ static void autofs4_update_usage(struct vfsmount *mnt, struct dentry *dentry)
        spin_unlock(&dcache_lock);
 }
 
-/*
- * From 2.4 kernel readdir.c
- */
-static int autofs4_dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)
-{
-       int i;
-       struct dentry *dentry = filp->f_dentry;
-
-       i = filp->f_pos;
-       switch (i) {
-               case 0:
-                       if (filldir(dirent, ".", 1, i, dentry->d_inode->i_ino, DT_DIR) < 0)
-                               break;
-                       i++;
-                       filp->f_pos++;
-                       /* fallthrough */
-               case 1:
-                       if (filldir(dirent, "..", 2, i, dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
-                               break;
-                       i++;
-                       filp->f_pos++;
-                       /* fallthrough */
-               default: {
-                       struct list_head *list;
-                       int j = i-2;
-
-                       spin_lock(&dcache_lock);
-                       list = dentry->d_subdirs.next;
-
-                       for (;;) {
-                               if (list == &dentry->d_subdirs) {
-                                       spin_unlock(&dcache_lock);
-                                       return 0;
-                               }
-                               if (!j)
-                                       break;
-                               j--;
-                               list = list->next;
-                       }
-
-                       while(1) {
-                               struct dentry *de = list_entry(list,
-                                               struct dentry, d_u.d_child);
-
-                               if (!d_unhashed(de) && de->d_inode) {
-                                       spin_unlock(&dcache_lock);
-                                       if (filldir(dirent, de->d_name.name, de->d_name.len, filp->f_pos, de->d_inode->i_ino, DT_UNKNOWN) < 0)
-                                               break;
-                                       spin_lock(&dcache_lock);
-                               }
-                               filp->f_pos++;
-                               list = list->next;
-                               if (list != &dentry->d_subdirs)
-                                       continue;
-                               spin_unlock(&dcache_lock);
-                               break;
-                       }
-               }
-       }
-       return 0;
-}
-
 static int autofs4_dir_open(struct inode *inode, struct file *file)
 {
        struct dentry *dentry = file->f_dentry;
        struct vfsmount *mnt = file->f_vfsmnt;
        struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
+       struct dentry *cursor;
        int status;
 
+       status = dcache_dir_open(inode, file);
+       if (status)
+               goto out;
+
+       cursor = file->private_data;
+       cursor->d_fsdata = NULL;
+
        DPRINTK("file=%p dentry=%p %.*s",
                file, dentry, dentry->d_name.len, dentry->d_name.name);
 
@@ -180,12 +125,15 @@ static int autofs4_dir_open(struct inode *inode, struct file *file)
 
        if (autofs4_ispending(dentry)) {
                DPRINTK("dentry busy");
-               return -EBUSY;
+               dcache_dir_close(inode, file);
+               status = -EBUSY;
+               goto out;
        }
 
+       status = -ENOENT;
        if (!d_mountpoint(dentry) && dentry->d_op && dentry->d_op->d_revalidate) {
                struct nameidata nd;
-               int empty;
+               int empty, ret;
 
                /* In case there are stale directory dentrys from a failed mount */
                spin_lock(&dcache_lock);
@@ -195,13 +143,13 @@ static int autofs4_dir_open(struct inode *inode, struct file *file)
                if (!empty)
                        d_invalidate(dentry);
 
-               nd.dentry = dentry;
-               nd.mnt = mnt;
                nd.flags = LOOKUP_DIRECTORY;
-               status = (dentry->d_op->d_revalidate)(dentry, &nd);
+               ret = (dentry->d_op->d_revalidate)(dentry, &nd);
 
-               if (!status)
-                       return -ENOENT;
+               if (!ret) {
+                       dcache_dir_close(inode, file);
+                       goto out;
+               }
        }
 
        if (d_mountpoint(dentry)) {
@@ -212,25 +160,29 @@ static int autofs4_dir_open(struct inode *inode, struct file *file)
                if (!autofs4_follow_mount(&fp_mnt, &fp_dentry)) {
                        dput(fp_dentry);
                        mntput(fp_mnt);
-                       return -ENOENT;
+                       dcache_dir_close(inode, file);
+                       goto out;
                }
 
                fp = dentry_open(fp_dentry, fp_mnt, file->f_flags);
                status = PTR_ERR(fp);
                if (IS_ERR(fp)) {
-                       file->private_data = NULL;
-                       return status;
+                       dcache_dir_close(inode, file);
+                       goto out;
                }
-               file->private_data = fp;
+               cursor->d_fsdata = fp;
        }
-out:
        return 0;
+out:
+       return status;
 }
 
 static int autofs4_dir_close(struct inode *inode, struct file *file)
 {
        struct dentry *dentry = file->f_dentry;
        struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
+       struct dentry *cursor = file->private_data;
+       int status = 0;
 
        DPRINTK("file=%p dentry=%p %.*s",
                file, dentry, dentry->d_name.len, dentry->d_name.name);
@@ -240,26 +192,28 @@ static int autofs4_dir_close(struct inode *inode, struct file *file)
 
        if (autofs4_ispending(dentry)) {
                DPRINTK("dentry busy");
-               return -EBUSY;
+               status = -EBUSY;
+               goto out;
        }
 
        if (d_mountpoint(dentry)) {
-               struct file *fp = file->private_data;
-
-               if (!fp)
-                       return -ENOENT;
-
+               struct file *fp = cursor->d_fsdata;
+               if (!fp) {
+                       status = -ENOENT;
+                       goto out;
+               }
                filp_close(fp, current->files);
-               file->private_data = NULL;
        }
 out:
-       return 0;
+       dcache_dir_close(inode, file);
+       return status;
 }
 
 static int autofs4_dir_readdir(struct file *file, void *dirent, filldir_t filldir)
 {
        struct dentry *dentry = file->f_dentry;
        struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
+       struct dentry *cursor = file->private_data;
        int status;
 
        DPRINTK("file=%p dentry=%p %.*s",
@@ -274,7 +228,7 @@ static int autofs4_dir_readdir(struct file *file, void *dirent, filldir_t filldi
        }
 
        if (d_mountpoint(dentry)) {
-               struct file *fp = file->private_data;
+               struct file *fp = cursor->d_fsdata;
 
                if (!fp)
                        return -ENOENT;
@@ -289,7 +243,7 @@ static int autofs4_dir_readdir(struct file *file, void *dirent, filldir_t filldi
                return status;
        }
 out:
-       return autofs4_dcache_readdir(file, dirent, filldir);
+       return dcache_readdir(file, dirent, filldir);
 }
 
 static int try_to_fill_dentry(struct vfsmount *mnt, struct dentry *dentry, int flags)