Skip to content

Commit be7f415

Browse files
committed
btrfs-progs: mkfs/rootdir: enhance inode flags detection
Currently for --inode-flags parameter, we save the full path of the host fs into rootdir_inode_flags_entry sturcture, then compare each inode we hit with that saved full path. This string comparison can be time consuming (up to PATH_MAX characters), and we're doing it for every inode. On the other hand, nftw() also provides a stat structure of the current inode, stat::st_dev and stat::st_ino pair can always uniquely locate an inode in the host filesystem. With that said, we can just save the st_dev/st_ino pair when validating the inode flag parameters, and use st_dev/st_ino to check if we hit the target inode. This has two benefits: - Reduce the memory usage of each rootdir_inode_flags_entry Now we need no full_path member, replacing it with two u64. This saves (4K - 16) bytes per rootdir_inode_flags_entry. - Reduce the runtime of inode comparison Instead of doing strcmp() for up to 4K bytes, it's just two u64 comparison. Signed-off-by: Qu Wenruo <[email protected]>
1 parent a40d9ca commit be7f415

File tree

2 files changed

+23
-12
lines changed

2 files changed

+23
-12
lines changed

mkfs/rootdir.c

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1139,32 +1139,42 @@ int btrfs_mkfs_validate_inode_flags(const char *source_dir, struct list_head *in
11391139

11401140
list_for_each_entry(rif, inode_flags, list) {
11411141
char path[PATH_MAX];
1142+
char full_path[PATH_MAX];
11421143
struct rootdir_inode_flags_entry *rif2;
1144+
struct stat stbuf;
11431145
int ret;
11441146

11451147
if (path_cat_out(path, source_dir, rif->inode_path)) {
11461148
error("path invalid: %s", path);
11471149
return -EINTR;
11481150
}
1149-
if (!realpath(path, rif->full_path)) {
1151+
if (!realpath(path, full_path)) {
11501152
ret = -errno;
11511153
error("could not get canonical path: %s: %m", path);
11521154
return ret;
11531155
}
1154-
if (!path_exists(rif->full_path)) {
1155-
error("inode path does not exist: %s", rif->full_path);
1156+
if (!path_exists(full_path)) {
1157+
error("inode path does not exist: %s", full_path);
11561158
return -ENOENT;
11571159
}
1160+
ret = lstat(full_path, &stbuf);
1161+
if (ret < 0) {
1162+
ret = -errno;
1163+
error("failed to get stat of '%s': %m", full_path);
1164+
return ret;
1165+
}
1166+
rif->st_dev = stbuf.st_dev;
1167+
rif->st_ino = stbuf.st_ino;
11581168
list_for_each_entry(rif2, inode_flags, list) {
11591169
/*
11601170
* Only compare entries before us. So we won't compare
11611171
* the same pair twice.
11621172
*/
11631173
if (rif2 == rif)
11641174
break;
1165-
if (strcmp(rif2->full_path, rif->full_path) == 0) {
1175+
if (rif2->st_dev == rif->st_dev && rif2->st_ino == rif->st_ino) {
11661176
error("duplicated inode flag entries for %s",
1167-
rif->full_path);
1177+
full_path);
11681178
return -EEXIST;
11691179
}
11701180
}
@@ -1410,12 +1420,12 @@ static void update_inode_flags(const struct rootdir_inode_flags_entry *rif,
14101420
}
14111421

14121422
static void search_and_update_inode_flags(struct btrfs_inode_item *stack_inode,
1413-
const char *full_path)
1423+
const struct stat *st)
14141424
{
14151425
struct rootdir_inode_flags_entry *rif;
14161426

14171427
list_for_each_entry(rif, g_inode_flags_list, list) {
1418-
if (strcmp(rif->full_path, full_path) == 0) {
1428+
if (rif->st_dev == st->st_dev && rif->st_ino == st->st_ino) {
14191429
update_inode_flags(rif, stack_inode);
14201430

14211431
list_del(&rif->list);
@@ -1493,7 +1503,7 @@ static int ftw_add_subvol(const char *full_path, const struct stat *st,
14931503
}
14941504
stat_to_inode_item(&inode_item, st);
14951505

1496-
search_and_update_inode_flags(&inode_item, full_path);
1506+
search_and_update_inode_flags(&inode_item, st);
14971507
btrfs_set_stack_inode_nlink(&inode_item, 1);
14981508
ret = update_inode_item(g_trans, new_root, &inode_item, ino);
14991509
if (ret < 0) {
@@ -1687,7 +1697,7 @@ static int ftw_add_inode(const char *full_path, const struct stat *st,
16871697
return ret;
16881698
}
16891699
stat_to_inode_item(&inode_item, st);
1690-
search_and_update_inode_flags(&inode_item, full_path);
1700+
search_and_update_inode_flags(&inode_item, st);
16911701

16921702
ret = btrfs_insert_inode(g_trans, root, ino, &inode_item);
16931703
if (ret < 0) {

mkfs/rootdir.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,15 @@ struct rootdir_subvol {
4949
};
5050

5151
/*
52-
* Represent a flag for specified inode at @full_path.
52+
* Represent a flag for specified inode at "$source_dir/$inode_path".
5353
*/
5454
struct rootdir_inode_flags_entry {
5555
struct list_head list;
56-
/* Fully canonicalized path to the source file. */
57-
char full_path[PATH_MAX];
5856
/* Path inside the source directory. */
5957
char inode_path[PATH_MAX];
58+
/* st_dev and st_ino is going to uniquely determine an inode inside the host fs. */
59+
dev_t st_dev;
60+
ino_t st_ino;
6061

6162
bool nodatacow;
6263
bool nodatasum;

0 commit comments

Comments
 (0)