#include <stdint.h>
#include <string.h>
#include "libgfs2.h"
#include "clusterautoconfig.h"
#ifdef GFS2_HAS_UUID
#include <uuid.h>
#endif
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
#define SYM(x) { x, #x },
const struct lgfs2_symbolic lgfs2_metatypes[] = {
SYM(GFS2_METATYPE_NONE)
SYM(GFS2_METATYPE_SB)
SYM(GFS2_METATYPE_RG)
SYM(GFS2_METATYPE_RB)
SYM(GFS2_METATYPE_DI)
SYM(GFS2_METATYPE_IN)
SYM(GFS2_METATYPE_LF)
SYM(GFS2_METATYPE_JD)
SYM(GFS2_METATYPE_LH)
SYM(GFS2_METATYPE_LD)
SYM(GFS2_METATYPE_LB)
SYM(GFS2_METATYPE_EA)
SYM(GFS2_METATYPE_ED)
SYM(GFS2_METATYPE_QC)
};
const unsigned lgfs2_metatype_size = ARRAY_SIZE(lgfs2_metatypes);
const struct lgfs2_symbolic lgfs2_metaformats[] = {
SYM(GFS2_FORMAT_NONE)
SYM(GFS2_FORMAT_SB)
SYM(GFS2_FORMAT_RG)
SYM(GFS2_FORMAT_RB)
SYM(GFS2_FORMAT_DI)
SYM(GFS2_FORMAT_IN)
SYM(GFS2_FORMAT_LF)
SYM(GFS2_FORMAT_JD)
SYM(GFS2_FORMAT_LH)
SYM(GFS2_FORMAT_LD)
SYM(GFS2_FORMAT_LB)
SYM(GFS2_FORMAT_EA)
SYM(GFS2_FORMAT_ED)
SYM(GFS2_FORMAT_QC)
SYM(GFS2_FORMAT_RI)
SYM(GFS2_FORMAT_DE)
SYM(GFS2_FORMAT_QU)
};
const unsigned lgfs2_metaformat_size = ARRAY_SIZE(lgfs2_metaformats);
const struct lgfs2_symbolic lgfs2_di_flags[] = {
SYM(GFS2_DIF_JDATA)
SYM(GFS2_DIF_EXHASH)
SYM(GFS2_DIF_UNUSED)
SYM(GFS2_DIF_EA_INDIRECT)
SYM(GFS2_DIF_DIRECTIO)
SYM(GFS2_DIF_IMMUTABLE)
SYM(GFS2_DIF_APPENDONLY)
SYM(GFS2_DIF_NOATIME)
SYM(GFS2_DIF_SYNC)
SYM(GFS2_DIF_SYSTEM)
SYM(GFS2_DIF_TRUNC_IN_PROG)
SYM(GFS2_DIF_INHERIT_DIRECTIO)
SYM(GFS2_DIF_INHERIT_JDATA)
};
const unsigned lgfs2_di_flag_size = ARRAY_SIZE(lgfs2_di_flags);
const struct lgfs2_symbolic lgfs2_lh_flags[] = {
SYM(GFS2_LOG_HEAD_UNMOUNT)
};
const unsigned int lgfs2_lh_flag_size = ARRAY_SIZE(lgfs2_lh_flags);
const struct lgfs2_symbolic lgfs2_ld_types[] = {
SYM(GFS2_LOG_DESC_METADATA)
SYM(GFS2_LOG_DESC_REVOKE)
SYM(GFS2_LOG_DESC_JDATA)
};
const unsigned int lgfs2_ld_type_size = ARRAY_SIZE(lgfs2_ld_types);
const struct lgfs2_symbolic lgfs2_ld1_types[] = {
SYM(GFS_LOG_DESC_METADATA)
SYM(GFS_LOG_DESC_IUL)
SYM(GFS_LOG_DESC_IDA)
SYM(GFS_LOG_DESC_Q)
SYM(GFS_LOG_DESC_LAST)
};
const unsigned int lgfs2_ld1_type_size = ARRAY_SIZE(lgfs2_ld1_types);
#undef SYM
#define F(f,...) { .name = #f, \
.offset = offsetof(struct STRUCT, f), \
.length = sizeof(((struct STRUCT *)(0))->f), \
__VA_ARGS__ },
#define FP(f,...) F(f, .flags = LGFS2_MFF_POINTER, __VA_ARGS__)
#define RF(f) F(f, .flags = LGFS2_MFF_RESERVED)
#define RFP(f,...) F(f, .flags = LGFS2_MFF_POINTER|LGFS2_MFF_RESERVED, __VA_ARGS__)
#define MH(f) F(f.mh_magic) \
F(f.mh_type, .flags = LGFS2_MFF_ENUM, .symtab=lgfs2_metatypes, .nsyms=ARRAY_SIZE(lgfs2_metatypes)) \
RF(f.__pad0) \
F(f.mh_format, .flags = LGFS2_MFF_ENUM, .symtab=lgfs2_metaformats, .nsyms=ARRAY_SIZE(lgfs2_metaformats)) \
F(f.mh_jid)
#define IN(f,...) F(f.no_formal_ino) \
FP(f.no_addr, __VA_ARGS__)
#define INR(f,...) RF(f.no_formal_ino) \
RFP(f.no_addr, __VA_ARGS__)
#define ANY_COMMON_BLOCK (1 << LGFS2_MT_DIR_LEAF) | \
(1 << LGFS2_MT_JRNL_DATA) | \
(1 << LGFS2_MT_EA_ATTR) | \
(1 << LGFS2_MT_EA_DATA) | \
(1 << LGFS2_MT_DATA)
#define ANY_GFS2_BLOCK (1 << LGFS2_MT_GFS2_DINODE) | \
(1 << LGFS2_MT_GFS2_INDIRECT) | \
(1 << LGFS2_MT_GFS2_LOG_HEADER) | \
(1 << LGFS2_MT_GFS2_LOG_DESC) | \
(1 << LGFS2_MT_GFS2_LOG_BLOCK) | \
ANY_COMMON_BLOCK
#define ANY_GFS_BLOCK (1 << LGFS2_MT_GFS_DINODE) | \
(1 << LGFS2_MT_GFS_INDIRECT) | \
ANY_COMMON_BLOCK
#undef STRUCT
#define STRUCT gfs2_sb
static const struct lgfs2_metafield gfs2_sb_fields[] = {
MH(sb_header)
F(sb_fs_format)
F(sb_multihost_format)
RF(__pad0)
F(sb_bsize, .flags = LGFS2_MFF_BYTES)
F(sb_bsize_shift, .flags = LGFS2_MFF_BYTES|LGFS2_MFF_SHIFT)
RF(__pad1)
IN(sb_master_dir, .points_to = (1 << LGFS2_MT_GFS2_DINODE))
INR(__pad2, .points_to = (1 << LGFS2_MT_GFS2_DINODE))
IN(sb_root_dir, .points_to = (1 << LGFS2_MT_GFS2_DINODE))
F(sb_lockproto, .flags = LGFS2_MFF_STRING)
F(sb_locktable, .flags = LGFS2_MFF_STRING)
INR(__pad3, .points_to = (1 << LGFS2_MT_GFS2_DINODE))
INR(__pad4, .points_to = (1 << LGFS2_MT_GFS2_DINODE))
#ifdef GFS2_HAS_UUID
F(sb_uuid, .flags = LGFS2_MFF_UUID)
#endif
};
#undef STRUCT
#define STRUCT gfs_sb
static const struct lgfs2_metafield gfs_sb_fields[] = {
MH(sb_header)
F(sb_fs_format)
F(sb_multihost_format)
F(sb_flags)
F(sb_bsize, .flags = LGFS2_MFF_BYTES)
F(sb_bsize_shift, .flags = LGFS2_MFF_BYTES|LGFS2_MFF_SHIFT)
F(sb_seg_size, .flags = LGFS2_MFF_FSBLOCKS)
IN(sb_jindex_di, .points_to = (1 << LGFS2_MT_GFS_DINODE))
IN(sb_rindex_di, .points_to = (1 << LGFS2_MT_GFS_DINODE))
IN(sb_root_di, .points_to = (1 << LGFS2_MT_GFS_DINODE))
F(sb_lockproto, .flags = LGFS2_MFF_STRING)
F(sb_locktable, .flags = LGFS2_MFF_STRING)
IN(sb_quota_di, .points_to = (1 << LGFS2_MT_GFS_DINODE))
IN(sb_license_di, .points_to = (1 << LGFS2_MT_GFS_DINODE))
RF(sb_reserved)
};
#undef STRUCT
#define STRUCT gfs2_rindex
static const struct lgfs2_metafield gfs2_rindex_fields[] = {
FP(ri_addr, .points_to = (1 << LGFS2_MT_GFS2_RGRP))
F(ri_length, .flags = LGFS2_MFF_FSBLOCKS)
RF(__pad)
FP(ri_data0, .points_to = ANY_GFS2_BLOCK|(1 << LGFS2_MT_FREE))
F(ri_data, .flags = LGFS2_MFF_FSBLOCKS)
F(ri_bitbytes, .flags = LGFS2_MFF_BYTES)
F(ri_reserved)
};
#undef STRUCT
#define STRUCT gfs2_rgrp
static const struct lgfs2_metafield gfs2_rgrp_fields[] = {
MH(rg_header)
F(rg_flags)
F(rg_free, .flags = LGFS2_MFF_FSBLOCKS)
F(rg_dinodes, .flags = LGFS2_MFF_FSBLOCKS)
#ifdef GFS2_HAS_RG_SKIP
FP(rg_skip, .points_to = (1 << LGFS2_MT_GFS2_RGRP))
#else
RF(__pad)
#endif
F(rg_igeneration)
#ifdef GFS2_HAS_RG_RI_FIELDS
FP(rg_data0, .points_to = ANY_GFS2_BLOCK|(1 << LGFS2_MT_FREE))
F(rg_data, .flags = LGFS2_MFF_FSBLOCKS)
F(rg_bitbytes, .flags = LGFS2_MFF_BYTES)
F(rg_crc, .flags = LGFS2_MFF_CHECK)
#endif
RF(rg_reserved)
};
#undef STRUCT
#define STRUCT gfs_rgrp
static const struct lgfs2_metafield gfs_rgrp_fields[] = {
MH(rg_header)
F(rg_flags)
F(rg_free, .flags = LGFS2_MFF_FSBLOCKS)
F(rg_useddi, .flags = LGFS2_MFF_FSBLOCKS)
F(rg_freedi, .flags = LGFS2_MFF_FSBLOCKS)
IN(rg_freedi_list, .points_to = (1 << LGFS2_MT_GFS_DINODE))
F(rg_usedmeta, .flags = LGFS2_MFF_FSBLOCKS)
F(rg_freemeta, .flags = LGFS2_MFF_FSBLOCKS)
RF(rg_reserved)
};
#undef STRUCT
struct gfs2_rgrp_bitmap { struct gfs2_meta_header rb_header; };
#define STRUCT gfs2_rgrp_bitmap
static const struct lgfs2_metafield gfs2_rgrp_bitmap_fields[] = {
MH(rb_header)
};
#undef STRUCT
#define STRUCT gfs2_dinode
static const struct lgfs2_metafield gfs2_dinode_fields[] = {
MH(di_header)
IN(di_num, .points_to = (1 << LGFS2_MT_GFS2_DINODE))
F(di_mode, .flags = LGFS2_MFF_MODE)
F(di_uid, .flags = LGFS2_MFF_UID)
F(di_gid, .flags = LGFS2_MFF_GID)
F(di_nlink)
F(di_size, .flags = LGFS2_MFF_BYTES)
F(di_blocks, .flags = LGFS2_MFF_FSBLOCKS)
F(di_atime, .flags = LGFS2_MFF_SECS)
F(di_mtime, .flags = LGFS2_MFF_SECS)
F(di_ctime, .flags = LGFS2_MFF_SECS)
F(di_major, .flags = LGFS2_MFF_MAJOR)
F(di_minor, .flags = LGFS2_MFF_MINOR)
FP(di_goal_meta, .points_to = ANY_GFS2_BLOCK | (1 << LGFS2_MT_FREE))
FP(di_goal_data, .points_to = ANY_GFS2_BLOCK | (1 << LGFS2_MT_FREE))
F(di_generation)
F(di_flags, .flags = LGFS2_MFF_MASK, .symtab=lgfs2_di_flags, .nsyms=ARRAY_SIZE(lgfs2_di_flags))
F(di_payload_format)
RF(__pad1)
F(di_height)
RF(__pad2)
RF(__pad3)
F(di_depth)
F(di_entries)
INR(__pad4, .points_to = (1 << LGFS2_MT_GFS2_DINODE))
FP(di_eattr, .points_to = (1 << LGFS2_MT_EA_ATTR)|(1 << LGFS2_MT_GFS2_INDIRECT))
F(di_atime_nsec, .flags = LGFS2_MFF_NSECS)
F(di_mtime_nsec, .flags = LGFS2_MFF_NSECS)
F(di_ctime_nsec, .flags = LGFS2_MFF_NSECS)
RF(di_reserved)
};
#undef STRUCT
#define STRUCT gfs_dinode
static const struct lgfs2_metafield gfs_dinode_fields[] = {
MH(di_header)
IN(di_num, .points_to = (1 << LGFS2_MT_GFS_DINODE))
F(di_mode, .flags = LGFS2_MFF_MODE)
F(di_uid, .flags = LGFS2_MFF_UID)
F(di_gid, .flags = LGFS2_MFF_GID)
F(di_nlink)
F(di_size, .flags = LGFS2_MFF_BYTES)
F(di_blocks, .flags = LGFS2_MFF_FSBLOCKS)
F(di_atime, .flags = LGFS2_MFF_SECS)
F(di_mtime, .flags = LGFS2_MFF_SECS)
F(di_ctime, .flags = LGFS2_MFF_SECS)
F(di_major, .flags = LGFS2_MFF_MAJOR)
F(di_minor, .flags = LGFS2_MFF_MINOR)
FP(di_rgrp, .points_to = LGFS2_MT_GFS_RGRP)
FP(di_goal_rgrp, .points_to = LGFS2_MT_GFS_RGRP)
F(di_goal_dblk)
F(di_goal_mblk)
F(di_flags, .flags = LGFS2_MFF_MASK, .symtab=lgfs2_di_flags, .nsyms=ARRAY_SIZE(lgfs2_di_flags))
F(di_payload_format)
F(di_type)
F(di_height)
F(di_incarn)
F(di_pad)
F(di_depth)
F(di_entries)
INR(di_next_unused, .points_to = (1 << LGFS2_MT_GFS_DINODE))
FP(di_eattr, .points_to = (1 << LGFS2_MT_EA_ATTR)|(1 << LGFS2_MT_GFS_INDIRECT))
F(di_reserved)
};
#undef STRUCT
struct gfs2_indirect { struct gfs2_meta_header in_header; };
#define STRUCT gfs2_indirect
static const struct lgfs2_metafield gfs2_indirect_fields[] = {
MH(in_header)
};
#undef STRUCT
#define STRUCT gfs_indirect
static const struct lgfs2_metafield gfs_indirect_fields[] = {
MH(in_header)
RF(in_reserved)
};
#undef STRUCT
#define STRUCT gfs2_leaf
static const struct lgfs2_metafield gfs2_leaf_fields[] = {
MH(lf_header)
F(lf_depth)
F(lf_entries)
F(lf_dirent_format)
F(lf_next)
#ifdef GFS2_HAS_LEAF_HINTS
FP(lf_inode, .points_to = (1 << LGFS2_MT_GFS2_DINODE))
F(lf_dist)
F(lf_nsec, .flags = LGFS2_MFF_NSECS)
F(lf_sec, .flags = LGFS2_MFF_SECS)
RF(lf_reserved2)
#else
RF(lf_reserved)
#endif
};
#undef STRUCT
struct gfs2_jrnl_data { struct gfs2_meta_header jd_header; };
#define STRUCT gfs2_jrnl_data
static const struct lgfs2_metafield gfs2_jdata_fields[] = {
MH(jd_header)
};
#undef STRUCT
#define STRUCT gfs2_log_header
static const struct lgfs2_metafield gfs2_log_header_fields[] = {
MH(lh_header)
F(lh_sequence)
F(lh_flags)
F(lh_tail)
F(lh_blkno)
F(lh_hash, .flags = LGFS2_MFF_CHECK)
#ifdef GFS2_HAS_LH_V2
F(lh_crc, .flags = LGFS2_MFF_CHECK)
F(lh_nsec, .flags = LGFS2_MFF_NSECS)
F(lh_sec, .flags = LGFS2_MFF_SECS)
FP(lh_addr, .points_to = (1 << LGFS2_MT_GFS2_LOG_BLOCK))
FP(lh_jinode, .points_to = (1 << LGFS2_MT_GFS2_DINODE))
FP(lh_statfs_addr, .points_to = (1 << LGFS2_MT_GFS2_DINODE))
FP(lh_quota_addr, .points_to = (1 << LGFS2_MT_GFS2_DINODE))
F(lh_local_total, .flags = LGFS2_MFF_FSBLOCKS)
F(lh_local_free, .flags = LGFS2_MFF_FSBLOCKS)
F(lh_local_dinodes, .flags = LGFS2_MFF_FSBLOCKS)
#endif
};
#undef STRUCT
#define STRUCT gfs_log_header
static const struct lgfs2_metafield gfs_log_header_fields[] = {
MH(lh_header)
F(lh_flags, .flags = LGFS2_MFF_MASK, .symtab = lgfs2_lh_flags, .nsyms = ARRAY_SIZE(lgfs2_lh_flags))
RF(lh_pad)
F(lh_first)
F(lh_sequence)
F(lh_tail)
F(lh_last_dump)
RF(lh_reserved)
};
#undef STRUCT
#define STRUCT gfs2_log_descriptor
static const struct lgfs2_metafield gfs2_log_desc_fields[] = {
MH(ld_header)
F(ld_type, .flags = LGFS2_MFF_ENUM, .symtab = lgfs2_ld_types, .nsyms = ARRAY_SIZE(lgfs2_ld_types))
F(ld_length, .flags = LGFS2_MFF_FSBLOCKS)
F(ld_data1)
F(ld_data2)
RF(ld_reserved)
};
#undef STRUCT
#define STRUCT gfs_log_descriptor
static const struct lgfs2_metafield gfs_log_desc_fields[] = {
MH(ld_header)
F(ld_type, .flags = LGFS2_MFF_ENUM, .symtab = lgfs2_ld1_types, .nsyms = ARRAY_SIZE(lgfs2_ld1_types))
F(ld_length, .flags = LGFS2_MFF_FSBLOCKS)
F(ld_data1)
F(ld_data2)
RF(ld_reserved)
};
#undef STRUCT
struct gfs2_log_block { struct gfs2_meta_header lb_header; };
#define STRUCT gfs2_log_block
static const struct lgfs2_metafield gfs2_log_block_fields[] = {
MH(lb_header)
};
#undef STRUCT
struct gfs2_ea_attr { struct gfs2_meta_header ea_header; };
#define STRUCT gfs2_ea_attr
static const struct lgfs2_metafield gfs2_ea_attr_fields[] = {
MH(ea_header)
};
#undef STRUCT
struct gfs2_ea_data { struct gfs2_meta_header ed_header; };
#define STRUCT gfs2_ea_data
static const struct lgfs2_metafield gfs2_ea_data_fields[] = {
MH(ed_header)
};
#undef STRUCT
#define STRUCT gfs2_quota_change
static const struct lgfs2_metafield gfs2_quota_change_fields[] = {
F(qc_change, .flags = LGFS2_MFF_FSBLOCKS)
F(qc_flags)
F(qc_id)
};
#undef STRUCT
#define STRUCT gfs2_dirent
static const struct lgfs2_metafield gfs2_dirent_fields[] = {
IN(de_inum, .points_to = (1 << LGFS2_MT_GFS_DINODE)|(1 << LGFS2_MT_GFS2_DINODE))
F(de_hash, .flags = LGFS2_MFF_CHECK)
F(de_rec_len, .flags = LGFS2_MFF_BYTES)
F(de_name_len, .flags = LGFS2_MFF_BYTES)
F(de_type)
#ifdef GFS2_HAS_DE_RAHEAD
F(de_rahead)
#ifdef GFS2_HAS_DE_COOKIE
F(de_cookie)
RF(pad3)
#else
RF(pad2)
#endif /* GFS2_HAS_DE_COOKIE */
#else
RF(__pad)
#endif /* GFS2_HAS_DE_RAHEAD */
};
#undef STRUCT
#define STRUCT gfs2_ea_header
static const struct lgfs2_metafield gfs2_ea_header_fields[] = {
F(ea_rec_len, .flags = LGFS2_MFF_BYTES)
F(ea_data_len, .flags = LGFS2_MFF_BYTES)
F(ea_name_len, .flags = LGFS2_MFF_BYTES)
F(ea_type)
F(ea_flags)
F(ea_num_ptrs)
RF(__pad)
};
#undef STRUCT
#define STRUCT gfs2_inum_range
static const struct lgfs2_metafield gfs2_inum_range_fields[] = {
F(ir_start)
F(ir_length)
};
#undef STRUCT
#define STRUCT gfs2_statfs_change
static const struct lgfs2_metafield gfs2_statfs_change_fields[] = {
F(sc_total, .flags = LGFS2_MFF_FSBLOCKS)
F(sc_free, .flags = LGFS2_MFF_FSBLOCKS)
F(sc_dinodes, .flags = LGFS2_MFF_FSBLOCKS)
};
#undef STRUCT
#define STRUCT gfs_jindex
static const struct lgfs2_metafield gfs_jindex_fields[] = {
FP(ji_addr, .points_to = (1 << LGFS2_MT_DATA))
F(ji_nsegment)
RF(ji_pad)
RF(ji_reserved)
};
#undef STRUCT
struct gfs_block_tag {
uint64_t bt_blkno; /* inplace block number */
uint32_t bt_flags; /* ?? */
uint32_t bt_pad;
};
#define STRUCT gfs_block_tag
static const struct lgfs2_metafield gfs_block_tag_fields[] = {
FP(bt_blkno, .points_to = ANY_GFS_BLOCK)
RF(bt_flags)
RF(bt_pad)
};
const struct lgfs2_metadata lgfs2_metadata[] = {
[LGFS2_MT_GFS2_SB] = {
.versions = LGFS2_MD_GFS2,
.header = 1,
.mh_type = GFS2_METATYPE_SB,
.mh_format = GFS2_FORMAT_SB,
.name = "gfs2_sb",
.fields = gfs2_sb_fields,
.nfields = ARRAY_SIZE(gfs2_sb_fields),
.size = sizeof(struct gfs2_sb),
},
[LGFS2_MT_GFS_SB] = {
.versions = LGFS2_MD_GFS1,
.header = 1,
.mh_type = GFS2_METATYPE_SB,
.mh_format = GFS_FORMAT_SB,
.name = "gfs_sb",
.fields = gfs_sb_fields,
.nfields = ARRAY_SIZE(gfs_sb_fields),
.size = sizeof(struct gfs_sb),
},
[LGFS2_MT_RINDEX] = {
.versions = LGFS2_MD_GFS1 | LGFS2_MD_GFS2,
.name = "rindex",
.fields = gfs2_rindex_fields,
.nfields = ARRAY_SIZE(gfs2_rindex_fields),
.size = sizeof(struct gfs2_rindex),
},
[LGFS2_MT_GFS2_RGRP] = {
.versions = LGFS2_MD_GFS2,
.header = 1,
.mh_type = GFS2_METATYPE_RG,
.mh_format = GFS2_FORMAT_RG,
.name = "gfs2_rgrp",
.fields = gfs2_rgrp_fields,
.nfields = ARRAY_SIZE(gfs2_rgrp_fields),
.size = sizeof(struct gfs2_rgrp),
},
[LGFS2_MT_GFS_RGRP] = {
.versions = LGFS2_MD_GFS1,
.header = 1,
.mh_type = GFS2_METATYPE_RG,
.mh_format = GFS2_FORMAT_RG,
.name = "gfs_rgrp",
.fields = gfs_rgrp_fields,
.nfields = ARRAY_SIZE(gfs_rgrp_fields),
.size = sizeof(struct gfs_rgrp),
},
[LGFS2_MT_RGRP_BITMAP] = {
.versions = LGFS2_MD_GFS1 | LGFS2_MD_GFS2,
.header = 1,
.mh_type = GFS2_METATYPE_RB,
.mh_format = GFS2_FORMAT_RB,
.name = "gfs2_rgrp_bitmap",
.fields = gfs2_rgrp_bitmap_fields,
.nfields = ARRAY_SIZE(gfs2_rgrp_bitmap_fields),
.size = sizeof(struct gfs2_meta_header),
},
[LGFS2_MT_GFS2_DINODE] = {
.versions = LGFS2_MD_GFS2,
.header = 1,
.mh_type = GFS2_METATYPE_DI,
.mh_format = GFS2_FORMAT_DI,
.name = "gfs2_dinode",
.fields = gfs2_dinode_fields,
.nfields = ARRAY_SIZE(gfs2_dinode_fields),
.size = sizeof(struct gfs2_dinode),
},
[LGFS2_MT_GFS_DINODE] = {
.versions = LGFS2_MD_GFS1,
.header = 1,
.mh_type = GFS2_METATYPE_DI,
.mh_format = GFS2_FORMAT_DI,
.name = "gfs_dinode",
.fields = gfs_dinode_fields,
.nfields = ARRAY_SIZE(gfs_dinode_fields),
.size = sizeof(struct gfs_dinode),
},
[LGFS2_MT_GFS2_INDIRECT] = {
.versions = LGFS2_MD_GFS2,
.header = 1,
.mh_type = GFS2_METATYPE_IN,
.mh_format = GFS2_FORMAT_IN,
.name = "gfs2_indirect",
.fields = gfs2_indirect_fields,
.nfields = ARRAY_SIZE(gfs2_indirect_fields),
.size = sizeof(struct gfs2_meta_header),
},
[LGFS2_MT_GFS_INDIRECT] = {
.versions = LGFS2_MD_GFS1,
.header = 1,
.mh_type = GFS2_METATYPE_IN,
.mh_format = GFS2_FORMAT_IN,
.name = "gfs_indirect",
.fields = gfs_indirect_fields,
.nfields = ARRAY_SIZE(gfs_indirect_fields),
.size = sizeof(struct gfs_indirect),
},
[LGFS2_MT_DIR_LEAF] = {
.versions = LGFS2_MD_GFS1 | LGFS2_MD_GFS2,
.header = 1,
.mh_type = GFS2_METATYPE_LF,
.mh_format = GFS2_FORMAT_LF,
.name = "gfs2_leaf",
.fields = gfs2_leaf_fields,
.nfields = ARRAY_SIZE(gfs2_leaf_fields),
.size = sizeof(struct gfs2_leaf),
},
[LGFS2_MT_JRNL_DATA] = {
.versions = LGFS2_MD_GFS1 | LGFS2_MD_GFS2,
.header = 1,
.mh_type = GFS2_METATYPE_JD,
.mh_format = GFS2_FORMAT_JD,
.name = "gfs2_jdata",
.fields = gfs2_jdata_fields,
.nfields = ARRAY_SIZE(gfs2_jdata_fields),
.size = sizeof(struct gfs2_meta_header),
},
[LGFS2_MT_GFS2_LOG_HEADER] = {
.versions = LGFS2_MD_GFS2,
.header = 1,
.mh_type = GFS2_METATYPE_LH,
.mh_format = GFS2_FORMAT_LH,
.name = "gfs2_log_header",
.fields = gfs2_log_header_fields,
.nfields = ARRAY_SIZE(gfs2_log_header_fields),
.size = sizeof(struct gfs2_log_header),
},
[LGFS2_MT_GFS_LOG_HEADER] = {
.versions = LGFS2_MD_GFS1,
.header = 1,
.mh_type = GFS2_METATYPE_LH,
.mh_format = GFS2_FORMAT_LH,
.name = "gfs_log_header",
.fields = gfs_log_header_fields,
.nfields = ARRAY_SIZE(gfs_log_header_fields),
.size = sizeof(struct gfs_log_header),
},
[LGFS2_MT_GFS2_LOG_DESC] = {
.versions = LGFS2_MD_GFS2,
.header = 1,
.mh_type = GFS2_METATYPE_LD,
.mh_format = GFS2_FORMAT_LD,
.name = "gfs2_log_desc",
.fields = gfs2_log_desc_fields,
.nfields = ARRAY_SIZE(gfs2_log_desc_fields),
.size = sizeof(struct gfs2_log_descriptor),
},
[LGFS2_MT_GFS_LOG_DESC] = {
.versions = LGFS2_MD_GFS1,
.header = 1,
.mh_type = GFS2_METATYPE_LD,
.mh_format = GFS2_FORMAT_LD,
.name = "gfs_log_desc",
.fields = gfs_log_desc_fields,
.nfields = ARRAY_SIZE(gfs_log_desc_fields),
.size = sizeof(struct gfs_log_descriptor),
},
[LGFS2_MT_GFS2_LOG_BLOCK] = {
.versions = LGFS2_MD_GFS2,
.header = 1,
.mh_type = GFS2_METATYPE_LB,
.mh_format = GFS2_FORMAT_LB,
.name = "gfs2_log_block",
.fields = gfs2_log_block_fields,
.nfields = ARRAY_SIZE(gfs2_log_block_fields),
.size = sizeof(struct gfs2_meta_header),
},
[LGFS2_MT_EA_ATTR] = {
.versions = LGFS2_MD_GFS1 | LGFS2_MD_GFS2,
.header = 1,
.mh_type = GFS2_METATYPE_EA,
.mh_format = GFS2_FORMAT_EA,
.name = "gfs2_ea_attr",
.fields = gfs2_ea_attr_fields,
.nfields = ARRAY_SIZE(gfs2_ea_attr_fields),
.size = sizeof(struct gfs2_meta_header),
},
[LGFS2_MT_EA_DATA] = {
.versions = LGFS2_MD_GFS1 | LGFS2_MD_GFS2,
.header = 1,
.mh_type = GFS2_METATYPE_ED,
.mh_format = GFS2_FORMAT_ED,
.name = "gfs2_ea_data",
.fields = gfs2_ea_data_fields,
.nfields = ARRAY_SIZE(gfs2_ea_data_fields),
.size = sizeof(struct gfs2_meta_header),
},
[LGFS2_MT_GFS2_QUOTA_CHANGE] = {
.versions = LGFS2_MD_GFS2,
.name = "gfs2_quota_change",
.fields = gfs2_quota_change_fields,
.nfields = ARRAY_SIZE(gfs2_quota_change_fields),
.size = sizeof(struct gfs2_quota_change),
},
[LGFS2_MT_DIRENT] = {
.versions = LGFS2_MD_GFS1 | LGFS2_MD_GFS2,
.name = "gfs2_dirent",
.fields = gfs2_dirent_fields,
.nfields = ARRAY_SIZE(gfs2_dirent_fields),
.size = sizeof(struct gfs2_dirent),
},
[LGFS2_MT_EA_HEADER] = {
.versions = LGFS2_MD_GFS1 | LGFS2_MD_GFS2,
.name = "gfs2_ea_header",
.fields = gfs2_ea_header_fields,
.nfields = ARRAY_SIZE(gfs2_ea_header_fields),
.size = sizeof(struct gfs2_ea_header),
},
[LGFS2_MT_GFS2_INUM_RANGE] = {
.versions = LGFS2_MD_GFS2,
.name = "gfs2_inum_range",
.fields = gfs2_inum_range_fields,
.nfields = ARRAY_SIZE(gfs2_inum_range_fields),
.size = sizeof(struct gfs2_inum_range),
},
[LGFS2_MT_STATFS_CHANGE] = {
.versions = LGFS2_MD_GFS1 | LGFS2_MD_GFS2,
.name = "gfs2_statfs_change",
.fields = gfs2_statfs_change_fields,
.nfields = ARRAY_SIZE(gfs2_statfs_change_fields),
.size = sizeof(struct gfs2_statfs_change),
},
[LGFS2_MT_GFS_JINDEX] = {
.versions = LGFS2_MD_GFS1,
.name = "gfs_jindex",
.fields = gfs_jindex_fields,
.nfields = ARRAY_SIZE(gfs_jindex_fields),
.size = sizeof(struct gfs_jindex),
},
[LGFS2_MT_GFS_BLOCK_TAG] = {
.versions = LGFS2_MD_GFS1,
.name = "gfs_block_tag",
.fields = gfs_block_tag_fields,
.nfields = ARRAY_SIZE(gfs_block_tag_fields),
.size = sizeof(struct gfs_block_tag),
},
[LGFS2_MT_DATA] = {
.versions = LGFS2_MD_GFS1 | LGFS2_MD_GFS2,
.name = "data",
},
[LGFS2_MT_FREE] = {
.versions = LGFS2_MD_GFS1 | LGFS2_MD_GFS2,
.name = "free",
},
};
const unsigned lgfs2_metadata_size = ARRAY_SIZE(lgfs2_metadata);
const struct lgfs2_metafield *lgfs2_find_mfield_name(const char *name, const struct lgfs2_metadata *mtype)
{
int j;
const struct lgfs2_metafield *f;
for (j = 0; j < mtype->nfields; j++) {
f = &mtype->fields[j];
if (strcmp(f->name, name) == 0)
return f;
}
return NULL;
}
static int check_metadata_sizes(void)
{
unsigned offset;
int i, j;
int ret = 0;
for (i = 0; i < lgfs2_metadata_size; i++) {
const struct lgfs2_metadata *m = &lgfs2_metadata[i];
offset = 0;
for (j = 0; j < m->nfields; j++) {
const struct lgfs2_metafield *f = &m->fields[j];
if (f->offset != offset) {
fprintf(stderr, "%s: %s: offset is %u, expected %u\n", m->name, f->name, f->offset, offset);
ret = -1;
}
offset += f->length;
}
if (offset != m->size) {
fprintf(stderr, "%s: size mismatch between struct %u and fields %u\n", m->name, m->size, offset);
ret = -1;
}
}
return ret;
}
static int check_symtab(void)
{
int i, j;
int ret = 0;
for (i = 0; i < lgfs2_metadata_size; i++) {
const struct lgfs2_metadata *m = &lgfs2_metadata[i];
for (j = 0; j < m->nfields; j++) {
const struct lgfs2_metafield *f = &m->fields[j];
if (f->flags & (LGFS2_MFF_MASK|LGFS2_MFF_ENUM)) {
if (f->symtab == NULL) {
fprintf(stderr, "%s: Missing symtab for %s\n", m->name, f->name);
ret = -1;
}
}
if (f->symtab) {
if (!(f->flags & (LGFS2_MFF_MASK|LGFS2_MFF_ENUM))) {
fprintf(stderr, "%s: Symtab for non-enum and non-mask field %s\n", m->name, f->name);
ret = -1;
}
}
}
}
return ret;
}
static int check_ptrs(void)
{
int i, j;
int ret = 0;
for (i = 0; i < lgfs2_metadata_size; i++) {
const struct lgfs2_metadata *m = &lgfs2_metadata[i];
for (j = 0; j < m->nfields; j++) {
const struct lgfs2_metafield *f = &m->fields[j];
if ((f->flags & LGFS2_MFF_POINTER) && !f->points_to) {
fprintf(stderr, "%s: Pointer entry %s has no destination\n", m->name, f->name);
ret = -1;
}
}
}
return ret;
}
int lgfs2_selfcheck(void)
{
int ret = 0;
ret |= check_metadata_sizes();
ret |= check_symtab();
ret |= check_ptrs();
return ret;
}
const struct lgfs2_metadata *lgfs2_find_mtype(uint32_t mh_type, const unsigned versions)
{
const struct lgfs2_metadata *m = lgfs2_metadata;
unsigned n = 0;
do {
if ((m[n].versions & versions) && m[n].mh_type == mh_type)
return &m[n];
n++;
} while (n < lgfs2_metadata_size);
return NULL;
}
const struct lgfs2_metadata *lgfs2_find_mtype_name(const char *name, const unsigned versions)
{
const struct lgfs2_metadata *m = lgfs2_metadata;
unsigned n = 0;
do {
if ((m[n].versions & versions) && !strcmp(m[n].name, name))
return &m[n];
n++;
} while (n < lgfs2_metadata_size);
return NULL;
}
int lgfs2_field_str(char *str, const size_t size, const char *blk, const struct lgfs2_metafield *field, int hex)
{
const char *fieldp = blk + field->offset;
errno = EINVAL;
if (str == NULL)
return 1;
if (field->flags & LGFS2_MFF_UUID) {
#ifdef GFS2_HAS_UUID
char readable_uuid[36+1];
uuid_t uuid;
memcpy(uuid, fieldp, sizeof(uuid_t));
uuid_unparse(uuid, readable_uuid);
snprintf(str, size, "%s", readable_uuid);
#endif
} else if (field->flags & LGFS2_MFF_STRING) {
snprintf(str, size, "%s", fieldp);
} else {
switch(field->length) {
case sizeof(uint8_t):
snprintf(str, size, hex? "%"PRIx8 : "%"PRIu8, *(uint8_t *)fieldp);
break;
case sizeof(uint16_t):
snprintf(str, size, hex? "%"PRIx16 : "%"PRIu16, be16_to_cpu(*(uint16_t *)fieldp));
break;
case sizeof(uint32_t):
snprintf(str, size, hex? "%"PRIx32 : "%"PRIu32, be32_to_cpu(*(uint32_t *)fieldp));
break;
case sizeof(uint64_t):
snprintf(str, size, hex? "%"PRIx64 : "%"PRIu64, be64_to_cpu(*(uint64_t *)fieldp));
break;
default:
break;
}
}
str[size - 1] = '\0';
return 0;
}
int lgfs2_field_assign(char *blk, const struct lgfs2_metafield *field, const void *val)
{
char *fieldp = blk + field->offset;
uint64_t num = *(uint64_t *)val;
if (field->flags & LGFS2_MFF_UUID) {
memcpy(fieldp, val, 16);
return 0;
}
errno = EINVAL;
if (field->flags & LGFS2_MFF_STRING) {
size_t len = strnlen(val, field->length);
if (len >= field->length)
return 1;
strncpy(fieldp, val, field->length - 1);
fieldp[field->length - 1] = '\0';
return 0;
}
switch(field->length) {
case sizeof(uint8_t):
*fieldp = (uint8_t)num;
return 0;
case sizeof(uint16_t):
*(uint16_t *)fieldp = cpu_to_be16((uint16_t)num);
return 0;
case sizeof(uint32_t):
*(uint32_t *)fieldp = cpu_to_be32((uint32_t)num);
return 0;
case sizeof(uint64_t):
*(uint64_t *)fieldp = cpu_to_be64((uint64_t)num);
return 0;
default:
/* Will never happen */
break;
}
return 1;
}