From: Matthew W. <wi...@de...> - 2002-11-28 16:55:35
|
I'm sure that, once fixed, this bug will never come up again, but it's useful to have regression tests. ----- Forwarded message from "Stephen C. Tweedie" <sc...@re...> ----- From: "Stephen C. Tweedie" <sc...@re...> To: Trond Myklebust <tro...@fy...> Cc: "Stephen C. Tweedie" <sc...@re...>, Jeremy Fitzhardinge <je...@go...>, Ext2 devel <ext...@li...>, NFS maillist <nf...@li...>, Linux Kernel List <lin...@vg...> Subject: Re: [Ext2-devel] Re: [NFS] htree+NFS (NFS client bug?) Date: Thu, 28 Nov 2002 16:44:39 +0000 Hi, On Wed, Nov 27, 2002 at 08:55:54PM +0000, Stephen C. Tweedie wrote: > Having said that, the server is clearly in error in sending a > duplicate cookie in the first place, and if it did so we'd never get > into such a state. And it's ext3's fault. Reproducer below. Run the attached readdir against an htree directory and you get something like: [root@host1 htest]# ~sct/test/fs/readdir getdents at f_pos 0000000000000000 returned 4084. getdents at f_pos 0X0000000B753BE7 returned 4080. getdents at f_pos 0X000000158C4C61 returned 4080. getdents at f_pos 0X00000021E86BDC returned 4080. getdents at f_pos 0X0000002D60F25D returned 4080. getdents at f_pos 0X00000037BC95D7 returned 4096. getdents at f_pos 0X000000434E2AA3 returned 4080. getdents at f_pos 0X0000004EF11AE6 returned 4080. getdents at f_pos 0X000000596EBC2F returned 4080. getdents at f_pos 0X00000065A76668 returned 4080. getdents at f_pos 0X0000007060CF8B returned 4080. getdents at f_pos 0X0000007B9213FA returned 1464. getdents at f_pos 0X0000007B9213FA returned 0. Final f_pos is 0X0000007B9213FA. [root@host1 htest]# The problem is that the htree readdir code is not updating f_pos after returning the very last chunk of data to the caller. That doesn't hurt most callers because the location is cached in the filp->private data, but it really upsets NFS. --Stephen #define _LARGEFILE64_SOURCE #include <assert.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <signal.h> #include <sys/fcntl.h> #include <sys/stat.h> #include <sys/vfs.h> #include <sys/resource.h> #include <linux/types.h> #include <linux/unistd.h> #include <linux/dirent.h> _syscall3(int, getdents, uint, fd, struct dirent *, dirp, uint, count); void try(const char *what, int err) { if (!err) return; fprintf (stderr, "Unexpected result %d. %s: %s\n", err, what, strerror(errno)); exit(1); } int test_readdir(int fd) { loff_t offset; char dirbuf[4096]; int res; offset = lseek64(fd, 0, SEEK_CUR); res = getdents(fd, (struct dirent *)dirbuf, sizeof(dirbuf)); printf("getdents at f_pos %#016llX returned %d.\n", offset, res); return res; } int main() { int fd; int res; loff_t offset; fd = open64(".", O_RDONLY, 0); try ("open \".\"", fd < 0); do { res = test_readdir(fd); } while (res > 0); offset = lseek64(fd, 0, SEEK_CUR); printf("Final f_pos is %#016llX.\n", offset); return 0; } ----- End forwarded message ----- -- "It's not Hollywood. War is real, war is primarily not about defeat or victory, it is about death. I've seen thousands and thousands of dead bodies. Do you think I want to have an academic debate on this subject?" -- Robert Fisk |