NFS still has caching problem

Kees Bakker (kees_bakker@tasking.nl)
Wed, 10 Jul 1996 18:44:59 +0200


Hi Linus,

Today I have booted my system with linux-2.0.4, and saw it still has the
following problem with directory caching. Let's first briefly describe the
test environment.
NFS server, called napoli, is an Alpha, and runs OSF1 v2.0
NFS client 1, called lahti, runs linux-2.0.4 ('out of the box')
NFS client 2, called pori, runs linux-1.3.83 (with my nfs/dir.c patch)

The test is as follows:
- on one client, write a file
- then do a 'rsh' to another client and 'cat' the file
- again, on the first client, write the same file, different contents
- again, do a 'rsh' to another client and 'cat' the file
You will see that the Linux clients keep showing the old contents if the
size of the file remains the same. If the new size is different, then the
Linux client shows the new contents.

To sync the NFS server, I have written a small C program that uses
fsync(). But that does not change the behavior.

Here is a logging of the test.

/usr/sec/kees > rlogin turku
No mail.
/usr/sec/kees > RNODE=pori ./t4-nfs
going to do: rsh pori cd `pwd`\; cat t3-nfs.txt
1 --Hello, world
going to do: rsh pori cd `pwd`\; cat t3-nfs.txt
2 --Hallo, 12345
going to do: rsh pori cd `pwd`\; cat t3-nfs.txt
3 --Hello, wwwww 3
going to do: rsh pori cd `pwd`\; cat t3-nfs.txt
4 --Hallo, world 4
going to do: rsh pori cd `pwd`\; cat t3-nfs.txt
5 --Hallo, world 5
going to do: rsh pori cd `pwd`\; cat t3-nfs.txt
6 --Hallo, world 6
going to do: rsh pori cd `pwd`\; cat t3-nfs.txt
7 --Hallo, world 7
going to do: rsh pori cd `pwd`\; cat t3-nfs.txt
8 --Hallo, world 8

/usr/sec/kees > RNODE=lahti ./t4-nfs
going to do: rsh lahti cd `pwd`\; cat t3-nfs.txt
1 --Hello, world
going to do: rsh lahti cd `pwd`\; cat t3-nfs.txt
1 --Hello, world
going to do: rsh lahti cd `pwd`\; cat t3-nfs.txt
3 --Hello, wwwww 3
going to do: rsh lahti cd `pwd`\; cat t3-nfs.txt
3 --Hello, wwwww 3
going to do: rsh lahti cd `pwd`\; cat t3-nfs.txt
3 --Hello, wwwww 3
going to do: rsh lahti cd `pwd`\; cat t3-nfs.txt
3 --Hello, wwwww 3
going to do: rsh lahti cd `pwd`\; cat t3-nfs.txt
3 --Hello, wwwww 3
going to do: rsh lahti cd `pwd`\; cat t3-nfs.txt
3 --Hello, wwwww 3

The first session is correct, the Linux system pori has my patch. The
second session is wrong, the Linux system lahti, does not have the patch.

My patch:
If you have a look at fs/nfs/dir.c you see the following piece of code:

was_empty = (inode->i_mode == 0);
inode->i_mode = fattr->mode;
inode->i_nlink = fattr->nlink;
inode->i_uid = fattr->uid;
inode->i_gid = fattr->gid;

/* Size changed from outside: invalidate caches on next read */
if (inode->i_size != fattr->size)
NFS_CACHEINV(inode);
inode->i_size = fattr->size;
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
inode->i_rdev = to_kdev_t(fattr->rdev);
else
inode->i_rdev = 0;
inode->i_blocks = fattr->blocks;
inode->i_atime = fattr->atime.seconds;
inode->i_mtime = fattr->mtime.seconds;
inode->i_ctime = fattr->ctime.seconds;

Notice that this part only checks for changed file sizes, not for anything
else. Perhaps you are assuming that modification times are check somewhere
else, but it certainly does not affect this part. I tried a little patch,
which seems to work, but I don't know if this is the right place to make
this modification. This is what I tried:

--- linux/fs/nfs/dir.c.orig Wed Mar 13 12:53:09 1996
+++ linux/fs/nfs/dir.c Fri Mar 22 09:06:10 1996
@@ -613,14 +613,17 @@
return;
}
was_empty = (inode->i_mode == 0);
- inode->i_mode = fattr->mode;
inode->i_nlink = fattr->nlink;
inode->i_uid = fattr->uid;
inode->i_gid = fattr->gid;

- /* Size changed from outside: invalidate caches on next read */
- if (inode->i_size != fattr->size)
+ /* Size and/or time changed from outside: invalidate caches on next read */
+ if (inode->i_size != fattr->size ||
+ inode->i_mtime != fattr->mtime.seconds ||
+ inode->i_mode != fattr->mode
+ )
NFS_CACHEINV(inode);
+ inode->i_mode = fattr->mode;
inode->i_size = fattr->size;
inode->i_blksize = fattr->blocksize;
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))

Now it will also look at i_mtime and i_mode. Question is, should that be
checked here?

I would happy to send you the C file, and the shell script, if you want to
try it out.

-- 
============================================================
Kees Bakker                           phone : +31 33 4558584
Tasking Software BV                     fax : +31 33 4550033
Plotterweg 31                                kees@tasking.nl
Amersfoort, The Netherlands            http://www.tasking.nl
============================================================
Speak the word, the word is all of us - Queensryche