Skip to content

Commit

Permalink
erofs: introduce meta buffer operations
Browse files Browse the repository at this point in the history
In order to support subpage and folio for all uncompressed files,
introduce meta buffer descriptors, which can be effectively stored
on stack, in place of meta page operations.

This converts the uncompressed data path to meta buffers.

Link: https://lore.kernel.org/r/[email protected]
Reviewed-by: Liu Bo <[email protected]>
Reviewed-by: Chao Yu <[email protected]>
Signed-off-by: Gao Xiang <[email protected]>
  • Loading branch information
hsiangkao committed Jan 4, 2022
1 parent ab92184 commit fdf80a4
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 21 deletions.
98 changes: 77 additions & 21 deletions fs/erofs/data.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,57 @@ struct page *erofs_get_meta_page(struct super_block *sb, erofs_blk_t blkaddr)
return page;
}

void erofs_unmap_metabuf(struct erofs_buf *buf)
{
if (buf->kmap_type == EROFS_KMAP)
kunmap(buf->page);
else if (buf->kmap_type == EROFS_KMAP_ATOMIC)
kunmap_atomic(buf->base);
buf->base = NULL;
buf->kmap_type = EROFS_NO_KMAP;
}

void erofs_put_metabuf(struct erofs_buf *buf)
{
if (!buf->page)
return;
erofs_unmap_metabuf(buf);
put_page(buf->page);
buf->page = NULL;
}

void *erofs_read_metabuf(struct erofs_buf *buf, struct super_block *sb,
erofs_blk_t blkaddr, enum erofs_kmap_type type)
{
struct address_space *const mapping = sb->s_bdev->bd_inode->i_mapping;
erofs_off_t offset = blknr_to_addr(blkaddr);
pgoff_t index = offset >> PAGE_SHIFT;
struct page *page = buf->page;

if (!page || page->index != index) {
erofs_put_metabuf(buf);
page = read_cache_page_gfp(mapping, index,
mapping_gfp_constraint(mapping, ~__GFP_FS));
if (IS_ERR(page))
return page;
/* should already be PageUptodate, no need to lock page */
buf->page = page;
}
if (buf->kmap_type == EROFS_NO_KMAP) {
if (type == EROFS_KMAP)
buf->base = kmap(page);
else if (type == EROFS_KMAP_ATOMIC)
buf->base = kmap_atomic(page);
buf->kmap_type = type;
} else if (buf->kmap_type != type) {
DBG_BUGON(1);
return ERR_PTR(-EFAULT);
}
if (type == EROFS_NO_KMAP)
return NULL;
return buf->base + (offset & ~PAGE_MASK);
}

static int erofs_map_blocks_flatmode(struct inode *inode,
struct erofs_map_blocks *map,
int flags)
Expand All @@ -31,7 +82,7 @@ static int erofs_map_blocks_flatmode(struct inode *inode,
struct erofs_inode *vi = EROFS_I(inode);
bool tailendpacking = (vi->datalayout == EROFS_INODE_FLAT_INLINE);

nblocks = DIV_ROUND_UP(inode->i_size, PAGE_SIZE);
nblocks = DIV_ROUND_UP(inode->i_size, EROFS_BLKSIZ);
lastblk = nblocks - tailendpacking;

/* there is no hole in flatmode */
Expand Down Expand Up @@ -72,10 +123,11 @@ static int erofs_map_blocks(struct inode *inode,
struct super_block *sb = inode->i_sb;
struct erofs_inode *vi = EROFS_I(inode);
struct erofs_inode_chunk_index *idx;
struct page *page;
struct erofs_buf buf = __EROFS_BUF_INITIALIZER;
u64 chunknr;
unsigned int unit;
erofs_off_t pos;
void *kaddr;
int err = 0;

trace_erofs_map_blocks_enter(inode, map, flags);
Expand All @@ -101,9 +153,9 @@ static int erofs_map_blocks(struct inode *inode,
pos = ALIGN(iloc(EROFS_SB(sb), vi->nid) + vi->inode_isize +
vi->xattr_isize, unit) + unit * chunknr;

page = erofs_get_meta_page(inode->i_sb, erofs_blknr(pos));
if (IS_ERR(page)) {
err = PTR_ERR(page);
kaddr = erofs_read_metabuf(&buf, sb, erofs_blknr(pos), EROFS_KMAP);
if (IS_ERR(kaddr)) {
err = PTR_ERR(kaddr);
goto out;
}
map->m_la = chunknr << vi->chunkbits;
Expand All @@ -112,7 +164,7 @@ static int erofs_map_blocks(struct inode *inode,

/* handle block map */
if (!(vi->chunkformat & EROFS_CHUNK_FORMAT_INDEXES)) {
__le32 *blkaddr = page_address(page) + erofs_blkoff(pos);
__le32 *blkaddr = kaddr + erofs_blkoff(pos);

if (le32_to_cpu(*blkaddr) == EROFS_NULL_ADDR) {
map->m_flags = 0;
Expand All @@ -123,7 +175,7 @@ static int erofs_map_blocks(struct inode *inode,
goto out_unlock;
}
/* parse chunk indexes */
idx = page_address(page) + erofs_blkoff(pos);
idx = kaddr + erofs_blkoff(pos);
switch (le32_to_cpu(idx->blkaddr)) {
case EROFS_NULL_ADDR:
map->m_flags = 0;
Expand All @@ -136,8 +188,7 @@ static int erofs_map_blocks(struct inode *inode,
break;
}
out_unlock:
unlock_page(page);
put_page(page);
erofs_put_metabuf(&buf);
out:
if (!err)
map->m_llen = map->m_plen;
Expand Down Expand Up @@ -226,16 +277,16 @@ static int erofs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
}

if (map.m_flags & EROFS_MAP_META) {
struct page *ipage;
void *ptr;
struct erofs_buf buf = __EROFS_BUF_INITIALIZER;

iomap->type = IOMAP_INLINE;
ipage = erofs_get_meta_page(inode->i_sb,
erofs_blknr(mdev.m_pa));
if (IS_ERR(ipage))
return PTR_ERR(ipage);
iomap->inline_data = page_address(ipage) +
erofs_blkoff(mdev.m_pa);
iomap->private = ipage;
ptr = erofs_read_metabuf(&buf, inode->i_sb,
erofs_blknr(mdev.m_pa), EROFS_KMAP);
if (IS_ERR(ptr))
return PTR_ERR(ptr);
iomap->inline_data = ptr + erofs_blkoff(mdev.m_pa);
iomap->private = buf.base;
} else {
iomap->type = IOMAP_MAPPED;
iomap->addr = mdev.m_pa;
Expand All @@ -246,12 +297,17 @@ static int erofs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
static int erofs_iomap_end(struct inode *inode, loff_t pos, loff_t length,
ssize_t written, unsigned int flags, struct iomap *iomap)
{
struct page *ipage = iomap->private;
void *ptr = iomap->private;

if (ptr) {
struct erofs_buf buf = {
.page = kmap_to_page(ptr),
.base = ptr,
.kmap_type = EROFS_KMAP,
};

if (ipage) {
DBG_BUGON(iomap->type != IOMAP_INLINE);
unlock_page(ipage);
put_page(ipage);
erofs_put_metabuf(&buf);
} else {
DBG_BUGON(iomap->type == IOMAP_INLINE);
}
Expand Down
13 changes: 13 additions & 0 deletions fs/erofs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,19 @@ static inline int erofs_wait_on_workgroup_freezed(struct erofs_workgroup *grp)
#error erofs cannot be used in this platform
#endif

enum erofs_kmap_type {
EROFS_NO_KMAP, /* don't map the buffer */
EROFS_KMAP, /* use kmap() to map the buffer */
EROFS_KMAP_ATOMIC, /* use kmap_atomic() to map the buffer */
};

struct erofs_buf {
struct page *page;
void *base;
enum erofs_kmap_type kmap_type;
};
#define __EROFS_BUF_INITIALIZER ((struct erofs_buf){ .page = NULL })

#define ROOT_NID(sb) ((sb)->root_nid)

#define erofs_blknr(addr) ((addr) / EROFS_BLKSIZ)
Expand Down

0 comments on commit fdf80a4

Please sign in to comment.