1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
// 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->metazone_startblk == 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;
/* FIXME: sbi->meta_blkaddr should be 0 for 48-bit layouts */
sbi->meta_blkaddr = EROFS_META_NEW_ADDR;
}
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;
bh = erofs_balloc(sbi->bmgr, DATA, 0, 0);
if (!bh)
return PTR_ERR(bh);
erofs_mapbh(NULL, bh->block);
pos_out = erofs_btell(bh, false);
meta_blkaddr = pos_out >> sbi->blkszbits;
sbi->metazone_startblk = meta_blkaddr;
m2bgr = m2gr->bmgr;
ret = erofs_bflush(m2bgr, NULL);
if (ret)
return ret;
length = erofs_mapbh(m2bgr, NULL) << sbi->blkszbits;
ret = erofs_bh_balloon(bh, length);
if (ret < 0)
return ret;
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;
}
|