[PATCH] --one-file-system and automounter

Dick Streefland dick.streefland at altium.nl
Mon Feb 2 11:01:12 GMT 2004


We use rsync in a Linux installation script. First, the root filesystem
of another machine on the network is cloned with "rsync -axzH", and then
a few files are updated to give the clone its own identity. This works
fine, but last week, the Postfix mailer daemon on a new machine refused
to start because some lock files had a link count of 2. It turned out
that rsync had created two copies of the root filesystem, and
hard-linked all files (-H option), because the original machine had a
"bind" mount at the time of the clone. The bind mount has the same
device number as the root, but it is inside an automount directory, so
it should have been skipped by the -x option.

The automounter uses a program map file to NFS-mount the root filesystem
of other machines on the network. When the machine itself is accessed, a
"bind" mount is used instead of NFS as an optimization. For example,
when you have the automounter on /mnt/net, and a bind mount to the
machine itself (kemi), the device numbers are:

$ stat -c '%4D %n' /mnt /mnt/net /mnt/net/kemi
 302 /mnt
  19 /mnt/net
 302 /mnt/net/kemi

The followin rsync invocation shows that the "kemi" subdirectory is
*not* skipped by the -x option, but later by the --exclude option:

$ rsync -axvvn --exclude=kemi /mnt /tmp/dest
expand file_list to 4000 bytes, did move
excluding directory mnt/net/kemi because of pattern kemi
delta-transmission disabled for local transfer or --whole-file
total: matches=0  tag_hits=0  false_alarms=0 data=0

The attached patch for rsync-2.6.0 moves the cross-filesystem check to
just before a directory is traversed. This obsoletes the function
skip_filesystem() to test the parent directory. The mount point itself
is still included, but its contents is skipped.

-- 
Dick Streefland                      ////                      Altium BV
dick.streefland at altium.nl           (@ @)          http://www.altium.com
--------------------------------oOO--(_)--OOo---------------------------
-------------- next part --------------
--- rsync-2.6.0/flist.c.orig	2003-12-15 09:10:31.000000000 +0100
+++ rsync-2.6.0/flist.c	2004-02-02 10:35:06.000000000 +0100
@@ -618,32 +618,6 @@ static void receive_file_entry(struct fi
 }
 
 
-/* determine if a file in a different filesstem should be skipped
-   when one_file_system is set. We bascally only want to include
-   the mount points - but they can be hard to find! */
-static int skip_filesystem(char *fname, STRUCT_STAT * st)
-{
-	STRUCT_STAT st2;
-	char *p = strrchr(fname, '/');
-
-	/* skip all but directories */
-	if (!S_ISDIR(st->st_mode))
-		return 1;
-
-	/* if its not a subdirectory then allow */
-	if (!p)
-		return 0;
-
-	*p = 0;
-	if (link_stat(fname, &st2)) {
-		*p = '/';
-		return 0;
-	}
-	*p = '/';
-
-	return (st2.st_dev != filesystem_dev);
-}
-
 #define STRDUP(ap, p)	(ap ? string_area_strdup(ap, p) : strdup(p))
 /* IRIX cc cares that the operands to the ternary have the same type. */
 #define MALLOC(ap, i)	(ap ? (void*) string_area_malloc(ap, i) : malloc(i))
@@ -710,11 +684,6 @@ struct file_struct *make_file(char *fnam
 		return NULL;
 	}
 
-	if (one_file_system && st.st_dev != filesystem_dev) {
-		if (skip_filesystem(fname, &st))
-			return NULL;
-	}
-
 	if (check_exclude_file(fname, S_ISDIR(st.st_mode) != 0, exclude_level))
 		return NULL;
 
@@ -825,6 +794,8 @@ void send_file_name(int f, struct file_l
 	}
 
 	if (S_ISDIR(file->mode) && recursive) {
+		if (one_file_system && file->dev != filesystem_dev)
+			return;
 		struct exclude_struct **last_exclude_list =
 		    local_exclude_list;
 		send_directory(f, flist, f_name(file));


More information about the rsync mailing list