linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / fs / autofs4 / inode.c
index 649c3df..2d30828 100644 (file)
 #include <linux/file.h>
 #include <linux/pagemap.h>
 #include <linux/parser.h>
-#include <asm/bitops.h>
+#include <linux/bitops.h>
+#include <linux/smp_lock.h>
 #include "autofs_i.h"
 #include <linux/module.h>
 
 static void ino_lnkfree(struct autofs_info *ino)
 {
-       if (ino->u.symlink) {
-               kfree(ino->u.symlink);
-               ino->u.symlink = NULL;
-       }
+       kfree(ino->u.symlink);
+       ino->u.symlink = NULL;
 }
 
 struct autofs_info *autofs4_init_ino(struct autofs_info *ino,
@@ -76,6 +75,66 @@ void autofs4_free_ino(struct autofs_info *ino)
        kfree(ino);
 }
 
+/*
+ * Deal with the infamous "Busy inodes after umount ..." message.
+ *
+ * Clean up the dentry tree. This happens with autofs if the user
+ * space program goes away due to a SIGKILL, SIGSEGV etc.
+ */
+static void autofs4_force_release(struct autofs_sb_info *sbi)
+{
+       struct dentry *this_parent = sbi->root;
+       struct list_head *next;
+
+       spin_lock(&dcache_lock);
+repeat:
+       next = this_parent->d_subdirs.next;
+resume:
+       while (next != &this_parent->d_subdirs) {
+               struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child);
+
+               /* Negative dentry - don`t care */
+               if (!simple_positive(dentry)) {
+                       next = next->next;
+                       continue;
+               }
+
+               if (!list_empty(&dentry->d_subdirs)) {
+                       this_parent = dentry;
+                       goto repeat;
+               }
+
+               next = next->next;
+               spin_unlock(&dcache_lock);
+
+               DPRINTK("dentry %p %.*s",
+                       dentry, (int)dentry->d_name.len, dentry->d_name.name);
+
+               dput(dentry);
+               spin_lock(&dcache_lock);
+       }
+
+       if (this_parent != sbi->root) {
+               struct dentry *dentry = this_parent;
+
+               next = this_parent->d_u.d_child.next;
+               this_parent = this_parent->d_parent;
+               spin_unlock(&dcache_lock);
+               DPRINTK("parent dentry %p %.*s",
+                       dentry, (int)dentry->d_name.len, dentry->d_name.name);
+               dput(dentry);
+               spin_lock(&dcache_lock);
+               goto resume;
+       }
+       spin_unlock(&dcache_lock);
+
+       dput(sbi->root);
+       sbi->root = NULL;
+       shrink_dcache_sb(sbi->sb);
+
+       return;
+}
+
 static void autofs4_put_super(struct super_block *sb)
 {
        struct autofs_sb_info *sbi = autofs4_sbi(sb);
@@ -85,9 +144,13 @@ static void autofs4_put_super(struct super_block *sb)
        if ( !sbi->catatonic )
                autofs4_catatonic_mode(sbi); /* Free wait queues, close pipe */
 
+       /* Clean up and release dangling references */
+       if (sbi)
+               autofs4_force_release(sbi);
+
        kfree(sbi);
 
-       DPRINTK(("autofs: shutting down\n"));
+       DPRINTK("shutting down");
 }
 
 static struct super_operations autofs4_sops = {
@@ -187,32 +250,42 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
        struct file * pipe;
        int pipefd;
        struct autofs_sb_info *sbi;
+       struct autofs_info *ino;
        int minproto, maxproto;
 
        sbi = (struct autofs_sb_info *) kmalloc(sizeof(*sbi), GFP_KERNEL);
        if ( !sbi )
                goto fail_unlock;
-       DPRINTK(("autofs: starting up, sbi = %p\n",sbi));
+       DPRINTK("starting up, sbi = %p",sbi);
 
        memset(sbi, 0, sizeof(*sbi));
 
        s->s_fs_info = sbi;
        sbi->magic = AUTOFS_SBI_MAGIC;
+       sbi->root = NULL;
        sbi->catatonic = 0;
        sbi->exp_timeout = 0;
        sbi->oz_pgrp = process_group(current);
        sbi->sb = s;
        sbi->version = 0;
+       sbi->sub_version = 0;
+       init_MUTEX(&sbi->wq_sem);
+       spin_lock_init(&sbi->fs_lock);
        sbi->queues = NULL;
        s->s_blocksize = 1024;
        s->s_blocksize_bits = 10;
        s->s_magic = AUTOFS_SUPER_MAGIC;
        s->s_op = &autofs4_sops;
+       s->s_time_gran = 1;
 
        /*
         * Get the root inode and dentry, but defer checking for errors.
         */
-       root_inode = autofs4_get_inode(s, autofs4_mkroot(sbi));
+       ino = autofs4_mkroot(sbi);
+       if (!ino)
+               goto fail_free;
+       root_inode = autofs4_get_inode(s, ino);
+       kfree(ino);
        if (!root_inode)
                goto fail_free;
 
@@ -244,8 +317,9 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
        }
 
        sbi->version = maxproto > AUTOFS_MAX_PROTO_VERSION ? AUTOFS_MAX_PROTO_VERSION : maxproto;
+       sbi->sub_version = AUTOFS_PROTO_SUBVERSION;
 
-       DPRINTK(("autofs: pipe fd = %d, pgrp = %u\n", pipefd, sbi->oz_pgrp));
+       DPRINTK("pipe fd = %d, pgrp = %u", pipefd, sbi->oz_pgrp);
        pipe = fget(pipefd);
        
        if ( !pipe ) {
@@ -256,6 +330,13 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
                goto fail_fput;
        sbi->pipe = pipe;
 
+       /*
+        * Take a reference to the root dentry so we get a chance to
+        * clean up the dentry tree on umount.
+        * See autofs4_force_release.
+        */
+       sbi->root = dget(root);
+
        /*
         * Success! Install the root dentry now to indicate completion.
         */
@@ -305,7 +386,7 @@ struct inode *autofs4_get_inode(struct super_block *sb,
        if (S_ISDIR(inf->mode)) {
                inode->i_nlink = 2;
                inode->i_op = &autofs4_dir_inode_operations;
-               inode->i_fop = &simple_dir_operations;
+               inode->i_fop = &autofs4_dir_operations;
        } else if (S_ISLNK(inf->mode)) {
                inode->i_size = inf->size;
                inode->i_op = &autofs4_symlink_inode_operations;