Andrew Morton <[EMAIL PROTECTED]> wrote:
> But why was yum (or an RPM script) dinking with loop and
> mounting/unmounting things?
It may have restarted the automounter... this may cause mounts and unmounts...
I've done a bit of probing, and when both ext3 and NFS go into the superblock
squidger with a tree that only has a root dentry, that root dentry has a usage
count of 1:
### Shrink root c629b088{1}
-->shrink_dcache_for_umount_subtree(c629b088)
- AT c629b088{0}
- consume c629b088{0}
### Shrunk
### Shrink root c621d710{1}
-->shrink_dcache_for_umount_subtree(c621d710)
- AT c621d710{0}
- consume c621d710{0}
### Shrunk
But when autofs4 goes in there with a minimal tree:
### Shrink root c6b714b0{2}
-->shrink_dcache_for_umount_subtree(c6b714b0)
- AT c6b714b0{1}
- consume c6b714b0{1}
BUG: Dentry c6b714b0{i=1a80,n=/} still in use (1) [unmount of autofs
autofs]
------------[ cut here ]------------
kernel BUG at fs/dcache.c:618!
It's got a usage count of *2*. That means the root dentry is still in use
somewhere beyond the superblock s_root reference.
I think this in autofs4_fill_super() is the problem:
/*
* 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);
autofs4 violates the assumptions that I was told I could make. autofs4
expects to clean up its dentries in autofs4_put_super(), when it should
perhaps really be overloading the kill_sb() op and doing it before calling
kill_anon_super().
I've attached the pair of debugging patches I used to generate the above.
David
diff --git a/fs/dcache.c b/fs/dcache.c
index 4fddd12..ae041da 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -597,7 +597,20 @@ static void shrink_dcache_for_umount_sub
do {
struct inode *inode;
- BUG_ON(atomic_read(&dentry->d_count) != 0);
+ if (atomic_read(&dentry->d_count) != 0) {
+ printk(KERN_ERR
+ "BUG: Dentry %p{i=%lx,n=%s}"
+ " still in use (%d)"
+ " [unmount of %s %s]\n",
+ dentry,
+ dentry->d_inode ?
+ dentry->d_inode->i_ino : 0UL,
+ dentry->d_name.name,
+ atomic_read(&dentry->d_count),
+ dentry->d_sb->s_type->name,
+ dentry->d_sb->s_id);
+ BUG();
+ }
parent = dentry->d_parent;
if (parent == dentry)
diff --git a/fs/dcache.c b/fs/dcache.c
index ae041da..61159d2 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -558,6 +558,8 @@ static void shrink_dcache_for_umount_sub
BUG_ON(!IS_ROOT(dentry));
+ printk("-->shrink_dcache_for_umount_subtree(%p)\n", dentry);
+
/* detach this root from the system */
spin_lock(&dcache_lock);
if (!list_empty(&dentry->d_lru)) {
@@ -568,6 +570,8 @@ static void shrink_dcache_for_umount_sub
spin_unlock(&dcache_lock);
for (;;) {
+ printk("- AT %p{%d}\n", dentry, atomic_read(&dentry->d_count));
+
/* descend to the first leaf in the current subtree */
while (!list_empty(&dentry->d_subdirs)) {
struct dentry *loop;
@@ -590,6 +594,8 @@ static void shrink_dcache_for_umount_sub
/* move to the first child */
dentry = list_entry(dentry->d_subdirs.next,
struct dentry, d_u.d_child);
+
+ printk("- descend %p{%d}\n", dentry,
atomic_read(&dentry->d_count));
}
/* consume the dentries from this leaf up through its parents
@@ -643,6 +649,7 @@ #endif
return;
dentry = parent;
+ printk("- ascend %p{%d}\n", dentry,
atomic_read(&dentry->d_count));
} while (list_empty(&dentry->d_subdirs));
@@ -671,13 +678,17 @@ void shrink_dcache_for_umount(struct sup
dentry = sb->s_root;
sb->s_root = NULL;
+ printk("### Shrink root %p{%d}\n", dentry,
atomic_read(&dentry->d_count));
atomic_dec(&dentry->d_count);
shrink_dcache_for_umount_subtree(dentry);
while (!hlist_empty(&sb->s_anon)) {
+ printk("### Shrink anon\n");
dentry = hlist_entry(sb->s_anon.first, struct dentry, d_hash);
shrink_dcache_for_umount_subtree(dentry);
}
+
+ printk("### Shrunk\n");
}
/*
_______________________________________________
autofs mailing list
[email protected]
http://linux.kernel.org/mailman/listinfo/autofs