bug-gnu-utils
[Top][All Lists]
Advanced

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

tar bug report; NFS f/s detection


From: Phil Budne
Subject: tar bug report; NFS f/s detection
Date: Fri, 22 Nov 2002 20:38:05 -0500 (EST)

Tar does a poor job of detecting NFS mounted directories on modern
systems, which confuses listed incremental backups.  Enclosed is a
patch that (with suitable autoconf mumbo jumbo) should help.

Upgrading to a new, fixed version of tar doesn't fix existing backups,
since the non-nfs status is inherited from the directory entries in
the listing file?  I don't have a fix for this, other than adding +'s
to the start of each directory line...

*** tar-1.13.25/src/incremen.c.orig     Wed Aug 29 14:20:19 2001
--- tar-1.13.25/src/incremen.c  Fri Nov 22 19:56:17 2002
***************
*** 1,3 ****
--- 1,10 ----
+ /* should be set by autoconf */
+ #define HAVE_STATVFS 0
+ #define HAVE_LINUX_STATFS 0
+ #define HAVE_BSD_STATFS 1
+ #define HAVE_SUNOS4_STATFS 0
+ #define HAVE_ST_VFSTYPE 0
+ 
  /* GNU dump extensions to tar.
  
     Copyright 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001 Free
***************
*** 97,109 ****
  static Hash_table *directory_table;
  
  #if HAVE_ST_FSTYPE_STRING
!   static char const nfs_string[] = "nfs";
! # define NFS_FILE_STAT(st) (strcmp ((st).st_fstype, nfs_string) == 0)
  #else
! # define ST_DEV_MSB(st) (~ (dev_t) 0 << (sizeof (st).st_dev * CHAR_BIT - 1))
! # define NFS_FILE_STAT(st) (((st).st_dev & ST_DEV_MSB (st)) != 0)
  #endif
  
  /* Calculate the hash of a directory.  */
  static unsigned
  hash_directory (void const *entry, unsigned n_buckets)
--- 104,227 ----
  static Hash_table *directory_table;
  
  #if HAVE_ST_FSTYPE_STRING
!   static const char nfs[] = "nfs";
! # define ISNFS(path,stp) (strcmp ((stp)->st_fstype, nfs) == 0)
! #elif HAVE_ST_VFSTYPE
! /* AIX */
! #include <sys/stat.h>
! #include <sys/vmount.h>
! #ifdef MNT_NFS3
! #  define ISNFS(path,stp) \
!       ((stp)->st_vfstype == MNT_NFS || (stp)->st_vfstype == MNT_NFS3)
  #else
! #  define ISNFS(path,stp) ((stp)->st_vfstype == MNT_NFS)
  #endif
  
+ #elif HAVE_STATVFS
+ /* works on SunOS5, HP-UX 10.20, HP-UX 11.0, IRIX 6.5, AIX 4.3 */
+ 
+ #include <sys/types.h>
+ #include <sys/statvfs.h>
+ #define NEED_CACHE
+ 
+ static int
+ isnfs(char *path, struct stat *stp)
+ {
+   struct statvfs f;
+ 
+   if (statvfs(path, &f) < 0)
+     return 0;
+ 
+   return strcmp(f.f_basetype, "nfs3") == 0 || strcmp(f.f_basetype, "nfs") == 
0;
+ }
+ #elif HAVE_BSD_STATFS
+ /* BSD4.4 */
+ #include <sys/param.h>
+ #include <sys/mount.h>
+ #define NEED_CACHE
+ 
+ static int
+ isnfs(char *path, struct stat *stp)
+ {
+   struct statfs f;
+ 
+   if (statfs(path, &f) < 0)
+     return 0;
+   return strcmp(f.f_fstypename, "nfs") == 0;
+ }
+ #elif HAVE_LINUX_STATFS
+ #include <sys/vfs.h>
+ 
+ /* it's in linux/nfs_fs.h, but can't include it?! */
+ #define NFS_SUPER_MAGIC 0x6969
+ #define NEED_CACHE
+ 
+ static int
+ isnfs(char *path, struct stat *stp)
+ {
+   struct statfs f;
+ 
+   if (statfs(path, &f) < 0)
+     return 0;
+ 
+   return f.f_type == NFS_SUPER_MAGIC;
+ }
+ #elif HAVE_SUNOS4_STATFS
+ #include <sys/types.h>
+ #include <sys/vfs.h>
+ #define NEED_CACHE
+ 
+ static int
+ isnfs(path)
+      char *path;
+ {
+   struct statfs f;
+ 
+   if (statfs(path, &f) < 0)
+     return 0;
+ 
+   /* SunOS4 only supports NFSv2 which doesn't return inode info */
+   return f.f_files == -1 && f.f_ffree == -1;
+ }
+ #else
+ /* try ustat call, check for f_tinode == -1??? */
+ 
+ /* fall back to the old and unreliable way.... */
+ # define ST_DEV_MSB(stp) (~ (dev_t) 0 << (sizeof (stp)->st_dev * CHAR_BIT - 
1))
+ # define ISNFS(path,stp) (((stp)->st_dev & ST_DEV_MSB (stp)) != 0)
+ /* check minor(dev) == 0xff?? */
+ #endif
+ 
+ #ifdef NEED_CACHE
+ # define ISNFS(path,stp) check_nfs_cache(path,stp)
+ 
+ #define ISNFS_CACHE_LOG2 0    /* log2 of number of cache entries */
+ #define ISNFS_CACHE_ENTRIES (1<<(ISNFS_CACHE_LOG2)) /* must be power of 2 */
+ #define ISNFS_CACHE_MASK (ISNFS_CACHE_ENTRIES-1)
+ 
+ struct isnfs_cache_line {
+     dev_t dev;
+     char flags;
+ } isnfs_cache[ISNFS_CACHE_ENTRIES];
+ 
+ #define NC_VALID 01
+ #define NC_ISNFS 02
+ 
+ static int
+ check_nfs_cache(char *path, struct stat *stp)
+ {
+   struct isnfs_cache_line *cp = isnfs_cache + (stp->st_dev & 
ISNFS_CACHE_MASK);
+   if (!(cp->flags & NC_VALID) || cp->dev != stp->st_dev) {
+     /* here with mismatched cache entry, or invalid cache entry */
+     cp->dev = stp->st_dev;
+     cp->flags = NC_VALID;
+     if (isnfs(path, stp))
+       cp->flags |= NC_ISNFS;
+   }
+   return (cp->flags & NC_ISNFS) != 0;
+ }
+ #endif /* NEED_CACHE */
+ 
  /* Calculate the hash of a directory.  */
  static unsigned
  hash_directory (void const *entry, unsigned n_buckets)
***************
*** 233,239 ****
  
              if (S_ISDIR (stat_data.st_mode))
                {
!                 bool nfs = NFS_FILE_STAT (stat_data);
  
                  if (directory = find_directory (name_buffer), directory)
                    {
--- 351,357 ----
  
              if (S_ISDIR (stat_data.st_mode))
                {
!                 bool nfs = ISNFS (name_buffer, &stat_data);
  
                  if (directory = find_directory (name_buffer), directory)
                    {
***************
*** 244,250 ****
                         directories, consider all NFS devices as equal,
                         relying on the i-node to establish differences.  */
  
!                     if (! (((directory->nfs & nfs)
                              || directory->device_number == stat_data.st_dev)
                             && directory->inode_number == stat_data.st_ino))
                        {
--- 362,368 ----
                         directories, consider all NFS devices as equal,
                         relying on the i-node to establish differences.  */
  
!                     if (! (((directory->nfs && nfs)
                              || directory->device_number == stat_data.st_dev)
                             && directory->inode_number == stat_data.st_ino))
                        {





reply via email to

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