blob: 37267ddb73cf6de379b376d1043df37f9d9d2f53 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0
#include <stdlib.h>
#include "erofs/inode.h"
#include "erofs/importer.h"
#include "erofs/print.h"
#include "liberofs_cache.h"
#include "liberofs_private.h"
#include "liberofs_metabox.h"
const char *erofs_metabox_identifier = "metabox";
struct erofs_metamgr {
struct erofs_vfile vf;
struct erofs_bufmgr *bmgr;
};
static void erofs_metamgr_exit(struct erofs_metamgr *m2gr)
{
DBG_BUGON(!m2gr->bmgr);
erofs_buffer_exit(m2gr->bmgr);
erofs_io_close(&m2gr->vf);
free(m2gr);
}
static int erofs_metamgr_init(struct erofs_sb_info *sbi,
struct erofs_metamgr *m2gr)
{
int ret;
ret = erofs_tmpfile();
if (ret < 0)
return ret;
m2gr->vf = (struct erofs_vfile){ .fd = ret };
m2gr->bmgr = erofs_buffer_init(sbi, 0, &m2gr->vf);
if (!m2gr->bmgr)
return -ENOMEM;
return 0;
}
void erofs_metadata_exit(struct erofs_sb_info *sbi)
{
if (sbi->m2gr) {
erofs_metamgr_exit(sbi->m2gr);
sbi->m2gr = NULL;
}
if (sbi->mxgr) {
erofs_metamgr_exit(sbi->mxgr);
sbi->mxgr = NULL;
}
}
int erofs_metadata_init(struct erofs_sb_info *sbi)
{
struct erofs_metamgr *m2gr;
int ret;
if (!sbi->m2gr && sbi->meta_blkaddr == EROFS_META_NEW_ADDR) {
m2gr = malloc(sizeof(*m2gr));
if (!m2gr)
return -ENOMEM;
ret = erofs_metamgr_init(sbi, m2gr);
if (ret)
goto err_free;
sbi->m2gr = m2gr;
}
if (!sbi->mxgr && erofs_sb_has_metabox(sbi)) {
m2gr = malloc(sizeof(*m2gr));
if (!m2gr)
return -ENOMEM;
ret = erofs_metamgr_init(sbi, m2gr);
if (ret)
goto err_free;
sbi->mxgr = m2gr;
}
return 0;
err_free:
free(m2gr);
return ret;
}
struct erofs_bufmgr *erofs_metadata_bmgr(struct erofs_sb_info *sbi, bool mbox)
{
if (mbox) {
if (sbi->mxgr)
return sbi->mxgr->bmgr;
} else if (sbi->m2gr) {
return sbi->m2gr->bmgr;
}
return NULL;
}
int erofs_metabox_iflush(struct erofs_importer *im)
{
struct erofs_sb_info *sbi = im->sbi;
struct erofs_metamgr *mxgr = sbi->mxgr;
struct erofs_inode *inode;
int err;
if (!mxgr || !erofs_sb_has_metabox(sbi))
return -EINVAL;
err = erofs_bflush(mxgr->bmgr, NULL);
if (err)
return err;
if (erofs_io_lseek(&mxgr->vf, 0, SEEK_END) <= 0)
return 0;
inode = erofs_mkfs_build_special_from_fd(im, mxgr->vf.fd,
EROFS_METABOX_INODE);
sbi->metabox_nid = erofs_lookupnid(inode);
erofs_iput(inode);
return 0;
}
int erofs_metazone_flush(struct erofs_sb_info *sbi)
{
struct erofs_metamgr *m2gr = sbi->m2gr;
struct erofs_buffer_head *bh;
struct erofs_bufmgr *m2bgr;
erofs_blk_t meta_blkaddr;
u64 length, pos_out;
int ret, count;
if (!m2gr)
return 0;
m2bgr = m2gr->bmgr;
ret = erofs_bflush(m2bgr, NULL);
if (ret)
return ret;
length = erofs_mapbh(m2bgr, NULL) << sbi->blkszbits;
bh = erofs_balloc(sbi->bmgr, DATA, length, 0);
if (!bh)
return PTR_ERR(bh);
erofs_mapbh(NULL, bh->block);
pos_out = erofs_btell(bh, false);
meta_blkaddr = pos_out >> sbi->blkszbits;
do {
count = min_t(erofs_off_t, length, INT_MAX);
ret = erofs_io_xcopy(sbi->bmgr->vf, pos_out,
&m2gr->vf, count, false);
if (ret < 0)
break;
pos_out += count;
} while (length -= count);
bh->op = &erofs_drop_directly_bhops;
erofs_bdrop(bh, false);
sbi->meta_blkaddr += meta_blkaddr;
return 0;
}