Use __fpurge to ensure single-line writes to cache files
authorJ. Bruce Fields <bfields@citi.umich.edu>
Thu, 26 Jul 2007 20:30:46 +0000 (16:30 -0400)
committerNeil Brown <neilb@suse.de>
Fri, 27 Jul 2007 00:25:52 +0000 (10:25 +1000)
On a recent Debian/Sid machine, I saw libc retrying stdio writes that
returned write errors.  The result is that if an export downcall returns
an error (which it can in normal operation, since it currently
(incorrectly) returns -ENOENT on any negative downcall), then subsequent
downcalls will write multiple lines (including the original line that
received the error).

The result is that the server fails to respond to any rpc call that
refers to an unexported mount point (such as a readdir of a directory
containing such a mountpoint), so client commands hang.

I don't know whether this libc behavior is correct or expected, but it
seems safest to add the __fpurge() (suggested by Neil) to ensure data is
thrown away.

Signed-off-by: "J. Bruce Fields" <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@suse.de>
support/nfs/cacheio.c

index a76915b..9d271cd 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <nfslib.h>
 #include <stdio.h>
+#include <stdio_ext.h>
 #include <ctype.h>
 #include <unistd.h>
 #include <sys/types.h>
@@ -111,7 +112,18 @@ void qword_printint(FILE *f, int num)
 
 int qword_eol(FILE *f)
 {
+       int err;
+
        fprintf(f,"\n");
+       err = fflush(f);
+       /*
+        * We must send one line (and one line only) in a single write
+        * call.  In case of a write error, libc may accumulate the
+        * unwritten data and try to write it again later, resulting in a
+        * multi-line write.  So we must explicitly ask it to throw away
+        * any such cached data:
+        */
+       __fpurge(f);
        return fflush(f);
 }