blob: 466ade1dd3670fbc9ab0099db210e974438b9e26 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
* All Rights Reserved.
*/
#include "libxfs.h"
#include <sys/stat.h>
#include "libfrog/convert.h"
#include "proto.h"
/*
* Prototypes for internal functions.
*/
static char *getstr(char **pp);
static void fail(char *msg, int i);
static struct xfs_trans * getres(struct xfs_mount *mp, uint blocks);
static void rsvfile(xfs_mount_t *mp, xfs_inode_t *ip, long long len);
static char *newregfile(char **pp, int *len);
static int metadir_create(struct xfs_mount *mp);
static void rtinit(xfs_mount_t *mp);
static long filesize(int fd);
/*
* Use this for block reservations needed for mkfs's conditions
* (basically no fragmentation).
*/
#define MKFS_BLOCKRES_INODE \
((uint)(M_IGEO(mp)->ialloc_blks + (M_IGEO(mp)->inobt_maxlevels - 1)))
#define MKFS_BLOCKRES(rb) \
((uint)(MKFS_BLOCKRES_INODE + XFS_DA_NODE_MAXDEPTH + \
(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1) + (rb)))
static long long
getnum(
const char *str,
unsigned int blksize,
unsigned int sectsize,
bool convert)
{
long long i;
char *sp;
if (convert)
return cvtnum(blksize, sectsize, str);
i = strtoll(str, &sp, 0);
if (i == 0 && sp == str)
return -1LL;
if (*sp != '\0')
return -1LL; /* trailing garbage */
return i;
}
char *
setup_proto(
char *fname)
{
char *buf = NULL;
static char dflt[] = "d--755 0 0 $";
int fd;
long size;
if (!fname)
return dflt;
if ((fd = open(fname, O_RDONLY)) < 0 || (size = filesize(fd)) < 0) {
fprintf(stderr, _("%s: failed to open %s: %s\n"),
progname, fname, strerror(errno));
goto out_fail;
}
buf = malloc(size + 1);
if (read(fd, buf, size) < size) {
fprintf(stderr, _("%s: read failed on %s: %s\n"),
progname, fname, strerror(errno));
goto out_fail;
}
if (buf[size - 1] != '\n') {
fprintf(stderr, _("%s: proto file %s premature EOF\n"),
progname, fname);
goto out_fail;
}
buf[size] = '\0';
/*
* Skip past the stuff there for compatibility, a string and 2 numbers.
*/
(void)getstr(&buf); /* boot image name */
(void)getnum(getstr(&buf), 0, 0, false); /* block count */
(void)getnum(getstr(&buf), 0, 0, false); /* inode count */
close(fd);
return buf;
out_fail:
if (fd >= 0)
close(fd);
free(buf);
exit(1);
}
static void
fail(
char *msg,
int i)
{
fprintf(stderr, "%s: %s [%d - %s]\n", progname, msg, i, strerror(i));
exit(1);
}
void
res_failed(
int i)
{
fail(_("cannot reserve space"), i);
}
static struct xfs_trans *
getres(
struct xfs_mount *mp,
uint blocks)
{
struct xfs_trans *tp;
int i;
uint r;
for (i = 0, r = MKFS_BLOCKRES(blocks); r >= blocks; r--) {
i = -libxfs_trans_alloc_rollable(mp, r, &tp);
if (i == 0)
return tp;
}
res_failed(i);
/* NOTREACHED */
return NULL;
}
static char *
getstr(
char **pp)
{
char c;
char *p;
char *rval;
p = *pp;
while ((c = *p)) {
switch (c) {
case ' ':
case '\t':
case '\n':
p++;
continue;
case ':':
p++;
while (*p++ != '\n')
;
continue;
default:
rval = p;
while (c != ' ' && c != '\t' && c != '\n' && c != '\0')
c = *++p;
*p++ = '\0';
*pp = p;
return rval;
}
}
if (c != '\0') {
fprintf(stderr, _("%s: premature EOF in prototype file\n"),
progname);
exit(1);
}
return NULL;
}
static void
rsvfile(
xfs_mount_t *mp,
xfs_inode_t *ip,
long long llen)
{
int error;
xfs_trans_t *tp;
error = -libxfs_alloc_file_space(ip, 0, llen, XFS_BMAPI_PREALLOC);
if (error) {
fail(_("error reserving space for a file"), error);
exit(1);
}
/*
* update the inode timestamp, mode, and prealloc flag bits
*/
error = -libxfs_trans_alloc_rollable(mp, 0, &tp);
if (error)
fail(_("allocating transaction for a file"), error);
libxfs_trans_ijoin(tp, ip, 0);
VFS_I(ip)->i_mode &= ~S_ISUID;
/*
* Note that we don't have to worry about mandatory
* file locking being disabled here because we only
* clear the S_ISGID bit if the Group execute bit is
* on, but if it was on then mandatory locking wouldn't
* have been enabled.
*/
if (VFS_I(ip)->i_mode & S_IXGRP)
VFS_I(ip)->i_mode &= ~S_ISGID;
libxfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
ip->i_diflags |= XFS_DIFLAG_PREALLOC;
libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
error = -libxfs_trans_commit(tp);
if (error)
fail(_("committing space for a file failed"), error);
}
static void
writesymlink(
struct xfs_trans *tp,
struct xfs_inode *ip,
char *buf,
int len)
{
struct xfs_mount *mp = tp->t_mountp;
xfs_extlen_t nb = XFS_B_TO_FSB(mp, len);
int error;
error = -libxfs_symlink_write_target(tp, ip, buf, len, nb, nb);
if (error) {
fprintf(stderr,
_("%s: error %d creating symlink to '%s'.\n"), progname, error, buf);
exit(1);
}
}
static void
writefile(
struct xfs_trans *tp,
struct xfs_inode *ip,
char *buf,
int len)
{
struct xfs_bmbt_irec map;
struct xfs_mount *mp;
xfs_extlen_t nb;
int nmap;
int error;
mp = ip->i_mount;
if (len > 0) {
nb = XFS_B_TO_FSB(mp, len);
nmap = 1;
error = -libxfs_bmapi_write(tp, ip, 0, nb, 0, nb, &map, &nmap);
if (error == ENOSYS && XFS_IS_REALTIME_INODE(ip)) {
fprintf(stderr,
_("%s: creating realtime files from proto file not supported.\n"),
progname);
exit(1);
}
if (error)
fail(_("error allocating space for a file"), error);
if (nmap != 1) {
fprintf(stderr,
_("%s: cannot allocate space for file\n"),
progname);
exit(1);
}
error = -libxfs_file_write(tp, ip, buf, len, false);
if (error)
fail(_("error writing file"), error);
}
ip->i_disk_size = len;
}
static char *
newregfile(
char **pp,
int *len)
{
char *buf;
int fd;
char *fname;
long size;
fname = getstr(pp);
if ((fd = open(fname, O_RDONLY)) < 0 || (size = filesize(fd)) < 0) {
fprintf(stderr, _("%s: cannot open %s: %s\n"),
progname, fname, strerror(errno));
exit(1);
}
if ((*len = (int)size)) {
buf = malloc(size);
if (read(fd, buf, size) < size) {
fprintf(stderr, _("%s: read failed on %s: %s\n"),
progname, fname, strerror(errno));
exit(1);
}
} else
buf = NULL;
close(fd);
return buf;
}
static void
newdirent(
xfs_mount_t *mp,
xfs_trans_t *tp,
xfs_inode_t *pip,
struct xfs_name *name,
xfs_ino_t inum)
{
int error;
int rsv;
rsv = XFS_DIRENTER_SPACE_RES(mp, name->len);
error = -libxfs_dir_createname(tp, pip, name, inum, rsv);
if (error)
fail(_("directory createname error"), error);
}
static void
newdirectory(
xfs_mount_t *mp,
xfs_trans_t *tp,
xfs_inode_t *dp,
xfs_inode_t *pdp)
{
int error;
error = -libxfs_dir_init(tp, dp, pdp);
if (error)
fail(_("directory create error"), error);
}
struct cred {
uid_t cr_uid;
gid_t cr_gid;
};
static int
creatproto(
struct xfs_trans **tpp,
struct xfs_inode *dp,
mode_t mode,
nlink_t nlink,
xfs_dev_t rdev,
struct cred *cr,
struct fsxattr *fsx,
struct xfs_inode **ipp)
{
struct xfs_icreate_args args = {
.pip = dp,
.uid = make_kuid(cr->cr_uid),
.gid = make_kgid(cr->cr_gid),
.prid = dp ? libxfs_get_initial_prid(dp) : 0,
.nlink = nlink,
.rdev = rdev,
.mode = mode,
.flags = XFS_ICREATE_ARGS_FORCE_UID |
XFS_ICREATE_ARGS_FORCE_GID |
XFS_ICREATE_ARGS_FORCE_MODE,
};
struct xfs_inode *ip;
xfs_ino_t ino;
int error;
error = -libxfs_dialloc(tpp, dp, mode, &ino);
if (error)
return error;
error = -libxfs_icreate(*tpp, ino, &args, ipp);
if (error || dp)
return error;
/* Set root directory inode flags from the provided fsxattr. */
ip = *ipp;
ip->i_projid = fsx->fsx_projid;
ip->i_extsize = fsx->fsx_extsize;
ip->i_diflags = xfs_flags2diflags(ip, fsx->fsx_xflags);
if (xfs_has_v3inodes(ip->i_mount)) {
ip->i_diflags2 = xfs_flags2diflags2(ip, fsx->fsx_xflags);
ip->i_cowextsize = fsx->fsx_cowextsize;
}
libxfs_trans_log_inode(*tpp, ip, XFS_ILOG_CORE);
return 0;
}
static void
parseproto(
xfs_mount_t *mp,
xfs_inode_t *pip,
struct fsxattr *fsxp,
char **pp,
char *name)
{
#define IF_REGULAR 0
#define IF_RESERVED 1
#define IF_BLOCK 2
#define IF_CHAR 3
#define IF_DIRECTORY 4
#define IF_SYMLINK 5
#define IF_FIFO 6
char *buf;
int error;
int flags;
int fmt;
int i;
xfs_inode_t *ip;
int len;
long long llen;
int majdev;
int mindev;
int mode;
char *mstr;
xfs_trans_t *tp;
int val;
int isroot = 0;
struct cred creds;
char *value;
struct xfs_name xname;
memset(&creds, 0, sizeof(creds));
mstr = getstr(pp);
switch (mstr[0]) {
case '-':
fmt = IF_REGULAR;
break;
case 'r':
fmt = IF_RESERVED;
break;
case 'b':
fmt = IF_BLOCK;
break;
case 'c':
fmt = IF_CHAR;
break;
case 'd':
fmt = IF_DIRECTORY;
break;
case 'l':
fmt = IF_SYMLINK;
break;
case 'p':
fmt = IF_FIFO;
break;
default:
fprintf(stderr, _("%s: bad format string %s\n"),
progname, mstr);
exit(1);
}
mode = 0;
switch (mstr[1]) {
case '-':
break;
case 'u':
mode |= S_ISUID;
break;
default:
fprintf(stderr, _("%s: bad format string %s\n"),
progname, mstr);
exit(1);
}
switch (mstr[2]) {
case '-':
break;
case 'g':
mode |= S_ISGID;
break;
default:
fprintf(stderr, _("%s: bad format string %s\n"),
progname, mstr);
exit(1);
}
val = 0;
for (i = 3; i < 6; i++) {
if (mstr[i] < '0' || mstr[i] > '7') {
fprintf(stderr, _("%s: bad format string %s\n"),
progname, mstr);
exit(1);
}
val = val * 8 + mstr[i] - '0';
}
mode |= val;
creds.cr_uid = (int)getnum(getstr(pp), 0, 0, false);
creds.cr_gid = (int)getnum(getstr(pp), 0, 0, false);
xname.name = (unsigned char *)name;
xname.len = name ? strlen(name) : 0;
xname.type = 0;
flags = XFS_ILOG_CORE;
switch (fmt) {
case IF_REGULAR:
buf = newregfile(pp, &len);
tp = getres(mp, XFS_B_TO_FSB(mp, len));
error = creatproto(&tp, pip, mode | S_IFREG, 1, 0, &creds,
fsxp, &ip);
if (error)
fail(_("Inode allocation failed"), error);
writefile(tp, ip, buf, len);
if (buf)
free(buf);
libxfs_trans_ijoin(tp, pip, 0);
xname.type = XFS_DIR3_FT_REG_FILE;
newdirent(mp, tp, pip, &xname, ip->i_ino);
break;
case IF_RESERVED: /* pre-allocated space only */
value = getstr(pp);
llen = getnum(value, mp->m_sb.sb_blocksize,
mp->m_sb.sb_sectsize, true);
if (llen < 0) {
fprintf(stderr,
_("%s: Bad value %s for proto file %s\n"),
progname, value, name);
exit(1);
}
tp = getres(mp, XFS_B_TO_FSB(mp, llen));
error = creatproto(&tp, pip, mode | S_IFREG, 1, 0, &creds,
fsxp, &ip);
if (error)
fail(_("Inode pre-allocation failed"), error);
libxfs_trans_ijoin(tp, pip, 0);
xname.type = XFS_DIR3_FT_REG_FILE;
newdirent(mp, tp, pip, &xname, ip->i_ino);
libxfs_trans_log_inode(tp, ip, flags);
error = -libxfs_trans_commit(tp);
if (error)
fail(_("Space preallocation failed."), error);
rsvfile(mp, ip, llen);
libxfs_irele(ip);
return;
case IF_BLOCK:
tp = getres(mp, 0);
majdev = getnum(getstr(pp), 0, 0, false);
mindev = getnum(getstr(pp), 0, 0, false);
error = creatproto(&tp, pip, mode | S_IFBLK, 1,
IRIX_MKDEV(majdev, mindev), &creds, fsxp, &ip);
if (error) {
fail(_("Inode allocation failed"), error);
}
libxfs_trans_ijoin(tp, pip, 0);
xname.type = XFS_DIR3_FT_BLKDEV;
newdirent(mp, tp, pip, &xname, ip->i_ino);
flags |= XFS_ILOG_DEV;
break;
case IF_CHAR:
tp = getres(mp, 0);
majdev = getnum(getstr(pp), 0, 0, false);
mindev = getnum(getstr(pp), 0, 0, false);
error = creatproto(&tp, pip, mode | S_IFCHR, 1,
IRIX_MKDEV(majdev, mindev), &creds, fsxp, &ip);
if (error)
fail(_("Inode allocation failed"), error);
libxfs_trans_ijoin(tp, pip, 0);
xname.type = XFS_DIR3_FT_CHRDEV;
newdirent(mp, tp, pip, &xname, ip->i_ino);
flags |= XFS_ILOG_DEV;
break;
case IF_FIFO:
tp = getres(mp, 0);
error = creatproto(&tp, pip, mode | S_IFIFO, 1, 0, &creds,
fsxp, &ip);
if (error)
fail(_("Inode allocation failed"), error);
libxfs_trans_ijoin(tp, pip, 0);
xname.type = XFS_DIR3_FT_FIFO;
newdirent(mp, tp, pip, &xname, ip->i_ino);
break;
case IF_SYMLINK:
buf = getstr(pp);
len = (int)strlen(buf);
tp = getres(mp, XFS_B_TO_FSB(mp, len));
error = creatproto(&tp, pip, mode | S_IFLNK, 1, 0, &creds,
fsxp, &ip);
if (error)
fail(_("Inode allocation failed"), error);
writesymlink(tp, ip, buf, len);
libxfs_trans_ijoin(tp, pip, 0);
xname.type = XFS_DIR3_FT_SYMLINK;
newdirent(mp, tp, pip, &xname, ip->i_ino);
break;
case IF_DIRECTORY:
tp = getres(mp, 0);
error = creatproto(&tp, pip, mode | S_IFDIR, 1, 0, &creds,
fsxp, &ip);
if (error)
fail(_("Inode allocation failed"), error);
inc_nlink(VFS_I(ip)); /* account for . */
if (!pip) {
pip = ip;
mp->m_sb.sb_rootino = ip->i_ino;
libxfs_log_sb(tp);
isroot = 1;
} else {
libxfs_trans_ijoin(tp, pip, 0);
xname.type = XFS_DIR3_FT_DIR;
newdirent(mp, tp, pip, &xname, ip->i_ino);
inc_nlink(VFS_I(pip));
libxfs_trans_log_inode(tp, pip, XFS_ILOG_CORE);
}
newdirectory(mp, tp, ip, pip);
libxfs_trans_log_inode(tp, ip, flags);
error = -libxfs_trans_commit(tp);
if (error)
fail(_("Directory inode allocation failed."), error);
/*
* RT initialization. Do this here to ensure that
* the RT inodes get placed after the root inode.
*/
if (isroot) {
error = metadir_create(mp);
if (error)
fail(
_("Creation of the metadata directory inode failed"),
error);
rtinit(mp);
}
tp = NULL;
for (;;) {
name = getstr(pp);
if (!name)
break;
if (strcmp(name, "$") == 0)
break;
parseproto(mp, ip, fsxp, pp, name);
}
libxfs_irele(ip);
return;
default:
ASSERT(0);
fail(_("Unknown format"), EINVAL);
}
libxfs_trans_log_inode(tp, ip, flags);
error = -libxfs_trans_commit(tp);
if (error) {
fail(_("Error encountered creating file from prototype file"),
error);
}
libxfs_irele(ip);
}
void
parse_proto(
xfs_mount_t *mp,
struct fsxattr *fsx,
char **pp)
{
parseproto(mp, NULL, fsx, pp, NULL);
}
/* Create a new metadata root directory. */
static int
metadir_create(
struct xfs_mount *mp)
{
struct xfs_imeta_update upd;
struct xfs_trans *tp;
struct xfs_inode *ip;
int error;
if (!xfs_has_metadir(mp))
return 0;
/*
* The root of the metadata directory tree must be the next inode
* after the root directory. Reset the AGI rotor to satisfy this
* requirement.
*/
mp->m_agirotor = 0;
error = -libxfs_imeta_start_update(mp, &XFS_IMETA_METADIR, &upd);
if (error)
return error;
/*
* The metadata directory should always be the inode after the root
* directory. The chunk containing both of those inodes should already
* exist, because we (re)create the root directory first. So, no block
* reservation is necessary.
*/
error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_imeta_create,
libxfs_imeta_create_space_res(mp), 0, 0, &tp);
if (error)
goto out_end;
error = -libxfs_imeta_create(&tp, &XFS_IMETA_METADIR, S_IFDIR, 0, &ip,
&upd);
if (error)
goto out_cancel;
error = -libxfs_trans_commit(tp);
if (error)
goto out_end;
libxfs_imeta_end_update(mp, &upd, error);
mp->m_metadirip = ip;
return 0;
out_cancel:
libxfs_trans_cancel(tp);
out_end:
libxfs_imeta_end_update(mp, &upd, error);
return error;
}
/* Create the realtime bitmap inode. */
static void
rtbitmap_create(
struct xfs_mount *mp)
{
struct xfs_imeta_update upd;
struct xfs_trans *tp;
struct xfs_inode *rbmip;
int error;
error = -libxfs_imeta_ensure_dirpath(mp, &XFS_IMETA_RTBITMAP);
if (error)
fail(_("Realtime bitmap directory allocation failed"), error);
error = -libxfs_imeta_start_update(mp, &XFS_IMETA_RTBITMAP, &upd);
if (error)
res_failed(error);
error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_imeta_create,
libxfs_imeta_create_space_res(mp), 0, 0, &tp);
if (error)
res_failed(error);
error = -libxfs_imeta_create(&tp, &XFS_IMETA_RTBITMAP, S_IFREG, 0,
&rbmip, &upd);
if (error)
fail(_("Realtime bitmap inode allocation failed"), error);
rbmip->i_disk_size = mp->m_sb.sb_rbmblocks * mp->m_sb.sb_blocksize;
rbmip->i_diflags |= XFS_DIFLAG_NEWRTBM;
*(uint64_t *)&VFS_I(rbmip)->i_atime = 0;
libxfs_trans_log_inode(tp, rbmip, XFS_ILOG_CORE);
error = -libxfs_trans_commit(tp);
if (error)
fail(_("Completion of the realtime bitmap inode failed"),
error);
mp->m_rbmip = rbmip;
libxfs_imeta_end_update(mp, &upd, 0);
}
/* Create the realtime summary inode. */
static void
rtsummary_create(
struct xfs_mount *mp)
{
struct xfs_imeta_update upd;
struct xfs_trans *tp;
struct xfs_inode *rsumip;
int error;
error = -libxfs_imeta_ensure_dirpath(mp, &XFS_IMETA_RTSUMMARY);
if (error)
fail(_("Realtime summary directory allocation failed"), error);
error = -libxfs_imeta_start_update(mp, &XFS_IMETA_RTSUMMARY, &upd);
if (error)
res_failed(error);
error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_imeta_create,
libxfs_imeta_create_space_res(mp), 0, 0, &tp);
if (error)
res_failed(error);
error = -libxfs_imeta_create(&tp, &XFS_IMETA_RTSUMMARY, S_IFREG, 0,
&rsumip, &upd);
if (error)
fail(_("Realtime summary inode allocation failed"), error);
rsumip->i_disk_size = mp->m_rsumsize;
libxfs_trans_log_inode(tp, rsumip, XFS_ILOG_CORE);
error = -libxfs_trans_commit(tp);
if (error)
fail(_("Completion of the realtime summary inode failed"),
error);
mp->m_rsumip = rsumip;
libxfs_imeta_end_update(mp, &upd, 0);
}
/* Create the realtime rmap btree inode. */
static void
rtrmapbt_create(
struct xfs_mount *mp)
{
struct xfs_imeta_update upd;
struct xfs_trans *tp;
int error;
error = -libxfs_imeta_ensure_dirpath(mp, &XFS_IMETA_RTRMAPBT);
if (error)
fail(_("Realtime rmapbt directory allocation failed"),
error);
error = -libxfs_imeta_start_update(mp, &XFS_IMETA_RTRMAPBT, &upd);
if (error)
res_failed(error);
error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_imeta_create,
libxfs_imeta_create_space_res(mp), 0, 0, &tp);
if (error)
res_failed(error);
error = -libxfs_rtrmapbt_create(&tp, &upd, &mp->m_rrmapip);
if (error)
fail(_("Completion of the realtime rmapbt failed"),
error);
error = -libxfs_trans_commit(tp);
if (error)
fail(_("Completion of the realtime rmapbt inode failed"),
error);
libxfs_imeta_end_update(mp, &upd, 0);
}
/* Zero the realtime bitmap. */
static void
rtbitmap_init(
struct xfs_mount *mp)
{
int error;
error = -libxfs_alloc_file_space(mp->m_rbmip, 0,
mp->m_sb.sb_rbmblocks << mp->m_sb.sb_blocklog,
XFS_BMAPI_ZERO);
if (error)
fail(
_("Block allocation of the realtime bitmap inode failed"),
error);
}
/* Zero the realtime summary file. */
static void
rtsummary_init(
struct xfs_mount *mp)
{
int error;
error = -libxfs_alloc_file_space(mp->m_rsumip, 0, mp->m_rsumsize,
XFS_BMAPI_ZERO);
if (error)
fail(
_("Block allocation of the realtime summary inode failed"),
error);
}
/*
* Free the whole realtime area using transactions.
* Do one transaction per bitmap block.
*/
static void
rtfreesp_init(
struct xfs_mount *mp)
{
struct xfs_trans *tp;
xfs_fileoff_t bno;
xfs_fileoff_t ebno;
int error;
for (bno = 0; bno < mp->m_sb.sb_rextents; bno = ebno) {
error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate,
0, 0, 0, &tp);
if (error)
res_failed(error);
libxfs_trans_ijoin(tp, mp->m_rbmip, 0);
ebno = XFS_RTMIN(mp->m_sb.sb_rextents,
bno + NBBY * mp->m_sb.sb_blocksize);
error = -libxfs_rtfree_extent(tp, bno, (xfs_extlen_t)(ebno-bno));
if (error) {
fail(_("Error initializing the realtime space"),
error);
}
error = -libxfs_trans_commit(tp);
if (error)
fail(_("Initialization of the realtime space failed"),
error);
}
}
/*
* Allocate the realtime bitmap and summary inodes, and fill in data if any.
*/
static void
rtinit(
struct xfs_mount *mp)
{
rtbitmap_create(mp);
rtsummary_create(mp);
if (xfs_has_rtrmapbt(mp))
rtrmapbt_create(mp);
if (mp->m_sb.sb_rbmblocks) {
rtbitmap_init(mp);
rtsummary_init(mp);
rtfreesp_init(mp);
}
}
static long
filesize(
int fd)
{
struct stat stb;
if (fstat(fd, &stb) < 0)
return -1;
return (long)stb.st_size;
}