656 lines
15 KiB
C
656 lines
15 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
|
|
* Copyright (c) 2016 Oracle, Inc.
|
|
* All Rights Reserved.
|
|
*/
|
|
#include "libxfs.h"
|
|
#include "libxlog.h"
|
|
|
|
#include "logprint.h"
|
|
|
|
/* Extent Free Items */
|
|
|
|
static int
|
|
xfs_efi_copy_format(
|
|
char *buf,
|
|
uint len,
|
|
struct xfs_efi_log_format *dst_efi_fmt,
|
|
int continued)
|
|
{
|
|
uint i;
|
|
uint nextents = ((xfs_efi_log_format_t *)buf)->efi_nextents;
|
|
uint dst_len = sizeof(xfs_efi_log_format_t) + (nextents - 1) * sizeof(xfs_extent_t);
|
|
uint len32 = sizeof(xfs_efi_log_format_32_t) + (nextents - 1) * sizeof(xfs_extent_32_t);
|
|
uint len64 = sizeof(xfs_efi_log_format_64_t) + (nextents - 1) * sizeof(xfs_extent_64_t);
|
|
|
|
if (len == dst_len || continued) {
|
|
memcpy((char *)dst_efi_fmt, buf, len);
|
|
return 0;
|
|
} else if (len == len32) {
|
|
xfs_efi_log_format_32_t *src_efi_fmt_32 = (xfs_efi_log_format_32_t *)buf;
|
|
|
|
dst_efi_fmt->efi_type = src_efi_fmt_32->efi_type;
|
|
dst_efi_fmt->efi_size = src_efi_fmt_32->efi_size;
|
|
dst_efi_fmt->efi_nextents = src_efi_fmt_32->efi_nextents;
|
|
dst_efi_fmt->efi_id = src_efi_fmt_32->efi_id;
|
|
for (i = 0; i < dst_efi_fmt->efi_nextents; i++) {
|
|
dst_efi_fmt->efi_extents[i].ext_start =
|
|
src_efi_fmt_32->efi_extents[i].ext_start;
|
|
dst_efi_fmt->efi_extents[i].ext_len =
|
|
src_efi_fmt_32->efi_extents[i].ext_len;
|
|
}
|
|
return 0;
|
|
} else if (len == len64) {
|
|
xfs_efi_log_format_64_t *src_efi_fmt_64 = (xfs_efi_log_format_64_t *)buf;
|
|
|
|
dst_efi_fmt->efi_type = src_efi_fmt_64->efi_type;
|
|
dst_efi_fmt->efi_size = src_efi_fmt_64->efi_size;
|
|
dst_efi_fmt->efi_nextents = src_efi_fmt_64->efi_nextents;
|
|
dst_efi_fmt->efi_id = src_efi_fmt_64->efi_id;
|
|
for (i = 0; i < dst_efi_fmt->efi_nextents; i++) {
|
|
dst_efi_fmt->efi_extents[i].ext_start =
|
|
src_efi_fmt_64->efi_extents[i].ext_start;
|
|
dst_efi_fmt->efi_extents[i].ext_len =
|
|
src_efi_fmt_64->efi_extents[i].ext_len;
|
|
}
|
|
return 0;
|
|
}
|
|
fprintf(stderr, _("%s: bad size of efi format: %u; expected %u or %u; nextents = %u\n"),
|
|
progname, len, len32, len64, nextents);
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
xlog_print_trans_efi(
|
|
char **ptr,
|
|
uint src_len,
|
|
int continued)
|
|
{
|
|
xfs_efi_log_format_t *src_f, *f = NULL;
|
|
uint dst_len;
|
|
xfs_extent_t *ex;
|
|
int i;
|
|
int error = 0;
|
|
int core_size = offsetof(xfs_efi_log_format_t, efi_extents);
|
|
|
|
/*
|
|
* memmove to ensure 8-byte alignment for the long longs in
|
|
* xfs_efi_log_format_t structure
|
|
*/
|
|
if ((src_f = (xfs_efi_log_format_t *)malloc(src_len)) == NULL) {
|
|
fprintf(stderr, _("%s: xlog_print_trans_efi: malloc failed\n"), progname);
|
|
exit(1);
|
|
}
|
|
memmove((char*)src_f, *ptr, src_len);
|
|
*ptr += src_len;
|
|
|
|
/* convert to native format */
|
|
dst_len = sizeof(xfs_efi_log_format_t) + (src_f->efi_nextents - 1) * sizeof(xfs_extent_t);
|
|
|
|
if (continued && src_len < core_size) {
|
|
printf(_("EFI: Not enough data to decode further\n"));
|
|
error = 1;
|
|
goto error;
|
|
}
|
|
|
|
if ((f = (xfs_efi_log_format_t *)malloc(dst_len)) == NULL) {
|
|
fprintf(stderr, _("%s: xlog_print_trans_efi: malloc failed\n"), progname);
|
|
exit(1);
|
|
}
|
|
if (xfs_efi_copy_format((char*)src_f, src_len, f, continued)) {
|
|
error = 1;
|
|
goto error;
|
|
}
|
|
|
|
printf(_("EFI: #regs: %d num_extents: %d id: 0x%llx\n"),
|
|
f->efi_size, f->efi_nextents, (unsigned long long)f->efi_id);
|
|
|
|
if (continued) {
|
|
printf(_("EFI free extent data skipped (CONTINUE set, no space)\n"));
|
|
goto error;
|
|
}
|
|
|
|
ex = f->efi_extents;
|
|
for (i=0; i < f->efi_nextents; i++) {
|
|
printf("(s: 0x%llx, l: %d) ",
|
|
(unsigned long long)ex->ext_start, ex->ext_len);
|
|
if (i % 4 == 3) printf("\n");
|
|
ex++;
|
|
}
|
|
if (i % 4 != 0)
|
|
printf("\n");
|
|
error:
|
|
free(src_f);
|
|
free(f);
|
|
return error;
|
|
} /* xlog_print_trans_efi */
|
|
|
|
void
|
|
xlog_recover_print_efi(
|
|
xlog_recover_item_t *item)
|
|
{
|
|
xfs_efi_log_format_t *f, *src_f;
|
|
xfs_extent_t *ex;
|
|
int i;
|
|
uint src_len, dst_len;
|
|
|
|
src_f = (xfs_efi_log_format_t *)item->ri_buf[0].i_addr;
|
|
src_len = item->ri_buf[0].i_len;
|
|
/*
|
|
* An xfs_efi_log_format structure contains a variable length array
|
|
* as the last field.
|
|
* Each element is of size xfs_extent_32_t or xfs_extent_64_t.
|
|
* Need to convert to native format.
|
|
*/
|
|
dst_len = sizeof(xfs_efi_log_format_t) +
|
|
(src_f->efi_nextents - 1) * sizeof(xfs_extent_t);
|
|
if ((f = (xfs_efi_log_format_t *)malloc(dst_len)) == NULL) {
|
|
fprintf(stderr, _("%s: xlog_recover_print_efi: malloc failed\n"),
|
|
progname);
|
|
exit(1);
|
|
}
|
|
if (xfs_efi_copy_format((char*)src_f, src_len, f, 0)) {
|
|
free(f);
|
|
return;
|
|
}
|
|
|
|
printf(_(" EFI: #regs:%d num_extents:%d id:0x%llx\n"),
|
|
f->efi_size, f->efi_nextents, (unsigned long long)f->efi_id);
|
|
ex = f->efi_extents;
|
|
printf(" ");
|
|
for (i=0; i< f->efi_nextents; i++) {
|
|
printf("(s: 0x%llx, l: %d) ",
|
|
(unsigned long long)ex->ext_start, ex->ext_len);
|
|
if (i % 4 == 3)
|
|
printf("\n");
|
|
ex++;
|
|
}
|
|
if (i % 4 != 0)
|
|
printf("\n");
|
|
free(f);
|
|
}
|
|
|
|
int
|
|
xlog_print_trans_efd(char **ptr, uint len)
|
|
{
|
|
xfs_efd_log_format_t *f;
|
|
xfs_efd_log_format_t lbuf;
|
|
/* size without extents at end */
|
|
uint core_size = sizeof(xfs_efd_log_format_t) - sizeof(xfs_extent_t);
|
|
|
|
/*
|
|
* memmove to ensure 8-byte alignment for the long longs in
|
|
* xfs_efd_log_format_t structure
|
|
*/
|
|
memmove(&lbuf, *ptr, min(core_size, len));
|
|
f = &lbuf;
|
|
*ptr += len;
|
|
if (len >= core_size) {
|
|
printf(_("EFD: #regs: %d num_extents: %d id: 0x%llx\n"),
|
|
f->efd_size, f->efd_nextents,
|
|
(unsigned long long)f->efd_efi_id);
|
|
|
|
/* don't print extents as they are not used */
|
|
|
|
return 0;
|
|
} else {
|
|
printf(_("EFD: Not enough data to decode further\n"));
|
|
return 1;
|
|
}
|
|
} /* xlog_print_trans_efd */
|
|
|
|
void
|
|
xlog_recover_print_efd(
|
|
xlog_recover_item_t *item)
|
|
{
|
|
xfs_efd_log_format_t *f;
|
|
|
|
f = (xfs_efd_log_format_t *)item->ri_buf[0].i_addr;
|
|
/*
|
|
* An xfs_efd_log_format structure contains a variable length array
|
|
* as the last field.
|
|
* Each element is of size xfs_extent_32_t or xfs_extent_64_t.
|
|
* However, the extents are never used and won't be printed.
|
|
*/
|
|
printf(_(" EFD: #regs: %d num_extents: %d id: 0x%llx\n"),
|
|
f->efd_size, f->efd_nextents,
|
|
(unsigned long long)f->efd_efi_id);
|
|
}
|
|
|
|
/* Reverse Mapping Update Items */
|
|
|
|
static int
|
|
xfs_rui_copy_format(
|
|
char *buf,
|
|
uint len,
|
|
struct xfs_rui_log_format *dst_fmt,
|
|
int continued)
|
|
{
|
|
uint nextents = ((struct xfs_rui_log_format *)buf)->rui_nextents;
|
|
uint dst_len = xfs_rui_log_format_sizeof(nextents);
|
|
|
|
if (len == dst_len || continued) {
|
|
memcpy((char *)dst_fmt, buf, len);
|
|
return 0;
|
|
}
|
|
fprintf(stderr, _("%s: bad size of RUI format: %u; expected %u; nextents = %u\n"),
|
|
progname, len, dst_len, nextents);
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
xlog_print_trans_rui(
|
|
char **ptr,
|
|
uint src_len,
|
|
int continued)
|
|
{
|
|
struct xfs_rui_log_format *src_f, *f = NULL;
|
|
uint dst_len;
|
|
uint nextents;
|
|
struct xfs_map_extent *ex;
|
|
int i;
|
|
int error = 0;
|
|
int core_size;
|
|
|
|
core_size = offsetof(struct xfs_rui_log_format, rui_extents);
|
|
|
|
/*
|
|
* memmove to ensure 8-byte alignment for the long longs in
|
|
* struct xfs_rui_log_format structure
|
|
*/
|
|
src_f = malloc(src_len);
|
|
if (src_f == NULL) {
|
|
fprintf(stderr, _("%s: %s: malloc failed\n"),
|
|
progname, __func__);
|
|
exit(1);
|
|
}
|
|
memmove((char*)src_f, *ptr, src_len);
|
|
*ptr += src_len;
|
|
|
|
/* convert to native format */
|
|
nextents = src_f->rui_nextents;
|
|
dst_len = xfs_rui_log_format_sizeof(nextents);
|
|
|
|
if (continued && src_len < core_size) {
|
|
printf(_("RUI: Not enough data to decode further\n"));
|
|
error = 1;
|
|
goto error;
|
|
}
|
|
|
|
f = malloc(dst_len);
|
|
if (f == NULL) {
|
|
fprintf(stderr, _("%s: %s: malloc failed\n"),
|
|
progname, __func__);
|
|
exit(1);
|
|
}
|
|
if (xfs_rui_copy_format((char *)src_f, src_len, f, continued)) {
|
|
error = 1;
|
|
goto error;
|
|
}
|
|
|
|
printf(_("RUI: #regs: %d num_extents: %d id: 0x%llx\n"),
|
|
f->rui_size, f->rui_nextents, (unsigned long long)f->rui_id);
|
|
|
|
if (continued) {
|
|
printf(_("RUI extent data skipped (CONTINUE set, no space)\n"));
|
|
goto error;
|
|
}
|
|
|
|
ex = f->rui_extents;
|
|
for (i=0; i < f->rui_nextents; i++) {
|
|
printf("(s: 0x%llx, l: %d, own: %lld, off: %llu, f: 0x%x) ",
|
|
(unsigned long long)ex->me_startblock, ex->me_len,
|
|
(long long)ex->me_owner,
|
|
(unsigned long long)ex->me_startoff, ex->me_flags);
|
|
printf("\n");
|
|
ex++;
|
|
}
|
|
error:
|
|
free(src_f);
|
|
free(f);
|
|
return error;
|
|
}
|
|
|
|
void
|
|
xlog_recover_print_rui(
|
|
struct xlog_recover_item *item)
|
|
{
|
|
char *src_f;
|
|
uint src_len;
|
|
|
|
src_f = item->ri_buf[0].i_addr;
|
|
src_len = item->ri_buf[0].i_len;
|
|
|
|
xlog_print_trans_rui(&src_f, src_len, 0);
|
|
}
|
|
|
|
int
|
|
xlog_print_trans_rud(
|
|
char **ptr,
|
|
uint len)
|
|
{
|
|
struct xfs_rud_log_format *f;
|
|
struct xfs_rud_log_format lbuf;
|
|
|
|
/* size without extents at end */
|
|
uint core_size = sizeof(struct xfs_rud_log_format);
|
|
|
|
/*
|
|
* memmove to ensure 8-byte alignment for the long longs in
|
|
* xfs_efd_log_format_t structure
|
|
*/
|
|
memmove(&lbuf, *ptr, min(core_size, len));
|
|
f = &lbuf;
|
|
*ptr += len;
|
|
if (len >= core_size) {
|
|
printf(_("RUD: #regs: %d id: 0x%llx\n"),
|
|
f->rud_size,
|
|
(unsigned long long)f->rud_rui_id);
|
|
|
|
/* don't print extents as they are not used */
|
|
|
|
return 0;
|
|
} else {
|
|
printf(_("RUD: Not enough data to decode further\n"));
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
void
|
|
xlog_recover_print_rud(
|
|
struct xlog_recover_item *item)
|
|
{
|
|
char *f;
|
|
|
|
f = item->ri_buf[0].i_addr;
|
|
xlog_print_trans_rud(&f, sizeof(struct xfs_rud_log_format));
|
|
}
|
|
|
|
/* Reference Count Update Items */
|
|
|
|
static int
|
|
xfs_cui_copy_format(
|
|
struct xfs_cui_log_format *cui,
|
|
uint len,
|
|
struct xfs_cui_log_format *dst_fmt,
|
|
int continued)
|
|
{
|
|
uint nextents;
|
|
uint dst_len;
|
|
|
|
nextents = cui->cui_nextents;
|
|
dst_len = xfs_cui_log_format_sizeof(nextents);
|
|
|
|
if (len == dst_len || continued) {
|
|
memcpy(dst_fmt, cui, len);
|
|
return 0;
|
|
}
|
|
fprintf(stderr, _("%s: bad size of CUI format: %u; expected %u; nextents = %u\n"),
|
|
progname, len, dst_len, nextents);
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
xlog_print_trans_cui(
|
|
char **ptr,
|
|
uint src_len,
|
|
int continued)
|
|
{
|
|
struct xfs_cui_log_format *src_f, *f = NULL;
|
|
uint dst_len;
|
|
uint nextents;
|
|
struct xfs_phys_extent *ex;
|
|
int i;
|
|
int error = 0;
|
|
int core_size;
|
|
|
|
core_size = offsetof(struct xfs_cui_log_format, cui_extents);
|
|
|
|
src_f = malloc(src_len);
|
|
if (src_f == NULL) {
|
|
fprintf(stderr, _("%s: %s: malloc failed\n"),
|
|
progname, __func__);
|
|
exit(1);
|
|
}
|
|
memcpy(src_f, *ptr, src_len);
|
|
*ptr += src_len;
|
|
|
|
/* convert to native format */
|
|
nextents = src_f->cui_nextents;
|
|
dst_len = xfs_cui_log_format_sizeof(nextents);
|
|
|
|
if (continued && src_len < core_size) {
|
|
printf(_("CUI: Not enough data to decode further\n"));
|
|
error = 1;
|
|
goto error;
|
|
}
|
|
|
|
f = malloc(dst_len);
|
|
if (f == NULL) {
|
|
fprintf(stderr, _("%s: %s: malloc failed\n"),
|
|
progname, __func__);
|
|
exit(1);
|
|
}
|
|
if (xfs_cui_copy_format(src_f, src_len, f, continued)) {
|
|
error = 1;
|
|
goto error;
|
|
}
|
|
|
|
printf(_("CUI: #regs: %d num_extents: %d id: 0x%llx\n"),
|
|
f->cui_size, f->cui_nextents, (unsigned long long)f->cui_id);
|
|
|
|
if (continued) {
|
|
printf(_("CUI extent data skipped (CONTINUE set, no space)\n"));
|
|
goto error;
|
|
}
|
|
|
|
ex = f->cui_extents;
|
|
for (i=0; i < f->cui_nextents; i++) {
|
|
printf("(s: 0x%llx, l: %d, f: 0x%x) ",
|
|
(unsigned long long)ex->pe_startblock, ex->pe_len,
|
|
ex->pe_flags);
|
|
printf("\n");
|
|
ex++;
|
|
}
|
|
error:
|
|
free(src_f);
|
|
free(f);
|
|
return error;
|
|
}
|
|
|
|
void
|
|
xlog_recover_print_cui(
|
|
struct xlog_recover_item *item)
|
|
{
|
|
char *src_f;
|
|
uint src_len;
|
|
|
|
src_f = item->ri_buf[0].i_addr;
|
|
src_len = item->ri_buf[0].i_len;
|
|
|
|
xlog_print_trans_cui(&src_f, src_len, 0);
|
|
}
|
|
|
|
int
|
|
xlog_print_trans_cud(
|
|
char **ptr,
|
|
uint len)
|
|
{
|
|
struct xfs_cud_log_format *f;
|
|
struct xfs_cud_log_format lbuf;
|
|
|
|
/* size without extents at end */
|
|
uint core_size = sizeof(struct xfs_cud_log_format);
|
|
|
|
memcpy(&lbuf, *ptr, min(core_size, len));
|
|
f = &lbuf;
|
|
*ptr += len;
|
|
if (len >= core_size) {
|
|
printf(_("CUD: #regs: %d id: 0x%llx\n"),
|
|
f->cud_size,
|
|
(unsigned long long)f->cud_cui_id);
|
|
|
|
/* don't print extents as they are not used */
|
|
|
|
return 0;
|
|
} else {
|
|
printf(_("CUD: Not enough data to decode further\n"));
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
void
|
|
xlog_recover_print_cud(
|
|
struct xlog_recover_item *item)
|
|
{
|
|
char *f;
|
|
|
|
f = item->ri_buf[0].i_addr;
|
|
xlog_print_trans_cud(&f, sizeof(struct xfs_cud_log_format));
|
|
}
|
|
|
|
/* Block Mapping Update Items */
|
|
|
|
static int
|
|
xfs_bui_copy_format(
|
|
struct xfs_bui_log_format *bui,
|
|
uint len,
|
|
struct xfs_bui_log_format *dst_fmt,
|
|
int continued)
|
|
{
|
|
uint nextents;
|
|
uint dst_len;
|
|
|
|
nextents = bui->bui_nextents;
|
|
dst_len = xfs_bui_log_format_sizeof(nextents);
|
|
|
|
if (len == dst_len || continued) {
|
|
memcpy(dst_fmt, bui, len);
|
|
return 0;
|
|
}
|
|
fprintf(stderr, _("%s: bad size of BUI format: %u; expected %u; nextents = %u\n"),
|
|
progname, len, dst_len, nextents);
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
xlog_print_trans_bui(
|
|
char **ptr,
|
|
uint src_len,
|
|
int continued)
|
|
{
|
|
struct xfs_bui_log_format *src_f, *f = NULL;
|
|
uint dst_len;
|
|
uint nextents;
|
|
struct xfs_map_extent *ex;
|
|
int i;
|
|
int error = 0;
|
|
int core_size;
|
|
|
|
core_size = offsetof(struct xfs_bui_log_format, bui_extents);
|
|
|
|
src_f = malloc(src_len);
|
|
if (src_f == NULL) {
|
|
fprintf(stderr, _("%s: %s: malloc failed\n"),
|
|
progname, __func__);
|
|
exit(1);
|
|
}
|
|
memcpy(src_f, *ptr, src_len);
|
|
*ptr += src_len;
|
|
|
|
/* convert to native format */
|
|
nextents = src_f->bui_nextents;
|
|
dst_len = xfs_bui_log_format_sizeof(nextents);
|
|
|
|
if (continued && src_len < core_size) {
|
|
printf(_("BUI: Not enough data to decode further\n"));
|
|
error = 1;
|
|
goto error;
|
|
}
|
|
|
|
f = malloc(dst_len);
|
|
if (f == NULL) {
|
|
fprintf(stderr, _("%s: %s: malloc failed\n"),
|
|
progname, __func__);
|
|
exit(1);
|
|
}
|
|
if (xfs_bui_copy_format(src_f, src_len, f, continued)) {
|
|
error = 1;
|
|
goto error;
|
|
}
|
|
|
|
printf(_("BUI: #regs: %d num_extents: %d id: 0x%llx\n"),
|
|
f->bui_size, f->bui_nextents, (unsigned long long)f->bui_id);
|
|
|
|
if (continued) {
|
|
printf(_("BUI extent data skipped (CONTINUE set, no space)\n"));
|
|
goto error;
|
|
}
|
|
|
|
ex = f->bui_extents;
|
|
for (i=0; i < f->bui_nextents; i++) {
|
|
printf("(s: 0x%llx, l: %d, own: %lld, off: %llu, f: 0x%x) ",
|
|
(unsigned long long)ex->me_startblock, ex->me_len,
|
|
(long long)ex->me_owner,
|
|
(unsigned long long)ex->me_startoff, ex->me_flags);
|
|
printf("\n");
|
|
ex++;
|
|
}
|
|
error:
|
|
free(src_f);
|
|
free(f);
|
|
return error;
|
|
}
|
|
|
|
void
|
|
xlog_recover_print_bui(
|
|
struct xlog_recover_item *item)
|
|
{
|
|
char *src_f;
|
|
uint src_len;
|
|
|
|
src_f = item->ri_buf[0].i_addr;
|
|
src_len = item->ri_buf[0].i_len;
|
|
|
|
xlog_print_trans_bui(&src_f, src_len, 0);
|
|
}
|
|
|
|
int
|
|
xlog_print_trans_bud(
|
|
char **ptr,
|
|
uint len)
|
|
{
|
|
struct xfs_bud_log_format *f;
|
|
struct xfs_bud_log_format lbuf;
|
|
|
|
/* size without extents at end */
|
|
uint core_size = sizeof(struct xfs_bud_log_format);
|
|
|
|
memcpy(&lbuf, *ptr, min(core_size, len));
|
|
f = &lbuf;
|
|
*ptr += len;
|
|
if (len >= core_size) {
|
|
printf(_("BUD: #regs: %d id: 0x%llx\n"),
|
|
f->bud_size,
|
|
(unsigned long long)f->bud_bui_id);
|
|
|
|
/* don't print extents as they are not used */
|
|
|
|
return 0;
|
|
} else {
|
|
printf(_("BUD: Not enough data to decode further\n"));
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
void
|
|
xlog_recover_print_bud(
|
|
struct xlog_recover_item *item)
|
|
{
|
|
char *f;
|
|
|
|
f = item->ri_buf[0].i_addr;
|
|
xlog_print_trans_bud(&f, sizeof(struct xfs_bud_log_format));
|
|
}
|