mirror of https://github.com/torvalds/linux.git
erofs: implement metadata compression
Thanks to the meta buffer infrastructure, metadata-compressed inodes are just read from the metabox inode instead of the blockdevice (or backing file) inode. The same is true for shared extended attributes. When metadata compression is enabled, inode numbers are divided from on-disk NIDs because of non-LTS 32-bit application compatibility. Co-developed-by: Gao Xiang <hsiangkao@linux.alibaba.com> Signed-off-by: Bo Liu (OpenAnolis) <liubo03@inspur.com> Acked-by: Chao Yu <chao@kernel.org> Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com> Link: https://lore.kernel.org/r/20250722003229.2121752-1-hsiangkao@linux.alibaba.com
This commit is contained in:
parent
681acbda3a
commit
414091322c
|
|
@ -5,7 +5,7 @@ Description: Shows all enabled kernel features.
|
||||||
Supported features:
|
Supported features:
|
||||||
zero_padding, compr_cfgs, big_pcluster, chunked_file,
|
zero_padding, compr_cfgs, big_pcluster, chunked_file,
|
||||||
device_table, compr_head2, sb_chksum, ztailpacking,
|
device_table, compr_head2, sb_chksum, ztailpacking,
|
||||||
dedupe, fragments.
|
dedupe, fragments, 48bit, metabox.
|
||||||
|
|
||||||
What: /sys/fs/erofs/<disk>/sync_decompress
|
What: /sys/fs/erofs/<disk>/sync_decompress
|
||||||
Date: November 2021
|
Date: November 2021
|
||||||
|
|
|
||||||
|
|
@ -49,11 +49,18 @@ void *erofs_bread(struct erofs_buf *buf, erofs_off_t offset, bool need_kmap)
|
||||||
return buf->base + (offset & ~PAGE_MASK);
|
return buf->base + (offset & ~PAGE_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
void erofs_init_metabuf(struct erofs_buf *buf, struct super_block *sb)
|
int erofs_init_metabuf(struct erofs_buf *buf, struct super_block *sb,
|
||||||
|
bool in_metabox)
|
||||||
{
|
{
|
||||||
struct erofs_sb_info *sbi = EROFS_SB(sb);
|
struct erofs_sb_info *sbi = EROFS_SB(sb);
|
||||||
|
|
||||||
buf->file = NULL;
|
buf->file = NULL;
|
||||||
|
if (in_metabox) {
|
||||||
|
if (unlikely(!sbi->metabox_inode))
|
||||||
|
return -EFSCORRUPTED;
|
||||||
|
buf->mapping = sbi->metabox_inode->i_mapping;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
buf->off = sbi->dif0.fsoff;
|
buf->off = sbi->dif0.fsoff;
|
||||||
if (erofs_is_fileio_mode(sbi)) {
|
if (erofs_is_fileio_mode(sbi)) {
|
||||||
buf->file = sbi->dif0.file; /* some fs like FUSE needs it */
|
buf->file = sbi->dif0.file; /* some fs like FUSE needs it */
|
||||||
|
|
@ -62,12 +69,17 @@ void erofs_init_metabuf(struct erofs_buf *buf, struct super_block *sb)
|
||||||
buf->mapping = sbi->dif0.fscache->inode->i_mapping;
|
buf->mapping = sbi->dif0.fscache->inode->i_mapping;
|
||||||
else
|
else
|
||||||
buf->mapping = sb->s_bdev->bd_mapping;
|
buf->mapping = sb->s_bdev->bd_mapping;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *erofs_read_metabuf(struct erofs_buf *buf, struct super_block *sb,
|
void *erofs_read_metabuf(struct erofs_buf *buf, struct super_block *sb,
|
||||||
erofs_off_t offset)
|
erofs_off_t offset, bool in_metabox)
|
||||||
{
|
{
|
||||||
erofs_init_metabuf(buf, sb);
|
int err;
|
||||||
|
|
||||||
|
err = erofs_init_metabuf(buf, sb, in_metabox);
|
||||||
|
if (err)
|
||||||
|
return ERR_PTR(err);
|
||||||
return erofs_bread(buf, offset, true);
|
return erofs_bread(buf, offset, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -118,7 +130,7 @@ int erofs_map_blocks(struct inode *inode, struct erofs_map_blocks *map)
|
||||||
pos = ALIGN(erofs_iloc(inode) + vi->inode_isize +
|
pos = ALIGN(erofs_iloc(inode) + vi->inode_isize +
|
||||||
vi->xattr_isize, unit) + unit * chunknr;
|
vi->xattr_isize, unit) + unit * chunknr;
|
||||||
|
|
||||||
idx = erofs_read_metabuf(&buf, sb, pos);
|
idx = erofs_read_metabuf(&buf, sb, pos, erofs_inode_in_metabox(inode));
|
||||||
if (IS_ERR(idx)) {
|
if (IS_ERR(idx)) {
|
||||||
err = PTR_ERR(idx);
|
err = PTR_ERR(idx);
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -264,7 +276,6 @@ static int erofs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
|
||||||
|
|
||||||
map.m_la = offset;
|
map.m_la = offset;
|
||||||
map.m_llen = length;
|
map.m_llen = length;
|
||||||
|
|
||||||
ret = erofs_map_blocks(inode, &map);
|
ret = erofs_map_blocks(inode, &map);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -273,35 +284,37 @@ static int erofs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
|
||||||
iomap->length = map.m_llen;
|
iomap->length = map.m_llen;
|
||||||
iomap->flags = 0;
|
iomap->flags = 0;
|
||||||
iomap->private = NULL;
|
iomap->private = NULL;
|
||||||
|
iomap->addr = IOMAP_NULL_ADDR;
|
||||||
if (!(map.m_flags & EROFS_MAP_MAPPED)) {
|
if (!(map.m_flags & EROFS_MAP_MAPPED)) {
|
||||||
iomap->type = IOMAP_HOLE;
|
iomap->type = IOMAP_HOLE;
|
||||||
iomap->addr = IOMAP_NULL_ADDR;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
mdev = (struct erofs_map_dev) {
|
if (!(map.m_flags & EROFS_MAP_META) || !erofs_inode_in_metabox(inode)) {
|
||||||
.m_deviceid = map.m_deviceid,
|
mdev = (struct erofs_map_dev) {
|
||||||
.m_pa = map.m_pa,
|
.m_deviceid = map.m_deviceid,
|
||||||
};
|
.m_pa = map.m_pa,
|
||||||
ret = erofs_map_dev(sb, &mdev);
|
};
|
||||||
if (ret)
|
ret = erofs_map_dev(sb, &mdev);
|
||||||
return ret;
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
if (flags & IOMAP_DAX)
|
if (flags & IOMAP_DAX)
|
||||||
iomap->dax_dev = mdev.m_dif->dax_dev;
|
iomap->dax_dev = mdev.m_dif->dax_dev;
|
||||||
else
|
else
|
||||||
iomap->bdev = mdev.m_bdev;
|
iomap->bdev = mdev.m_bdev;
|
||||||
|
iomap->addr = mdev.m_dif->fsoff + mdev.m_pa;
|
||||||
iomap->addr = mdev.m_dif->fsoff + mdev.m_pa;
|
if (flags & IOMAP_DAX)
|
||||||
if (flags & IOMAP_DAX)
|
iomap->addr += mdev.m_dif->dax_part_off;
|
||||||
iomap->addr += mdev.m_dif->dax_part_off;
|
}
|
||||||
|
|
||||||
if (map.m_flags & EROFS_MAP_META) {
|
if (map.m_flags & EROFS_MAP_META) {
|
||||||
void *ptr;
|
void *ptr;
|
||||||
struct erofs_buf buf = __EROFS_BUF_INITIALIZER;
|
struct erofs_buf buf = __EROFS_BUF_INITIALIZER;
|
||||||
|
|
||||||
iomap->type = IOMAP_INLINE;
|
iomap->type = IOMAP_INLINE;
|
||||||
ptr = erofs_read_metabuf(&buf, sb, mdev.m_pa);
|
ptr = erofs_read_metabuf(&buf, sb, map.m_pa,
|
||||||
|
erofs_inode_in_metabox(inode));
|
||||||
if (IS_ERR(ptr))
|
if (IS_ERR(ptr))
|
||||||
return PTR_ERR(ptr);
|
return PTR_ERR(ptr);
|
||||||
iomap->inline_data = ptr;
|
iomap->inline_data = ptr;
|
||||||
|
|
|
||||||
|
|
@ -467,7 +467,7 @@ int z_erofs_parse_cfgs(struct super_block *sb, struct erofs_super_block *dsb)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
erofs_init_metabuf(&buf, sb);
|
(void)erofs_init_metabuf(&buf, sb, false);
|
||||||
offset = EROFS_SUPER_OFFSET + sbi->sb_size;
|
offset = EROFS_SUPER_OFFSET + sbi->sb_size;
|
||||||
alg = 0;
|
alg = 0;
|
||||||
for (algs = sbi->available_compr_algs; algs; algs >>= 1, ++alg) {
|
for (algs = sbi->available_compr_algs; algs; algs >>= 1, ++alg) {
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,8 @@ static int erofs_fill_dentries(struct inode *dir, struct dir_context *ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dir_emit(ctx, de_name, de_namelen,
|
if (!dir_emit(ctx, de_name, de_namelen,
|
||||||
le64_to_cpu(de->nid), d_type))
|
erofs_nid_to_ino64(EROFS_SB(dir->i_sb),
|
||||||
|
le64_to_cpu(de->nid)), d_type))
|
||||||
return 1;
|
return 1;
|
||||||
++de;
|
++de;
|
||||||
ctx->pos += sizeof(struct erofs_dirent);
|
ctx->pos += sizeof(struct erofs_dirent);
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
#define EROFS_FEATURE_INCOMPAT_48BIT 0x00000080
|
#define EROFS_FEATURE_INCOMPAT_48BIT 0x00000080
|
||||||
#define EROFS_FEATURE_INCOMPAT_METABOX 0x00000100
|
#define EROFS_FEATURE_INCOMPAT_METABOX 0x00000100
|
||||||
#define EROFS_ALL_FEATURE_INCOMPAT \
|
#define EROFS_ALL_FEATURE_INCOMPAT \
|
||||||
((EROFS_FEATURE_INCOMPAT_48BIT << 1) - 1)
|
((EROFS_FEATURE_INCOMPAT_METABOX << 1) - 1)
|
||||||
|
|
||||||
#define EROFS_SB_EXTSLOT_SIZE 16
|
#define EROFS_SB_EXTSLOT_SIZE 16
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@ static int erofs_fileio_scan_folio(struct erofs_fileio *io, struct folio *folio)
|
||||||
void *src;
|
void *src;
|
||||||
|
|
||||||
src = erofs_read_metabuf(&buf, inode->i_sb,
|
src = erofs_read_metabuf(&buf, inode->i_sb,
|
||||||
map->m_pa + ofs);
|
map->m_pa + ofs, erofs_inode_in_metabox(inode));
|
||||||
if (IS_ERR(src)) {
|
if (IS_ERR(src)) {
|
||||||
err = PTR_ERR(src);
|
err = PTR_ERR(src);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -274,7 +274,8 @@ static int erofs_fscache_data_read_slice(struct erofs_fscache_rq *req)
|
||||||
size_t size = map.m_llen;
|
size_t size = map.m_llen;
|
||||||
void *src;
|
void *src;
|
||||||
|
|
||||||
src = erofs_read_metabuf(&buf, sb, map.m_pa);
|
src = erofs_read_metabuf(&buf, sb, map.m_pa,
|
||||||
|
erofs_inode_in_metabox(inode));
|
||||||
if (IS_ERR(src))
|
if (IS_ERR(src))
|
||||||
return PTR_ERR(src);
|
return PTR_ERR(src);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ static int erofs_read_inode(struct inode *inode)
|
||||||
struct super_block *sb = inode->i_sb;
|
struct super_block *sb = inode->i_sb;
|
||||||
erofs_blk_t blkaddr = erofs_blknr(sb, erofs_iloc(inode));
|
erofs_blk_t blkaddr = erofs_blknr(sb, erofs_iloc(inode));
|
||||||
unsigned int ofs = erofs_blkoff(sb, erofs_iloc(inode));
|
unsigned int ofs = erofs_blkoff(sb, erofs_iloc(inode));
|
||||||
|
bool in_mbox = erofs_inode_in_metabox(inode);
|
||||||
struct erofs_buf buf = __EROFS_BUF_INITIALIZER;
|
struct erofs_buf buf = __EROFS_BUF_INITIALIZER;
|
||||||
struct erofs_sb_info *sbi = EROFS_SB(sb);
|
struct erofs_sb_info *sbi = EROFS_SB(sb);
|
||||||
erofs_blk_t addrmask = BIT_ULL(48) - 1;
|
erofs_blk_t addrmask = BIT_ULL(48) - 1;
|
||||||
|
|
@ -39,7 +40,7 @@ static int erofs_read_inode(struct inode *inode)
|
||||||
void *ptr;
|
void *ptr;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
ptr = erofs_read_metabuf(&buf, sb, erofs_pos(sb, blkaddr));
|
ptr = erofs_read_metabuf(&buf, sb, erofs_pos(sb, blkaddr), in_mbox);
|
||||||
if (IS_ERR(ptr)) {
|
if (IS_ERR(ptr)) {
|
||||||
err = PTR_ERR(ptr);
|
err = PTR_ERR(ptr);
|
||||||
erofs_err(sb, "failed to read inode meta block (nid: %llu): %d",
|
erofs_err(sb, "failed to read inode meta block (nid: %llu): %d",
|
||||||
|
|
@ -78,7 +79,7 @@ static int erofs_read_inode(struct inode *inode)
|
||||||
|
|
||||||
memcpy(&copied, dic, gotten);
|
memcpy(&copied, dic, gotten);
|
||||||
ptr = erofs_read_metabuf(&buf, sb,
|
ptr = erofs_read_metabuf(&buf, sb,
|
||||||
erofs_pos(sb, blkaddr + 1));
|
erofs_pos(sb, blkaddr + 1), in_mbox);
|
||||||
if (IS_ERR(ptr)) {
|
if (IS_ERR(ptr)) {
|
||||||
err = PTR_ERR(ptr);
|
err = PTR_ERR(ptr);
|
||||||
erofs_err(sb, "failed to read inode payload block (nid: %llu): %d",
|
erofs_err(sb, "failed to read inode payload block (nid: %llu): %d",
|
||||||
|
|
@ -264,13 +265,13 @@ static int erofs_fill_inode(struct inode *inode)
|
||||||
* ino_t is 32-bits on 32-bit arch. We have to squash the 64-bit value down
|
* ino_t is 32-bits on 32-bit arch. We have to squash the 64-bit value down
|
||||||
* so that it will fit.
|
* so that it will fit.
|
||||||
*/
|
*/
|
||||||
static ino_t erofs_squash_ino(erofs_nid_t nid)
|
static ino_t erofs_squash_ino(struct super_block *sb, erofs_nid_t nid)
|
||||||
{
|
{
|
||||||
ino_t ino = (ino_t)nid;
|
u64 ino64 = erofs_nid_to_ino64(EROFS_SB(sb), nid);
|
||||||
|
|
||||||
if (sizeof(ino_t) < sizeof(erofs_nid_t))
|
if (sizeof(ino_t) < sizeof(erofs_nid_t))
|
||||||
ino ^= nid >> (sizeof(erofs_nid_t) - sizeof(ino_t)) * 8;
|
ino64 ^= ino64 >> (sizeof(erofs_nid_t) - sizeof(ino_t)) * 8;
|
||||||
return ino;
|
return (ino_t)ino64;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int erofs_iget5_eq(struct inode *inode, void *opaque)
|
static int erofs_iget5_eq(struct inode *inode, void *opaque)
|
||||||
|
|
@ -282,7 +283,7 @@ static int erofs_iget5_set(struct inode *inode, void *opaque)
|
||||||
{
|
{
|
||||||
const erofs_nid_t nid = *(erofs_nid_t *)opaque;
|
const erofs_nid_t nid = *(erofs_nid_t *)opaque;
|
||||||
|
|
||||||
inode->i_ino = erofs_squash_ino(nid);
|
inode->i_ino = erofs_squash_ino(inode->i_sb, nid);
|
||||||
EROFS_I(inode)->nid = nid;
|
EROFS_I(inode)->nid = nid;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -291,7 +292,7 @@ struct inode *erofs_iget(struct super_block *sb, erofs_nid_t nid)
|
||||||
{
|
{
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
|
|
||||||
inode = iget5_locked(sb, erofs_squash_ino(nid), erofs_iget5_eq,
|
inode = iget5_locked(sb, erofs_squash_ino(sb, nid), erofs_iget5_eq,
|
||||||
erofs_iget5_set, &nid);
|
erofs_iget5_set, &nid);
|
||||||
if (!inode)
|
if (!inode)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
|
||||||
|
|
@ -125,6 +125,7 @@ struct erofs_sb_info {
|
||||||
struct erofs_sb_lz4_info lz4;
|
struct erofs_sb_lz4_info lz4;
|
||||||
#endif /* CONFIG_EROFS_FS_ZIP */
|
#endif /* CONFIG_EROFS_FS_ZIP */
|
||||||
struct inode *packed_inode;
|
struct inode *packed_inode;
|
||||||
|
struct inode *metabox_inode;
|
||||||
struct erofs_dev_context *devs;
|
struct erofs_dev_context *devs;
|
||||||
u64 total_blocks;
|
u64 total_blocks;
|
||||||
|
|
||||||
|
|
@ -148,6 +149,7 @@ struct erofs_sb_info {
|
||||||
/* what we really care is nid, rather than ino.. */
|
/* what we really care is nid, rather than ino.. */
|
||||||
erofs_nid_t root_nid;
|
erofs_nid_t root_nid;
|
||||||
erofs_nid_t packed_nid;
|
erofs_nid_t packed_nid;
|
||||||
|
erofs_nid_t metabox_nid;
|
||||||
/* used for statfs, f_files - f_favail */
|
/* used for statfs, f_files - f_favail */
|
||||||
u64 inos;
|
u64 inos;
|
||||||
|
|
||||||
|
|
@ -232,6 +234,23 @@ EROFS_FEATURE_FUNCS(sb_chksum, compat, COMPAT_SB_CHKSUM)
|
||||||
EROFS_FEATURE_FUNCS(xattr_filter, compat, COMPAT_XATTR_FILTER)
|
EROFS_FEATURE_FUNCS(xattr_filter, compat, COMPAT_XATTR_FILTER)
|
||||||
EROFS_FEATURE_FUNCS(shared_ea_in_metabox, compat, COMPAT_SHARED_EA_IN_METABOX)
|
EROFS_FEATURE_FUNCS(shared_ea_in_metabox, compat, COMPAT_SHARED_EA_IN_METABOX)
|
||||||
|
|
||||||
|
static inline u64 erofs_nid_to_ino64(struct erofs_sb_info *sbi, erofs_nid_t nid)
|
||||||
|
{
|
||||||
|
if (!erofs_sb_has_metabox(sbi))
|
||||||
|
return nid;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When metadata compression is enabled, avoid generating excessively
|
||||||
|
* large inode numbers for metadata-compressed inodes. Shift NIDs in
|
||||||
|
* the 31-62 bit range left by one and move the metabox flag to bit 31.
|
||||||
|
*
|
||||||
|
* Note: on-disk NIDs remain unchanged as they are primarily used for
|
||||||
|
* compatibility with non-LFS 32-bit applications.
|
||||||
|
*/
|
||||||
|
return ((nid << 1) & GENMASK_ULL(63, 32)) | (nid & GENMASK(30, 0)) |
|
||||||
|
((nid >> EROFS_DIRENT_NID_METABOX_BIT) << 31);
|
||||||
|
}
|
||||||
|
|
||||||
/* atomic flag definitions */
|
/* atomic flag definitions */
|
||||||
#define EROFS_I_EA_INITED_BIT 0
|
#define EROFS_I_EA_INITED_BIT 0
|
||||||
#define EROFS_I_Z_INITED_BIT 1
|
#define EROFS_I_Z_INITED_BIT 1
|
||||||
|
|
@ -281,12 +300,20 @@ struct erofs_inode {
|
||||||
|
|
||||||
#define EROFS_I(ptr) container_of(ptr, struct erofs_inode, vfs_inode)
|
#define EROFS_I(ptr) container_of(ptr, struct erofs_inode, vfs_inode)
|
||||||
|
|
||||||
|
static inline bool erofs_inode_in_metabox(struct inode *inode)
|
||||||
|
{
|
||||||
|
return EROFS_I(inode)->nid & BIT_ULL(EROFS_DIRENT_NID_METABOX_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
static inline erofs_off_t erofs_iloc(struct inode *inode)
|
static inline erofs_off_t erofs_iloc(struct inode *inode)
|
||||||
{
|
{
|
||||||
struct erofs_sb_info *sbi = EROFS_I_SB(inode);
|
struct erofs_sb_info *sbi = EROFS_I_SB(inode);
|
||||||
|
erofs_nid_t nid_lo = EROFS_I(inode)->nid & EROFS_DIRENT_NID_MASK;
|
||||||
|
|
||||||
|
if (erofs_inode_in_metabox(inode))
|
||||||
|
return nid_lo << sbi->islotbits;
|
||||||
return erofs_pos(inode->i_sb, sbi->meta_blkaddr) +
|
return erofs_pos(inode->i_sb, sbi->meta_blkaddr) +
|
||||||
(EROFS_I(inode)->nid << sbi->islotbits);
|
(nid_lo << sbi->islotbits);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned int erofs_inode_version(unsigned int ifmt)
|
static inline unsigned int erofs_inode_version(unsigned int ifmt)
|
||||||
|
|
@ -385,9 +412,10 @@ void *erofs_read_metadata(struct super_block *sb, struct erofs_buf *buf,
|
||||||
void erofs_unmap_metabuf(struct erofs_buf *buf);
|
void erofs_unmap_metabuf(struct erofs_buf *buf);
|
||||||
void erofs_put_metabuf(struct erofs_buf *buf);
|
void erofs_put_metabuf(struct erofs_buf *buf);
|
||||||
void *erofs_bread(struct erofs_buf *buf, erofs_off_t offset, bool need_kmap);
|
void *erofs_bread(struct erofs_buf *buf, erofs_off_t offset, bool need_kmap);
|
||||||
void erofs_init_metabuf(struct erofs_buf *buf, struct super_block *sb);
|
int erofs_init_metabuf(struct erofs_buf *buf, struct super_block *sb,
|
||||||
|
bool in_metabox);
|
||||||
void *erofs_read_metabuf(struct erofs_buf *buf, struct super_block *sb,
|
void *erofs_read_metabuf(struct erofs_buf *buf, struct super_block *sb,
|
||||||
erofs_off_t offset);
|
erofs_off_t offset, bool in_metabox);
|
||||||
int erofs_map_dev(struct super_block *sb, struct erofs_map_dev *dev);
|
int erofs_map_dev(struct super_block *sb, struct erofs_map_dev *dev);
|
||||||
int erofs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
int erofs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||||
u64 start, u64 len);
|
u64 start, u64 len);
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,7 @@ static int erofs_init_device(struct erofs_buf *buf, struct super_block *sb,
|
||||||
struct erofs_deviceslot *dis;
|
struct erofs_deviceslot *dis;
|
||||||
struct file *file;
|
struct file *file;
|
||||||
|
|
||||||
dis = erofs_read_metabuf(buf, sb, *pos);
|
dis = erofs_read_metabuf(buf, sb, *pos, false);
|
||||||
if (IS_ERR(dis))
|
if (IS_ERR(dis))
|
||||||
return PTR_ERR(dis);
|
return PTR_ERR(dis);
|
||||||
|
|
||||||
|
|
@ -258,7 +258,7 @@ static int erofs_read_superblock(struct super_block *sb)
|
||||||
void *data;
|
void *data;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
data = erofs_read_metabuf(&buf, sb, 0);
|
data = erofs_read_metabuf(&buf, sb, 0, false);
|
||||||
if (IS_ERR(data)) {
|
if (IS_ERR(data)) {
|
||||||
erofs_err(sb, "cannot read erofs superblock");
|
erofs_err(sb, "cannot read erofs superblock");
|
||||||
return PTR_ERR(data);
|
return PTR_ERR(data);
|
||||||
|
|
@ -319,6 +319,14 @@ static int erofs_read_superblock(struct super_block *sb)
|
||||||
sbi->root_nid = le16_to_cpu(dsb->rb.rootnid_2b);
|
sbi->root_nid = le16_to_cpu(dsb->rb.rootnid_2b);
|
||||||
}
|
}
|
||||||
sbi->packed_nid = le64_to_cpu(dsb->packed_nid);
|
sbi->packed_nid = le64_to_cpu(dsb->packed_nid);
|
||||||
|
if (erofs_sb_has_metabox(sbi)) {
|
||||||
|
if (sbi->sb_size <= offsetof(struct erofs_super_block,
|
||||||
|
metabox_nid))
|
||||||
|
return -EFSCORRUPTED;
|
||||||
|
sbi->metabox_nid = le64_to_cpu(dsb->metabox_nid);
|
||||||
|
if (sbi->metabox_nid & BIT_ULL(EROFS_DIRENT_NID_METABOX_BIT))
|
||||||
|
return -EFSCORRUPTED; /* self-loop detection */
|
||||||
|
}
|
||||||
sbi->inos = le64_to_cpu(dsb->inos);
|
sbi->inos = le64_to_cpu(dsb->inos);
|
||||||
|
|
||||||
sbi->epoch = (s64)le64_to_cpu(dsb->epoch);
|
sbi->epoch = (s64)le64_to_cpu(dsb->epoch);
|
||||||
|
|
@ -335,6 +343,8 @@ static int erofs_read_superblock(struct super_block *sb)
|
||||||
|
|
||||||
if (erofs_sb_has_48bit(sbi))
|
if (erofs_sb_has_48bit(sbi))
|
||||||
erofs_info(sb, "EXPERIMENTAL 48-bit layout support in use. Use at your own risk!");
|
erofs_info(sb, "EXPERIMENTAL 48-bit layout support in use. Use at your own risk!");
|
||||||
|
if (erofs_sb_has_metabox(sbi))
|
||||||
|
erofs_info(sb, "EXPERIMENTAL metadata compression support in use. Use at your own risk!");
|
||||||
if (erofs_is_fscache_mode(sb))
|
if (erofs_is_fscache_mode(sb))
|
||||||
erofs_info(sb, "[deprecated] fscache-based on-demand read feature in use. Use at your own risk!");
|
erofs_info(sb, "[deprecated] fscache-based on-demand read feature in use. Use at your own risk!");
|
||||||
out:
|
out:
|
||||||
|
|
@ -690,6 +700,12 @@ static int erofs_fc_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||||
return PTR_ERR(inode);
|
return PTR_ERR(inode);
|
||||||
sbi->packed_inode = inode;
|
sbi->packed_inode = inode;
|
||||||
}
|
}
|
||||||
|
if (erofs_sb_has_metabox(sbi)) {
|
||||||
|
inode = erofs_iget(sb, sbi->metabox_nid);
|
||||||
|
if (IS_ERR(inode))
|
||||||
|
return PTR_ERR(inode);
|
||||||
|
sbi->metabox_inode = inode;
|
||||||
|
}
|
||||||
|
|
||||||
inode = erofs_iget(sb, sbi->root_nid);
|
inode = erofs_iget(sb, sbi->root_nid);
|
||||||
if (IS_ERR(inode))
|
if (IS_ERR(inode))
|
||||||
|
|
@ -845,6 +861,8 @@ static void erofs_drop_internal_inodes(struct erofs_sb_info *sbi)
|
||||||
{
|
{
|
||||||
iput(sbi->packed_inode);
|
iput(sbi->packed_inode);
|
||||||
sbi->packed_inode = NULL;
|
sbi->packed_inode = NULL;
|
||||||
|
iput(sbi->metabox_inode);
|
||||||
|
sbi->metabox_inode = NULL;
|
||||||
#ifdef CONFIG_EROFS_FS_ZIP
|
#ifdef CONFIG_EROFS_FS_ZIP
|
||||||
iput(sbi->managed_cache);
|
iput(sbi->managed_cache);
|
||||||
sbi->managed_cache = NULL;
|
sbi->managed_cache = NULL;
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,7 @@ EROFS_ATTR_FEATURE(ztailpacking);
|
||||||
EROFS_ATTR_FEATURE(fragments);
|
EROFS_ATTR_FEATURE(fragments);
|
||||||
EROFS_ATTR_FEATURE(dedupe);
|
EROFS_ATTR_FEATURE(dedupe);
|
||||||
EROFS_ATTR_FEATURE(48bit);
|
EROFS_ATTR_FEATURE(48bit);
|
||||||
|
EROFS_ATTR_FEATURE(metabox);
|
||||||
|
|
||||||
static struct attribute *erofs_feat_attrs[] = {
|
static struct attribute *erofs_feat_attrs[] = {
|
||||||
ATTR_LIST(zero_padding),
|
ATTR_LIST(zero_padding),
|
||||||
|
|
@ -108,6 +109,7 @@ static struct attribute *erofs_feat_attrs[] = {
|
||||||
ATTR_LIST(fragments),
|
ATTR_LIST(fragments),
|
||||||
ATTR_LIST(dedupe),
|
ATTR_LIST(dedupe),
|
||||||
ATTR_LIST(48bit),
|
ATTR_LIST(48bit),
|
||||||
|
ATTR_LIST(metabox),
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
ATTRIBUTE_GROUPS(erofs_feat);
|
ATTRIBUTE_GROUPS(erofs_feat);
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,9 @@ static int erofs_init_inode_xattrs(struct inode *inode)
|
||||||
}
|
}
|
||||||
|
|
||||||
it.buf = __EROFS_BUF_INITIALIZER;
|
it.buf = __EROFS_BUF_INITIALIZER;
|
||||||
erofs_init_metabuf(&it.buf, sb);
|
ret = erofs_init_metabuf(&it.buf, sb, erofs_inode_in_metabox(inode));
|
||||||
|
if (ret)
|
||||||
|
goto out_unlock;
|
||||||
it.pos = erofs_iloc(inode) + vi->inode_isize;
|
it.pos = erofs_iloc(inode) + vi->inode_isize;
|
||||||
|
|
||||||
/* read in shared xattr array (non-atomic, see kmalloc below) */
|
/* read in shared xattr array (non-atomic, see kmalloc below) */
|
||||||
|
|
@ -326,6 +328,9 @@ static int erofs_xattr_iter_inline(struct erofs_xattr_iter *it,
|
||||||
return -ENODATA;
|
return -ENODATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = erofs_init_metabuf(&it->buf, it->sb, erofs_inode_in_metabox(inode));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
remaining = vi->xattr_isize - xattr_header_sz;
|
remaining = vi->xattr_isize - xattr_header_sz;
|
||||||
it->pos = erofs_iloc(inode) + vi->inode_isize + xattr_header_sz;
|
it->pos = erofs_iloc(inode) + vi->inode_isize + xattr_header_sz;
|
||||||
|
|
||||||
|
|
@ -361,12 +366,17 @@ static int erofs_xattr_iter_shared(struct erofs_xattr_iter *it,
|
||||||
struct erofs_inode *const vi = EROFS_I(inode);
|
struct erofs_inode *const vi = EROFS_I(inode);
|
||||||
struct super_block *const sb = it->sb;
|
struct super_block *const sb = it->sb;
|
||||||
struct erofs_sb_info *sbi = EROFS_SB(sb);
|
struct erofs_sb_info *sbi = EROFS_SB(sb);
|
||||||
unsigned int i;
|
unsigned int i = 0;
|
||||||
int ret = -ENODATA;
|
int ret;
|
||||||
|
|
||||||
for (i = 0; i < vi->xattr_shared_count; ++i) {
|
ret = erofs_init_metabuf(&it->buf, sb,
|
||||||
|
erofs_sb_has_shared_ea_in_metabox(sbi));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
while (i < vi->xattr_shared_count) {
|
||||||
it->pos = erofs_pos(sb, sbi->xattr_blkaddr) +
|
it->pos = erofs_pos(sb, sbi->xattr_blkaddr) +
|
||||||
vi->xattr_shared_xattrs[i] * sizeof(__le32);
|
vi->xattr_shared_xattrs[i++] * sizeof(__le32);
|
||||||
it->kaddr = erofs_bread(&it->buf, it->pos, true);
|
it->kaddr = erofs_bread(&it->buf, it->pos, true);
|
||||||
if (IS_ERR(it->kaddr))
|
if (IS_ERR(it->kaddr))
|
||||||
return PTR_ERR(it->kaddr);
|
return PTR_ERR(it->kaddr);
|
||||||
|
|
@ -378,7 +388,7 @@ static int erofs_xattr_iter_shared(struct erofs_xattr_iter *it,
|
||||||
if ((getxattr && ret != -ENODATA) || (!getxattr && ret))
|
if ((getxattr && ret != -ENODATA) || (!getxattr && ret))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return ret;
|
return i ? ret : -ENODATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
int erofs_getxattr(struct inode *inode, int index, const char *name,
|
int erofs_getxattr(struct inode *inode, int index, const char *name,
|
||||||
|
|
@ -413,7 +423,6 @@ int erofs_getxattr(struct inode *inode, int index, const char *name,
|
||||||
|
|
||||||
it.sb = inode->i_sb;
|
it.sb = inode->i_sb;
|
||||||
it.buf = __EROFS_BUF_INITIALIZER;
|
it.buf = __EROFS_BUF_INITIALIZER;
|
||||||
erofs_init_metabuf(&it.buf, it.sb);
|
|
||||||
it.buffer = buffer;
|
it.buffer = buffer;
|
||||||
it.buffer_size = buffer_size;
|
it.buffer_size = buffer_size;
|
||||||
it.buffer_ofs = 0;
|
it.buffer_ofs = 0;
|
||||||
|
|
@ -439,7 +448,6 @@ ssize_t erofs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
|
||||||
|
|
||||||
it.sb = dentry->d_sb;
|
it.sb = dentry->d_sb;
|
||||||
it.buf = __EROFS_BUF_INITIALIZER;
|
it.buf = __EROFS_BUF_INITIALIZER;
|
||||||
erofs_init_metabuf(&it.buf, it.sb);
|
|
||||||
it.dentry = dentry;
|
it.dentry = dentry;
|
||||||
it.buffer = buffer;
|
it.buffer = buffer;
|
||||||
it.buffer_size = buffer_size;
|
it.buffer_size = buffer_size;
|
||||||
|
|
@ -485,7 +493,7 @@ int erofs_xattr_prefixes_init(struct super_block *sb)
|
||||||
if (sbi->packed_inode)
|
if (sbi->packed_inode)
|
||||||
buf.mapping = sbi->packed_inode->i_mapping;
|
buf.mapping = sbi->packed_inode->i_mapping;
|
||||||
else
|
else
|
||||||
erofs_init_metabuf(&buf, sb);
|
(void)erofs_init_metabuf(&buf, sb, false);
|
||||||
|
|
||||||
for (i = 0; i < sbi->xattr_prefix_count; i++) {
|
for (i = 0; i < sbi->xattr_prefix_count; i++) {
|
||||||
void *ptr = erofs_read_metadata(sb, &buf, &pos, &len);
|
void *ptr = erofs_read_metadata(sb, &buf, &pos, &len);
|
||||||
|
|
|
||||||
|
|
@ -855,7 +855,10 @@ static int z_erofs_pcluster_begin(struct z_erofs_frontend *fe)
|
||||||
/* bind cache first when cached decompression is preferred */
|
/* bind cache first when cached decompression is preferred */
|
||||||
z_erofs_bind_cache(fe);
|
z_erofs_bind_cache(fe);
|
||||||
} else {
|
} else {
|
||||||
erofs_init_metabuf(&map->buf, sb);
|
ret = erofs_init_metabuf(&map->buf, sb,
|
||||||
|
erofs_inode_in_metabox(fe->inode));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
ptr = erofs_bread(&map->buf, map->m_pa, false);
|
ptr = erofs_bread(&map->buf, map->m_pa, false);
|
||||||
if (IS_ERR(ptr)) {
|
if (IS_ERR(ptr)) {
|
||||||
ret = PTR_ERR(ptr);
|
ret = PTR_ERR(ptr);
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ struct z_erofs_maprecorder {
|
||||||
u16 delta[2];
|
u16 delta[2];
|
||||||
erofs_blk_t pblk, compressedblks;
|
erofs_blk_t pblk, compressedblks;
|
||||||
erofs_off_t nextpackoff;
|
erofs_off_t nextpackoff;
|
||||||
bool partialref;
|
bool partialref, in_mbox;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int z_erofs_load_full_lcluster(struct z_erofs_maprecorder *m,
|
static int z_erofs_load_full_lcluster(struct z_erofs_maprecorder *m,
|
||||||
|
|
@ -31,7 +31,7 @@ static int z_erofs_load_full_lcluster(struct z_erofs_maprecorder *m,
|
||||||
struct z_erofs_lcluster_index *di;
|
struct z_erofs_lcluster_index *di;
|
||||||
unsigned int advise;
|
unsigned int advise;
|
||||||
|
|
||||||
di = erofs_read_metabuf(&m->map->buf, inode->i_sb, pos);
|
di = erofs_read_metabuf(&m->map->buf, inode->i_sb, pos, m->in_mbox);
|
||||||
if (IS_ERR(di))
|
if (IS_ERR(di))
|
||||||
return PTR_ERR(di);
|
return PTR_ERR(di);
|
||||||
m->lcn = lcn;
|
m->lcn = lcn;
|
||||||
|
|
@ -146,7 +146,7 @@ static int z_erofs_load_compact_lcluster(struct z_erofs_maprecorder *m,
|
||||||
else
|
else
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
in = erofs_read_metabuf(&m->map->buf, m->inode->i_sb, pos);
|
in = erofs_read_metabuf(&m->map->buf, inode->i_sb, pos, m->in_mbox);
|
||||||
if (IS_ERR(in))
|
if (IS_ERR(in))
|
||||||
return PTR_ERR(in);
|
return PTR_ERR(in);
|
||||||
|
|
||||||
|
|
@ -392,6 +392,7 @@ static int z_erofs_map_blocks_fo(struct inode *inode,
|
||||||
struct z_erofs_maprecorder m = {
|
struct z_erofs_maprecorder m = {
|
||||||
.inode = inode,
|
.inode = inode,
|
||||||
.map = map,
|
.map = map,
|
||||||
|
.in_mbox = erofs_inode_in_metabox(inode),
|
||||||
};
|
};
|
||||||
int err = 0;
|
int err = 0;
|
||||||
unsigned int endoff, afmt;
|
unsigned int endoff, afmt;
|
||||||
|
|
@ -521,6 +522,7 @@ static int z_erofs_map_blocks_ext(struct inode *inode,
|
||||||
unsigned int recsz = z_erofs_extent_recsize(vi->z_advise);
|
unsigned int recsz = z_erofs_extent_recsize(vi->z_advise);
|
||||||
erofs_off_t pos = round_up(Z_EROFS_MAP_HEADER_END(erofs_iloc(inode) +
|
erofs_off_t pos = round_up(Z_EROFS_MAP_HEADER_END(erofs_iloc(inode) +
|
||||||
vi->inode_isize + vi->xattr_isize), recsz);
|
vi->inode_isize + vi->xattr_isize), recsz);
|
||||||
|
bool in_mbox = erofs_inode_in_metabox(inode);
|
||||||
erofs_off_t lend = inode->i_size;
|
erofs_off_t lend = inode->i_size;
|
||||||
erofs_off_t l, r, mid, pa, la, lstart;
|
erofs_off_t l, r, mid, pa, la, lstart;
|
||||||
struct z_erofs_extent *ext;
|
struct z_erofs_extent *ext;
|
||||||
|
|
@ -530,7 +532,7 @@ static int z_erofs_map_blocks_ext(struct inode *inode,
|
||||||
map->m_flags = 0;
|
map->m_flags = 0;
|
||||||
if (recsz <= offsetof(struct z_erofs_extent, pstart_hi)) {
|
if (recsz <= offsetof(struct z_erofs_extent, pstart_hi)) {
|
||||||
if (recsz <= offsetof(struct z_erofs_extent, pstart_lo)) {
|
if (recsz <= offsetof(struct z_erofs_extent, pstart_lo)) {
|
||||||
ext = erofs_read_metabuf(&map->buf, sb, pos);
|
ext = erofs_read_metabuf(&map->buf, sb, pos, in_mbox);
|
||||||
if (IS_ERR(ext))
|
if (IS_ERR(ext))
|
||||||
return PTR_ERR(ext);
|
return PTR_ERR(ext);
|
||||||
pa = le64_to_cpu(*(__le64 *)ext);
|
pa = le64_to_cpu(*(__le64 *)ext);
|
||||||
|
|
@ -543,7 +545,7 @@ static int z_erofs_map_blocks_ext(struct inode *inode,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; lstart <= map->m_la; lstart += 1 << vi->z_lclusterbits) {
|
for (; lstart <= map->m_la; lstart += 1 << vi->z_lclusterbits) {
|
||||||
ext = erofs_read_metabuf(&map->buf, sb, pos);
|
ext = erofs_read_metabuf(&map->buf, sb, pos, in_mbox);
|
||||||
if (IS_ERR(ext))
|
if (IS_ERR(ext))
|
||||||
return PTR_ERR(ext);
|
return PTR_ERR(ext);
|
||||||
map->m_plen = le32_to_cpu(ext->plen);
|
map->m_plen = le32_to_cpu(ext->plen);
|
||||||
|
|
@ -563,7 +565,7 @@ static int z_erofs_map_blocks_ext(struct inode *inode,
|
||||||
for (l = 0, r = vi->z_extents; l < r; ) {
|
for (l = 0, r = vi->z_extents; l < r; ) {
|
||||||
mid = l + (r - l) / 2;
|
mid = l + (r - l) / 2;
|
||||||
ext = erofs_read_metabuf(&map->buf, sb,
|
ext = erofs_read_metabuf(&map->buf, sb,
|
||||||
pos + mid * recsz);
|
pos + mid * recsz, in_mbox);
|
||||||
if (IS_ERR(ext))
|
if (IS_ERR(ext))
|
||||||
return PTR_ERR(ext);
|
return PTR_ERR(ext);
|
||||||
|
|
||||||
|
|
@ -645,7 +647,7 @@ static int z_erofs_fill_inode(struct inode *inode, struct erofs_map_blocks *map)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
||||||
pos = ALIGN(erofs_iloc(inode) + vi->inode_isize + vi->xattr_isize, 8);
|
pos = ALIGN(erofs_iloc(inode) + vi->inode_isize + vi->xattr_isize, 8);
|
||||||
h = erofs_read_metabuf(&map->buf, sb, pos);
|
h = erofs_read_metabuf(&map->buf, sb, pos, erofs_inode_in_metabox(inode));
|
||||||
if (IS_ERR(h)) {
|
if (IS_ERR(h)) {
|
||||||
err = PTR_ERR(h);
|
err = PTR_ERR(h);
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue