summary refs log tree commit diff
path: root/nscd/hstcache.c
diff options
context:
space:
mode:
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>2018-05-16 10:51:15 -0300
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>2018-05-16 13:44:53 -0300
commit8c78faa9ef5c6cae455739f162e4b9d690e32eca (patch)
tree747cfdcde125142a2af392602043c9b174a67472 /nscd/hstcache.c
parent04958880e04264da97873b4d41d9bc34567afaef (diff)
downloadglibc-8c78faa9ef5c6cae455739f162e4b9d690e32eca.tar.gz
glibc-8c78faa9ef5c6cae455739f162e4b9d690e32eca.tar.xz
glibc-8c78faa9ef5c6cae455739f162e4b9d690e32eca.zip
Fix concurrent changes on nscd aware files (BZ #23178)
As indicated by BZ#23178, concurrent access on some files read by nscd
may result non expected data send through service requisition.  This is
due 'sendfile' Linux implementation where for sockets with zero-copy
support, callers must ensure the transferred portions of the the file
reffered by input file descriptor remain unmodified until the reader
on the other end of socket has consumed the transferred data.

I could not find any explicit documentation stating this behaviour on
Linux kernel documentation.  However man-pages sendfile entry [1] states
in NOTES the aforementioned remark.  It was initially pushed on man-pages
with an explicit testcase [2] that shows changing the file used in
'sendfile' call prior the socket input data consumption results in
previous data being lost.

From commit message it stated on tested Linux version (3.15) only TCP
socket showed this issues, however on recent kernels (4.4) I noticed the
same behaviour for local sockets as well.

Since sendfile on HURD is a read/write operation and the underlying
issue on Linux, the straightforward fix is just remove sendfile use
altogether.  I am really skeptical it is hitting some hotstop (there
are indication over internet that sendfile is helpfull only for large
files, more than 10kb) here to justify that extra code complexity or
to pursuit other possible fix (through memory or file locks for
instance, which I am not sure it is doable).

Checked on x86_64-linux-gnu.

	[BZ #23178]
	* nscd/nscd-client.h (sendfileall): Remove prototype.
	* nscd/connections.c [HAVE_SENDFILE] (sendfileall): Remove function.
	(handle_request): Use writeall instead of sendfileall.
	* nscd/aicache.c (addhstaiX): Likewise.
	* nscd/grpcache.c (cache_addgr): Likewise.
	* nscd/hstcache.c (cache_addhst): Likewise.
	* nscd/initgrcache.c (addinitgroupsX): Likewise.
	* nscd/netgroupcache.c (addgetnetgrentX, addinnetgrX): Likewise.
	* nscd/pwdcache.c (cache_addpw): Likewise.
	* nscd/servicescache.c (cache_addserv): Likewise.
	* sysdeps/unix/sysv/linux/Makefile [$(subdir) == nscd]
	(sysdep-CFLAGS): Remove -DHAVE_SENDFILE.
	* sysdeps/unix/sysv/linux/kernel-features.h (__ASSUME_SENDFILE):
	Remove define.

[1] http://man7.org/linux/man-pages/man2/sendfile.2.html
[2] https://github.com/mkerrisk/man-pages/commit/7b6a3299776b5c1c4f169a591434a855d50c68b4#diff-efd6af3a70f0f07c578e85b51e83b3c3
Diffstat (limited to 'nscd/hstcache.c')
-rw-r--r--nscd/hstcache.c37
1 files changed, 3 insertions, 34 deletions
diff --git a/nscd/hstcache.c b/nscd/hstcache.c
index 344a2b3052..6ef0c653ea 100644
--- a/nscd/hstcache.c
+++ b/nscd/hstcache.c
@@ -37,9 +37,6 @@
 
 #include "nscd.h"
 #include "dbg_log.h"
-#ifdef HAVE_SENDFILE
-# include <kernel-features.h>
-#endif
 
 
 /* This is the standard reply in case the service is disabled.  */
@@ -352,37 +349,9 @@ cache_addhst (struct database_dyn *db, int fd, request_header *req,
 	     unnecessarily keep the receiver waiting.  */
 	  assert (fd != -1);
 
-#ifdef HAVE_SENDFILE
-	  if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
-	    {
-	      assert (db->wr_fd != -1);
-	      assert ((char *) &dataset->resp > (char *) db->data);
-	      assert ((char *) dataset - (char *) db->head
-		      + total
-		      <= (sizeof (struct database_pers_head)
-			  + db->head->module * sizeof (ref_t)
-			  + db->head->data_size));
-	      ssize_t written = sendfileall (fd, db->wr_fd,
-					     (char *) &dataset->resp
-					     - (char *) db->head,
-					     dataset->head.recsize);
-	      if (written != dataset->head.recsize)
-		{
-# ifndef __ASSUME_SENDFILE
-		  if (written == -1 && errno == ENOSYS)
-		    goto use_write;
-# endif
-		  all_written = false;
-		}
-	    }
-	  else
-# ifndef __ASSUME_SENDFILE
-	  use_write:
-# endif
-#endif
-	    if (writeall (fd, &dataset->resp, dataset->head.recsize)
-		!= dataset->head.recsize)
-	      all_written = false;
+	  if (writeall (fd, &dataset->resp, dataset->head.recsize)
+	      != dataset->head.recsize)
+	    all_written = false;
 	}
 
       /* Add the record to the database.  But only if it has not been