kern/57696: NFS client readdir terminates prematurely if renaming
files
Brian Candler
B.Candler at pobox.com
Tue Oct 7 05:40:19 PDT 2003
>Number: 57696
>Category: kern
>Synopsis: NFS client readdir terminates prematurely if renaming files
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Tue Oct 07 05:40:14 PDT 2003
>Closed-Date:
>Last-Modified:
>Originator: B.Candler at pobox.com
>Release: FreeBSD 4.8p3 i386
>Organization:
>Environment:
FreeBSD-4.7-RELEASE, FreeBSD-4.8p3
>Description:
If you have an opendir/readdir loop which rename()s files out of that
directory while the directory is being read, and the directory is mounted
over NFS, the readdir terminates prematurely - i.e. not all files are seen.
Problem verified with the following combinations:
FreeBSD client - NetApp server: problem [1]
FreeBSD client - Solaris 2.8 server: problem [1]
FreeBSD client - FreeBSD server: problem [2]
FreeBSD client - Linux server: problem [3]
Linux client - Linux server: no problem [3]
Solaris 2.8 client - Netapp server: no problem [4]
That seems to nail it as a FreeBSD NFS client issue. References:
[1] http://www.mail-archive.com/sqwebmail%40inter7.com/msg06643.html
[2] http://www.mail-archive.com/sqwebmail%40inter7.com/msg06644.html
[3] not yet appeared on archive, message from Stefan Kaltenbrunner
[4] http://www.mail-archive.com/sqwebmail%40inter7.com/msg06657.html
It's a problem in particular for Maildir messages, when moving files from
Maildir/new/* to Maildir/cur/*
>How-To-Repeat:
Run the following program with an NFS-mounted directory as the command-line
argument. The failure mode is:
bash-2.05a# ./testnfs /na0/testdir
Transferred 169 out of 200 files
This program also posted at reference [1] above.
/* Demonstrate problem with NFS readdir */
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h> /* for mkdir */
#include <sys/stat.h> /* for mkdir */
#include <dirent.h> /* opendir/readdir etc */
#define TESTSIZE 200
int main(int argc, char *argv[])
{
int i;
char fnbuf[1024], fnbuf2[1024];
char *dir = argv[1];
int count;
DIR *dp;
struct dirent *de;
if (argc < 2 || !dir || !dir[0])
dir = ".";
sprintf(fnbuf, "%s/new", dir);
mkdir(fnbuf, 0777);
sprintf(fnbuf, "%s/cur", dir);
mkdir(fnbuf, 0777);
for (i=0; i<TESTSIZE; i++) {
FILE *f;
sprintf(fnbuf, "%s/new/MYTESTFILE%d", dir, i);
f = fopen(fnbuf, "w");
if (!f) { perror("fopen"); exit(1); }
fprintf(f, "Some dummy content\n");
fclose(f);
}
sprintf(fnbuf, "%s/new", dir);
dp = opendir(fnbuf);
if (!dp) { perror("opendir"); exit(1); }
count = 0;
while ((de = readdir(dp))) {
if (de->d_name[0] == '.') continue;
sprintf(fnbuf, "%s/new/%s", dir, de->d_name);
sprintf(fnbuf2,"%s/cur/%s:2,S", dir, de->d_name);
if (rename(fnbuf, fnbuf2) < 0) {
perror("rename");
fprintf(stderr, "(from %s to %s)\n", fnbuf, fnbuf2);
continue;
}
count++;
}
fprintf(stderr, "Transferred %d out of %d files\n", count, TESTSIZE);
return count != TESTSIZE;
}
>Fix:
No idea. Workaround implemented in courier-imap is to opendir, readdir 20
items into array, closedir, process the 20 items, rinse and repeat.
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list