By annotating structure members and other on-disk structures as little endian, we can catch bugs more easily. The code was already endian safe except for three minor spots: 1) The badblock list code was initializing its key in an endian-unsafe way. 2) Indirect block pointer sequence printing was treating cpu-order values as little endian. 3) reiserfsck was trying to do endian switching on the lost+found key, but it was before it was even initialized to anything, so we can just remove that completely. These issues were fixed as part of this commit. Signed-off-by: Jeff Mahoney <jeffm@suse.com>
1111 lines
30 KiB
C
1111 lines
30 KiB
C
/*
|
|
* Copyright 1996-2004 by Hans Reiser, licensing governed by
|
|
* reiserfsprogs/README
|
|
*/
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
#include "includes.h"
|
|
#include <stdarg.h>
|
|
#include <limits.h>
|
|
#include <printf.h>
|
|
#include <limits.h>
|
|
#include <time.h>
|
|
|
|
#if defined(HAVE_LIBUUID) && defined(HAVE_UUID_UUID_H)
|
|
# include <uuid/uuid.h>
|
|
#endif
|
|
|
|
#ifndef HAVE_REGISTER_PRINTF_SPECIFIER
|
|
#define register_printf_specifier(x, y, z) register_printf_function(x, y, z)
|
|
static int arginfo_ptr(const struct printf_info *info, size_t n, int *argtypes)
|
|
#else
|
|
static int arginfo_ptr(const struct printf_info *info, size_t n,
|
|
int *argtypes, int *size)
|
|
#endif
|
|
{
|
|
if (n > 0) {
|
|
argtypes[0] = PA_FLAG_PTR;
|
|
#ifdef HAVE_REGISTER_PRINTF_SPECIFIER
|
|
size[0] = sizeof(void *);
|
|
#endif
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
#define FPRINTF \
|
|
if (len == -1) {\
|
|
return -1;\
|
|
}\
|
|
len = fprintf (stream, "%*s",\
|
|
info->left ? -info->width : info->width, buffer);\
|
|
free (buffer);\
|
|
return len;\
|
|
|
|
|
|
/* %b */
|
|
static int print_block_head(FILE * stream,
|
|
const struct printf_info *info,
|
|
const void *const *args)
|
|
{
|
|
const struct buffer_head *bh;
|
|
char *buffer;
|
|
int len;
|
|
|
|
bh = *((const struct buffer_head **)(args[0]));
|
|
len = asprintf(&buffer, "level=%d, nr_items=%d, free_space=%d rdkey",
|
|
B_LEVEL(bh), B_NR_ITEMS(bh), B_FREE_SPACE(bh));
|
|
FPRINTF;
|
|
}
|
|
|
|
/* %K */
|
|
static int print_short_key(FILE * stream,
|
|
const struct printf_info *info,
|
|
const void *const *args)
|
|
{
|
|
const struct reiserfs_key *key;
|
|
char *buffer;
|
|
int len;
|
|
|
|
key = *((const struct reiserfs_key **)(args[0]));
|
|
len = asprintf(&buffer, "[%u %u]", get_key_dirid(key),
|
|
get_key_objectid(key));
|
|
FPRINTF;
|
|
}
|
|
|
|
/* %k */
|
|
static int print_key(FILE * stream,
|
|
const struct printf_info *info, const void *const *args)
|
|
{
|
|
const struct reiserfs_key *key;
|
|
char *buffer;
|
|
int len;
|
|
|
|
key = *((const struct reiserfs_key **)(args[0]));
|
|
len = asprintf(&buffer, "[%u %u 0x%Lx %s (%d)]",
|
|
get_key_dirid(key), get_key_objectid(key),
|
|
(unsigned long long)get_offset(key), key_of_what(key),
|
|
get_type(key));
|
|
FPRINTF;
|
|
}
|
|
|
|
/* %H */
|
|
static int print_item_head(FILE * stream,
|
|
const struct printf_info *info,
|
|
const void *const *args)
|
|
{
|
|
const struct item_head *ih;
|
|
char *buffer;
|
|
int len;
|
|
|
|
ih = *((const struct item_head **)(args[0]));
|
|
len = asprintf(&buffer, "%u %u 0x%Lx %s (%d), "
|
|
"len %u, location %u entry count %u, fsck need %u, format %s",
|
|
get_key_dirid(&ih->ih_key),
|
|
get_key_objectid(&ih->ih_key),
|
|
(unsigned long long)get_offset(&ih->ih_key),
|
|
key_of_what(&ih->ih_key), get_type(&ih->ih_key),
|
|
get_ih_item_len(ih), get_ih_location(ih),
|
|
get_ih_entry_count(ih), get_ih_flags(ih),
|
|
get_ih_key_format(ih) ==
|
|
KEY_FORMAT_2 ? "new"
|
|
: ((get_ih_key_format(ih) ==
|
|
KEY_FORMAT_1) ? "old" : "BAD"));
|
|
FPRINTF;
|
|
}
|
|
|
|
static int print_disk_child(FILE * stream,
|
|
const struct printf_info *info,
|
|
const void *const *args)
|
|
{
|
|
const struct disk_child *dc;
|
|
char *buffer;
|
|
int len;
|
|
|
|
dc = *((const struct disk_child **)(args[0]));
|
|
len =
|
|
asprintf(&buffer, "[dc_number=%u, dc_size=%u]",
|
|
get_dc_child_blocknr(dc), get_dc_child_size(dc));
|
|
FPRINTF;
|
|
}
|
|
|
|
char ftypelet(mode_t mode)
|
|
{
|
|
if (S_ISBLK(mode))
|
|
return 'b';
|
|
if (S_ISCHR(mode))
|
|
return 'c';
|
|
if (S_ISDIR(mode))
|
|
return 'd';
|
|
if (S_ISREG(mode))
|
|
return '-';
|
|
if (S_ISFIFO(mode))
|
|
return 'p';
|
|
if (S_ISLNK(mode))
|
|
return 'l';
|
|
if (S_ISSOCK(mode))
|
|
return 's';
|
|
return '?';
|
|
}
|
|
|
|
static int rwx(FILE * stream, mode_t mode)
|
|
{
|
|
return fprintf(stream, "%c%c%c",
|
|
(mode & S_IRUSR) ? 'r' : '-',
|
|
(mode & S_IWUSR) ? 'w' : '-',
|
|
(mode & S_IXUSR) ? 'x' : '-');
|
|
}
|
|
|
|
/* %M */
|
|
static int print_sd_mode(FILE * stream,
|
|
const struct printf_info *info,
|
|
const void *const *args)
|
|
{
|
|
int len = 0;
|
|
__u16 mode;
|
|
|
|
mode = *(mode_t *) args[0];
|
|
len = fprintf(stream, "%c", ftypelet(mode));
|
|
len += rwx(stream, (mode & 0700) << 0);
|
|
len += rwx(stream, (mode & 0070) << 3);
|
|
len += rwx(stream, (mode & 0007) << 6);
|
|
return len;
|
|
}
|
|
|
|
/* %U */
|
|
static int print_sd_uuid(FILE * stream,
|
|
const struct printf_info *info,
|
|
const void *const *args)
|
|
{
|
|
#if defined(HAVE_LIBUUID) && defined(HAVE_UUID_UUID_H)
|
|
const unsigned char *uuid = *((const unsigned char **)(args[0]));
|
|
char buf[37];
|
|
|
|
buf[36] = '\0';
|
|
uuid_unparse(uuid, buf);
|
|
return fprintf(stream, "%s", buf);
|
|
#else
|
|
return fprintf(stream, "<no libuuid installed>");
|
|
#endif
|
|
}
|
|
|
|
void reiserfs_warning(FILE * fp, const char *fmt, ...)
|
|
{
|
|
static int registered = 0;
|
|
va_list args;
|
|
|
|
if (!registered) {
|
|
registered = 1;
|
|
|
|
register_printf_specifier('K', print_short_key, arginfo_ptr);
|
|
register_printf_specifier('k', print_key, arginfo_ptr);
|
|
register_printf_specifier('H', print_item_head, arginfo_ptr);
|
|
register_printf_specifier('b', print_block_head, arginfo_ptr);
|
|
register_printf_specifier('y', print_disk_child, arginfo_ptr);
|
|
register_printf_specifier('M', print_sd_mode, arginfo_ptr);
|
|
register_printf_specifier('U', print_sd_uuid, arginfo_ptr);
|
|
}
|
|
|
|
va_start(args, fmt);
|
|
vfprintf(fp, fmt, args);
|
|
va_end(args);
|
|
}
|
|
|
|
static char *vi_type(struct virtual_item *vi)
|
|
{
|
|
static char *types[] =
|
|
{ "directory", "direct", "indirect", "stat data" };
|
|
|
|
if (vi->vi_type & VI_TYPE_STAT_DATA)
|
|
return types[3];
|
|
if (vi->vi_type & VI_TYPE_INDIRECT)
|
|
return types[2];
|
|
if (vi->vi_type & VI_TYPE_DIRECT)
|
|
return types[1];
|
|
if (vi->vi_type & VI_TYPE_DIRECTORY)
|
|
return types[0];
|
|
|
|
reiserfs_panic("vi_type: 6000: unknown type (0x%x)", vi->vi_type);
|
|
return NULL;
|
|
}
|
|
|
|
static void print_virtual_node(struct virtual_node *vn)
|
|
{
|
|
int i, j;
|
|
|
|
printf
|
|
("VIRTUAL NODE CONTAINS %d items, has size %d,%s,%s, ITEM_POS=%d POS_IN_ITEM=%d MODE=\'%c\'\n",
|
|
vn->vn_nr_item, vn->vn_size,
|
|
(vn->vn_vi[0].
|
|
vi_type & VI_TYPE_LEFT_MERGEABLE) ? "left mergeable" : "",
|
|
(vn->vn_vi[vn->vn_nr_item - 1].
|
|
vi_type & VI_TYPE_RIGHT_MERGEABLE) ? "right mergeable" : "",
|
|
vn->vn_affected_item_num, vn->vn_pos_in_item, vn->vn_mode);
|
|
|
|
for (i = 0; i < vn->vn_nr_item; i++) {
|
|
printf("%s %d %d", vi_type(&vn->vn_vi[i]), i,
|
|
vn->vn_vi[i].vi_item_len);
|
|
if (vn->vn_vi[i].vi_entry_sizes) {
|
|
printf("It is directory with %d entries: ",
|
|
vn->vn_vi[i].vi_entry_count);
|
|
for (j = 0; j < vn->vn_vi[i].vi_entry_count; j++)
|
|
printf("%d ", vn->vn_vi[i].vi_entry_sizes[j]);
|
|
}
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
static void print_path(struct tree_balance *tb, struct reiserfs_path *path)
|
|
{
|
|
int offset = path->path_length;
|
|
struct buffer_head *bh;
|
|
|
|
printf("Offset Bh (b_blocknr, b_count) Position Nr_item\n");
|
|
while (offset > ILLEGAL_PATH_ELEMENT_OFFSET) {
|
|
bh = PATH_OFFSET_PBUFFER(path, offset);
|
|
printf("%6d %10p (%9lu, %7d) %8d %7d\n", offset,
|
|
bh, bh ? bh->b_blocknr : 0, bh ? bh->b_count : 0,
|
|
PATH_OFFSET_POSITION(path, offset),
|
|
bh ? B_NR_ITEMS(bh) : -1);
|
|
|
|
offset--;
|
|
}
|
|
}
|
|
|
|
static void print_directory_item(FILE *fp, reiserfs_filsys_t *fs,
|
|
struct buffer_head *bh, struct item_head *ih)
|
|
{
|
|
int i;
|
|
int namelen;
|
|
struct reiserfs_de_head *deh;
|
|
char *name;
|
|
/* static char namebuf [80];*/
|
|
|
|
if (!I_IS_DIRECTORY_ITEM(ih))
|
|
return;
|
|
|
|
//printk ("\n%2%-25s%-30s%-15s%-15s%-15s\n", " Name", "length", "Object key", "Hash", "Gen number", "Status");
|
|
reiserfs_warning(fp, "%3s: %-25s%s%-22s%-12s%s\n", "###", "Name",
|
|
"length", " Object key", " Hash", "Gen number");
|
|
deh = B_I_DEH(bh, ih);
|
|
for (i = 0; i < get_ih_entry_count(ih); i++, deh++) {
|
|
if (dir_entry_bad_location(deh, ih, i == 0 ? 1 : 0)) {
|
|
reiserfs_warning(fp,
|
|
"%3d: wrong entry location %u, deh_offset %u\n",
|
|
i, get_deh_location(deh),
|
|
get_deh_offset(deh));
|
|
continue;
|
|
}
|
|
if (i
|
|
&& dir_entry_bad_location(deh - 1, ih,
|
|
((i - 1) == 0) ? 1 : 0))
|
|
/* previous entry has bad location so we can not calculate entry
|
|
length */
|
|
namelen = 25;
|
|
else
|
|
namelen = name_in_entry_length(ih, deh, i);
|
|
|
|
name = name_in_entry(deh, i);
|
|
reiserfs_warning(fp,
|
|
"%3d: \"%-25.*s\"(%3d)%20K%12d%5d, loc %u, state %x %s\n",
|
|
i, namelen, name, namelen,
|
|
(struct reiserfs_key *)&(deh->deh2_dir_id),
|
|
GET_HASH_VALUE(get_deh_offset(deh)),
|
|
GET_GENERATION_NUMBER(get_deh_offset(deh)),
|
|
get_deh_location(deh), get_deh_state(deh),
|
|
code2name(find_hash_in_use
|
|
(name, namelen, get_deh_offset(deh),
|
|
fs ? get_sb_hash_code(fs->
|
|
fs_ondisk_sb)
|
|
: UNSET_HASH)));
|
|
/*fs ? (is_properly_hashed (fs, name, namelen, deh_offset (deh)) ? "" : "(BROKEN)") : "??"); */
|
|
}
|
|
}
|
|
|
|
//
|
|
// printing of indirect item
|
|
//
|
|
static void start_new_sequence(__u32 * start, int *len, __u32 new)
|
|
{
|
|
*start = new;
|
|
*len = 1;
|
|
}
|
|
|
|
static int sequence_finished(__u32 start, int *len, __u32 new)
|
|
{
|
|
if (start == INT_MAX)
|
|
return 1;
|
|
|
|
if (start == 0 && new == 0) {
|
|
(*len)++;
|
|
return 0;
|
|
}
|
|
if (start != 0 && (start + *len) == new) {
|
|
(*len)++;
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static void print_sequence(FILE * fp, __u32 start, int len)
|
|
{
|
|
if (start == INT_MAX)
|
|
return;
|
|
|
|
if (len == 1)
|
|
reiserfs_warning(fp, " %u", start);
|
|
else
|
|
reiserfs_warning(fp, " %u(%d)", start, len);
|
|
}
|
|
|
|
void print_indirect_item(FILE * fp, struct buffer_head *bh, int item_num)
|
|
{
|
|
struct item_head *ih;
|
|
unsigned int j;
|
|
__le32 *unp;
|
|
__u32 prev = INT_MAX;
|
|
int num = 0;
|
|
|
|
ih = item_head(bh, item_num);
|
|
unp = (__le32 *) ih_item_body(bh, ih);
|
|
|
|
if (get_ih_item_len(ih) % UNFM_P_SIZE)
|
|
reiserfs_warning(fp, "print_indirect_item: invalid item len");
|
|
|
|
reiserfs_warning(fp, "%d pointer%s\n[", I_UNFM_NUM(ih),
|
|
I_UNFM_NUM(ih) != 1 ? "s" : "");
|
|
for (j = 0; j < I_UNFM_NUM(ih); j++) {
|
|
if (sequence_finished(prev, &num, d32_get(unp, j))) {
|
|
print_sequence(fp, prev, num);
|
|
start_new_sequence(&prev, &num, d32_get(unp, j));
|
|
}
|
|
}
|
|
print_sequence(fp, prev, num);
|
|
reiserfs_warning(fp, "]\n");
|
|
}
|
|
|
|
static char timebuf[256];
|
|
|
|
static char *timestamp(time_t t)
|
|
{
|
|
strftime(timebuf, 256, "%d/%Y %T", localtime(&t));
|
|
return timebuf;
|
|
}
|
|
|
|
static int print_stat_data(FILE * fp, struct buffer_head *bh,
|
|
struct item_head *ih, int alltimes)
|
|
{
|
|
int retval;
|
|
|
|
/* we cannot figure out if it is new stat data or old by key_format
|
|
macro. Stat data's key looks identical in both formats */
|
|
if (get_ih_key_format(ih) == KEY_FORMAT_1) {
|
|
struct stat_data_v1 *sd_v1 =
|
|
(struct stat_data_v1 *)ih_item_body(bh, ih);
|
|
reiserfs_warning(fp,
|
|
"(OLD SD), mode %M, size %u, nlink %u, uid %u, FDB %u, mtime %s blocks %u",
|
|
sd_v1_mode(sd_v1), sd_v1_size(sd_v1),
|
|
sd_v1_nlink(sd_v1), sd_v1_uid(sd_v1),
|
|
sd_v1_first_direct_byte(sd_v1),
|
|
timestamp(sd_v1_mtime(sd_v1)),
|
|
sd_v1_blocks(sd_v1));
|
|
retval = (S_ISLNK(sd_v1_mode(sd_v1))) ? 1 : 0;
|
|
if (alltimes)
|
|
reiserfs_warning(fp, "%s %s\n",
|
|
timestamp(sd_v1_ctime(sd_v1)),
|
|
timestamp(sd_v1_atime(sd_v1)));
|
|
} else {
|
|
struct stat_data *sd = (struct stat_data *)ih_item_body(bh, ih);
|
|
reiserfs_warning(fp,
|
|
"(NEW SD), mode %M, size %Lu, nlink %u, mtime %s blocks %u, uid %u",
|
|
sd_v2_mode(sd), sd_v2_size(sd),
|
|
sd_v2_nlink(sd), timestamp(sd_v2_mtime(sd)),
|
|
sd_v2_blocks(sd), sd_v2_uid(sd));
|
|
retval = (S_ISLNK(sd_v2_mode(sd))) ? 1 : 0;
|
|
if (alltimes)
|
|
reiserfs_warning(fp, "%s %s\n",
|
|
timestamp(sd_v2_ctime(sd)),
|
|
timestamp(sd_v2_atime(sd)));
|
|
}
|
|
|
|
reiserfs_warning(fp, "\n");
|
|
return retval;
|
|
}
|
|
|
|
/* used by debugreiserfs/scan.c */
|
|
void reiserfs_print_item(FILE * fp, struct buffer_head *bh,
|
|
struct item_head *ih)
|
|
{
|
|
reiserfs_warning(fp, "block %lu, item %d: %H\n",
|
|
bh->b_blocknr,
|
|
(ih -
|
|
item_head(bh, 0)) / sizeof(struct item_head),
|
|
ih);
|
|
if (is_stat_data_ih(ih)) {
|
|
print_stat_data(fp, bh, ih, 0 /*all times */ );
|
|
return;
|
|
}
|
|
if (is_indirect_ih(ih)) {
|
|
print_indirect_item(fp, bh, ih - item_head(bh, 0));
|
|
return;
|
|
}
|
|
if (is_direct_ih(ih)) {
|
|
reiserfs_warning(fp,
|
|
"direct item: block %lu, start %d, %d bytes\n",
|
|
bh->b_blocknr, get_ih_location(ih),
|
|
get_ih_item_len(ih));
|
|
return;
|
|
}
|
|
|
|
print_directory_item(fp, NULL, bh, ih);
|
|
}
|
|
|
|
/* this prints internal nodes (4 keys/items in line) (dc_number,
|
|
dc_size)[k_dirid, k_objectid, k_offset, k_uniqueness](dc_number,
|
|
dc_size)...*/
|
|
static int print_internal(FILE * fp, struct buffer_head *bh, int first,
|
|
int last)
|
|
{
|
|
struct reiserfs_key *key;
|
|
struct disk_child *dc;
|
|
int i;
|
|
int from, to;
|
|
|
|
if (!is_internal_node(bh))
|
|
return 1;
|
|
|
|
if (first == -1) {
|
|
from = 0;
|
|
to = B_NR_ITEMS(bh);
|
|
} else {
|
|
from = first;
|
|
to = last < B_NR_ITEMS(bh) ? last : B_NR_ITEMS(bh);
|
|
}
|
|
|
|
reiserfs_warning(fp, "INTERNAL NODE (%lu) contains %b\n", bh->b_blocknr,
|
|
bh);
|
|
|
|
dc = B_N_CHILD(bh, from);
|
|
reiserfs_warning(fp, "PTR %d: %y ", from, dc);
|
|
|
|
for (i = from, key = internal_key(bh, from), dc++; i < to;
|
|
i++, key++, dc++) {
|
|
reiserfs_warning(fp, "KEY %d: %20k PTR %d: %20y ", i, key,
|
|
i + 1, dc);
|
|
if (i && i % 4 == 0)
|
|
reiserfs_warning(fp, "\n");
|
|
}
|
|
reiserfs_warning(fp, "\n");
|
|
return 0;
|
|
}
|
|
|
|
static int is_symlink = 0;
|
|
static int print_leaf(FILE * fp, reiserfs_filsys_t *fs, struct buffer_head *bh,
|
|
int print_mode, int first, int last)
|
|
{
|
|
struct item_head *ih;
|
|
int i;
|
|
int from, to;
|
|
int real_nr, nr;
|
|
|
|
if (!is_tree_node(bh, DISK_LEAF_NODE_LEVEL))
|
|
return 1;
|
|
|
|
ih = item_head(bh, 0);
|
|
real_nr = leaf_count_ih(bh->b_data, bh->b_size);
|
|
nr = get_blkh_nr_items((struct block_head *)bh->b_data);
|
|
|
|
reiserfs_warning(fp,
|
|
"\n===================================================================\n");
|
|
reiserfs_warning(fp, "LEAF NODE (%lu) contains %b (real items %d)\n",
|
|
bh->b_blocknr, bh, real_nr);
|
|
|
|
if (!(print_mode & PRINT_TREE_DETAILS)) {
|
|
reiserfs_warning(fp, "FIRST ITEM_KEY: %k, LAST ITEM KEY: %k\n",
|
|
&(ih->ih_key), &((ih + real_nr - 1)->ih_key));
|
|
return 0;
|
|
}
|
|
|
|
if (first < 0 || first > real_nr - 1)
|
|
from = 0;
|
|
else
|
|
from = first;
|
|
|
|
if (last < 0 || last > real_nr)
|
|
to = real_nr;
|
|
else
|
|
to = last;
|
|
|
|
reiserfs_warning(fp,
|
|
"-------------------------------------------------------------------------------\n"
|
|
"|###|type|ilen|f/sp| loc|fmt|fsck| key |\n"
|
|
"| | | |e/cn| | |need| |\n");
|
|
for (i = from; i < to; i++) {
|
|
reiserfs_warning(fp,
|
|
"-------------------------------------------------------------------------------\n"
|
|
"|%3d|%30H|%s\n", i, ih + i,
|
|
i >= nr ? " DELETED" : "");
|
|
|
|
if (I_IS_STAT_DATA_ITEM(ih + i)) {
|
|
is_symlink =
|
|
print_stat_data(fp, bh, ih + i, 0 /*all times */ );
|
|
continue;
|
|
}
|
|
|
|
if (I_IS_DIRECTORY_ITEM(ih + i)) {
|
|
print_directory_item(fp, fs, bh, ih + i);
|
|
continue;
|
|
}
|
|
|
|
if (I_IS_INDIRECT_ITEM(ih + i)) {
|
|
print_indirect_item(fp, bh, i);
|
|
continue;
|
|
}
|
|
|
|
if (I_IS_DIRECT_ITEM(ih + i)) {
|
|
int j = 0;
|
|
if (is_symlink || print_mode & PRINT_DIRECT_ITEMS) {
|
|
reiserfs_warning(fp, "\"");
|
|
while (j < get_ih_item_len(&ih[i])) {
|
|
if (ih_item_body(bh, ih + i)[j] == 10)
|
|
reiserfs_warning(fp, "\\n");
|
|
else
|
|
reiserfs_warning(fp, "%c",
|
|
ih_item_body(bh,
|
|
ih +
|
|
i)
|
|
[j]);
|
|
j++;
|
|
}
|
|
reiserfs_warning(fp, "\"\n");
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
reiserfs_warning(fp,
|
|
"===================================================================\n");
|
|
return 0;
|
|
}
|
|
|
|
void print_journal_params(FILE * fp, struct journal_params *jp)
|
|
{
|
|
reiserfs_warning(fp, "\tDevice [0x%x]\n", get_jp_journal_dev(jp));
|
|
reiserfs_warning(fp, "\tMagic [0x%x]\n", get_jp_journal_magic(jp));
|
|
|
|
reiserfs_warning(fp,
|
|
"\tSize %u blocks (including 1 for journal header) (first block %u)\n",
|
|
get_jp_journal_size(jp) + 1,
|
|
get_jp_journal_1st_block(jp));
|
|
reiserfs_warning(fp, "\tMax transaction length %u blocks\n",
|
|
get_jp_journal_max_trans_len(jp));
|
|
reiserfs_warning(fp, "\tMax batch size %u blocks\n",
|
|
get_jp_journal_max_batch(jp));
|
|
reiserfs_warning(fp, "\tMax commit age %u\n",
|
|
get_jp_journal_max_commit_age(jp));
|
|
/*reiserfs_warning (fp, "\tMax transaction age %u\n", get_jp_journal_max_trans_age (jp)); */
|
|
}
|
|
|
|
/* return 1 if this is not super block */
|
|
int print_super_block(FILE * fp, reiserfs_filsys_t *fs, char *file_name,
|
|
struct buffer_head *bh, int short_print)
|
|
{
|
|
struct reiserfs_super_block *sb =
|
|
(struct reiserfs_super_block *)(bh->b_data);
|
|
dev_t rdev;
|
|
int format = 0;
|
|
__u16 state;
|
|
time_t last_check = get_sb_v2_lastcheck(sb);
|
|
char last_check_buf[26];
|
|
|
|
if (!does_look_like_super_block(sb))
|
|
return 1;
|
|
|
|
rdev = misc_device_rdev(file_name);
|
|
|
|
reiserfs_warning(fp, "Reiserfs super block in block %lu on 0x%x of ",
|
|
bh->b_blocknr, rdev);
|
|
switch (get_reiserfs_format(sb)) {
|
|
case REISERFS_FORMAT_3_5:
|
|
reiserfs_warning(fp, "format 3.5 with ");
|
|
format = 1;
|
|
break;
|
|
case REISERFS_FORMAT_3_6:
|
|
reiserfs_warning(fp, "format 3.6 with ");
|
|
format = 2;
|
|
break;
|
|
default:
|
|
reiserfs_warning(fp, "unknown format with ");
|
|
break;
|
|
}
|
|
if (is_reiserfs_jr_magic_string(sb))
|
|
reiserfs_warning(fp, "non-");
|
|
reiserfs_warning(fp, "standard journal\n");
|
|
if (short_print) {
|
|
reiserfs_warning(fp, "Blocks (total/free): %u/%u by %d bytes\n",
|
|
get_sb_block_count(sb), get_sb_free_blocks(sb),
|
|
get_sb_block_size(sb));
|
|
} else {
|
|
reiserfs_warning(fp, "Count of blocks on the device: %u\n",
|
|
get_sb_block_count(sb));
|
|
reiserfs_warning(fp, "Number of bitmaps: %u",
|
|
get_sb_bmap_nr(sb));
|
|
if (get_sb_bmap_nr(sb) != reiserfs_fs_bmap_nr(fs))
|
|
reiserfs_warning(fp, " (really uses %u)",
|
|
reiserfs_fs_bmap_nr(fs));
|
|
reiserfs_warning(fp, "\nBlocksize: %d\n",
|
|
get_sb_block_size(sb));
|
|
reiserfs_warning(fp,
|
|
"Free blocks (count of blocks - used [journal, "
|
|
"bitmaps, data, reserved] blocks): %u\n",
|
|
get_sb_free_blocks(sb));
|
|
reiserfs_warning(fp, "Root block: %u\n", get_sb_root_block(sb));
|
|
}
|
|
reiserfs_warning(fp, "Filesystem is %sclean\n",
|
|
(get_sb_umount_state(sb) ==
|
|
FS_CLEANLY_UMOUNTED) ? "" : "NOT ");
|
|
|
|
if (short_print)
|
|
return 0;
|
|
reiserfs_warning(fp, "Tree height: %d\n", get_sb_tree_height(sb));
|
|
reiserfs_warning(fp, "Hash function used to sort names: %s\n",
|
|
code2name(get_sb_hash_code(sb)));
|
|
reiserfs_warning(fp, "Objectid map size %d, max %d\n",
|
|
get_sb_oid_cursize(sb), get_sb_oid_maxsize(sb));
|
|
reiserfs_warning(fp, "Journal parameters:\n");
|
|
print_journal_params(fp, sb_jp(sb));
|
|
reiserfs_warning(fp, "Blocks reserved by journal: %u\n",
|
|
get_sb_reserved_for_journal(sb));
|
|
state = get_sb_fs_state(sb);
|
|
reiserfs_warning(fp, "Fs state field: 0x%x:\n", state);
|
|
if ((state & FS_FATAL) == FS_FATAL)
|
|
reiserfs_warning(fp, "\tFATAL corruptions exist.\n");
|
|
if ((state & FS_ERROR) == FS_ERROR)
|
|
reiserfs_warning(fp, "\t some corruptions exist.\n");
|
|
if ((state & IO_ERROR) == IO_ERROR)
|
|
reiserfs_warning(fp, "\tI/O corruptions exist.\n");
|
|
|
|
reiserfs_warning(fp, "sb_version: %u\n", get_sb_version(sb));
|
|
if (format == 2) {
|
|
reiserfs_warning(fp, "inode generation number: %u\n",
|
|
get_sb_v2_inode_generation(sb));
|
|
reiserfs_warning(fp, "UUID: %U\n", sb->s_uuid);
|
|
reiserfs_warning(fp, "LABEL: %.16s\n", sb->s_label);
|
|
reiserfs_warning(fp, "Set flags in SB:\n");
|
|
if ((get_sb_v2_flag(sb, reiserfs_attrs_cleared)))
|
|
reiserfs_warning(fp, "\tATTRIBUTES CLEAN\n");
|
|
reiserfs_warning(fp, "Mount count: %u\n",
|
|
get_sb_v2_mnt_count(sb));
|
|
reiserfs_warning(fp, "Maximum mount count: ");
|
|
if (get_sb_v2_max_mnt_count(sb) &&
|
|
get_sb_v2_max_mnt_count(sb) != USHRT_MAX)
|
|
reiserfs_warning(fp, "%u\n",
|
|
get_sb_v2_max_mnt_count(sb));
|
|
else if (get_sb_v2_max_mnt_count(sb) == USHRT_MAX)
|
|
reiserfs_warning(fp, "Administratively disabled.\n");
|
|
else
|
|
reiserfs_warning(fp,
|
|
"Disabled. Run fsck.reiserfs(8) or use tunefs.reiserfs(8) to enable.\n");
|
|
if (last_check) {
|
|
ctime_r(&last_check, last_check_buf);
|
|
reiserfs_warning(fp, "Last fsck run: %s",
|
|
last_check_buf);
|
|
} else
|
|
reiserfs_warning(fp,
|
|
"Last fsck run: Never with a version "
|
|
"that supports this feature.\n");
|
|
reiserfs_warning(fp, "Check interval in days: ");
|
|
if (get_sb_v2_check_interval(sb) &&
|
|
get_sb_v2_check_interval(sb) != UINT_MAX)
|
|
reiserfs_warning(fp, "%u\n",
|
|
get_sb_v2_check_interval(sb) / (24 *
|
|
60 *
|
|
60));
|
|
else if (get_sb_v2_check_interval(sb) == UINT_MAX)
|
|
reiserfs_warning(fp, "Administratively disabled.\n");
|
|
else
|
|
reiserfs_warning(fp,
|
|
"Disabled. Run fsck.reiserfs(8) or use tunefs.reiserfs(8) to enable.\n");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void print_filesystem_state(FILE * fp, reiserfs_filsys_t *fs)
|
|
{
|
|
reiserfs_warning(fp, "\nFilesystem state: ");
|
|
if (reiserfs_is_fs_consistent(fs))
|
|
reiserfs_warning(fp, "consistent\n\n");
|
|
else
|
|
reiserfs_warning(fp,
|
|
"consistency is not checked after last mounting\n\n");
|
|
}
|
|
|
|
static int print_desc_block(FILE * fp, struct buffer_head *bh)
|
|
{
|
|
if (memcmp(get_jd_magic(bh), JOURNAL_DESC_MAGIC, 8))
|
|
return 1;
|
|
|
|
reiserfs_warning(fp,
|
|
"Desc block %lu (j_trans_id %ld, j_mount_id %ld, j_len %ld)\n",
|
|
bh->b_blocknr, get_desc_trans_id(bh),
|
|
get_desc_mount_id(bh), get_desc_trans_len(bh));
|
|
|
|
return 0;
|
|
}
|
|
|
|
void print_block(FILE * fp, reiserfs_filsys_t *fs, struct buffer_head *bh, ...) //int print_mode, int first, int last)
|
|
{
|
|
va_list args;
|
|
int mode, first, last;
|
|
char *file_name;
|
|
|
|
va_start(args, bh);
|
|
|
|
if (!bh) {
|
|
reiserfs_warning(stderr, "print_block: buffer is NULL\n");
|
|
return;
|
|
}
|
|
|
|
mode = va_arg(args, int);
|
|
first = va_arg(args, int);
|
|
last = va_arg(args, int);
|
|
file_name = (fs) ? fs->fs_file_name : NULL;
|
|
if (print_desc_block(fp, bh))
|
|
if (print_super_block(fp, fs, file_name, bh, 0))
|
|
if (print_leaf(fp, fs, bh, mode, first, last))
|
|
if (print_internal(fp, bh, first, last))
|
|
reiserfs_warning(fp,
|
|
"Block %lu contains unformatted data\n",
|
|
bh->b_blocknr);
|
|
}
|
|
|
|
void print_tb(int mode, int item_pos, int pos_in_item, struct tree_balance *tb,
|
|
char *mes)
|
|
{
|
|
unsigned int h = 0;
|
|
struct buffer_head *tbSh, *tbFh;
|
|
|
|
if (!tb)
|
|
return;
|
|
|
|
printf("\n********************** PRINT_TB for %s *******************\n",
|
|
mes);
|
|
printf("MODE=%c, ITEM_POS=%d POS_IN_ITEM=%d\n", mode, item_pos,
|
|
pos_in_item);
|
|
printf
|
|
("*********************************************************************\n");
|
|
|
|
printf
|
|
("* h * S * L * R * F * FL * FR * CFL * CFR *\n");
|
|
/*
|
|
01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
|
1 2 3 4 5 6 7 8
|
|
printk ("*********************************************************************\n");
|
|
*/
|
|
|
|
for (h = 0; h < sizeof(tb->insert_size) / sizeof(tb->insert_size[0]);
|
|
h++) {
|
|
if (PATH_H_PATH_OFFSET(tb->tb_path, h) <=
|
|
tb->tb_path->path_length
|
|
&& PATH_H_PATH_OFFSET(tb->tb_path,
|
|
h) > ILLEGAL_PATH_ELEMENT_OFFSET) {
|
|
tbSh = PATH_H_PBUFFER(tb->tb_path, h);
|
|
tbFh = PATH_H_PPARENT(tb->tb_path, h);
|
|
} else {
|
|
/* printk ("print_tb: h=%d, PATH_H_PATH_OFFSET=%d, path_length=%d\n",
|
|
h, PATH_H_PATH_OFFSET (tb->tb_path, h), tb->tb_path->path_length); */
|
|
tbSh = NULL;
|
|
tbFh = NULL;
|
|
}
|
|
printf
|
|
("* %u * %3lu(%2lu) * %3lu(%2lu) * %3lu(%2lu) * %5lu * %5lu * %5lu * %5lu * %5lu *\n",
|
|
h, tbSh ? tbSh->b_blocknr : ~0ul,
|
|
tbSh ? tbSh->b_count : ~0ul,
|
|
tb->L[h] ? tb->L[h]->b_blocknr : ~0ul,
|
|
tb->L[h] ? tb->L[h]->b_count : ~0ul,
|
|
tb->R[h] ? tb->R[h]->b_blocknr : ~0ul,
|
|
tb->R[h] ? tb->R[h]->b_count : ~0ul,
|
|
tbFh ? tbFh->b_blocknr : ~0ul,
|
|
tb->FL[h] ? tb->FL[h]->b_blocknr : ~0ul,
|
|
tb->FR[h] ? tb->FR[h]->b_blocknr : ~0ul,
|
|
tb->CFL[h] ? tb->CFL[h]->b_blocknr : ~0ul,
|
|
tb->CFR[h] ? tb->CFR[h]->b_blocknr : ~0ul);
|
|
}
|
|
|
|
printf
|
|
("*********************************************************************\n");
|
|
|
|
/* print balance parameters for leaf level */
|
|
h = 0;
|
|
printf
|
|
("* h * size * ln * lb * rn * rb * blkn * s0 * s1 * s1b * s2 * s2b * curb * lk * rk *\n");
|
|
printf
|
|
("* %d * %4d * %2d * %2d * %2d * %2d * %4d * %2d * %2d * %3d * %2d * %3d * %4d * %2d * %2d *\n",
|
|
h, tb->insert_size[h], tb->lnum[h], tb->lbytes, tb->rnum[h],
|
|
tb->rbytes, tb->blknum[h], tb->s0num, tb->s1num, tb->s1bytes,
|
|
tb->s2num, tb->s2bytes, tb->cur_blknum, tb->lkey[h], tb->rkey[h]);
|
|
|
|
/* this prints balance parameters for non-leaf levels */
|
|
do {
|
|
h++;
|
|
printf("* %d * %4d * %2d * * %2d * * %2d *\n",
|
|
h, tb->insert_size[h], tb->lnum[h], tb->rnum[h],
|
|
tb->blknum[h]);
|
|
} while (tb->insert_size[h]);
|
|
|
|
printf
|
|
("*********************************************************************\n");
|
|
|
|
/* print FEB list (list of buffers in form (bh (b_blocknr, b_count), that will be used for new nodes) */
|
|
for (h = 0; h < sizeof(tb->FEB) / sizeof(tb->FEB[0]); h++)
|
|
printf("%s%p (%lu %d)", h == 0 ? "FEB list: " : ", ",
|
|
tb->FEB[h], tb->FEB[h] ? tb->FEB[h]->b_blocknr : 0,
|
|
tb->FEB[h] ? tb->FEB[h]->b_count : 0);
|
|
printf("\n");
|
|
|
|
printf
|
|
("********************** END OF PRINT_TB *******************\n\n");
|
|
}
|
|
|
|
static void print_bmap_block(FILE * fp, int i, unsigned long block, char *map,
|
|
int blocks, int silent, int blocksize)
|
|
{
|
|
int j, k;
|
|
int bits = blocksize * 8;
|
|
int zeros = 0, ones = 0;
|
|
|
|
reiserfs_warning(fp, "#%d: block %lu: ", i, block);
|
|
|
|
blocks = blocksize * 8;
|
|
|
|
if (misc_test_bit(0, map)) {
|
|
/* first block addressed by this bitmap block is used */
|
|
ones++;
|
|
if (!silent)
|
|
reiserfs_warning(fp, "Busy (%d-", i * bits);
|
|
for (j = 1; j < blocks; j++) {
|
|
while (misc_test_bit(j, map)) {
|
|
ones++;
|
|
if (j == blocks - 1) {
|
|
if (!silent)
|
|
reiserfs_warning(fp, "%d)\n",
|
|
j + i * bits);
|
|
goto end;
|
|
}
|
|
j++;
|
|
}
|
|
if (!silent)
|
|
reiserfs_warning(fp, "%d) Free(%d-",
|
|
j - 1 + i * bits,
|
|
j + i * bits);
|
|
|
|
while (!misc_test_bit(j, map)) {
|
|
zeros++;
|
|
if (j == blocks - 1) {
|
|
if (!silent)
|
|
reiserfs_warning(fp, "%d)\n",
|
|
j + i * bits);
|
|
goto end;
|
|
}
|
|
j++;
|
|
}
|
|
if (!silent)
|
|
reiserfs_warning(fp, "%d) Busy(%d-",
|
|
j - 1 + i * bits,
|
|
j + i * bits);
|
|
|
|
j--;
|
|
end:
|
|
/* to make gcc 3.2 do not sware here */ ;
|
|
}
|
|
} else {
|
|
/* first block addressed by this bitmap is free */
|
|
zeros++;
|
|
if (!silent)
|
|
reiserfs_warning(fp, "Free (%d-", i * bits);
|
|
for (j = 1; j < blocks; j++) {
|
|
k = 0;
|
|
while (!misc_test_bit(j, map)) {
|
|
k++;
|
|
if (j == blocks - 1) {
|
|
if (!silent)
|
|
reiserfs_warning(fp, "%d)\n",
|
|
j + i * bits);
|
|
zeros += k;
|
|
goto end2;
|
|
}
|
|
j++;
|
|
}
|
|
zeros += k;
|
|
if (!silent)
|
|
reiserfs_warning(fp, "%d) Busy(%d-",
|
|
j - 1 + i * bits,
|
|
j + i * bits);
|
|
|
|
k = 0;
|
|
while (misc_test_bit(j, map)) {
|
|
ones++;
|
|
if (j == blocks - 1) {
|
|
if (!silent)
|
|
reiserfs_warning(fp, "%d)\n",
|
|
j + i * bits);
|
|
ones += k;
|
|
goto end2;
|
|
}
|
|
j++;
|
|
}
|
|
ones += k;
|
|
if (!silent)
|
|
reiserfs_warning(fp, "%d) Free(%d-",
|
|
j - 1 + i * bits,
|
|
j + i * bits);
|
|
|
|
j--;
|
|
end2:
|
|
/* to make gcc 3.2 do not sware here */ ;
|
|
}
|
|
}
|
|
|
|
reiserfs_warning(fp, "used %d, free %d\n", ones, zeros);
|
|
}
|
|
|
|
/* read bitmap of disk and print details */
|
|
void print_bmap(FILE * fp, reiserfs_filsys_t *fs, int silent)
|
|
{
|
|
struct reiserfs_super_block *sb;
|
|
int bmap_nr;
|
|
int i;
|
|
int bits_per_block;
|
|
int blocks;
|
|
unsigned long block;
|
|
struct buffer_head *bh;
|
|
|
|
sb = fs->fs_ondisk_sb;
|
|
bmap_nr = reiserfs_fs_bmap_nr(fs);
|
|
bits_per_block = fs->fs_blocksize * 8;
|
|
blocks = bits_per_block;
|
|
|
|
reiserfs_warning(fp, "Bitmap blocks are:\n");
|
|
block = fs->fs_super_bh->b_blocknr + 1;
|
|
for (i = 0; i < bmap_nr; i++) {
|
|
bh = bread(fs->fs_dev, block, fs->fs_blocksize);
|
|
if (!bh) {
|
|
reiserfs_warning(stderr,
|
|
"print_bmap: bread failed for %d: %lu\n",
|
|
i, block);
|
|
continue;
|
|
}
|
|
if (i == bmap_nr - 1)
|
|
if (get_sb_block_count(sb) % bits_per_block)
|
|
blocks =
|
|
get_sb_block_count(sb) % bits_per_block;
|
|
print_bmap_block(fp, i, block, bh->b_data, blocks, silent,
|
|
fs->fs_blocksize);
|
|
brelse(bh);
|
|
|
|
if (spread_bitmaps(fs))
|
|
block =
|
|
(block / (fs->fs_blocksize * 8) +
|
|
1) * (fs->fs_blocksize * 8);
|
|
else
|
|
block++;
|
|
|
|
}
|
|
}
|
|
|
|
void print_objectid_map(FILE * fp, reiserfs_filsys_t *fs)
|
|
{
|
|
int i;
|
|
struct reiserfs_super_block *sb;
|
|
__le32 *omap;
|
|
|
|
sb = fs->fs_ondisk_sb;
|
|
if (fs->fs_format == REISERFS_FORMAT_3_6)
|
|
omap = (__le32 *) (sb + 1);
|
|
else if (fs->fs_format == REISERFS_FORMAT_3_5)
|
|
omap = (__le32 *) ((struct reiserfs_super_block_v1 *)sb + 1);
|
|
else {
|
|
reiserfs_warning(fp,
|
|
"print_objectid_map: proper signature is not found\n");
|
|
return;
|
|
}
|
|
|
|
reiserfs_warning(fp, "Map of objectids (super block size %d)\n",
|
|
(char *)omap - (char *)sb);
|
|
|
|
for (i = 0; i < get_sb_oid_cursize(sb); i++) {
|
|
if (i % 2 == 0) {
|
|
reiserfs_warning(fp, "busy(%u-%u) ",
|
|
le32_to_cpu(omap[i]),
|
|
le32_to_cpu(omap[i + 1]) - 1);
|
|
} else {
|
|
reiserfs_warning(fp, "free(%u-%u) ",
|
|
le32_to_cpu(omap[i]),
|
|
((i + 1) ==
|
|
get_sb_oid_cursize(sb)) ? ~(__u32) 0
|
|
: (le32_to_cpu(omap[i + 1]) - 1));
|
|
}
|
|
}
|
|
|
|
reiserfs_warning(fp, "\nObject id array has size %d (max %d):",
|
|
get_sb_oid_cursize(sb), get_sb_oid_maxsize(sb));
|
|
|
|
for (i = 0; i < get_sb_oid_cursize(sb); i++)
|
|
reiserfs_warning(fp, "%s%u ", i % 2 ? "" : "*",
|
|
le32_to_cpu(omap[i]));
|
|
reiserfs_warning(fp, "\n");
|
|
|
|
}
|
|
|
|
void print_journal_header(reiserfs_filsys_t *fs)
|
|
{
|
|
struct reiserfs_journal_header *j_head;
|
|
|
|
j_head = (struct reiserfs_journal_header *)(fs->fs_jh_bh->b_data);
|
|
reiserfs_warning(stdout, "Journal header (block #%lu of %s):\n"
|
|
"\tj_last_flush_trans_id %ld\n"
|
|
"\tj_first_unflushed_offset %ld\n"
|
|
"\tj_mount_id %ld\n",
|
|
fs->fs_jh_bh->b_blocknr, fs->fs_j_file_name,
|
|
get_jh_last_flushed(j_head),
|
|
get_jh_replay_start_offset(j_head),
|
|
get_jh_mount_id(j_head));
|
|
print_journal_params(stdout, &j_head->jh_journal);
|
|
}
|
|
|
|
static void print_trans_element(reiserfs_filsys_t *fs,
|
|
reiserfs_trans_t *trans, unsigned int index,
|
|
unsigned long in_journal,
|
|
unsigned long in_place)
|
|
{
|
|
if (index % 8 == 0)
|
|
reiserfs_warning(stdout, "#%d\t", index);
|
|
|
|
reiserfs_warning(stdout, "%lu->%lu%s ", in_journal, in_place,
|
|
block_of_bitmap(fs, in_place) ? "B" : "");
|
|
if ((index + 1) % 8 == 0 || index == trans->trans_len - 1)
|
|
reiserfs_warning(stdout, "\n");
|
|
}
|
|
|
|
void print_one_transaction(reiserfs_filsys_t *fs, reiserfs_trans_t *trans)
|
|
{
|
|
reiserfs_warning(stdout,
|
|
"Mountid %u, transid %u, desc %lu, length %u, commit %lu\n",
|
|
trans->mount_id, trans->trans_id, trans->desc_blocknr,
|
|
trans->trans_len, trans->commit_blocknr);
|
|
for_each_block(fs, trans, print_trans_element);
|
|
}
|
|
|
|
/* print all valid transactions and found dec blocks */
|
|
void print_journal(reiserfs_filsys_t *fs)
|
|
{
|
|
if (!reiserfs_journal_opened(fs)) {
|
|
reiserfs_warning(stderr,
|
|
"print_journal: journal is not opened\n");
|
|
return;
|
|
}
|
|
print_journal_header(fs);
|
|
|
|
for_each_transaction(fs, print_one_transaction);
|
|
}
|