Add an arg 'ignore_existed' to btrfs_add_link. If ignore_existed=1, continue to add while relative dir index/item or inode ref is already existed.
This patch is for further repair. Signed-off-by: Su Yue <suy.f...@cn.fujitsu.com> --- cmds-check.c | 6 +++--- convert/main.c | 2 +- ctree.h | 2 +- inode.c | 46 ++++++++++++++++++++++++++-------------------- 4 files changed, 31 insertions(+), 25 deletions(-) diff --git a/cmds-check.c b/cmds-check.c index 685f4f5d..bda0849b 100644 --- a/cmds-check.c +++ b/cmds-check.c @@ -2855,7 +2855,7 @@ static int reset_nlink(struct btrfs_trans_handle *trans, list_for_each_entry(backref, &rec->backrefs, list) { ret = btrfs_add_link(trans, root, rec->ino, backref->dir, backref->name, backref->namelen, - backref->filetype, &backref->index, 1); + backref->filetype, &backref->index, 1, 0); if (ret < 0) goto out; } @@ -2947,7 +2947,7 @@ static int repair_inode_nlinks(struct btrfs_trans_handle *trans, goto out; } ret = btrfs_add_link(trans, root, rec->ino, lost_found_ino, - namebuf, namelen, type, NULL, 1); + namebuf, namelen, type, NULL, 1, 0); /* * Add ".INO" suffix several times to handle case where * "FILENAME.INO" is already taken by another file. @@ -2966,7 +2966,7 @@ static int repair_inode_nlinks(struct btrfs_trans_handle *trans, namelen += count_digits(rec->ino) + 1; ret = btrfs_add_link(trans, root, rec->ino, lost_found_ino, namebuf, - namelen, type, NULL, 1); + namelen, type, NULL, 1, 0); } if (ret < 0) { fprintf(stderr, diff --git a/convert/main.c b/convert/main.c index 8d9f29fa..7607bec1 100644 --- a/convert/main.c +++ b/convert/main.c @@ -998,7 +998,7 @@ static int create_image(struct btrfs_root *root, if (ret < 0) goto out; ret = btrfs_add_link(trans, root, ino, BTRFS_FIRST_FREE_OBJECTID, name, - strlen(name), BTRFS_FT_REG_FILE, NULL, 1); + strlen(name), BTRFS_FT_REG_FILE, NULL, 1, 0); if (ret < 0) goto out; diff --git a/ctree.h b/ctree.h index 0c34ae20..a28e36de 100644 --- a/ctree.h +++ b/ctree.h @@ -2779,7 +2779,7 @@ int btrfs_change_inode_flags(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 ino, u64 flags); int btrfs_add_link(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 ino, u64 parent_ino, char *name, int namelen, - u8 type, u64 *index, int add_backref); + u8 type, u64 *index, int add_backref, int ignore_existed); int btrfs_unlink(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 ino, u64 parent_ino, u64 index, const char *name, int namelen, int add_orphan); diff --git a/inode.c b/inode.c index 991b8ddb..62e8abec 100644 --- a/inode.c +++ b/inode.c @@ -161,7 +161,7 @@ out: */ int btrfs_add_link(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 ino, u64 parent_ino, char *name, int namelen, - u8 type, u64 *index, int add_backref) + u8 type, u64 *index, int add_backref, int ignore_existed) { struct btrfs_path *path; struct btrfs_key key; @@ -184,33 +184,38 @@ int btrfs_add_link(struct btrfs_trans_handle *trans, struct btrfs_root *root, } ret = check_dir_conflict(root, name, namelen, parent_ino, ret_index); - if (ret < 0) + if (ret < 0 && (!ignore_existed || ret != -EEXIST)) goto out; /* Add inode ref */ if (add_backref) { ret = btrfs_insert_inode_ref(trans, root, name, namelen, ino, parent_ino, ret_index); - if (ret < 0) + if (ret < 0 && (!ignore_existed || ret != -EEXIST)) goto out; - /* Update nlinks for the inode */ - key.objectid = ino; - key.type = BTRFS_INODE_ITEM_KEY; - key.offset = 0; - ret = btrfs_search_slot(trans, root, &key, path, 1, 1); - if (ret) { - if (ret > 0) - ret = -ENOENT; - goto out; + /* do not update nlinks if existed */ + if (!ret) { + /* Update nlinks for the inode */ + key.objectid = ino; + key.type = BTRFS_INODE_ITEM_KEY; + key.offset = 0; + ret = btrfs_search_slot(trans, root, &key, path, 1, 1); + if (ret) { + if (ret > 0) + ret = -ENOENT; + goto out; + } + inode_item = btrfs_item_ptr(path->nodes[0], + path->slots[0], + struct btrfs_inode_item); + nlink = btrfs_inode_nlink(path->nodes[0], inode_item); + nlink++; + btrfs_set_inode_nlink(path->nodes[0], inode_item, + nlink); + btrfs_mark_buffer_dirty(path->nodes[0]); + btrfs_release_path(path); } - inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_inode_item); - nlink = btrfs_inode_nlink(path->nodes[0], inode_item); - nlink++; - btrfs_set_inode_nlink(path->nodes[0], inode_item, nlink); - btrfs_mark_buffer_dirty(path->nodes[0]); - btrfs_release_path(path); } /* Add dir_item and dir_index */ @@ -219,6 +224,7 @@ int btrfs_add_link(struct btrfs_trans_handle *trans, struct btrfs_root *root, key.offset = 0; ret = btrfs_insert_dir_item(trans, root, name, namelen, parent_ino, &key, type, ret_index); + if (ret < 0) goto out; @@ -561,7 +567,7 @@ int btrfs_mkdir(struct btrfs_trans_handle *trans, struct btrfs_root *root, if (ret) goto out; ret = btrfs_add_link(trans, root, ret_ino, parent_ino, name, namelen, - BTRFS_FT_DIR, NULL, 1); + BTRFS_FT_DIR, NULL, 1, 0); if (ret) goto out; out: -- 2.11.1 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html