aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/send.c
diff options
context:
space:
mode:
authorFilipe Manana <fdmanana@gmail.com>2014-02-20 19:01:32 -0500
committerJosef Bacik <jbacik@fb.com>2014-03-10 15:16:51 -0400
commitbf0d1f441d1679136c25e6141dd7e66cc7a14218 (patch)
tree759d60c75d7f47e05df2aacf563e972fba007d8b /fs/btrfs/send.c
parent6baa4293af8abe95018e911c3df60ed5bfacc76f (diff)
Btrfs: fix send issuing outdated paths for utimes, chown and chmod
When doing an incremental send, if we had a directory pending a move/rename operation and none of its parents, except for the immediate parent, were pending a move/rename, after processing the directory's references, we would be issuing utimes, chown and chmod intructions against am outdated path - a path which matched the one in the parent root. This change also simplifies a bit the code that deals with building a path for a directory which has a move/rename operation delayed. Steps to reproduce: $ mkfs.btrfs -f /dev/sdb3 $ mount /dev/sdb3 /mnt/btrfs $ mkdir -p /mnt/btrfs/a/b/c/d/e $ mkdir /mnt/btrfs/a/b/c/f $ chmod 0777 /mnt/btrfs/a/b/c/d/e $ btrfs subvolume snapshot -r /mnt/btrfs /mnt/btrfs/snap1 $ btrfs send /mnt/btrfs/snap1 -f /tmp/base.send $ mv /mnt/btrfs/a/b/c/f /mnt/btrfs/a/b/f2 $ mv /mnt/btrfs/a/b/c/d/e /mnt/btrfs/a/b/f2/e2 $ mv /mnt/btrfs/a/b/c /mnt/btrfs/a/b/c2 $ mv /mnt/btrfs/a/b/c2/d /mnt/btrfs/a/b/c2/d2 $ chmod 0700 /mnt/btrfs/a/b/f2/e2 $ btrfs subvolume snapshot -r /mnt/btrfs /mnt/btrfs/snap2 $ btrfs send -p /mnt/btrfs/snap1 /mnt/btrfs/snap2 -f /tmp/incremental.send $ umount /mnt/btrfs $ mkfs.btrfs -f /dev/sdb3 $ mount /dev/sdb3 /mnt/btrfs $ btrfs receive /mnt/btrfs -f /tmp/base.send $ btrfs receive /mnt/btrfs -f /tmp/incremental.send The second btrfs receive command failed with: ERROR: chmod a/b/c/d/e failed. No such file or directory A test case for xfstests follows. Signed-off-by: Filipe David Borba Manana <fdmanana@gmail.com> Signed-off-by: Josef Bacik <jbacik@fb.com>
Diffstat (limited to 'fs/btrfs/send.c')
-rw-r--r--fs/btrfs/send.c31
1 files changed, 12 insertions, 19 deletions
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index 46c6b5442f20..298e25de13ab 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -2000,7 +2000,6 @@ static void name_cache_free(struct send_ctx *sctx)
2000 */ 2000 */
2001static int __get_cur_name_and_parent(struct send_ctx *sctx, 2001static int __get_cur_name_and_parent(struct send_ctx *sctx,
2002 u64 ino, u64 gen, 2002 u64 ino, u64 gen,
2003 int skip_name_cache,
2004 u64 *parent_ino, 2003 u64 *parent_ino,
2005 u64 *parent_gen, 2004 u64 *parent_gen,
2006 struct fs_path *dest) 2005 struct fs_path *dest)
@@ -2010,8 +2009,6 @@ static int __get_cur_name_and_parent(struct send_ctx *sctx,
2010 struct btrfs_path *path = NULL; 2009 struct btrfs_path *path = NULL;
2011 struct name_cache_entry *nce = NULL; 2010 struct name_cache_entry *nce = NULL;
2012 2011
2013 if (skip_name_cache)
2014 goto get_ref;
2015 /* 2012 /*
2016 * First check if we already did a call to this function with the same 2013 * First check if we already did a call to this function with the same
2017 * ino/gen. If yes, check if the cache entry is still up-to-date. If yes 2014 * ino/gen. If yes, check if the cache entry is still up-to-date. If yes
@@ -2056,12 +2053,11 @@ static int __get_cur_name_and_parent(struct send_ctx *sctx,
2056 goto out_cache; 2053 goto out_cache;
2057 } 2054 }
2058 2055
2059get_ref:
2060 /* 2056 /*
2061 * Depending on whether the inode was already processed or not, use 2057 * Depending on whether the inode was already processed or not, use
2062 * send_root or parent_root for ref lookup. 2058 * send_root or parent_root for ref lookup.
2063 */ 2059 */
2064 if (ino < sctx->send_progress && !skip_name_cache) 2060 if (ino < sctx->send_progress)
2065 ret = get_first_ref(sctx->send_root, ino, 2061 ret = get_first_ref(sctx->send_root, ino,
2066 parent_ino, parent_gen, dest); 2062 parent_ino, parent_gen, dest);
2067 else 2063 else
@@ -2085,8 +2081,6 @@ get_ref:
2085 goto out; 2081 goto out;
2086 ret = 1; 2082 ret = 1;
2087 } 2083 }
2088 if (skip_name_cache)
2089 goto out;
2090 2084
2091out_cache: 2085out_cache:
2092 /* 2086 /*
@@ -2154,7 +2148,6 @@ static int get_cur_path(struct send_ctx *sctx, u64 ino, u64 gen,
2154 u64 parent_inode = 0; 2148 u64 parent_inode = 0;
2155 u64 parent_gen = 0; 2149 u64 parent_gen = 0;
2156 int stop = 0; 2150 int stop = 0;
2157 int skip_name_cache = 0;
2158 2151
2159 name = fs_path_alloc(); 2152 name = fs_path_alloc();
2160 if (!name) { 2153 if (!name) {
@@ -2162,9 +2155,6 @@ static int get_cur_path(struct send_ctx *sctx, u64 ino, u64 gen,
2162 goto out; 2155 goto out;
2163 } 2156 }
2164 2157
2165 if (is_waiting_for_move(sctx, ino))
2166 skip_name_cache = 1;
2167
2168 dest->reversed = 1; 2158 dest->reversed = 1;
2169 fs_path_reset(dest); 2159 fs_path_reset(dest);
2170 2160
@@ -2179,16 +2169,19 @@ static int get_cur_path(struct send_ctx *sctx, u64 ino, u64 gen,
2179 break; 2169 break;
2180 } 2170 }
2181 2171
2182 ret = __get_cur_name_and_parent(sctx, ino, gen, skip_name_cache, 2172 if (is_waiting_for_move(sctx, ino)) {
2183 &parent_inode, &parent_gen, name); 2173 ret = get_first_ref(sctx->parent_root, ino,
2174 &parent_inode, &parent_gen, name);
2175 } else {
2176 ret = __get_cur_name_and_parent(sctx, ino, gen,
2177 &parent_inode,
2178 &parent_gen, name);
2179 if (ret)
2180 stop = 1;
2181 }
2182
2184 if (ret < 0) 2183 if (ret < 0)
2185 goto out; 2184 goto out;
2186 if (ret)
2187 stop = 1;
2188
2189 if (!skip_name_cache &&
2190 is_waiting_for_move(sctx, parent_inode))
2191 skip_name_cache = 1;
2192 2185
2193 ret = fs_path_add_path(dest, name); 2186 ret = fs_path_add_path(dest, name);
2194 if (ret < 0) 2187 if (ret < 0)