diff mbox

[libstdc++v3] : Fallback to read/write ops in case sendfile fails with ENOSYS or EINVAL.

Message ID CAFULd4aDCvkwOfMMiw28HV1hmRdmTvxsw2R+b0BmWH9Ve2xi8Q@mail.gmail.com
State New
Headers show

Commit Message

Uros Bizjak Aug. 11, 2016, 7:27 p.m. UTC
Hello!

Attached patch implements note from sendfile manpage:

<q>
Applications may wish to fall back to read(2)/write(2) in the case
where sendfile() fails with EINVAL or ENOSYS.
</q>

Also, the patch fixes a small inconsistency in how
_GLIBCXX_USE_FCHMODAT config flag is handled in do_copy_file function.

2016-08-11  Uros Bizjak  <ubizjak@gmail.com>

    * src/filesystem/ops.cc: Always include ostream and
    ext/stdio_filebuf.h.
    (do_copy_file): Check if _GLIBCXX_USE_FCHMODAT is defined.
    [_GLIBCXX_USE_SENDFILE]: Fallback to read/write operations in case
    sendfile fails with ENOSYS or EINVAL.

Patch was bootstrapped and regression tested on x86_64-linux-gnu
{,-m32} on CentOS 5.11 (where sendfile returns EINVAL for file->file
copy) and Fedora 24. In addition, the patch was bootstraped and
regression tested with _GLIBCXX_USE_SENDFILE manually disabled after
configure.

OK for mainline?

Uros.

Comments

Jonathan Wakely Aug. 15, 2016, 9:44 a.m. UTC | #1
On 11/08/16 21:27 +0200, Uros Bizjak wrote:
>Hello!
>
>Attached patch implements note from sendfile manpage:
>
><q>
>Applications may wish to fall back to read(2)/write(2) in the case
>where sendfile() fails with EINVAL or ENOSYS.
></q>
>
>Also, the patch fixes a small inconsistency in how
>_GLIBCXX_USE_FCHMODAT config flag is handled in do_copy_file function.
>
>2016-08-11  Uros Bizjak  <ubizjak@gmail.com>
>
>    * src/filesystem/ops.cc: Always include ostream and
>    ext/stdio_filebuf.h.
>    (do_copy_file): Check if _GLIBCXX_USE_FCHMODAT is defined.
>    [_GLIBCXX_USE_SENDFILE]: Fallback to read/write operations in case
>    sendfile fails with ENOSYS or EINVAL.
>
>Patch was bootstrapped and regression tested on x86_64-linux-gnu
>{,-m32} on CentOS 5.11 (where sendfile returns EINVAL for file->file
>copy) and Fedora 24. In addition, the patch was bootstraped and
>regression tested with _GLIBCXX_USE_SENDFILE manually disabled after
>configure.
>
>OK for mainline?

Yes, thanks.

The src/filesystem/ops.cc code is identical on the gcc-5 and gcc-6
branches, so could you backport it there too please? (After the 6.3
release though).
diff mbox

Patch

Index: src/filesystem/ops.cc
===================================================================
--- src/filesystem/ops.cc	(revision 239384)
+++ src/filesystem/ops.cc	(working copy)
@@ -28,7 +28,9 @@ 
 
 #include <experimental/filesystem>
 #include <functional>
+#include <ostream>
 #include <stack>
+#include <ext/stdio_filebuf.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <errno.h>
@@ -48,9 +50,6 @@ 
 #endif
 #ifdef _GLIBCXX_USE_SENDFILE
 # include <sys/sendfile.h>
-#else
-# include <ext/stdio_filebuf.h>
-# include <ostream>
 #endif
 #if _GLIBCXX_HAVE_UTIME_H
 # include <utime.h>
@@ -416,7 +415,7 @@  namespace
 
 #ifdef _GLIBCXX_USE_FCHMOD
     if (::fchmod(out.fd, from_st->st_mode))
-#elif _GLIBCXX_USE_FCHMODAT
+#elif defined _GLIBCXX_USE_FCHMODAT
     if (::fchmodat(AT_FDCWD, to.c_str(), from_st->st_mode, 0))
 #else
     if (::chmod(to.c_str(), from_st->st_mode))
@@ -428,6 +427,31 @@  namespace
 
 #ifdef _GLIBCXX_USE_SENDFILE
     const auto n = ::sendfile(out.fd, in.fd, nullptr, from_st->st_size);
+    if (n < 0 && (errno == ENOSYS || errno == EINVAL))
+      {
+#endif
+	__gnu_cxx::stdio_filebuf<char> sbin(in.fd, std::ios::in);
+	__gnu_cxx::stdio_filebuf<char> sbout(out.fd, std::ios::out);
+	if (sbin.is_open())
+	  in.fd = -1;
+	if (sbout.is_open())
+	  out.fd = -1;
+	if (from_st->st_size && !(std::ostream(&sbout) << &sbin))
+	  {
+	    ec = std::make_error_code(std::errc::io_error);
+	    return false;
+	  }
+	if (!sbout.close() || !sbin.close())
+	  {
+	    ec.assign(errno, std::generic_category());
+	    return false;
+	  }
+
+	ec.clear();
+	return true;
+
+#ifdef _GLIBCXX_USE_SENDFILE
+      }
     if (n != from_st->st_size)
       {
 	ec.assign(errno, std::generic_category());
@@ -438,27 +462,10 @@  namespace
 	ec.assign(errno, std::generic_category());
 	return false;
       }
-#else
-    __gnu_cxx::stdio_filebuf<char> sbin(in.fd, std::ios::in);
-    __gnu_cxx::stdio_filebuf<char> sbout(out.fd, std::ios::out);
-    if (sbin.is_open())
-      in.fd = -1;
-    if (sbout.is_open())
-      out.fd = -1;
-    if (from_st->st_size && !(std::ostream(&sbout) << &sbin))
-      {
-	ec = std::make_error_code(std::errc::io_error);
-	return false;
-      }
-    if (!sbout.close() || !sbin.close())
-      {
-	ec.assign(errno, std::generic_category());
-	return false;
-      }
-#endif
 
     ec.clear();
     return true;
+#endif
   }
 }
 #endif