coreutils: Add odirect io option to cp and mv

Signed-off-by: Sunil Mushran <sunil.mushran@oracle.com>

Index: coreutils-5.2.1-odirect/src/cp.c
===================================================================
--- coreutils-5.2.1-odirect.orig/src/cp.c	2006-10-26 14:10:32.000000000 -0700
+++ coreutils-5.2.1-odirect/src/cp.c	2006-11-13 17:36:32.000000000 -0800
@@ -58,6 +58,12 @@ int selinux_enabled=0;
 uid_t geteuid ();
 #endif
 
+#ifdef __s390x__
+#define MIN_SECTOR_SIZE		4096
+#else
+#define MIN_SECTOR_SIZE		512
+#endif
+
 /* Used by do_copy, make_path_private, and re_protect
    to keep a list of leading directories whose protections
    need to be fixed after copying. */
@@ -78,6 +84,7 @@ enum
   PARENTS_OPTION,
   PRESERVE_ATTRIBUTES_OPTION,
   REPLY_OPTION,
+  SECTOR_SIZE_OPTION,
   SPARSE_OPTION,
   STRIP_TRAILING_SLASHES_OPTION,
   TARGET_DIRECTORY_OPTION,
@@ -128,6 +135,7 @@ static struct option const long_opts[] =
   {"backup", optional_argument, NULL, 'b'},
   {"copy-contents", no_argument, NULL, COPY_CONTENTS_OPTION},
   {"dereference", no_argument, NULL, 'L'},
+  {"directio", no_argument, NULL, 'D'},
   {"force", no_argument, NULL, 'f'},
   {"interactive", no_argument, NULL, 'i'},
   {"link", no_argument, NULL, 'l'},
@@ -140,6 +148,7 @@ static struct option const long_opts[] =
   {"recursive", no_argument, NULL, 'R'},
   {"remove-destination", no_argument, NULL, UNLINK_DEST_BEFORE_OPENING},
   {"reply", required_argument, NULL, REPLY_OPTION},
+  {"sector-size", required_argument, NULL, SECTOR_SIZE_OPTION},
   {"sparse", required_argument, NULL, SPARSE_OPTION},
   {"strip-trailing-slashes", no_argument, NULL, STRIP_TRAILING_SLASHES_OPTION},
   {"suffix", required_argument, NULL, 'S'},
@@ -186,6 +195,7 @@ Mandatory arguments to long options are 
 "), stdout);
       fputs (_("\
       --no-dereference         never follow symbolic links\n\
+  -D, --directio               use directio if possible\n\
   -f, --force                  if an existing destination file cannot be\n\
                                  opened, remove it and try again\n\
   -i, --interactive            prompt before overwrite\n\
@@ -215,6 +225,11 @@ Mandatory arguments to long options are 
       fputs (_("\
       --reply={yes,no,query}   specify how to handle the prompt about an\n\
                                  existing destination file\n\
+"), stdout);
+      printf (_("\
+      --sector-size=SIZE       specify sector size in bytes (default %u)\n\
+"), MIN_SECTOR_SIZE);
+      fputs (_("\
       --sparse=WHEN            control creation of sparse files\n\
       --strip-trailing-slashes remove any trailing slashes from each SOURCE\n\
                                  argument\n\
@@ -785,6 +800,9 @@ cp_option_init (struct cp_options *x)
   x->preserve_mode = 0;
   x->preserve_timestamps = 0;
 
+  x->directio = 0;
+  x->sector_size = MIN_SECTOR_SIZE;
+
 #ifdef WITH_SELINUX
   x->preserve_security_context = 0;
 #endif
@@ -897,6 +915,7 @@ main (int argc, char **argv)
   struct cp_options x;
   int copy_contents = 0;
   char *target_directory = NULL;
+  char *endptr;
 #ifdef WITH_SELINUX
   security_context_t scontext = NULL;
   selinux_enabled= (is_selinux_enabled()>0);
@@ -917,9 +936,9 @@ main (int argc, char **argv)
   backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
 
 #ifdef WITH_SELINUX
-  while ((c = getopt_long (argc, argv, "abcdfHilLprsuvxPRS:V:Z:", long_opts, NULL))
+  while ((c = getopt_long (argc, argv, "abcdDfHilLprsuvxPRS:V:Z:", long_opts, NULL))
 #else
-  while ((c = getopt_long (argc, argv, "abdfHilLprsuvxPRS:V:", long_opts, NULL))
+  while ((c = getopt_long (argc, argv, "abdDfHilLprsuvxPRS:V:", long_opts, NULL))
 #endif
 	 != -1)
     {
@@ -965,6 +984,10 @@ main (int argc, char **argv)
 	  x.dereference = DEREF_NEVER;
 	  break;
 
+	case 'D':
+	  x.directio = 1;
+	  break;
+
 	case 'f':
 	  x.unlink_dest_after_failed_open = 1;
 	  break;
@@ -1056,6 +1079,14 @@ main (int argc, char **argv)
 				     reply_args, reply_vals);
 	  break;
 
+	case SECTOR_SIZE_OPTION:
+	  x.sector_size = strtoul(optarg, &endptr, 0);
+	  if (*endptr) {
+		  (void) fprintf(stderr, _("%s: incorrect sector size\n"), argv[0]);
+		  exit( 1 );
+	  }
+	  break;
+
 	case UNLINK_DEST_BEFORE_OPENING:
 	  x.unlink_dest_before_opening = 1;
 	  break;
Index: coreutils-5.2.1-odirect/src/mv.c
===================================================================
--- coreutils-5.2.1-odirect.orig/src/mv.c	2006-10-26 14:10:32.000000000 -0700
+++ coreutils-5.2.1-odirect/src/mv.c	2006-11-13 17:36:32.000000000 -0800
@@ -44,6 +44,12 @@ int selinux_enabled=0;
 
 #define AUTHORS "Mike Parker", "David MacKenzie", "Jim Meyering"
 
+#ifdef __s390x__
+#define MIN_SECTOR_SIZE		4096
+#else
+#define MIN_SECTOR_SIZE		512
+#endif
+
 /* Initial number of entries in each hash table entry's table of inodes.  */
 #define INITIAL_HASH_MODULE 100
 
@@ -56,6 +62,7 @@ enum
 {
   TARGET_DIRECTORY_OPTION = CHAR_MAX + 1,
   STRIP_TRAILING_SLASHES_OPTION,
+  SECTOR_SIZE_OPTION,
   REPLY_OPTION
 };
 
@@ -83,9 +90,11 @@ static int const reply_vals[] =
 static struct option const long_options[] =
 {
   {"backup", optional_argument, NULL, 'b'},
+  {"directio", no_argument, NULL, 'D'},
   {"force", no_argument, NULL, 'f'},
   {"interactive", no_argument, NULL, 'i'},
   {"reply", required_argument, NULL, REPLY_OPTION},
+  {"sector-size", required_argument, NULL, SECTOR_SIZE_OPTION},
   {"strip-trailing-slashes", no_argument, NULL, STRIP_TRAILING_SLASHES_OPTION},
   {"suffix", required_argument, NULL, 'S'},
   {"target-directory", required_argument, NULL, TARGET_DIRECTORY_OPTION},
@@ -144,6 +153,9 @@ cp_option_init (struct cp_options *x)
   x->verbose = 0;
   x->dest_info = NULL;
   x->src_info = NULL;
+
+  x->directio = 0;
+  x->sector_size = MIN_SECTOR_SIZE;
 }
 
 /* If PATH is an existing directory, return nonzero, else 0.  */
@@ -320,6 +332,7 @@ Mandatory arguments to long options are 
       fputs (_("\
       --backup[=CONTROL]       make a backup of each existing destination file\n\
   -b                           like --backup but does not accept an argument\n\
+  -D, --directio               use directio if possible\n\
   -f, --force                  do not prompt before overwriting\n\
                                  (equivalent to --reply=yes)\n\
   -i, --interactive            prompt before overwrite\n\
@@ -328,6 +341,11 @@ Mandatory arguments to long options are 
       fputs (_("\
       --reply={yes,no,query}   specify how to handle the prompt about an\n\
                                  existing destination file\n\
+"), stdout);
+      printf (_("\
+      --sector-size=SIZE       specify sector size in bytes (default %u)\n\
+"), MIN_SECTOR_SIZE);
+      fputs (_("\
       --strip-trailing-slashes remove any trailing slashes from each SOURCE\n\
                                  argument\n\
   -S, --suffix=SUFFIX          override the usual backup suffix\n\
@@ -373,6 +391,7 @@ main (int argc, char **argv)
   int target_directory_specified;
   unsigned int n_files;
   char **file;
+  char *endptr;
 
   initialize_main (&argc, &argv);
   program_name = argv[0];
@@ -394,7 +413,7 @@ main (int argc, char **argv)
 
   errors = 0;
 
-  while ((c = getopt_long (argc, argv, "bfiuvS:V:", long_options, NULL)) != -1)
+  while ((c = getopt_long (argc, argv, "bDfiuvS:V:", long_options, NULL)) != -1)
     {
       switch (c)
 	{
@@ -413,6 +432,9 @@ main (int argc, char **argv)
 	  if (optarg)
 	    version_control_string = optarg;
 	  break;
+	case 'D':
+	  x.directio = 1;
+	  break;
 	case 'f':
 	  x.interactive = I_ALWAYS_YES;
 	  break;
@@ -423,6 +445,13 @@ main (int argc, char **argv)
 	  x.interactive = XARGMATCH ("--reply", optarg,
 				     reply_args, reply_vals);
 	  break;
+	case SECTOR_SIZE_OPTION:
+	  x.sector_size = strtoul(optarg, &endptr, 0);
+	  if (*endptr) {
+		  (void) fprintf(stderr, _("%s: incorrect sector size\n"), argv[0]);
+		  exit( 1 );
+	  }
+	  break;
 	case STRIP_TRAILING_SLASHES_OPTION:
 	  remove_trailing_slashes = 1;
 	  break;
Index: coreutils-5.2.1-odirect/src/copy.c
===================================================================
--- coreutils-5.2.1-odirect.orig/src/copy.c	2006-10-26 14:10:32.000000000 -0700
+++ coreutils-5.2.1-odirect/src/copy.c	2013-08-22 18:11:05.446999850 +0900
@@ -106,6 +106,23 @@
    than a few hundred levels.  See use of active_dir_map in remove.c  */
 
 static int
+direct_mode (int fd, bool enable)
+{
+  int fd_flags = fcntl (fd, F_GETFL);
+
+  if (0 < fd_flags)
+    {
+      int new_flags = (enable
+		       ? (fd_flags | O_DIRECT)
+		       : (fd_flags & ~O_DIRECT));
+
+      if (new_flags != fd_flags)
+        fd_flags = fcntl (fd, F_SETFL, new_flags);
+    }
+  return fd_flags;
+}
+
+static int
 is_ancestor (const struct stat *sb, const struct dir_list *ancestors)
 {
   while (ancestors != 0)
@@ -189,7 +206,7 @@
 	  struct stat const *src_sb)
 {
   char *buf;
-  int buf_size;
+  int buf_size = 0;
   int dest_desc;
   int source_desc;
   struct stat sb;
@@ -200,6 +217,10 @@
   off_t n_read_total = 0;
   int last_write_made_hole = 0;
   int make_holes = 0;
+  int src_dio = 0;
+  int dst_dio = 0;
+  int unlink_dest = 0;
+	struct stat src_stat, dest_stat;
 
   source_desc = open (src_path, O_RDONLY);
   if (source_desc < 0)
@@ -260,8 +281,43 @@
       goto close_src_desc;
     }
 
-  /* Determine the optimal buffer size.  */
+#define io_str(_a)	((_a) ? "direct io" : "buffered io")
+  if (x->directio)
+    {
+//      if (!(src_open_sb.st_size % x->sector_size))
+      if (1)
+        {
+          if (direct_mode (dest_desc, 1) != -1)
+              dst_dio = 1;
+          if (direct_mode (source_desc, 1) != -1)
+              src_dio = 1;
+//          if (!(dst_dio && src_dio))
+//            {
+//              fprintf (stderr, _("%s: source %s, destination %s? "),
+//                       program_name, io_str(src_dio), io_str(dst_dio));
+//              if (! yesno ())
+//	        {
+//                  unlink_dest = 1;
+//		  goto close_src_desc;
+//		}
+//	    }
+	}
+      else
+	{
+          fprintf (stderr, _("%s: cannot do direct io as the file size is not "
+			     "aligned to sector size. Continue buffered io? "),
+		   program_name);
+	  if (! yesno ())
+	    {
+              unlink_dest = 1;
+	      goto close_src_desc;
+	    }
+	}
+      if (x->verbose)
+          printf ("%s -> %s\n", io_str(src_dio), io_str(dst_dio));
+    }
 
+  /* Determine the optimal buffer size.  */
   if (fstat (dest_desc, &sb))
     {
       error (0, errno, _("cannot fstat %s"), quote (dst_path));
@@ -269,15 +325,20 @@
       goto close_src_and_dst_desc;
     }
 
-  buf_size = ST_BLKSIZE (sb);
+  if (src_dio || dst_dio)
+    buf_size = MAX (ST_BLKSIZE (src_open_sb), ST_BLKSIZE (sb));
+  else
+    buf_size = ST_BLKSIZE (sb);
 
   /* Even with --sparse=always, try to create holes only
      if the destination is a regular file.  */
-  if (x->sparse_mode == SPARSE_ALWAYS && S_ISREG (sb.st_mode))
+  if (x->sparse_mode == SPARSE_ALWAYS && S_ISREG (sb.st_mode) &&
+      !(src_dio || dst_dio))
     make_holes = 1;
 
 #if HAVE_STRUCT_STAT_ST_BLOCKS
-  if (x->sparse_mode == SPARSE_AUTO && S_ISREG (sb.st_mode))
+  if (x->sparse_mode == SPARSE_AUTO && S_ISREG (sb.st_mode) &&
+      !(src_dio || dst_dio))
     {
       /* Use a heuristic to determine whether SRC_PATH contains any
 	 sparse blocks. */
@@ -300,7 +361,18 @@
 
   /* Make a buffer with space for a sentinel at the end.  */
 
-  buf = alloca (buf_size + sizeof (int));
+  if (dst_dio || src_dio)
+    {
+      if (posix_memalign((void **)&buf, x->sector_size, buf_size))
+        {
+          error (0, 0, _("unable to allocate %d bytes of memory"), buf_size);
+          return_val = -1;
+          unlink_dest = 1;
+          goto close_src_and_dst_desc;
+        }
+    }
+  else
+    buf = alloca (buf_size + sizeof (int));
 
   for (;;)
     {
@@ -358,7 +430,8 @@
       if (ip == 0)
 	{
 	  size_t n = n_read;
-	  if (full_write (dest_desc, buf, n) != n)
+//	  if (full_write (dest_desc, buf, n) != n)
+	  if (full_write (dest_desc, buf, buf_size) != buf_size)
 	    {
 	      error (0, errno, _("writing %s"), quote (dst_path));
 	      return_val = -1;
@@ -390,12 +463,28 @@
     }
 
 close_src_and_dst_desc:
+  if (src_dio || dst_dio)
+    free(buf);
+	assert(fstat(dest_desc, &dest_stat) >= 0);
+	assert(fstat(source_desc, &src_stat) >= 0);
+	if(dest_stat.st_size > src_stat.st_size)
+		assert(ftruncate(dest_desc, src_stat.st_size) >= 0);
   if (close (dest_desc) < 0)
     {
       error (0, errno, _("closing %s"), quote (dst_path));
       return_val = -1;
     }
 close_src_desc:
+  if (unlink_dest)
+    {
+      if (unlink (dst_path) < 0)
+        {
+          error (0, errno, _("cannot remove %s"), quote (dst_path));
+          return_val = -1;
+        }
+      else
+        *new_dst = 1;
+    }
   if (close (source_desc) < 0)
     {
       error (0, errno, _("closing %s"), quote (src_path));
Index: coreutils-5.2.1-odirect/src/copy.h
===================================================================
--- coreutils-5.2.1-odirect.orig/src/copy.h	2006-10-26 14:10:32.000000000 -0700
+++ coreutils-5.2.1-odirect/src/copy.h	2006-11-13 17:36:32.000000000 -0800
@@ -156,6 +156,10 @@ struct cp_options
   /* If nonzero, stdin is a tty.  */
   int stdin_tty;
 
+  int directio;
+
+  int sector_size;
+
   /* This is a set of destination name/inode/dev triples.  Each such triple
      represents a file we have created corresponding to a source file name
      that was specified on the command line.  Use it to avoid clobbering
Index: coreutils-5.2.1-odirect/src/install.c
===================================================================
--- coreutils-5.2.1-odirect.orig/src/install.c	2006-10-26 14:10:32.000000000 -0700
+++ coreutils-5.2.1-odirect/src/install.c	2006-11-13 17:36:32.000000000 -0800
@@ -246,6 +246,9 @@ cp_option_init (struct cp_options *x)
   x->symbolic_link = 0;
   x->backup_type = none;
 
+  x->directio = 0;
+  x->sector_size = 0;
+
   /* Create destination files initially writable so we can run strip on them.
      Although GNU strip works fine on read-only files, some others
      would fail.  */
Index: coreutils-5.2.1-odirect/man/cp.1
===================================================================
--- coreutils-5.2.1-odirect.orig/man/cp.1	2006-10-26 14:10:32.000000000 -0700
+++ coreutils-5.2.1-odirect/man/cp.1	2006-11-13 17:51:59.000000000 -0800
@@ -36,6 +36,9 @@ same as \fB\-\-no\-dereference\fR \fB\-\
 \fB\-\-no\-dereference\fR
 never follow symbolic links
 .TP
+\fB\-D\fR, \fB\-\-directio\fR
+use directio if possible
+.TP
 \fB\-f\fR, \fB\-\-force\fR
 if an existing destination file cannot be
 opened, remove it and try again
@@ -80,6 +83,9 @@ attempting to open it (contrast with \fB
 specify how to handle the prompt about an
 existing destination file
 .TP
+\fB\-\-sector\-size\fR=\fISIZE\fR
+specify sector size in bytes (used only in directio mode)
+.TP
 \fB\-\-sparse\fR=\fIWHEN\fR
 control creation of sparse files
 .TP
@@ -121,6 +127,10 @@ selected by \fB\-\-sparse\fR=\fIauto\fR.
 file whenever the SOURCE file contains a long enough sequence of zero bytes.
 Use \fB\-\-sparse\fR=\fInever\fR to inhibit creation of sparse files.
 .PP
+Directio operations require the ios to be size aligned to the hardware sector size.
+As that value is not easily available, the tool uses an architecture dependent
+default value. Use the \-\-sector\-size to use a different value for your device.
+.PP
 The backup suffix is `~', unless set with \fB\-\-suffix\fR or SIMPLE_BACKUP_SUFFIX.
 The version control method may be selected via the \fB\-\-backup\fR option or through
 the VERSION_CONTROL environment variable.  Here are the values:
