bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH 0/7] contents of topic/libposix for merge to master


From: Bruno Haible
Subject: Re: [PATCH 0/7] contents of topic/libposix for merge to master
Date: Sat, 13 Nov 2010 01:13:53 +0100
User-agent: KMail/1.9.9

Hello Eric,

Gary reported:
>>    ix86 RHEL 5       gcc 4.1.2      (rename, renameat)
>>    x86_64 RHEL 5     gcc 4.1.2      (dprintf-posix2.sh, fprintf-posix3.sh
>>                                      rename, renameat)

I'm seeing the failures on Linux 2.6.18 systems:

  test-rename.h:119: assertion failed
  FAIL: test-rename
  test-rename.h:119: assertion failed
  FAIL: test-renameat

The cause is that the test happens on an NFS file system. After the line 117
has been executed (a rename of a non-empty directory over an empty directory),
for 30 seconds
  - the test whether BASE "dir" exists, via a readdir() loop, will tell
    that it is nonexistent,
  - but  stat (BASE "dir", &st)  will return 0, telling that the directory
    still exists.

sleep(1) and sync() don't help about this situation; only waiting 30 seconds
helps.

What should we do?
  a) Patch the test so that it uses a readdir() loop to detect the absence of
     the file even when stat() pretends it's still present. Or
  b) Use an rpl_rename override that will make the unit test work.

I think this behaviour of the NFS cache could also affect subsequent code
inside the coreutils 'mv' program, or even later commands in users' shell
scripts, therefore I would favour b).

For a), find attached a draft patch to the test (in its old, unreadable form).

For b), the fix is to enable the lib/rename.c replacement, with
  #define RENAME_DEST_EXISTS_BUG 1
  #define RENAME_HARD_LINK_BUG 1
Yes, both are needed. The first one fixes
  test-rename.h:119: assertion failed
The second one then fixes
  test-rename.h:191: assertion failed

But this will require an additional test in m4/rename.m4.

Which way you prefer?

Bruno


*** test-rename.h    Fri Jan  1 09:50:44 2010
--- test-rename.h       Fri Nov 12 23:33:25 2010
***************
*** 14,19 ****
--- 14,53 ----
     You should have received a copy of the GNU General Public License
     along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
  
+ #include <dirent.h>
+ 
+ static int dentry_exists (const char *filename)
+ {
+   int exists = 0;
+   DIR *dir = opendir (".");
+   ASSERT (dir != NULL);
+   for (;;)
+     {
+       struct dirent *d = readdir (dir);
+       if (d == NULL)
+         break;
+       if (strcmp (filename, d->d_name) == 0)
+         {
+           exists = 1;
+           break;
+         }
+     }
+   closedir (dir);
+   return exists;
+ }
+ 
+ static void assert_nonexistent (const char *filename)
+ {
+   struct stat st;
+ 
+   errno = 0;
+   if (stat (filename, &st) == -1)
+     ASSERT (errno == ENOENT);
+   else
+     /* Deal with NFS cache that keeps info about files present for 30 
seconds.  */
+     ASSERT (!dentry_exists (filename));
+ }
+ 
  /* This file is designed to test both rename(a,b) and
     renameat(AT_FDCWD,a,AT_FDCWD,b).  FUNC is the function to test.
     Assumes that BASE and ASSERT are already defined, and that
***************
*** 115,123 ****
    ASSERT (func (BASE "dir2", BASE "dir/") == -1);
    ASSERT (errno == EEXIST || errno == ENOTEMPTY);
    ASSERT (func (BASE "dir", BASE "dir2") == 0); /* Full onto empty.  */
!   errno = 0;
!   ASSERT (stat (BASE "dir", &st) == -1);
!   ASSERT (errno == ENOENT);
    ASSERT (stat (BASE "dir2/file", &st) == 0);
    ASSERT (mkdir (BASE "dir", 0700) == 0);
    ASSERT (func (BASE "dir2/", BASE "dir") == 0);
--- 149,155 ----
    ASSERT (func (BASE "dir2", BASE "dir/") == -1);
    ASSERT (errno == EEXIST || errno == ENOTEMPTY);
    ASSERT (func (BASE "dir", BASE "dir2") == 0); /* Full onto empty.  */
!   assert_nonexistent (BASE "dir");
    ASSERT (stat (BASE "dir2/file", &st) == 0);
    ASSERT (mkdir (BASE "dir", 0700) == 0);
    ASSERT (func (BASE "dir2/", BASE "dir") == 0);
***************
*** 127,135 ****
    ASSERT (errno == ENOENT);
    ASSERT (mkdir (BASE "dir2", 0700) == 0);
    ASSERT (func (BASE "dir", BASE "dir2/") == 0);
!   errno = 0;
!   ASSERT (stat (BASE "dir", &st) == -1);
!   ASSERT (errno == ENOENT);
    ASSERT (stat (BASE "dir2/file", &st) == 0);
    ASSERT (unlink (BASE "dir2/file") == 0);
    errno = 0; /* Reject trailing dot.  */
--- 159,165 ----
    ASSERT (errno == ENOENT);
    ASSERT (mkdir (BASE "dir2", 0700) == 0);
    ASSERT (func (BASE "dir", BASE "dir2/") == 0);
!   assert_nonexistent (BASE "dir");
    ASSERT (stat (BASE "dir2/file", &st) == 0);
    ASSERT (unlink (BASE "dir2/file") == 0);
    errno = 0; /* Reject trailing dot.  */



reply via email to

[Prev in Thread] Current Thread [Next in Thread]