Re: NFS client stuck in nfs_free_dentries (2.2.15)

From: Trond Myklebust (trond.myklebust@fys.uio.no)
Date: Fri May 19 2000 - 10:56:57 EST


>>>>> " " == Miquel van Smoorenburg <miquels@cistron.nl> writes:

> We have a shell server that mounts the user home directories,
> the mail directories and the stuff from our public FTP server
> using NFS from other Linux (unfsd) servers.

> We tried to run the 2.2.13 kernel on it, but it crashed every
> few hours. Last week I decided to retry it with 2.2.15, and it
> got an uptime of 9 days until it crashed again today.

> Magic sysrq revealed that the program counter was always in the
> same area:

> EIP: 0010:[c01466eb] EIP: 0010:[c0146702] EIP: 0010:[c014673c]
> EIP: 0010:[c0146777] EIP: 0010:[c0146771]

> Excerpt from System.map:

> c01466c4 t nfs_free_dentries c014678c t nfs_zap_caches

> In other words, it's stuck in nfs_free_dentries(). But how is
> it possible that it gets stuck in while ((tmp = tmp->next) !=
> head) { } ? Ah, perhaps if dentry->d_count == 0, is that a
> valid possibility ?

I'm thinking shrink_dcache_parent() might be the culprit here, and
causing dentry to be freed beneath us if it has already been
unhashed. The following patch should ensure that we have no trouble.

Cheers,
  Trond

--- linux-2.2.15/fs/nfs/inode.c.orig Thu May 4 02:16:46 2000
+++ linux-2.2.15/fs/nfs/inode.c Fri May 19 17:49:04 2000
@@ -413,23 +413,25 @@
         int unhashed;
 
 restart:
- tmp = head;
+ tmp = head->next;
         unhashed = 0;
- while ((tmp = tmp->next) != head) {
+ while (tmp != head) {
                 struct dentry *dentry = list_entry(tmp, struct dentry, d_alias);
+ dget(dentry);
                 if (!list_empty(&dentry->d_subdirs))
                         shrink_dcache_parent(dentry);
                 dprintk("nfs_free_dentries: found %s/%s, d_count=%d, hashed=%d\n",
                         dentry->d_parent->d_name.name, dentry->d_name.name,
                         dentry->d_count, !list_empty(&dentry->d_hash));
- if (!dentry->d_count) {
- dget(dentry);
+ if (dentry->d_count == 1) {
                         d_drop(dentry);
                         dput(dentry);
                         goto restart;
                 }
                 if (list_empty(&dentry->d_hash))
                         unhashed++;
+ tmp = tmp->next;
+ dput(dentry);
         }
         return unhashed;
 }

-
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/



This archive was generated by hypermail 2b29 : Tue May 23 2000 - 21:00:17 EST