diff options
author | Filipe Manana <fdmanana@gmail.com> | 2014-02-20 19:01:32 -0500 |
---|---|---|
committer | Josef Bacik <jbacik@fb.com> | 2014-03-10 15:16:51 -0400 |
commit | bf0d1f441d1679136c25e6141dd7e66cc7a14218 (patch) | |
tree | 759d60c75d7f47e05df2aacf563e972fba007d8b /fs/btrfs/send.c | |
parent | 6baa4293af8abe95018e911c3df60ed5bfacc76f (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.c | 31 |
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 | */ |
2001 | static int __get_cur_name_and_parent(struct send_ctx *sctx, | 2001 | static 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 | ||
2059 | get_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 | ||
2091 | out_cache: | 2085 | out_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) |