summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSu Yue <suy.fnst@cn.fujitsu.com>2017-08-28 15:48:16 +0800
committerDavid Sterba <dsterba@suse.com>2017-10-16 20:33:00 +0200
commitcac2b0390de8cd4f9a79ddf7e9a6a6e9522cef56 (patch)
treeba6d784a3facca5fc85582bdc4044c86be7abf35
parent3efc459166ad8d104912ec06c4ec9e0db6b7ef79 (diff)
btrfs-progs: check: introduce repair_inode_item_missing()
Introduce __create_inode_item() to create a new inode item. It is called by create_inode_item() and create_inode_item_lowmem(). Function repair_inode_item_missing() just adds a new inode item. Signed-off-by: Su Yue <suy.fnst@cn.fujitsu.com> Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r--cmds-check.c128
1 files changed, 96 insertions, 32 deletions
diff --git a/cmds-check.c b/cmds-check.c
index 4f3958b9..17ce0bb1 100644
--- a/cmds-check.c
+++ b/cmds-check.c
@@ -2691,13 +2691,54 @@ static int delete_dir_index(struct btrfs_root *root,
return ret;
}
+static int __create_inode_item(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, u64 ino, u64 size,
+ u64 nbytes, u64 nlink, u32 mode)
+{
+ struct btrfs_inode_item ii;
+ time_t now = time(NULL);
+ int ret;
+
+ btrfs_set_stack_inode_size(&ii, size);
+ btrfs_set_stack_inode_nbytes(&ii, nbytes);
+ btrfs_set_stack_inode_nlink(&ii, nlink);
+ btrfs_set_stack_inode_mode(&ii, mode);
+ btrfs_set_stack_inode_generation(&ii, trans->transid);
+ btrfs_set_stack_timespec_nsec(&ii.atime, 0);
+ btrfs_set_stack_timespec_sec(&ii.ctime, now);
+ btrfs_set_stack_timespec_nsec(&ii.ctime, 0);
+ btrfs_set_stack_timespec_sec(&ii.mtime, now);
+ btrfs_set_stack_timespec_nsec(&ii.mtime, 0);
+ btrfs_set_stack_timespec_sec(&ii.otime, 0);
+ btrfs_set_stack_timespec_nsec(&ii.otime, 0);
+
+ ret = btrfs_insert_inode(trans, root, ino, &ii);
+ ASSERT(!ret);
+
+ warning("root %llu inode %llu recreating inode item, this may "
+ "be incomplete, please check permissions and content after "
+ "the fsck completes.\n", (unsigned long long)root->objectid,
+ (unsigned long long)ino);
+
+ return 0;
+}
+
+static int create_inode_item_lowmem(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, u64 ino,
+ u8 filetype)
+{
+ u32 mode = (filetype == BTRFS_FT_DIR ? S_IFDIR : S_IFREG) | 0755;
+
+ return __create_inode_item(trans, root, ino, 0, 0, 0, mode);
+}
+
static int create_inode_item(struct btrfs_root *root,
- struct inode_record *rec,
- int root_dir)
+ struct inode_record *rec, int root_dir)
{
struct btrfs_trans_handle *trans;
- struct btrfs_inode_item inode_item;
- time_t now = time(NULL);
+ u64 nlink = 0;
+ u32 mode = 0;
+ u64 size = 0;
int ret;
trans = btrfs_start_transaction(root, 1);
@@ -2706,18 +2747,7 @@ static int create_inode_item(struct btrfs_root *root,
return ret;
}
- fprintf(stderr, "root %llu inode %llu recreating inode item, this may "
- "be incomplete, please check permissions and content after "
- "the fsck completes.\n", (unsigned long long)root->objectid,
- (unsigned long long)rec->ino);
-
- memset(&inode_item, 0, sizeof(inode_item));
- btrfs_set_stack_inode_generation(&inode_item, trans->transid);
- if (root_dir)
- btrfs_set_stack_inode_nlink(&inode_item, 1);
- else
- btrfs_set_stack_inode_nlink(&inode_item, rec->found_link);
- btrfs_set_stack_inode_nbytes(&inode_item, rec->found_size);
+ nlink = root_dir ? 1 : rec->found_link;
if (rec->found_dir_item) {
if (rec->found_file_extent)
fprintf(stderr, "root %llu inode %llu has both a dir "
@@ -2725,23 +2755,15 @@ static int create_inode_item(struct btrfs_root *root,
"regular file so setting it as a directory\n",
(unsigned long long)root->objectid,
(unsigned long long)rec->ino);
- btrfs_set_stack_inode_mode(&inode_item, S_IFDIR | 0755);
- btrfs_set_stack_inode_size(&inode_item, rec->found_size);
+ mode = S_IFDIR | 0755;
+ size = rec->found_size;
} else if (!rec->found_dir_item) {
- btrfs_set_stack_inode_size(&inode_item, rec->extent_end);
- btrfs_set_stack_inode_mode(&inode_item, S_IFREG | 0755);
- }
- btrfs_set_stack_timespec_sec(&inode_item.atime, now);
- btrfs_set_stack_timespec_nsec(&inode_item.atime, 0);
- btrfs_set_stack_timespec_sec(&inode_item.ctime, now);
- btrfs_set_stack_timespec_nsec(&inode_item.ctime, 0);
- btrfs_set_stack_timespec_sec(&inode_item.mtime, now);
- btrfs_set_stack_timespec_nsec(&inode_item.mtime, 0);
- btrfs_set_stack_timespec_sec(&inode_item.otime, 0);
- btrfs_set_stack_timespec_nsec(&inode_item.otime, 0);
-
- ret = btrfs_insert_inode(trans, root, rec->ino, &inode_item);
- BUG_ON(ret);
+ size = rec->extent_end;
+ mode = S_IFREG | 0755;
+ }
+
+ ret = __create_inode_item(trans, root, rec->ino, size, rec->nbytes,
+ nlink, mode);
btrfs_commit_transaction(trans, root);
return 0;
}
@@ -4469,6 +4491,48 @@ static void print_inode_ref_err(struct btrfs_root *root, struct btrfs_key *key,
}
/*
+ * Insert the missing inode item.
+ *
+ * Returns 0 means success.
+ * Returns <0 means error.
+ */
+static int repair_inode_item_missing(struct btrfs_root *root, u64 ino,
+ u8 filetype)
+{
+ struct btrfs_key key;
+ struct btrfs_trans_handle *trans;
+ struct btrfs_path path;
+ int ret;
+
+ key.objectid = ino;
+ key.type = BTRFS_INODE_ITEM_KEY;
+ key.offset = 0;
+
+ btrfs_init_path(&path);
+ trans = btrfs_start_transaction(root, 1);
+ if (IS_ERR(trans)) {
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = btrfs_search_slot(trans, root, &key, &path, 1, 1);
+ if (ret < 0 || !ret)
+ goto fail;
+
+ /* insert inode item */
+ create_inode_item_lowmem(trans, root, ino, filetype);
+ ret = 0;
+fail:
+ btrfs_commit_transaction(trans, root);
+out:
+ if (ret)
+ error("failed to repair root %llu INODE ITEM[%llu] missing",
+ root->objectid, ino);
+ btrfs_release_path(&path);
+ return ret;
+}
+
+/*
* Traverse the given INODE_REF and call find_dir_item() to find related
* DIR_ITEM/DIR_INDEX.
*