X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fautofs4%2Finode.c;h=2d3082854a292dec3fc1ad749b81b9c700a4addb;hb=987b0145d94eecf292d8b301228356f44611ab7c;hp=649c3dfd108a1442d5a36fc0a906fbf7dad6861d;hpb=daddc0d38b3571bed170afa273a49a0eba090c1e;p=linux-2.6.git diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index 649c3dfd1..2d3082854 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c @@ -15,16 +15,15 @@ #include #include #include -#include +#include +#include #include "autofs_i.h" #include 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;