blob: d39f8e9b9c76f9dc18542e2cafd42815758540a6 [file] [log] [blame]
/*
* Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
* Copyright (c) 2016 Oracle, Inc.
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it would be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#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));
}