Re: 2.2.0p6: autofs bug! unmountable filesystem

H. Peter Anvin (hpa@transmeta.com)
Mon, 11 Jan 1999 11:35:25 -0800 (PST)


> Hi,
>
> I can reproduce a autofs bug whereby the autofs filesystem cannot be
> unmounted.
>
> It is simple: first mount the autofs filesystem. I have RH5.2 so to do
> this I use /etc/rc.d/init.d/autofs start
>
> Now I mount my CD rom drive by doing cd /misc/cd
>
> This next step seems to break things. _Manually_ umount /misc/cd, rather
> than letting autofs timeout (before doing the the cwd will need to be
> moved from /misc/cd :-)
>
> Now, /misc cannot be unmounted, it is permanently reported as busy. Not
> good.

Hi there,

Try the following patch, please:

diff -ur stock/linux-2.2.0-pre6/fs/autofs/autofs_i.h linux-2.2.0-pre6/fs/autofs/autofs_i.h
--- stock/linux-2.2.0-pre6/fs/autofs/autofs_i.h Fri Jan 8 15:53:20 1999
+++ linux-2.2.0-pre6/fs/autofs/autofs_i.h Mon Jan 11 11:02:16 1999
@@ -92,10 +92,6 @@

#define AUTOFS_SYMLINK_BITMAP_LEN ((AUTOFS_MAX_SYMLINKS+31)/32)

-#ifndef END_OF_TIME
-#define END_OF_TIME ((time_t)((unsigned long)((time_t)(~0UL)) >> 1))
-#endif
-
#define AUTOFS_SBI_MAGIC 0x6d4a556d

struct autofs_sb_info {
@@ -111,6 +107,11 @@
u32 symlink_bitmap[AUTOFS_SYMLINK_BITMAP_LEN];
};

+extern inline struct autofs_sb_info *autofs_sbi(struct super_block *sb)
+{
+ return (struct autofs_sb_info *)(sb->u.generic_sbp);
+}
+
/* autofs_oz_mode(): do we see the man behind the curtain? (The
processes which do manipulations for us in user space sees the raw
filesystem without "magic".) */
@@ -126,6 +127,7 @@
void autofs_hash_insert(struct autofs_dirhash *,struct autofs_dir_ent *);
void autofs_hash_delete(struct autofs_dir_ent *);
struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *,off_t *,struct autofs_dir_ent *);
+void autofs_hash_dputall(struct autofs_dirhash *);
void autofs_hash_nuke(struct autofs_dirhash *);

/* Expiration-handling functions */
diff -ur stock/linux-2.2.0-pre6/fs/autofs/dirhash.c linux-2.2.0-pre6/fs/autofs/dirhash.c
--- stock/linux-2.2.0-pre6/fs/autofs/dirhash.c Tue Oct 27 14:13:53 1998
+++ linux-2.2.0-pre6/fs/autofs/dirhash.c Mon Jan 11 11:06:40 1999
@@ -47,7 +47,7 @@

ent = dh->expiry_head.exp_next;

- if ( ent == &(dh->expiry_head) )
+ if ( ent == &(dh->expiry_head) || sbi->catatonic )
return NULL; /* No entries */

while ( jiffies - ent->last_usage >= timeout ) {
@@ -62,8 +62,10 @@
dentry = ent->dentry;

if ( !dentry ) {
+ /* Should only happen in catatonic mode */
printk("autofs: dentry == NULL but inode range is directory, entry %s\n", ent->name);
autofs_delete_usage(ent);
+ continue;
}

if ( !dentry->d_inode ) {
@@ -200,6 +202,23 @@

*ptr = ((bucket+1) << 16) + ecount;
return ent;
+}
+
+/* Iterate over all the ents, and remove all dentry pointers. Used on
+ entering catatonic mode, in order to make the filesystem unmountable. */
+void autofs_hash_dputall(struct autofs_dirhash *dh)
+{
+ int i;
+ struct autofs_dir_ent *ent, *nent;
+
+ for ( i = 0 ; i < AUTOFS_HASH_SIZE ; i++ ) {
+ for ( ent = dh->h[i] ; ent ; ent = ent->next ) {
+ if ( ent->dentry ) {
+ dput(ent->dentry);
+ ent->dentry = NULL;
+ }
+ }
+ }
}

/* Delete everything. This is used on filesystem destruction, so we
diff -ur stock/linux-2.2.0-pre6/fs/autofs/inode.c linux-2.2.0-pre6/fs/autofs/inode.c
--- stock/linux-2.2.0-pre6/fs/autofs/inode.c Thu Dec 17 16:51:36 1998
+++ linux-2.2.0-pre6/fs/autofs/inode.c Mon Jan 11 10:46:26 1999
@@ -34,8 +34,7 @@

static void autofs_put_super(struct super_block *sb)
{
- struct autofs_sb_info *sbi =
- (struct autofs_sb_info *) sb->u.generic_sbp;
+ struct autofs_sb_info *sbi = autofs_sbi(sb);
unsigned int n;

if ( !sbi->catatonic )
@@ -297,8 +296,7 @@
{
ino_t ino = inode->i_ino;
unsigned int n;
- struct autofs_sb_info *sbi =
- (struct autofs_sb_info *) inode->i_sb->u.generic_sbp;
+ struct autofs_sb_info *sbi = autofs_sbi(inode->i_sb);

/* Initialize to the default case (stub directory) */

diff -ur stock/linux-2.2.0-pre6/fs/autofs/root.c linux-2.2.0-pre6/fs/autofs/root.c
--- stock/linux-2.2.0-pre6/fs/autofs/root.c Thu Dec 17 16:51:36 1998
+++ linux-2.2.0-pre6/fs/autofs/root.c Mon Jan 11 11:08:36 1999
@@ -68,13 +68,15 @@
{
struct autofs_dir_ent *ent = NULL;
struct autofs_dirhash *dirhash;
+ struct autofs_sb_info *sbi;
struct inode * inode = filp->f_dentry->d_inode;
off_t onr, nr;

if (!inode || !S_ISDIR(inode->i_mode))
return -ENOTDIR;

- dirhash = &((struct autofs_sb_info *)inode->i_sb->u.generic_sbp)->dirhash;
+ sbi = autofs_sbi(inode->i_sb);
+ dirhash = &sbi->dirhash;
nr = filp->f_pos;

switch(nr)
@@ -168,12 +170,10 @@
*/
static int autofs_revalidate(struct dentry * dentry)
{
- struct autofs_sb_info *sbi;
struct inode * dir = dentry->d_parent->d_inode;
+ struct autofs_sb_info *sbi = autofs_sbi(dir->i_sb);
struct autofs_dir_ent *ent;

- sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp;
-
/* Pending dentry */
if ( dentry->d_flags & DCACHE_AUTOFS_PENDING ) {
if (autofs_oz_mode(sbi))
@@ -220,7 +220,7 @@
if (!S_ISDIR(dir->i_mode))
return -ENOTDIR;

- sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp;
+ sbi = autofs_sbi(dir->i_sb);

oz_mode = autofs_oz_mode(sbi);
DPRINTK(("autofs_lookup: pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d\n",
@@ -267,7 +267,7 @@

static int autofs_root_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
{
- struct autofs_sb_info *sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp;
+ struct autofs_sb_info *sbi = autofs_sbi(dir->i_sb);
struct autofs_dirhash *dh = &sbi->dirhash;
struct autofs_dir_ent *ent;
unsigned int n;
@@ -338,7 +338,7 @@
*/
static int autofs_root_unlink(struct inode *dir, struct dentry *dentry)
{
- struct autofs_sb_info *sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp;
+ struct autofs_sb_info *sbi = autofs_sbi(dir->i_sb);
struct autofs_dirhash *dh = &sbi->dirhash;
struct autofs_dir_ent *ent;
unsigned int n;
@@ -365,7 +365,7 @@

static int autofs_root_rmdir(struct inode *dir, struct dentry *dentry)
{
- struct autofs_sb_info *sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp;
+ struct autofs_sb_info *sbi = autofs_sbi(dir->i_sb);
struct autofs_dirhash *dh = &sbi->dirhash;
struct autofs_dir_ent *ent;

@@ -393,7 +393,7 @@

static int autofs_root_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
- struct autofs_sb_info *sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp;
+ struct autofs_sb_info *sbi = autofs_sbi(dir->i_sb);
struct autofs_dirhash *dh = &sbi->dirhash;
struct autofs_dir_ent *ent;
ino_t ino;
@@ -492,8 +492,7 @@
static int autofs_root_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- struct autofs_sb_info *sbi =
- (struct autofs_sb_info *)inode->i_sb->u.generic_sbp;
+ struct autofs_sb_info *sbi = autofs_sbi(inode->i_sb);

DPRINTK(("autofs_ioctl: cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u\n",cmd,arg,sbi,current->pgrp));

diff -ur stock/linux-2.2.0-pre6/fs/autofs/waitq.c linux-2.2.0-pre6/fs/autofs/waitq.c
--- stock/linux-2.2.0-pre6/fs/autofs/waitq.c Mon Dec 28 00:47:48 1998
+++ linux-2.2.0-pre6/fs/autofs/waitq.c Mon Jan 11 11:03:03 1999
@@ -41,6 +41,7 @@
wq = nwq;
}
fput(sbi->pipe); /* Close the pipe */
+ autofs_hash_dputall(&sbi->dirhash); /* Remove all dentry pointers */
}

static int autofs_write(struct file *file, const void *addr, int bytes)

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/