Due to the current on-disk limitation (16-bit on-disk root_nid), on-disk
root inodes must be updated in place for now.
If rootdir xattr sizes are expanded during incremental updates, there
may be insufficient space to keep additional extended attributes.
To work around this, let's add a mkfs option `--root-xattr-isize=#` to
specify the minimum inline xattr size of root directories in advance.
Reviewed-by: Sandeep Dhavale <dhavale@google.com>
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20240729075027.712339-2-hsiangkao@linux.alibaba.com
u32 c_uid, c_gid;
const char *mount_point;
long long c_uid_offset, c_gid_offset;
+ u32 c_root_xattr_isize;
#ifdef WITH_ANDROID
char *target_out_path;
char *fs_config_file;
sizeof(struct erofs_xattr_entry) + 1; })
int erofs_scan_file_xattrs(struct erofs_inode *inode);
-int erofs_prepare_xattr_ibody(struct erofs_inode *inode);
+int erofs_prepare_xattr_ibody(struct erofs_inode *inode, bool noroom);
char *erofs_export_xattr_ibody(struct erofs_inode *inode);
int erofs_build_shared_xattrs_from_path(struct erofs_sb_info *sbi, const char *path);
if (ret < 0)
return ret;
- ret = erofs_prepare_xattr_ibody(inode);
+ ret = erofs_prepare_xattr_ibody(inode, false);
if (ret < 0)
return ret;
else if (inode->whiteouts)
erofs_set_origin_xattr(inode);
- ret = erofs_prepare_xattr_ibody(inode);
+ ret = erofs_prepare_xattr_ibody(inode, incremental && IS_ROOT(inode));
if (ret < 0)
return ret;
root->i_ino[1] = sbi->root_nid;
list_del(&root->i_hash);
erofs_insert_ihash(root);
+ } else if (cfg.c_root_xattr_isize) {
+ root->xattr_isize = cfg.c_root_xattr_isize;
}
err = !rebuild ? erofs_mkfs_handle_inode(root) :
erofs_err("failed to read inode @ %llu", fakeinode.nid);
return ret;
}
+
+ /* Inherit the maximum xattr size for the root directory */
+ if (__erofs_unlikely(IS_ROOT(dir)))
+ dir->xattr_isize = fakeinode.xattr_isize;
+
ctx = (struct erofs_rebuild_dir_context) {
.ctx.dir = &fakeinode,
.ctx.cb = erofs_rebuild_basedir_dirent_iter,
item->len[0] + item->len[1] - item->prefix_len);
}
-int erofs_prepare_xattr_ibody(struct erofs_inode *inode)
+int erofs_prepare_xattr_ibody(struct erofs_inode *inode, bool noroom)
{
- int ret;
- struct inode_xattr_node *node;
+ unsigned int target_xattr_isize = inode->xattr_isize;
struct list_head *ixattrs = &inode->i_xattrs;
+ struct inode_xattr_node *node;
unsigned int h_shared_count;
+ int ret;
if (list_empty(ixattrs)) {
- inode->xattr_isize = 0;
- return 0;
+ ret = 0;
+ goto out;
}
/* get xattr ibody size */
}
ret = erofs_next_xattr_align(ret, item);
}
+out:
+ while (ret < target_xattr_isize) {
+ ret += sizeof(struct erofs_xattr_entry);
+ if (ret < target_xattr_isize)
+ ret = EROFS_XATTR_ALIGN(ret +
+ min_t(int, target_xattr_isize - ret, UINT16_MAX));
+ }
+ if (noroom && target_xattr_isize && ret > target_xattr_isize) {
+ erofs_err("no enough space to keep xattrs @ nid %llu",
+ inode->nid | 0ULL);
+ return -ENOSPC;
+ }
inode->xattr_isize = ret;
return ret;
}
free(node);
put_xattritem(item);
}
- DBG_BUGON(p > size);
+ if (p < size) {
+ memset(buf + p, 0, size - p);
+ } else if (__erofs_unlikely(p > size)) {
+ DBG_BUGON(1);
+ return ERR_PTR(-EFAULT);
+ }
return buf;
}
{"zfeature-bits", required_argument, NULL, 521},
{"clean", optional_argument, NULL, 522},
{"incremental", optional_argument, NULL, 523},
+ {"root-xattr-isize", required_argument, NULL, 524},
{0, 0, 0, 0},
};
" --mount-point=X X=prefix of target fs path (default: /)\n"
" --preserve-mtime keep per-file modification time strictly\n"
" --offset=# skip # bytes at the beginning of IMAGE.\n"
+ " --root-xattr-isize=# ensure the inline xattr size of the root directory is # bytes at least\n"
" --aufs replace aufs special files with overlayfs metadata\n"
" --tar=X generate a full or index-only image from a tarball(-ish) source\n"
" (X = f|i|headerball; f=full mode, i=index mode,\n"
}
incremental_mode = (opt == 523);
break;
+ case 524:
+ cfg.c_root_xattr_isize = strtoull(optarg, &endptr, 0);
+ if (*endptr != '\0') {
+ erofs_err("invalid the minimum inline xattr size %s", optarg);
+ return -EINVAL;
+ }
+ break;
case 'V':
version();
exit(0);