lkml.org 
[lkml]   [1999]   [May]   [24]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From
SubjectPossible NFS client 2.2.9 kernel bug and fix
Hello,

Here is the bug I ran across:

NFS mount from server (nfs-server-2.2beta37, kernel 2.2.6, glibc) to a
2.2.9 kernel glibc (RH5.2+) machine. Initially found that on a find of
all files on a nfs mount, find used up all swap and caused nasty things to
happen. Tracked this down to a single directory that had an infinite
loop in its entries (readdir() keeps returning the directory entries
over and over again). I checked the following:

directory is fine on server (actually a read only mount of an NTFS)
directory mounted on a 2.0.36 kernel (RH 4.2+, libc) box is ok

Thus I figured it had to be the 2.2.9 (2.2.7 and 2.2.8 also) kernel.

So I hacked my way into fs/nfs/dir.c and traced it to the EOF (bit 15) bit
not being set on the last entry returned by the nfs_proc_readdir. I don't
know sunrpc (not that I know NFS either ;), thus it got too dense for me
to dig deeper. So I fixed it at that point. The attached patch addeds a
check for the EOF bit on the last directory entry and sets it if it is not
set on the initial read of the directory before it is put in the cache.
When it was not set the cache reading code never finds the directory entry
in the cache (it falls off the bottom of the j loop thru the entires
looking for the EOF bit set), so the dir is fetched again and again it is
not found in the cache, giving the infinite loop.

Someone might want to think about the consequences of hiting the break at
line 207 in dir.c, which AFAIK should never be hit. There does
seem to be an inconsistancy in the code that two different methods are used
to signal the end of the directory, initially size and then the EOF bit
when reading from the cache. When find used up all swap on this loop lots
of bad things happend, processes died, etc.

This is a hard error, so I can test any better fix that comes along.
However, my patch might be an addition to the NFS_PARANOIA as the
consequences are rather severe. But I don't think I've found the original
cause of this behavior.

thanks for your help,

Tom Shield
Aerospace Engineering and Mechanics
University of Minnesota
(612) 626-7793
http://www.aem.umn.edu/people/faculty/shield/
diff -C 2 -P /usr/tmp/nfs/dir.c fs/nfs/dir.c
*** /usr/tmp/nfs/dir.c Wed May 12 17:10:34 1999
--- fs/nfs/dir.c Thu May 20 19:38:05 1999
***************
*** 246,249 ****
--- 246,267 ----
cache->valid = 1;
entry = cache->entry + (index = 0);
+
+ /* make sure the last one has EOF set
+ this avoids the possibility of a nasty inf loop -- shield@aem.umn.edu */
+
+ {
+ __u32 *this_ent = cache->entry + 3*cache->size - 3;
+
+ if (*(this_ent+2) & (1 << 15))
+ {
+ dfprintk(VFS, "TWS: found EOF \n");
+ }
+ else
+ {
+ *(this_ent+2) = *(this_ent+2) | (1 << 15);
+ dfprintk(VFS, "TWS: SET EOF bit \n");
+ }
+ }
+
}
cache->mtime = inode->i_mtime;
\
 
 \ /
  Last update: 2005-03-22 13:51    [W:0.056 / U:0.560 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site