This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH][BZ #12723] Fix pathconf and fpathconf on Linux


Hi,

The pathconf(_PC_PIPE_BUF) gets the pipe buffer size on Linux using
F_GETPIPE_SZ on the file, or falls back to returning the default
PIPE_BUF.  The fallback is incorrect since the default pipe buffer
size for Linux is not PIPE_BUF.  Linux pipe buffer size is
configurable using F_SETPIPE_SZ and is initially set to
PIPE_DEF_BUFFERS * PAGE_SIZE, where PIPE_DEF_BUFFERS is 16.  The
fallback should return this value.  Patch below does that and also
includes a test case to verify that pathconf on a fifo and a directory
are the same.

I have verified that the test case breaks without the patch and that
the patch then fixes it.  No regressions noticed in the testsuite due
to this patch.  OK to commit?

Siddhesh

	[BZ #12723]
	* posix/Makefile (tests): Add tst-pathconf.
	* posix/tst-pathconf.c: New test case.
	* sysdeps/unix/sysv/linux/fpathconf.c (__fpathconf): Return
	PIPE_DEF_BUFFERS * PAGE_SIZE as fallback for _PC_PIPE_BUF.
	* sysdeps/unix/sysv/linux/pathconf.c (__pathconf): Likewise.
	* sysdeps/unix/sysv/linux/pathconf.h (PIPE_DEF_BUFFERS):
	Define.

diff --git a/posix/Makefile b/posix/Makefile
index 2cacd21..658c47e 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -86,7 +86,8 @@ tests		:= tstgetopt testfnm runtests runptests	     \
 		   tst-rfc3484-3 \
 		   tst-getaddrinfo3 tst-fnmatch2 tst-cpucount tst-cpuset \
 		   bug-getopt1 bug-getopt2 bug-getopt3 bug-getopt4 \
-		   bug-getopt5 tst-getopt_long1 bug-regex34 bug-regex35
+		   bug-getopt5 tst-getopt_long1 bug-regex34 bug-regex35 \
+		   tst-pathconf
 xtests		:= bug-ga2
 ifeq (yes,$(build-shared))
 test-srcs	:= globtest
diff --git a/posix/tst-pathconf.c b/posix/tst-pathconf.c
new file mode 100644
index 0000000..bb4cb16
--- /dev/null
+++ b/posix/tst-pathconf.c
@@ -0,0 +1,146 @@
+/* Test that values of pathconf and fpathconf are consistent for a file.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+static void prepare (void);
+#define PREPARE(argc, argv) prepare ()
+
+static int do_test (void);
+#define TEST_FUNCTION do_test ()
+
+#include "../test-skeleton.c"
+
+static int dir_fd;
+static char *dirbuf;
+
+static void
+prepare (void)
+{
+  size_t test_dir_len = strlen (test_dir);
+  static const char dir_name[] = "/tst-pathconf.XXXXXX";
+
+  size_t dirbuflen = test_dir_len + sizeof (dir_name);
+  dirbuf = malloc (dirbuflen);
+  if (dirbuf == NULL)
+    {
+      puts ("Out of memory");
+      exit (1);
+    }
+
+  snprintf (dirbuf, dirbuflen, "%s%s", test_dir, dir_name);
+  if (mkdtemp (dirbuf) == NULL)
+    {
+      printf ("Cannot create temporary directory: %s\n", strerror (errno));
+      exit (1);
+    }
+
+  add_temp_file (dirbuf);
+
+  dir_fd = open (dirbuf, O_RDONLY);
+  if (dir_fd == -1)
+    {
+      printf ("Cannot open directory: %s\n", strerror (errno));
+      exit (1);
+    }
+}
+
+
+static int
+do_test (void)
+{
+  int ret = 0;
+  static const char *fifo_name = "some-fifo";
+
+  size_t filenamelen = strlen (dirbuf) + strlen (fifo_name) + 2;
+  char *filename = malloc (filenamelen);
+
+  snprintf (filename, filenamelen, "%s/%s", dirbuf, fifo_name);
+
+  /* Create a fifo in the directory.  */
+  int e = mkfifo (filename, 0777);
+  if (e == -1)
+    {
+      printf ("fifo creation failed (%s)\n", strerror (errno));
+      ret = 1;
+      goto out_nofifo;
+    }
+
+  long dir_pathconf = pathconf (dirbuf, _PC_PIPE_BUF);
+  long fifo_pathconf = pathconf (filename, _PC_PIPE_BUF);
+
+  int fifo = open (filename, O_RDONLY | O_NONBLOCK);
+
+  if (fifo < 0)
+    {
+      printf ("fifo open failed (%s)\n", strerror (errno));
+      ret = 1;
+      goto out_nofifo;
+    }
+
+  long dir_fpathconf = fpathconf (dir_fd, _PC_PIPE_BUF);
+  long fifo_fpathconf = fpathconf (fifo, _PC_PIPE_BUF);
+
+  if (fifo_pathconf != fifo_fpathconf)
+    {
+      printf ("fifo pathconf (%ld) != fifo fpathconf (%ld)\n", fifo_pathconf,
+	      fifo_fpathconf);
+      ret = 1;
+      goto out;
+    }
+
+  if (dir_pathconf != fifo_pathconf)
+    {
+      printf ("directory pathconf (%ld) != fifo pathconf (%ld)\n",
+	      dir_pathconf, fifo_pathconf);
+      ret = 1;
+      goto out;
+    }
+
+  if (dir_fpathconf != fifo_fpathconf)
+    {
+      printf ("directory fpathconf (%ld) != fifo fpathconf (%ld)\n",
+	      dir_fpathconf, fifo_fpathconf);
+      ret = 1;
+      goto out;
+    }
+
+out:
+  close (fifo);
+out_nofifo:
+  close (dir_fd);
+
+  if (unlink (filename) != 0)
+    {
+      printf ("Could not remove fifo (%s)\n", strerror (errno));
+      ret = 1;
+    }
+
+  if (rmdir (dirbuf) != 0)
+    {
+      printf ("Could not remove directory (%s)\n", strerror (errno));
+      ret = 1;
+    }
+
+  return ret;
+}
diff --git a/sysdeps/unix/sysv/linux/fpathconf.c b/sysdeps/unix/sysv/linux/fpathconf.c
index c971644..2ca9808 100644
--- a/sysdeps/unix/sysv/linux/fpathconf.c
+++ b/sysdeps/unix/sysv/linux/fpathconf.c
@@ -53,7 +53,8 @@ __fpathconf (fd, name)
       r = __fcntl (fd, F_GETPIPE_SZ);
       if (r > 0)
 	return r;
-      /* FALLTHROUGH */
+      /* Default buffer size on Linux is not PIPE_BUF.  */
+      return PIPE_DEF_BUFFERS * __getpagesize ();
 
     default:
       return posix_fpathconf (fd, name);
diff --git a/sysdeps/unix/sysv/linux/pathconf.c b/sysdeps/unix/sysv/linux/pathconf.c
index e86925f..f5a1fcb 100644
--- a/sysdeps/unix/sysv/linux/pathconf.c
+++ b/sysdeps/unix/sysv/linux/pathconf.c
@@ -69,7 +69,8 @@ __pathconf (const char *file, int name)
 	  if (r > 0)
 	    return r;
 	}
-      /* FALLTHROUGH */
+      /* Default buffer size on Linux is not PIPE_BUF.  */
+      return PIPE_DEF_BUFFERS * __getpagesize ();
 
     default:
       return posix_pathconf (file, name);
diff --git a/sysdeps/unix/sysv/linux/pathconf.h b/sysdeps/unix/sysv/linux/pathconf.h
index 56071f8..c9b4bb8 100644
--- a/sysdeps/unix/sysv/linux/pathconf.h
+++ b/sysdeps/unix/sysv/linux/pathconf.h
@@ -20,6 +20,10 @@
 #include <unistd.h>
 #include <sys/statfs.h>
 
+/* The default number of buffers a new pipe gets.  Defined in the kernel in
+   include/linux/pipe_fs_i.h.  Each buffer is of page size, so the default
+   buffer size is PIPE_DEF_BUFERS * PAGE_SIZE.  */
+#define PIPE_DEF_BUFFERS 16
 
 /* Used like: return __statfs_link_max (__statfs (name, &buf), &buf,
 					name, -1); */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]