[Top][All Lists]
[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))
{
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- tar bug report; NFS f/s detection,
Phil Budne <=