* [PATCH 0/3] btrfs: log replay bug fixes and cleanup
@ 2025-07-11 20:26 fdmanana
2025-07-11 20:26 ` [PATCH 1/3] btrfs: don't ignore inode missing when replaying log tree fdmanana
` (3 more replies)
0 siblings, 4 replies; 9+ messages in thread
From: fdmanana @ 2025-07-11 20:26 UTC (permalink / raw)
To: linux-btrfs
From: Filipe Manana <fdmanana@suse.com>
A couple bug fixes for log replay and a cleanup.
Filipe Manana (3):
btrfs: don't ignore inode missing when replaying log tree
btrfs: don't skip remaining extrefs if dir not found during log replay
btrfs: use saner variable type and name to indicate extrefs at add_inode_ref()
fs/btrfs/tree-log.c | 35 +++++++++++++++++++++++++++--------
1 file changed, 27 insertions(+), 8 deletions(-)
--
2.47.2
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH 1/3] btrfs: don't ignore inode missing when replaying log tree 2025-07-11 20:26 [PATCH 0/3] btrfs: log replay bug fixes and cleanup fdmanana @ 2025-07-11 20:26 ` fdmanana 2025-07-11 20:26 ` [PATCH 2/3] btrfs: don't skip remaining extrefs if dir not found during log replay fdmanana ` (2 subsequent siblings) 3 siblings, 0 replies; 9+ messages in thread From: fdmanana @ 2025-07-11 20:26 UTC (permalink / raw) To: linux-btrfs From: Filipe Manana <fdmanana@suse.com> During log replay, at add_inode_ref(), we return -ENOENT if our current inode isn't found on the subvolume tree or if a parent directory isn't found. The error comes from btrfs_iget_logging() <- btrfs_iget() <- btrfs_read_locked_inode(). The single caller of add_inode_ref(), replay_one_buffer(), ignores an -ENOENT error because it expects that error to mean only that a parent directory wasn't found and that is ok. Before commit 5f61b961599a ("btrfs: fix inode lookup error handling during log replay") we were converting any error when getting a parent directory to -ENOENT and any error when getting the current inode to -EIO, so our caller would fail log replay in case we can't find the current inode. After that commit however in case the current inode is not found we return -ENOENT to the caller and therefore it ignores the critical fact that the current inode was not found in the subvolume tree. Fix this by converting -ENOENT to 0 when we don't find a parent directory, returning -ENOENT when we don't find the current inode and making the caller, replay_one_buffer(), not ignore -ENOENT anymore. Fixes: 5f61b961599a ("btrfs: fix inode lookup error handling during log replay") Signed-off-by: Filipe Manana <fdmanana@suse.com> --- fs/btrfs/tree-log.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 5bdd89c44193..beb47a603411 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -1416,6 +1416,8 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, dir = btrfs_iget_logging(parent_objectid, root); if (IS_ERR(dir)) { ret = PTR_ERR(dir); + if (ret == -ENOENT) + ret = 0; dir = NULL; goto out; } @@ -1440,6 +1442,15 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, if (IS_ERR(dir)) { ret = PTR_ERR(dir); dir = NULL; + /* + * A new parent dir may have not been + * logged and not exist in the subvolume + * tree, see the comment above before + * the loop when getting the first + * parent dir. + */ + if (ret == -ENOENT) + ret = 0; goto out; } } @@ -2551,9 +2562,8 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb, key.type == BTRFS_INODE_EXTREF_KEY) { ret = add_inode_ref(wc->trans, root, log, path, eb, i, &key); - if (ret && ret != -ENOENT) + if (ret) break; - ret = 0; } else if (key.type == BTRFS_EXTENT_DATA_KEY) { ret = replay_one_extent(wc->trans, root, path, eb, i, &key); -- 2.47.2 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 2/3] btrfs: don't skip remaining extrefs if dir not found during log replay 2025-07-11 20:26 [PATCH 0/3] btrfs: log replay bug fixes and cleanup fdmanana 2025-07-11 20:26 ` [PATCH 1/3] btrfs: don't ignore inode missing when replaying log tree fdmanana @ 2025-07-11 20:26 ` fdmanana 2025-07-11 20:26 ` [PATCH 3/3] btrfs: use saner variable type and name to indicate extrefs at add_inode_ref() fdmanana 2025-07-11 20:36 ` [PATCH v2 0/3] btrfs: log replay bug fixes and cleanup fdmanana 3 siblings, 0 replies; 9+ messages in thread From: fdmanana @ 2025-07-11 20:26 UTC (permalink / raw) To: linux-btrfs From: Filipe Manana <fdmanana@suse.com> During log replay, at add_inode_ref(), if we have an extref item that contains multiple extrefs and one of them points to a directory that does not exist in the subvolume tree, we are supposed to ignore it and process the remaining extrefs encoded in the extref item, since each extref can point to a different parent inode. However when that happens we just return from the function and ignore the remaining extrefs. The problem has been around since extrefs were introduced, in commit f186373fef00 ("btrfs: extended inode refs"), but it's hard to hit in practice because getting extref items encoding multiple extref requires getting a hash collision when computing the offset of the extref's key. The offset if computed like this: key.offset = btrfs_extref_hash(dir_ino, name->name, name->len); and btrfs_extref_hash() is just a wrapper around crc32c(). Fix this by moving to next iteration of the loop when we don't find the parent directory that an extref points to. Fixes: f186373fef00 ("btrfs: extended inode refs") Signed-off-by: Filipe Manana <fdmanana@suse.com> --- fs/btrfs/tree-log.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index beb47a603411..bbd1fca19022 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -1433,6 +1433,8 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, if (log_ref_ver) { ret = extref_get_fields(eb, ref_ptr, &name, &ref_index, &parent_objectid); + if (ret) + goto out; /* * parent object can change from one array * item to another. @@ -1449,16 +1451,23 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, * the loop when getting the first * parent dir. */ - if (ret == -ENOENT) + if (ret == -ENOENT) { + /* + * The next extref may refer to + * another parent dir that + * exists, so continue. + */ ret = 0; + goto next; + } goto out; } } } else { ret = ref_get_fields(eb, ref_ptr, &name, &ref_index); + if (ret) + goto out; } - if (ret) - goto out; ret = inode_in_dir(root, path, btrfs_ino(dir), btrfs_ino(inode), ref_index, &name); @@ -1492,6 +1501,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, } /* Else, ret == 1, we already have a perfect match, we're done. */ +next: ref_ptr = (unsigned long)(ref_ptr + ref_struct_size) + name.len; kfree(name.name); name.name = NULL; -- 2.47.2 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 3/3] btrfs: use saner variable type and name to indicate extrefs at add_inode_ref() 2025-07-11 20:26 [PATCH 0/3] btrfs: log replay bug fixes and cleanup fdmanana 2025-07-11 20:26 ` [PATCH 1/3] btrfs: don't ignore inode missing when replaying log tree fdmanana 2025-07-11 20:26 ` [PATCH 2/3] btrfs: don't skip remaining extrefs if dir not found during log replay fdmanana @ 2025-07-11 20:26 ` fdmanana 2025-07-11 20:36 ` [PATCH v2 0/3] btrfs: log replay bug fixes and cleanup fdmanana 3 siblings, 0 replies; 9+ messages in thread From: fdmanana @ 2025-07-11 20:26 UTC (permalink / raw) To: linux-btrfs From: Filipe Manana <fdmanana@suse.com> We are using a variable named 'log_ref_ver' of type int to indicate if we are processing an extref item or not, using a value of 1 if so, otherwise 0. This is an odd name and type, so rename it to 'is_extref_item' and change its type to bool. Signed-off-by: Filipe Manana <fdmanana@suse.com> --- fs/btrfs/tree-log.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index bbd1fca19022..9366a3bd2836 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -1385,7 +1385,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, unsigned long ref_end; struct fscrypt_str name = { 0 }; int ret; - int log_ref_ver = 0; + const bool is_extref_item = (key->type == BTRFS_INODE_EXTREF_KEY); u64 parent_objectid; u64 inode_objectid; u64 ref_index = 0; @@ -1398,7 +1398,6 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, struct btrfs_inode_extref *r; ref_struct_size = sizeof(struct btrfs_inode_extref); - log_ref_ver = 1; r = (struct btrfs_inode_extref *)ref_ptr; parent_objectid = btrfs_inode_extref_parent(eb, r); } else { @@ -1430,7 +1429,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, } while (ref_ptr < ref_end) { - if (log_ref_ver) { + if (is_extref_item) { ret = extref_get_fields(eb, ref_ptr, &name, &ref_index, &parent_objectid); if (ret) @@ -1505,7 +1504,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, ref_ptr = (unsigned long)(ref_ptr + ref_struct_size) + name.len; kfree(name.name); name.name = NULL; - if (log_ref_ver) { + if (is_extref_item) { iput(&dir->vfs_inode); dir = NULL; } -- 2.47.2 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 0/3] btrfs: log replay bug fixes and cleanup 2025-07-11 20:26 [PATCH 0/3] btrfs: log replay bug fixes and cleanup fdmanana ` (2 preceding siblings ...) 2025-07-11 20:26 ` [PATCH 3/3] btrfs: use saner variable type and name to indicate extrefs at add_inode_ref() fdmanana @ 2025-07-11 20:36 ` fdmanana 2025-07-11 20:36 ` [PATCH v2 1/3] btrfs: don't ignore inode missing when replaying log tree fdmanana ` (3 more replies) 3 siblings, 4 replies; 9+ messages in thread From: fdmanana @ 2025-07-11 20:36 UTC (permalink / raw) To: linux-btrfs From: Filipe Manana <fdmanana@suse.com> A couple bug fixes for log replay and a cleanup. V2: Updated patch 2/3 to avoid a NULL pointer deref on directory. Filipe Manana (3): btrfs: don't ignore inode missing when replaying log tree btrfs: don't skip remaining extrefs if dir not found during log replay btrfs: use saner variable type and name to indicate extrefs at add_inode_ref() fs/btrfs/tree-log.c | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) -- 2.47.2 ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 1/3] btrfs: don't ignore inode missing when replaying log tree 2025-07-11 20:36 ` [PATCH v2 0/3] btrfs: log replay bug fixes and cleanup fdmanana @ 2025-07-11 20:36 ` fdmanana 2025-07-11 20:36 ` [PATCH v2 2/3] btrfs: don't skip remaining extrefs if dir not found during log replay fdmanana ` (2 subsequent siblings) 3 siblings, 0 replies; 9+ messages in thread From: fdmanana @ 2025-07-11 20:36 UTC (permalink / raw) To: linux-btrfs From: Filipe Manana <fdmanana@suse.com> During log replay, at add_inode_ref(), we return -ENOENT if our current inode isn't found on the subvolume tree or if a parent directory isn't found. The error comes from btrfs_iget_logging() <- btrfs_iget() <- btrfs_read_locked_inode(). The single caller of add_inode_ref(), replay_one_buffer(), ignores an -ENOENT error because it expects that error to mean only that a parent directory wasn't found and that is ok. Before commit 5f61b961599a ("btrfs: fix inode lookup error handling during log replay") we were converting any error when getting a parent directory to -ENOENT and any error when getting the current inode to -EIO, so our caller would fail log replay in case we can't find the current inode. After that commit however in case the current inode is not found we return -ENOENT to the caller and therefore it ignores the critical fact that the current inode was not found in the subvolume tree. Fix this by converting -ENOENT to 0 when we don't find a parent directory, returning -ENOENT when we don't find the current inode and making the caller, replay_one_buffer(), not ignore -ENOENT anymore. Fixes: 5f61b961599a ("btrfs: fix inode lookup error handling during log replay") Signed-off-by: Filipe Manana <fdmanana@suse.com> --- fs/btrfs/tree-log.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 5bdd89c44193..beb47a603411 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -1416,6 +1416,8 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, dir = btrfs_iget_logging(parent_objectid, root); if (IS_ERR(dir)) { ret = PTR_ERR(dir); + if (ret == -ENOENT) + ret = 0; dir = NULL; goto out; } @@ -1440,6 +1442,15 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, if (IS_ERR(dir)) { ret = PTR_ERR(dir); dir = NULL; + /* + * A new parent dir may have not been + * logged and not exist in the subvolume + * tree, see the comment above before + * the loop when getting the first + * parent dir. + */ + if (ret == -ENOENT) + ret = 0; goto out; } } @@ -2551,9 +2562,8 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb, key.type == BTRFS_INODE_EXTREF_KEY) { ret = add_inode_ref(wc->trans, root, log, path, eb, i, &key); - if (ret && ret != -ENOENT) + if (ret) break; - ret = 0; } else if (key.type == BTRFS_EXTENT_DATA_KEY) { ret = replay_one_extent(wc->trans, root, path, eb, i, &key); -- 2.47.2 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 2/3] btrfs: don't skip remaining extrefs if dir not found during log replay 2025-07-11 20:36 ` [PATCH v2 0/3] btrfs: log replay bug fixes and cleanup fdmanana 2025-07-11 20:36 ` [PATCH v2 1/3] btrfs: don't ignore inode missing when replaying log tree fdmanana @ 2025-07-11 20:36 ` fdmanana 2025-07-11 20:36 ` [PATCH v2 3/3] btrfs: use saner variable type and name to indicate extrefs at add_inode_ref() fdmanana 2025-07-17 17:53 ` [PATCH v2 0/3] btrfs: log replay bug fixes and cleanup Boris Burkov 3 siblings, 0 replies; 9+ messages in thread From: fdmanana @ 2025-07-11 20:36 UTC (permalink / raw) To: linux-btrfs From: Filipe Manana <fdmanana@suse.com> During log replay, at add_inode_ref(), if we have an extref item that contains multiple extrefs and one of them points to a directory that does not exist in the subvolume tree, we are supposed to ignore it and process the remaining extrefs encoded in the extref item, since each extref can point to a different parent inode. However when that happens we just return from the function and ignore the remaining extrefs. The problem has been around since extrefs were introduced, in commit f186373fef00 ("btrfs: extended inode refs"), but it's hard to hit in practice because getting extref items encoding multiple extref requires getting a hash collision when computing the offset of the extref's key. The offset if computed like this: key.offset = btrfs_extref_hash(dir_ino, name->name, name->len); and btrfs_extref_hash() is just a wrapper around crc32c(). Fix this by moving to next iteration of the loop when we don't find the parent directory that an extref points to. Fixes: f186373fef00 ("btrfs: extended inode refs") Signed-off-by: Filipe Manana <fdmanana@suse.com> --- fs/btrfs/tree-log.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index beb47a603411..354761a8cbc1 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -1433,6 +1433,8 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, if (log_ref_ver) { ret = extref_get_fields(eb, ref_ptr, &name, &ref_index, &parent_objectid); + if (ret) + goto out; /* * parent object can change from one array * item to another. @@ -1449,16 +1451,23 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, * the loop when getting the first * parent dir. */ - if (ret == -ENOENT) + if (ret == -ENOENT) { + /* + * The next extref may refer to + * another parent dir that + * exists, so continue. + */ ret = 0; + goto next; + } goto out; } } } else { ret = ref_get_fields(eb, ref_ptr, &name, &ref_index); + if (ret) + goto out; } - if (ret) - goto out; ret = inode_in_dir(root, path, btrfs_ino(dir), btrfs_ino(inode), ref_index, &name); @@ -1492,10 +1501,11 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, } /* Else, ret == 1, we already have a perfect match, we're done. */ +next: ref_ptr = (unsigned long)(ref_ptr + ref_struct_size) + name.len; kfree(name.name); name.name = NULL; - if (log_ref_ver) { + if (log_ref_ver && dir) { iput(&dir->vfs_inode); dir = NULL; } -- 2.47.2 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 3/3] btrfs: use saner variable type and name to indicate extrefs at add_inode_ref() 2025-07-11 20:36 ` [PATCH v2 0/3] btrfs: log replay bug fixes and cleanup fdmanana 2025-07-11 20:36 ` [PATCH v2 1/3] btrfs: don't ignore inode missing when replaying log tree fdmanana 2025-07-11 20:36 ` [PATCH v2 2/3] btrfs: don't skip remaining extrefs if dir not found during log replay fdmanana @ 2025-07-11 20:36 ` fdmanana 2025-07-17 17:53 ` [PATCH v2 0/3] btrfs: log replay bug fixes and cleanup Boris Burkov 3 siblings, 0 replies; 9+ messages in thread From: fdmanana @ 2025-07-11 20:36 UTC (permalink / raw) To: linux-btrfs From: Filipe Manana <fdmanana@suse.com> We are using a variable named 'log_ref_ver' of type int to indicate if we are processing an extref item or not, using a value of 1 if so, otherwise 0. This is an odd name and type, so rename it to 'is_extref_item' and change its type to bool. Signed-off-by: Filipe Manana <fdmanana@suse.com> --- fs/btrfs/tree-log.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 354761a8cbc1..8ad6005257b8 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -1385,7 +1385,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, unsigned long ref_end; struct fscrypt_str name = { 0 }; int ret; - int log_ref_ver = 0; + const bool is_extref_item = (key->type == BTRFS_INODE_EXTREF_KEY); u64 parent_objectid; u64 inode_objectid; u64 ref_index = 0; @@ -1394,11 +1394,10 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, ref_ptr = btrfs_item_ptr_offset(eb, slot); ref_end = ref_ptr + btrfs_item_size(eb, slot); - if (key->type == BTRFS_INODE_EXTREF_KEY) { + if (is_extref_item) { struct btrfs_inode_extref *r; ref_struct_size = sizeof(struct btrfs_inode_extref); - log_ref_ver = 1; r = (struct btrfs_inode_extref *)ref_ptr; parent_objectid = btrfs_inode_extref_parent(eb, r); } else { @@ -1430,7 +1429,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, } while (ref_ptr < ref_end) { - if (log_ref_ver) { + if (is_extref_item) { ret = extref_get_fields(eb, ref_ptr, &name, &ref_index, &parent_objectid); if (ret) @@ -1505,7 +1504,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, ref_ptr = (unsigned long)(ref_ptr + ref_struct_size) + name.len; kfree(name.name); name.name = NULL; - if (log_ref_ver && dir) { + if (is_extref_item && dir) { iput(&dir->vfs_inode); dir = NULL; } -- 2.47.2 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v2 0/3] btrfs: log replay bug fixes and cleanup 2025-07-11 20:36 ` [PATCH v2 0/3] btrfs: log replay bug fixes and cleanup fdmanana ` (2 preceding siblings ...) 2025-07-11 20:36 ` [PATCH v2 3/3] btrfs: use saner variable type and name to indicate extrefs at add_inode_ref() fdmanana @ 2025-07-17 17:53 ` Boris Burkov 3 siblings, 0 replies; 9+ messages in thread From: Boris Burkov @ 2025-07-17 17:53 UTC (permalink / raw) To: fdmanana; +Cc: linux-btrfs On Fri, Jul 11, 2025 at 09:36:37PM +0100, fdmanana@kernel.org wrote: > From: Filipe Manana <fdmanana@suse.com> > > A couple bug fixes for log replay and a cleanup. > > V2: Updated patch 2/3 to avoid a NULL pointer deref on directory. Looks good, thanks. Reviewed-by: Boris Burkov <boris@bur.io> > > Filipe Manana (3): > btrfs: don't ignore inode missing when replaying log tree > btrfs: don't skip remaining extrefs if dir not found during log replay > btrfs: use saner variable type and name to indicate extrefs at add_inode_ref() > > fs/btrfs/tree-log.c | 37 ++++++++++++++++++++++++++++--------- > 1 file changed, 28 insertions(+), 9 deletions(-) > > -- > 2.47.2 > ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2025-07-17 17:52 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-07-11 20:26 [PATCH 0/3] btrfs: log replay bug fixes and cleanup fdmanana 2025-07-11 20:26 ` [PATCH 1/3] btrfs: don't ignore inode missing when replaying log tree fdmanana 2025-07-11 20:26 ` [PATCH 2/3] btrfs: don't skip remaining extrefs if dir not found during log replay fdmanana 2025-07-11 20:26 ` [PATCH 3/3] btrfs: use saner variable type and name to indicate extrefs at add_inode_ref() fdmanana 2025-07-11 20:36 ` [PATCH v2 0/3] btrfs: log replay bug fixes and cleanup fdmanana 2025-07-11 20:36 ` [PATCH v2 1/3] btrfs: don't ignore inode missing when replaying log tree fdmanana 2025-07-11 20:36 ` [PATCH v2 2/3] btrfs: don't skip remaining extrefs if dir not found during log replay fdmanana 2025-07-11 20:36 ` [PATCH v2 3/3] btrfs: use saner variable type and name to indicate extrefs at add_inode_ref() fdmanana 2025-07-17 17:53 ` [PATCH v2 0/3] btrfs: log replay bug fixes and cleanup Boris Burkov
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox