blob: 0cff9d63430fb33778dc1c7c38153e6d5ccde87d [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2000-2005 Silicon Graphics, Inc.
* All Rights Reserved.
*/
#include "libxfs.h"
#include "command.h"
#include "type.h"
#include "faddr.h"
#include "fprint.h"
#include "field.h"
#include "inode.h"
#include "io.h"
#include "print.h"
#include "block.h"
#include "bit.h"
#include "output.h"
#include "init.h"
static int inode_a_bmbt_count(void *obj, int startoff);
static int inode_a_bmx_count(void *obj, int startoff);
static int inode_a_count(void *obj, int startoff);
static int inode_a_offset(void *obj, int startoff, int idx);
static int inode_a_sfattr_count(void *obj, int startoff);
static int inode_core_nlinkv2_count(void *obj, int startoff);
static int inode_core_onlink_count(void *obj, int startoff);
static int inode_core_projid_count(void *obj, int startoff);
static int inode_core_nlinkv1_count(void *obj, int startoff);
static int inode_f(int argc, char **argv);
static int inode_u_offset(void *obj, int startoff, int idx);
static int inode_u_bmbt_count(void *obj, int startoff);
static int inode_u_bmx_count(void *obj, int startoff);
static int inode_u_c_count(void *obj, int startoff);
static int inode_u_dev_count(void *obj, int startoff);
static int inode_u_muuid_count(void *obj, int startoff);
static int inode_u_sfdir2_count(void *obj, int startoff);
static int inode_u_sfdir3_count(void *obj, int startoff);
static int inode_u_symlink_count(void *obj, int startoff);
static const cmdinfo_t inode_cmd =
{ "inode", NULL, inode_f, 0, 1, 1, "[inode#]",
"set current inode", NULL };
const field_t inode_hfld[] = {
{ "", FLDT_INODE, OI(0), C1, 0, TYP_NONE },
{ NULL }
};
const field_t inode_crc_hfld[] = {
{ "", FLDT_INODE_CRC, OI(0), C1, 0, TYP_NONE },
{ NULL }
};
/* XXX: fix this up! */
#define OFF(f) bitize(offsetof(xfs_dinode_t, di_ ## f))
const field_t inode_flds[] = {
{ "core", FLDT_DINODE_CORE, OI(OFF(magic)), C1, 0, TYP_NONE },
{ "next_unlinked", FLDT_AGINO, OI(OFF(next_unlinked)), C1, 0,
TYP_INODE },
{ "u", FLDT_DINODE_U, inode_u_offset, C1, FLD_OFFSET, TYP_NONE },
{ "a", FLDT_DINODE_A, inode_a_offset, inode_a_count,
FLD_COUNT|FLD_OFFSET, TYP_NONE },
{ NULL }
};
const field_t inode_crc_flds[] = {
{ "core", FLDT_DINODE_CORE, OI(OFF(magic)), C1, 0, TYP_NONE },
{ "next_unlinked", FLDT_AGINO, OI(OFF(next_unlinked)), C1, 0,
TYP_INODE },
{ "v3", FLDT_DINODE_V3, OI(OFF(magic)), C1, 0, TYP_NONE },
{ "u3", FLDT_DINODE_U, inode_u_offset, C1, FLD_OFFSET, TYP_NONE },
{ "a", FLDT_DINODE_A, inode_a_offset, inode_a_count,
FLD_COUNT|FLD_OFFSET, TYP_NONE },
{ NULL }
};
#define COFF(f) bitize(offsetof(xfs_dinode_t, di_ ## f))
const field_t inode_core_flds[] = {
{ "magic", FLDT_UINT16X, OI(COFF(magic)), C1, 0, TYP_NONE },
{ "mode", FLDT_UINT16O, OI(COFF(mode)), C1, 0, TYP_NONE },
{ "version", FLDT_INT8D, OI(COFF(version)), C1, 0, TYP_NONE },
{ "format", FLDT_DINODE_FMT, OI(COFF(format)), C1, 0, TYP_NONE },
{ "nlinkv1", FLDT_UINT16D, OI(COFF(onlink)), inode_core_nlinkv1_count,
FLD_COUNT, TYP_NONE },
{ "nlinkv2", FLDT_UINT32D, OI(COFF(nlink)), inode_core_nlinkv2_count,
FLD_COUNT, TYP_NONE },
{ "onlink", FLDT_UINT16D, OI(COFF(onlink)), inode_core_onlink_count,
FLD_COUNT, TYP_NONE },
{ "projid_lo", FLDT_UINT16D, OI(COFF(projid_lo)),
inode_core_projid_count, FLD_COUNT, TYP_NONE },
{ "projid_hi", FLDT_UINT16D, OI(COFF(projid_hi)),
inode_core_projid_count, FLD_COUNT, TYP_NONE },
{ "pad", FLDT_UINT8X, OI(OFF(pad)), CI(6), FLD_ARRAY|FLD_SKIPALL, TYP_NONE },
{ "uid", FLDT_UINT32D, OI(COFF(uid)), C1, 0, TYP_NONE },
{ "gid", FLDT_UINT32D, OI(COFF(gid)), C1, 0, TYP_NONE },
{ "flushiter", FLDT_UINT16D, OI(COFF(flushiter)), C1, 0, TYP_NONE },
{ "atime", FLDT_TIMESTAMP, OI(COFF(atime)), C1, 0, TYP_NONE },
{ "mtime", FLDT_TIMESTAMP, OI(COFF(mtime)), C1, 0, TYP_NONE },
{ "ctime", FLDT_TIMESTAMP, OI(COFF(ctime)), C1, 0, TYP_NONE },
{ "size", FLDT_FSIZE, OI(COFF(size)), C1, 0, TYP_NONE },
{ "nblocks", FLDT_DRFSBNO, OI(COFF(nblocks)), C1, 0, TYP_NONE },
{ "extsize", FLDT_EXTLEN, OI(COFF(extsize)), C1, 0, TYP_NONE },
{ "nextents", FLDT_EXTNUM, OI(COFF(nextents)), C1, 0, TYP_NONE },
{ "naextents", FLDT_AEXTNUM, OI(COFF(anextents)), C1, 0, TYP_NONE },
{ "forkoff", FLDT_UINT8D, OI(COFF(forkoff)), C1, 0, TYP_NONE },
{ "aformat", FLDT_DINODE_FMT, OI(COFF(aformat)), C1, 0, TYP_NONE },
{ "dmevmask", FLDT_UINT32X, OI(COFF(dmevmask)), C1, 0, TYP_NONE },
{ "dmstate", FLDT_UINT16D, OI(COFF(dmstate)), C1, 0, TYP_NONE },
{ "flags", FLDT_UINT16X, OI(COFF(flags)), C1, FLD_SKIPALL, TYP_NONE },
{ "newrtbm", FLDT_UINT1,
OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_NEWRTBM_BIT - 1), C1,
0, TYP_NONE },
{ "prealloc", FLDT_UINT1,
OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_PREALLOC_BIT - 1), C1,
0, TYP_NONE },
{ "realtime", FLDT_UINT1,
OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_REALTIME_BIT - 1), C1,
0, TYP_NONE },
{ "immutable", FLDT_UINT1,
OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_IMMUTABLE_BIT-1), C1,
0, TYP_NONE },
{ "append", FLDT_UINT1,
OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_APPEND_BIT - 1), C1,
0, TYP_NONE },
{ "sync", FLDT_UINT1,
OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_SYNC_BIT - 1), C1,
0, TYP_NONE },
{ "noatime", FLDT_UINT1,
OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_NOATIME_BIT - 1), C1,
0, TYP_NONE },
{ "nodump", FLDT_UINT1,
OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_NODUMP_BIT - 1), C1,
0, TYP_NONE },
{ "rtinherit", FLDT_UINT1,
OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_RTINHERIT_BIT-1), C1,
0, TYP_NONE },
{ "projinherit", FLDT_UINT1,
OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_PROJINHERIT_BIT-1), C1,
0, TYP_NONE },
{ "nosymlinks", FLDT_UINT1,
OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_NOSYMLINKS_BIT-1), C1,
0, TYP_NONE },
{ "extsz", FLDT_UINT1,
OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_EXTSIZE_BIT-1), C1,
0, TYP_NONE },
{ "extszinherit", FLDT_UINT1,
OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_EXTSZINHERIT_BIT-1), C1,
0, TYP_NONE },
{ "nodefrag", FLDT_UINT1,
OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_NODEFRAG_BIT-1), C1,
0, TYP_NONE },
{ "filestream", FLDT_UINT1,
OI(COFF(flags) + bitsz(uint16_t) - XFS_DIFLAG_FILESTREAM_BIT-1), C1,
0, TYP_NONE },
{ "gen", FLDT_UINT32D, OI(COFF(gen)), C1, 0, TYP_NONE },
{ NULL }
};
const field_t inode_v3_flds[] = {
{ "crc", FLDT_CRC, OI(COFF(crc)), C1, 0, TYP_NONE },
{ "change_count", FLDT_UINT64D, OI(COFF(changecount)), C1, 0, TYP_NONE },
{ "lsn", FLDT_UINT64X, OI(COFF(lsn)), C1, 0, TYP_NONE },
{ "flags2", FLDT_UINT64X, OI(COFF(flags2)), C1, 0, TYP_NONE },
{ "cowextsize", FLDT_EXTLEN, OI(COFF(cowextsize)), C1, 0, TYP_NONE },
{ "pad2", FLDT_UINT8X, OI(OFF(pad2)), CI(12), FLD_ARRAY|FLD_SKIPALL, TYP_NONE },
{ "crtime", FLDT_TIMESTAMP, OI(COFF(crtime)), C1, 0, TYP_NONE },
{ "inumber", FLDT_INO, OI(COFF(ino)), C1, 0, TYP_NONE },
{ "uuid", FLDT_UUID, OI(COFF(uuid)), C1, 0, TYP_NONE },
{ "reflink", FLDT_UINT1,
OI(COFF(flags2) + bitsz(uint64_t) - XFS_DIFLAG2_REFLINK_BIT-1), C1,
0, TYP_NONE },
{ "cowextsz", FLDT_UINT1,
OI(COFF(flags2) + bitsz(uint64_t) - XFS_DIFLAG2_COWEXTSIZE_BIT-1), C1,
0, TYP_NONE },
{ NULL }
};
#define TOFF(f) bitize(offsetof(xfs_timestamp_t, t_ ## f))
const field_t timestamp_flds[] = {
{ "sec", FLDT_TIME, OI(TOFF(sec)), C1, 0, TYP_NONE },
{ "nsec", FLDT_NSEC, OI(TOFF(nsec)), C1, 0, TYP_NONE },
{ NULL }
};
const field_t inode_u_flds[] = {
{ "bmbt", FLDT_BMROOTD, NULL, inode_u_bmbt_count, FLD_COUNT, TYP_NONE },
{ "bmx", FLDT_BMAPBTDREC, NULL, inode_u_bmx_count, FLD_ARRAY|FLD_COUNT,
TYP_NONE },
{ "c", FLDT_CHARNS, NULL, inode_u_c_count, FLD_COUNT, TYP_NONE },
{ "dev", FLDT_DEV, NULL, inode_u_dev_count, FLD_COUNT, TYP_NONE },
{ "muuid", FLDT_UUID, NULL, inode_u_muuid_count, FLD_COUNT, TYP_NONE },
{ "sfdir2", FLDT_DIR2SF, NULL, inode_u_sfdir2_count, FLD_COUNT, TYP_NONE },
{ "sfdir3", FLDT_DIR3SF, NULL, inode_u_sfdir3_count, FLD_COUNT, TYP_NONE },
{ "symlink", FLDT_CHARNS, NULL, inode_u_symlink_count, FLD_COUNT,
TYP_NONE },
{ NULL }
};
const field_t inode_a_flds[] = {
{ "bmbt", FLDT_BMROOTA, NULL, inode_a_bmbt_count, FLD_COUNT, TYP_NONE },
{ "bmx", FLDT_BMAPBTAREC, NULL, inode_a_bmx_count, FLD_ARRAY|FLD_COUNT,
TYP_NONE },
{ "sfattr", FLDT_ATTRSHORT, NULL, inode_a_sfattr_count, FLD_COUNT,
TYP_NONE },
{ NULL }
};
static const char *dinode_fmt_name[] =
{ "dev", "local", "extents", "btree", "uuid" };
static const int dinode_fmt_name_size =
sizeof(dinode_fmt_name) / sizeof(dinode_fmt_name[0]);
/*ARGSUSED*/
int
fp_dinode_fmt(
void *obj,
int bit,
int count,
char *fmtstr,
int size,
int arg,
int base,
int array)
{
int bitpos;
enum xfs_dinode_fmt f;
int i;
for (i = 0, bitpos = bit; i < count; i++, bitpos += size) {
f = (enum xfs_dinode_fmt)getbitval(obj, bitpos, size, BVUNSIGNED);
if (array)
dbprintf("%d:", i + base);
if (f < 0 || f >= dinode_fmt_name_size)
dbprintf("%d", (int)f);
else
dbprintf("%d (%s)", (int)f, dinode_fmt_name[(int)f]);
if (i < count - 1)
dbprintf(" ");
}
return 1;
}
static int
inode_a_bmbt_count(
void *obj,
int startoff)
{
xfs_dinode_t *dip;
ASSERT(bitoffs(startoff) == 0);
ASSERT(obj == iocur_top->data);
dip = obj;
if (!XFS_DFORK_Q(dip))
return 0;
ASSERT((char *)XFS_DFORK_APTR(dip) - (char *)dip == byteize(startoff));
return dip->di_aformat == XFS_DINODE_FMT_BTREE;
}
static int
inode_a_bmx_count(
void *obj,
int startoff)
{
xfs_dinode_t *dip;
ASSERT(bitoffs(startoff) == 0);
ASSERT(obj == iocur_top->data);
dip = obj;
if (!XFS_DFORK_Q(dip))
return 0;
ASSERT((char *)XFS_DFORK_APTR(dip) - (char *)dip == byteize(startoff));
return dip->di_aformat == XFS_DINODE_FMT_EXTENTS ?
be16_to_cpu(dip->di_anextents) : 0;
}
static int
inode_a_count(
void *obj,
int startoff)
{
xfs_dinode_t *dip;
ASSERT(startoff == 0);
dip = obj;
return XFS_DFORK_Q(dip);
}
static int
inode_a_offset(
void *obj,
int startoff,
int idx)
{
xfs_dinode_t *dip;
ASSERT(startoff == 0);
ASSERT(idx == 0);
dip = obj;
ASSERT(XFS_DFORK_Q(dip));
return bitize((int)((char *)XFS_DFORK_APTR(dip) - (char *)dip));
}
static int
inode_a_sfattr_count(
void *obj,
int startoff)
{
xfs_dinode_t *dip;
ASSERT(bitoffs(startoff) == 0);
ASSERT(obj == iocur_top->data);
dip = obj;
if (!XFS_DFORK_Q(dip))
return 0;
ASSERT((char *)XFS_DFORK_APTR(dip) - (char *)dip == byteize(startoff));
return dip->di_aformat == XFS_DINODE_FMT_LOCAL;
}
int
inode_a_size(
void *obj,
int startoff,
int idx)
{
xfs_attr_shortform_t *asf;
xfs_dinode_t *dip;
ASSERT(startoff == 0);
ASSERT(idx == 0);
dip = obj;
switch (dip->di_aformat) {
case XFS_DINODE_FMT_LOCAL:
asf = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip);
return bitize(be16_to_cpu(asf->hdr.totsize));
case XFS_DINODE_FMT_EXTENTS:
return (int)be16_to_cpu(dip->di_anextents) *
bitsz(xfs_bmbt_rec_t);
case XFS_DINODE_FMT_BTREE:
return bitize((int)XFS_DFORK_ASIZE(dip, mp));
default:
return 0;
}
}
static int
inode_core_nlinkv1_count(
void *obj,
int startoff)
{
xfs_dinode_t *dic;
ASSERT(startoff == 0);
ASSERT(obj == iocur_top->data);
dic = obj;
return dic->di_version == 1;
}
static int
inode_core_nlinkv2_count(
void *obj,
int startoff)
{
xfs_dinode_t *dic;
ASSERT(startoff == 0);
ASSERT(obj == iocur_top->data);
dic = obj;
return dic->di_version >= 2;
}
static int
inode_core_onlink_count(
void *obj,
int startoff)
{
xfs_dinode_t *dic;
ASSERT(startoff == 0);
ASSERT(obj == iocur_top->data);
dic = obj;
return dic->di_version >= 2;
}
static int
inode_core_projid_count(
void *obj,
int startoff)
{
xfs_dinode_t *dic;
ASSERT(startoff == 0);
ASSERT(obj == iocur_top->data);
dic = obj;
return dic->di_version >= 2;
}
static int
inode_f(
int argc,
char **argv)
{
xfs_ino_t ino;
char *p;
if (argc > 1) {
ino = strtoull(argv[1], &p, 0);
if (*p != '\0') {
dbprintf(_("bad value for inode number %s\n"), argv[1]);
return 0;
}
set_cur_inode(ino);
} else if (iocur_top->ino == NULLFSINO)
dbprintf(_("no current inode\n"));
else
dbprintf(_("current inode number is %lld\n"), iocur_top->ino);
return 0;
}
void
inode_init(void)
{
add_command(&inode_cmd);
}
typnm_t
inode_next_type(void)
{
switch (iocur_top->mode & S_IFMT) {
case S_IFDIR:
return TYP_DIR2;
case S_IFLNK:
return TYP_SYMLINK;
case S_IFREG:
if (iocur_top->ino == mp->m_sb.sb_rbmino)
return TYP_RTBITMAP;
else if (iocur_top->ino == mp->m_sb.sb_rsumino)
return TYP_RTSUMMARY;
else if (iocur_top->ino == mp->m_sb.sb_uquotino ||
iocur_top->ino == mp->m_sb.sb_gquotino ||
iocur_top->ino == mp->m_sb.sb_pquotino)
return TYP_DQBLK;
else
return TYP_DATA;
default:
return TYP_NONE;
}
}
int
inode_size(
void *obj,
int startoff,
int idx)
{
return bitize(mp->m_sb.sb_inodesize);
}
static int
inode_u_offset(
void *obj,
int startoff,
int idx)
{
xfs_dinode_t *dip;
ASSERT(startoff == 0);
ASSERT(idx == 0);
dip = obj;
return bitize((int)((char *)XFS_DFORK_DPTR(dip) - (char *)dip));
}
static int
inode_u_bmbt_count(
void *obj,
int startoff)
{
xfs_dinode_t *dip;
ASSERT(bitoffs(startoff) == 0);
ASSERT(obj == iocur_top->data);
dip = obj;
ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff));
return dip->di_format == XFS_DINODE_FMT_BTREE;
}
static int
inode_u_bmx_count(
void *obj,
int startoff)
{
xfs_dinode_t *dip;
ASSERT(bitoffs(startoff) == 0);
ASSERT(obj == iocur_top->data);
dip = obj;
ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff));
return dip->di_format == XFS_DINODE_FMT_EXTENTS ?
be32_to_cpu(dip->di_nextents) : 0;
}
static int
inode_u_c_count(
void *obj,
int startoff)
{
xfs_dinode_t *dip;
ASSERT(bitoffs(startoff) == 0);
ASSERT(obj == iocur_top->data);
dip = obj;
ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff));
return dip->di_format == XFS_DINODE_FMT_LOCAL &&
(be16_to_cpu(dip->di_mode) & S_IFMT) == S_IFREG ?
(int)be64_to_cpu(dip->di_size) : 0;
}
static int
inode_u_dev_count(
void *obj,
int startoff)
{
xfs_dinode_t *dip;
ASSERT(bitoffs(startoff) == 0);
ASSERT(obj == iocur_top->data);
dip = obj;
ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff));
return dip->di_format == XFS_DINODE_FMT_DEV;
}
static int
inode_u_muuid_count(
void *obj,
int startoff)
{
xfs_dinode_t *dip;
ASSERT(bitoffs(startoff) == 0);
ASSERT(obj == iocur_top->data);
dip = obj;
ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff));
return dip->di_format == XFS_DINODE_FMT_UUID;
}
static int
inode_u_sfdir2_count(
void *obj,
int startoff)
{
xfs_dinode_t *dip;
ASSERT(bitoffs(startoff) == 0);
ASSERT(obj == iocur_top->data);
dip = obj;
ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff));
return dip->di_format == XFS_DINODE_FMT_LOCAL &&
(be16_to_cpu(dip->di_mode) & S_IFMT) == S_IFDIR &&
!xfs_sb_version_hasftype(&mp->m_sb);
}
static int
inode_u_sfdir3_count(
void *obj,
int startoff)
{
xfs_dinode_t *dip;
ASSERT(bitoffs(startoff) == 0);
ASSERT(obj == iocur_top->data);
dip = obj;
ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff));
return dip->di_format == XFS_DINODE_FMT_LOCAL &&
(be16_to_cpu(dip->di_mode) & S_IFMT) == S_IFDIR &&
xfs_sb_version_hasftype(&mp->m_sb);
}
int
inode_u_size(
void *obj,
int startoff,
int idx)
{
xfs_dinode_t *dip;
ASSERT(startoff == 0);
ASSERT(idx == 0);
dip = obj;
switch (dip->di_format) {
case XFS_DINODE_FMT_DEV:
return bitsz(xfs_dev_t);
case XFS_DINODE_FMT_LOCAL:
return bitize((int)be64_to_cpu(dip->di_size));
case XFS_DINODE_FMT_EXTENTS:
return (int)be32_to_cpu(dip->di_nextents) *
bitsz(xfs_bmbt_rec_t);
case XFS_DINODE_FMT_BTREE:
return bitize((int)XFS_DFORK_DSIZE(dip, mp));
case XFS_DINODE_FMT_UUID:
return bitsz(uuid_t);
default:
return 0;
}
}
static int
inode_u_symlink_count(
void *obj,
int startoff)
{
xfs_dinode_t *dip;
ASSERT(bitoffs(startoff) == 0);
ASSERT(obj == iocur_top->data);
dip = obj;
ASSERT((char *)XFS_DFORK_DPTR(dip) - (char *)dip == byteize(startoff));
return dip->di_format == XFS_DINODE_FMT_LOCAL &&
(be16_to_cpu(dip->di_mode) & S_IFMT) == S_IFLNK ?
(int)be64_to_cpu(dip->di_size) : 0;
}
/*
* We are now using libxfs for our IO backend, so we should always try to use
* inode cluster buffers rather than filesystem block sized buffers for reading
* inodes. This means that we always use the same buffers as libxfs operations
* does, and that avoids buffer cache issues caused by overlapping buffers. This
* can be seen clearly when trying to read the root inode. Much of this logic is
* similar to libxfs_imap().
*/
void
set_cur_inode(
xfs_ino_t ino)
{
xfs_agblock_t agbno;
xfs_agino_t agino;
xfs_agnumber_t agno;
xfs_dinode_t *dip;
int offset;
int numblks = blkbb;
xfs_agblock_t cluster_agbno;
struct xfs_ino_geometry *igeo = M_IGEO(mp);
agno = XFS_INO_TO_AGNO(mp, ino);
agino = XFS_INO_TO_AGINO(mp, ino);
agbno = XFS_AGINO_TO_AGBNO(mp, agino);
offset = XFS_AGINO_TO_OFFSET(mp, agino);
if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks ||
offset >= mp->m_sb.sb_inopblock ||
XFS_AGINO_TO_INO(mp, agno, agino) != ino) {
dbprintf(_("bad inode number %lld\n"), ino);
return;
}
cur_agno = agno;
if (igeo->inode_cluster_size > mp->m_sb.sb_blocksize &&
igeo->inoalign_mask) {
xfs_agblock_t chunk_agbno;
xfs_agblock_t offset_agbno;
offset_agbno = agbno & igeo->inoalign_mask;
chunk_agbno = agbno - offset_agbno;
cluster_agbno = chunk_agbno +
((offset_agbno / M_IGEO(mp)->blocks_per_cluster) *
M_IGEO(mp)->blocks_per_cluster);
offset += ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock);
numblks = XFS_FSB_TO_BB(mp, M_IGEO(mp)->blocks_per_cluster);
} else
cluster_agbno = agbno;
/*
* First set_cur to the block with the inode
* then use off_cur to get the right part of the buffer.
*/
ASSERT(typtab[TYP_INODE].typnm == TYP_INODE);
/* ingore ring update here, do it explicitly below */
set_cur(&typtab[TYP_INODE], XFS_AGB_TO_DADDR(mp, agno, cluster_agbno),
numblks, DB_RING_IGN, NULL);
off_cur(offset << mp->m_sb.sb_inodelog, mp->m_sb.sb_inodesize);
if (!iocur_top->data)
return;
dip = iocur_top->data;
iocur_top->ino_buf = 1;
iocur_top->ino = ino;
iocur_top->mode = be16_to_cpu(dip->di_mode);
if ((iocur_top->mode & S_IFMT) == S_IFDIR)
iocur_top->dirino = ino;
if (xfs_sb_version_hascrc(&mp->m_sb)) {
iocur_top->ino_crc_ok = libxfs_verify_cksum((char *)dip,
mp->m_sb.sb_inodesize,
XFS_DINODE_CRC_OFF);
if (!iocur_top->ino_crc_ok)
dbprintf(
_("Metadata CRC error detected for ino %lld\n"),
ino);
}
/* track updated info in ring */
ring_add();
}
void
xfs_inode_set_crc(
struct xfs_buf *bp)
{
ASSERT(iocur_top->ino_buf);
ASSERT(iocur_top->bp == bp);
libxfs_dinode_calc_crc(mp, iocur_top->data);
iocur_top->ino_crc_ok = 1;
}