Detect errors in cifs_writepages when called from pdflush

Peter Schwenke <[email protected]>
Newsgroups gmane.linux.file-systems.cifs
Message-ID <[email protected]>
There is a data integrity problem when cifs_writepages is called from
pdflush when an error occurs while a large file is being written.  For
example, a short network break.

You'll need 2 computers.  One with the cifs server, one to run the test
from.  For the cifs server we have used a Linux box with a VMWare XP
client and an XP machine.

1. Have a console ready for you type into. This should be on the machine
with the CIFS client E.g. screen or minicom via serial console or even
the main  tty console.
2. Run the attached test program from an xterm  where you are ssh'd into
the machine running the CIFs client
3. When the fflush messages have started appearing, pull the cable on
the cifs server
4. In the console from 1. run 'sync'.  Get yourself ready to plug the
cable in
5. When the kernel message similar to Write2 ret=-11  message appears on
the console, plug the cable back in.

The test program should terminate successfully.  However, the resulting
file will have zeroes in it somewhere in place of the correct data.  I
do have another test program for checking the file, if required.

I have also caused the problem without running the sync.

The problem is that the return code from do_writepages is lost in the
hierarchy of calls from (missing some)

fs/fs_writeback.c : void generic_sync_sb_inodes
to
mm/page-writeback.c: int do_writepages
to cifs_writepages

The patch in the next message fixes the problem.

I have wondered if this could affect other file systems and if something
should be done in  fs_writeback.c or page-writeback.c.  However, it
would need to be fairly major like adding the ability to override
generic_sync_sb_inodes in file systems through  the super_operations
structure or something.

-- 
                                                              Regards
                                                              ...Peter

_______________________________________________
linux-cifs-client mailing list
[email protected]
https://lists.samba.org/mailman/listinfo/linux-cifs-client
fsBig.c (text/x-csrc, 2.2 KB)
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/mount.h>
#include <errno.h>
#include <pthread.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "fsstuff.h"

void print_error(char *reason, int eno) 
{
     printf("%s: %s (%d)\n", reason, strerror(eno), eno);
}

int main(int argc, char *argv[])
{
     FILE *f;
     char *str = "Peter was here";
     int str_len = strlen(str);
     int cnt;
     int ok=1;
     long total=0;
     long z=0;
	 int i=0;
     if (f = fopen(FILENAME, "w")) 
     {
	  while (ok) 
	  {
	  for(i=0;i<3000;i++){};
	       if ((cnt=fwrite(str, sizeof(char), strlen(str), f)) != strlen(str))
	       {
		    print_error("fwrite failed", errno);
		    ok = 0;
	       }
	       else 
		   	{
		    total += cnt;
		    if (total/FFLUSH_AMOUNT > z)
		    {
			 z = total/FFLUSH_AMOUNT;
			 printf("fflush at %ld\n", total);
			 if (fflush(f) != 0)
			 {
			      print_error("Error while flushing file", errno);
			      if (errno == ENOSPC) 
			      {
				   printf("File System full!!!!");
				   exit(ENOSPC);
			      }
			      else if (errno == EAGAIN) 
			      {
				   printf("EAGAIN. Keep going...");
			      }
			      else 
			      {
				   printf("Bye\n");
				   exit(errno);
			      }			 
			 }
			 else
			 {
			 if (!(z%FSYNC_RATIO)) {
			      printf("fsync at %ld\n", total);
			      if (fsync(fileno(f)) != 0)
			      {
				   print_error("Error while synching file", errno);
				   if (errno == ENOSPC)
				   {
					printf("File System full!!!!");
					exit(ENOSPC);
				   }
				   else if (errno == EAGAIN) 
				   {
					printf("EAGAIN. Keep going...");
				   }
				   else 
				   {
					printf("Bye\n");
					exit(errno);
				   }
			      }
			 }
			 }
		    }
		    if (total > BIG_SIZE) {
			 if (fflush(f) != 0) 
			 {
			      print_error("Error while flushing file", errno);

			 }
			 if (fsync(fileno(f)) != 0)
			 {
			     print_error("Error while syncing file", errno);
			 }
			 if (fclose(f) < 0) 
			 {
			      print_error("Error while closing", errno);
			 }
			 ok = 0;
		    }
	       }
	  }
	  
     }
     else {
	  print_error("fopen failed", errno);
     }
}
fsstuff.h (text/x-chdr, 400 B)
#define DIRNAME "/mnt/persistent/cifs"

#define FILENAME (DIRNAME "/bigFile3.txt")

/*#define BIG_SIZE (unsigned long)1000000000*/
/*#define BIG_SIZE   (unsigned long)10000000*/
#define BIG_SIZE (unsigned long)200000000

/*#define FFLUSH_AMOUNT 5000000*/
/*
#define FFLUSH_AMOUNT   500000
#define FSYNC_RATIO 5
*/
#define FFLUSH_AMOUNT   10000000
#define FSYNC_RATIO 15

#define TICKER_AMOUNT 200000
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.