Newer
Older
/*
* This file is part of UBIFS.
*
* Copyright (C) 2006-2008 Nokia Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will 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 to the Free Software Foundation, Inc., 51
* Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors: Artem Bityutskiy (Битюцкий Артём)
* Adrian Hunter
*/
/*
* This file implements most of the debugging stuff which is compiled in only
* when it is enabled. But some debugging check functions are implemented in
* corresponding subsystem, just because they are closely related and utilize
* various local functions of those subsystems.
*/
#include <linux/module.h>
#include <linux/random.h>
#include "ubifs.h"
static DEFINE_SPINLOCK(dbg_lock);
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
static const char *get_key_fmt(int fmt)
{
switch (fmt) {
case UBIFS_SIMPLE_KEY_FMT:
return "simple";
default:
return "unknown/invalid format";
}
}
static const char *get_key_hash(int hash)
{
switch (hash) {
case UBIFS_KEY_HASH_R5:
return "R5";
case UBIFS_KEY_HASH_TEST:
return "test";
default:
return "unknown/invalid name hash";
}
}
static const char *get_key_type(int type)
{
switch (type) {
case UBIFS_INO_KEY:
return "inode";
case UBIFS_DENT_KEY:
return "direntry";
case UBIFS_XENT_KEY:
return "xentry";
case UBIFS_DATA_KEY:
return "data";
case UBIFS_TRUN_KEY:
return "truncate";
default:
return "unknown/invalid key";
}
}
static const char *get_dent_type(int type)
{
switch (type) {
case UBIFS_ITYPE_REG:
return "file";
case UBIFS_ITYPE_DIR:
return "dir";
case UBIFS_ITYPE_LNK:
return "symlink";
case UBIFS_ITYPE_BLK:
return "blkdev";
case UBIFS_ITYPE_CHR:
return "char dev";
case UBIFS_ITYPE_FIFO:
return "fifo";
case UBIFS_ITYPE_SOCK:
return "socket";
default:
return "unknown/invalid type";
}
}
const char *dbg_snprintf_key(const struct ubifs_info *c,
const union ubifs_key *key, char *buffer, int len)
{
char *p = buffer;
int type = key_type(c, key);
if (c->key_fmt == UBIFS_SIMPLE_KEY_FMT) {
switch (type) {
case UBIFS_INO_KEY:
len -= snprintf(p, len, "(%lu, %s)",
(unsigned long)key_inum(c, key),
get_key_type(type));
break;
case UBIFS_DENT_KEY:
case UBIFS_XENT_KEY:
len -= snprintf(p, len, "(%lu, %s, %#08x)",
(unsigned long)key_inum(c, key),
get_key_type(type), key_hash(c, key));
len -= snprintf(p, len, "(%lu, %s, %u)",
(unsigned long)key_inum(c, key),
get_key_type(type), key_block(c, key));
len -= snprintf(p, len, "(%lu, %s)",
(unsigned long)key_inum(c, key),
get_key_type(type));
len -= snprintf(p, len, "(bad key type: %#08x, %#08x)",
key->u32[0], key->u32[1]);
len -= snprintf(p, len, "bad key format %d", c->key_fmt);
ubifs_assert(len > 0);
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
}
const char *dbg_ntype(int type)
{
switch (type) {
case UBIFS_PAD_NODE:
return "padding node";
case UBIFS_SB_NODE:
return "superblock node";
case UBIFS_MST_NODE:
return "master node";
case UBIFS_REF_NODE:
return "reference node";
case UBIFS_INO_NODE:
return "inode node";
case UBIFS_DENT_NODE:
return "direntry node";
case UBIFS_XENT_NODE:
return "xentry node";
case UBIFS_DATA_NODE:
return "data node";
case UBIFS_TRUN_NODE:
return "truncate node";
case UBIFS_IDX_NODE:
return "indexing node";
case UBIFS_CS_NODE:
return "commit start node";
case UBIFS_ORPH_NODE:
return "orphan node";
default:
return "unknown node";
}
}
static const char *dbg_gtype(int type)
{
switch (type) {
case UBIFS_NO_NODE_GROUP:
return "no node group";
case UBIFS_IN_NODE_GROUP:
return "in node group";
case UBIFS_LAST_OF_NODE_GROUP:
return "last of node group";
default:
return "unknown";
}
}
const char *dbg_cstate(int cmt_state)
{
switch (cmt_state) {
case COMMIT_RESTING:
return "commit resting";
case COMMIT_BACKGROUND:
return "background commit requested";
case COMMIT_REQUIRED:
return "commit required";
case COMMIT_RUNNING_BACKGROUND:
return "BACKGROUND commit running";
case COMMIT_RUNNING_REQUIRED:
return "commit running and required";
case COMMIT_BROKEN:
return "broken commit";
default:
return "unknown commit state";
}
}
const char *dbg_jhead(int jhead)
{
switch (jhead) {
case GCHD:
return "0 (GC)";
case BASEHD:
return "1 (base)";
case DATAHD:
return "2 (data)";
default:
return "unknown journal head";
}
}
static void dump_ch(const struct ubifs_ch *ch)
{
pr_err("\tmagic %#x\n", le32_to_cpu(ch->magic));
pr_err("\tcrc %#x\n", le32_to_cpu(ch->crc));
pr_err("\tnode_type %d (%s)\n", ch->node_type,
pr_err("\tgroup_type %d (%s)\n", ch->group_type,
(unsigned long long)le64_to_cpu(ch->sqnum));
pr_err("\tlen %u\n", le32_to_cpu(ch->len));
void ubifs_dump_inode(struct ubifs_info *c, const struct inode *inode)
{
const struct ubifs_inode *ui = ubifs_inode(inode);
struct qstr nm = { .name = NULL };
union ubifs_key key;
struct ubifs_dent_node *dent, *pdent = NULL;
int count = 2;
pr_err("Dump in-memory inode:");
pr_err("\tinode %lu\n", inode->i_ino);
pr_err("\tsize %llu\n",
(unsigned long long)i_size_read(inode));
pr_err("\tnlink %u\n", inode->i_nlink);
pr_err("\tuid %u\n", (unsigned int)i_uid_read(inode));
pr_err("\tgid %u\n", (unsigned int)i_gid_read(inode));
(unsigned int)inode->i_atime.tv_sec,
(unsigned int)inode->i_atime.tv_nsec);
(unsigned int)inode->i_mtime.tv_sec,
(unsigned int)inode->i_mtime.tv_nsec);
(unsigned int)inode->i_ctime.tv_sec,
(unsigned int)inode->i_ctime.tv_nsec);
pr_err("\tcreat_sqnum %llu\n", ui->creat_sqnum);
pr_err("\txattr_size %u\n", ui->xattr_size);
pr_err("\txattr_cnt %u\n", ui->xattr_cnt);
pr_err("\txattr_names %u\n", ui->xattr_names);
pr_err("\tdirty %u\n", ui->dirty);
pr_err("\txattr %u\n", ui->xattr);
pr_err("\tbulk_read %u\n", ui->xattr);
pr_err("\tsynced_i_size %llu\n",
pr_err("\tflags %d\n", ui->flags);
pr_err("\tcompr_type %d\n", ui->compr_type);
pr_err("\tlast_page_read %lu\n", ui->last_page_read);
pr_err("\tread_in_a_row %lu\n", ui->read_in_a_row);
pr_err("\tdata_len %d\n", ui->data_len);
if (!S_ISDIR(inode->i_mode))
return;
pr_err("List of directory entries:\n");
ubifs_assert(!mutex_is_locked(&c->tnc_mutex));
lowest_dent_key(c, &key, inode->i_ino);
while (1) {
dent = ubifs_tnc_next_ent(c, &key, &nm);
if (IS_ERR(dent)) {
if (PTR_ERR(dent) != -ENOENT)
pr_err("error %ld\n", PTR_ERR(dent));
count++, dent->name, get_dent_type(dent->type));
nm.name = dent->name;
nm.len = le16_to_cpu(dent->nlen);
kfree(pdent);
pdent = dent;
key_read(c, &dent->key, &key);
}
kfree(pdent);
void ubifs_dump_node(const struct ubifs_info *c, const void *node)
{
int i, n;
union ubifs_key key;
const struct ubifs_ch *ch = node;
/* If the magic is incorrect, just hexdump the first bytes */
if (le32_to_cpu(ch->magic) != UBIFS_NODE_MAGIC) {
pr_err("Not a node, first %zu bytes:", UBIFS_CH_SZ);
print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 32, 1,
(void *)node, UBIFS_CH_SZ, 1);
return;
}
spin_lock(&dbg_lock);
dump_ch(node);
switch (ch->node_type) {
case UBIFS_PAD_NODE:
{
const struct ubifs_pad_node *pad = node;
pr_err("\tpad_len %u\n", le32_to_cpu(pad->pad_len));
break;
}
case UBIFS_SB_NODE:
{
const struct ubifs_sb_node *sup = node;
unsigned int sup_flags = le32_to_cpu(sup->flags);
pr_err("\tkey_hash %d (%s)\n",
(int)sup->key_hash, get_key_hash(sup->key_hash));
pr_err("\tkey_fmt %d (%s)\n",
(int)sup->key_fmt, get_key_fmt(sup->key_fmt));
pr_err("\tflags %#x\n", sup_flags);
pr_err("\t big_lpt %u\n",
pr_err("\t space_fixup %u\n",
!!(sup_flags & UBIFS_FLG_SPACE_FIXUP));
pr_err("\tmin_io_size %u\n", le32_to_cpu(sup->min_io_size));
pr_err("\tleb_size %u\n", le32_to_cpu(sup->leb_size));
pr_err("\tleb_cnt %u\n", le32_to_cpu(sup->leb_cnt));
pr_err("\tmax_leb_cnt %u\n", le32_to_cpu(sup->max_leb_cnt));
pr_err("\tmax_bud_bytes %llu\n",
(unsigned long long)le64_to_cpu(sup->max_bud_bytes));
pr_err("\tlog_lebs %u\n", le32_to_cpu(sup->log_lebs));
pr_err("\tlpt_lebs %u\n", le32_to_cpu(sup->lpt_lebs));
pr_err("\torph_lebs %u\n", le32_to_cpu(sup->orph_lebs));
pr_err("\tjhead_cnt %u\n", le32_to_cpu(sup->jhead_cnt));
pr_err("\tfanout %u\n", le32_to_cpu(sup->fanout));
pr_err("\tlsave_cnt %u\n", le32_to_cpu(sup->lsave_cnt));
pr_err("\tdefault_compr %u\n",
(int)le16_to_cpu(sup->default_compr));
(unsigned long long)le64_to_cpu(sup->rp_size));
pr_err("\trp_uid %u\n", le32_to_cpu(sup->rp_uid));
pr_err("\trp_gid %u\n", le32_to_cpu(sup->rp_gid));
pr_err("\tfmt_version %u\n", le32_to_cpu(sup->fmt_version));
pr_err("\ttime_gran %u\n", le32_to_cpu(sup->time_gran));
pr_err("\tUUID %pUB\n", sup->uuid);
break;
}
case UBIFS_MST_NODE:
{
const struct ubifs_mst_node *mst = node;
pr_err("\thighest_inum %llu\n",
(unsigned long long)le64_to_cpu(mst->highest_inum));
pr_err("\tcommit number %llu\n",
(unsigned long long)le64_to_cpu(mst->cmt_no));
pr_err("\tflags %#x\n", le32_to_cpu(mst->flags));
pr_err("\tlog_lnum %u\n", le32_to_cpu(mst->log_lnum));
pr_err("\troot_lnum %u\n", le32_to_cpu(mst->root_lnum));
pr_err("\troot_offs %u\n", le32_to_cpu(mst->root_offs));
pr_err("\troot_len %u\n", le32_to_cpu(mst->root_len));
pr_err("\tgc_lnum %u\n", le32_to_cpu(mst->gc_lnum));
pr_err("\tihead_lnum %u\n", le32_to_cpu(mst->ihead_lnum));
pr_err("\tihead_offs %u\n", le32_to_cpu(mst->ihead_offs));
pr_err("\tindex_size %llu\n",
(unsigned long long)le64_to_cpu(mst->index_size));
pr_err("\tlpt_lnum %u\n", le32_to_cpu(mst->lpt_lnum));
pr_err("\tlpt_offs %u\n", le32_to_cpu(mst->lpt_offs));
pr_err("\tnhead_lnum %u\n", le32_to_cpu(mst->nhead_lnum));
pr_err("\tnhead_offs %u\n", le32_to_cpu(mst->nhead_offs));
pr_err("\tltab_lnum %u\n", le32_to_cpu(mst->ltab_lnum));
pr_err("\tltab_offs %u\n", le32_to_cpu(mst->ltab_offs));
pr_err("\tlsave_lnum %u\n", le32_to_cpu(mst->lsave_lnum));
pr_err("\tlsave_offs %u\n", le32_to_cpu(mst->lsave_offs));
pr_err("\tlscan_lnum %u\n", le32_to_cpu(mst->lscan_lnum));
pr_err("\tleb_cnt %u\n", le32_to_cpu(mst->leb_cnt));
pr_err("\tempty_lebs %u\n", le32_to_cpu(mst->empty_lebs));
pr_err("\tidx_lebs %u\n", le32_to_cpu(mst->idx_lebs));
pr_err("\ttotal_free %llu\n",
(unsigned long long)le64_to_cpu(mst->total_free));
pr_err("\ttotal_dirty %llu\n",
(unsigned long long)le64_to_cpu(mst->total_dirty));
pr_err("\ttotal_used %llu\n",
(unsigned long long)le64_to_cpu(mst->total_used));
pr_err("\ttotal_dead %llu\n",
(unsigned long long)le64_to_cpu(mst->total_dead));
pr_err("\ttotal_dark %llu\n",
(unsigned long long)le64_to_cpu(mst->total_dark));
break;
}
case UBIFS_REF_NODE:
{
const struct ubifs_ref_node *ref = node;
pr_err("\tlnum %u\n", le32_to_cpu(ref->lnum));
pr_err("\toffs %u\n", le32_to_cpu(ref->offs));
pr_err("\tjhead %u\n", le32_to_cpu(ref->jhead));
break;
}
case UBIFS_INO_NODE:
{
const struct ubifs_ino_node *ino = node;
key_read(c, &ino->key, &key);
dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
pr_err("\tcreat_sqnum %llu\n",
(unsigned long long)le64_to_cpu(ino->creat_sqnum));
(unsigned long long)le64_to_cpu(ino->size));
pr_err("\tnlink %u\n", le32_to_cpu(ino->nlink));
pr_err("\tatime %lld.%u\n",
(long long)le64_to_cpu(ino->atime_sec),
le32_to_cpu(ino->atime_nsec));
(long long)le64_to_cpu(ino->mtime_sec),
le32_to_cpu(ino->mtime_nsec));
(long long)le64_to_cpu(ino->ctime_sec),
le32_to_cpu(ino->ctime_nsec));
pr_err("\tuid %u\n", le32_to_cpu(ino->uid));
pr_err("\tgid %u\n", le32_to_cpu(ino->gid));
pr_err("\tmode %u\n", le32_to_cpu(ino->mode));
pr_err("\tflags %#x\n", le32_to_cpu(ino->flags));
pr_err("\txattr_cnt %u\n", le32_to_cpu(ino->xattr_cnt));
pr_err("\txattr_size %u\n", le32_to_cpu(ino->xattr_size));
pr_err("\txattr_names %u\n", le32_to_cpu(ino->xattr_names));
pr_err("\tcompr_type %#x\n",
pr_err("\tdata len %u\n", le32_to_cpu(ino->data_len));
break;
}
case UBIFS_DENT_NODE:
case UBIFS_XENT_NODE:
{
const struct ubifs_dent_node *dent = node;
int nlen = le16_to_cpu(dent->nlen);
key_read(c, &dent->key, &key);
dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
(unsigned long long)le64_to_cpu(dent->inum));
pr_err("\ttype %d\n", (int)dent->type);
pr_err("\tnlen %d\n", nlen);
pr_err("\tname ");
pr_err("(bad name length, not printing, bad or corrupted node)");
else {
for (i = 0; i < nlen && dent->name[i]; i++)
pr_cont("%c", dent->name[i]);
break;
}
case UBIFS_DATA_NODE:
{
const struct ubifs_data_node *dn = node;
int dlen = le32_to_cpu(ch->len) - UBIFS_DATA_NODE_SZ;
key_read(c, &dn->key, &key);
dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
pr_err("\tsize %u\n", le32_to_cpu(dn->size));
pr_err("\tcompr_typ %d\n",
pr_err("\tdata size %d\n", dlen);
pr_err("\tdata:\n");
print_hex_dump(KERN_ERR, "\t", DUMP_PREFIX_OFFSET, 32, 1,
(void *)&dn->data, dlen, 0);
break;
}
case UBIFS_TRUN_NODE:
{
const struct ubifs_trun_node *trun = node;
pr_err("\tinum %u\n", le32_to_cpu(trun->inum));
pr_err("\told_size %llu\n",
(unsigned long long)le64_to_cpu(trun->old_size));
(unsigned long long)le64_to_cpu(trun->new_size));
break;
}
case UBIFS_IDX_NODE:
{
const struct ubifs_idx_node *idx = node;
n = le16_to_cpu(idx->child_cnt);
pr_err("\tchild_cnt %d\n", n);
pr_err("\tlevel %d\n", (int)le16_to_cpu(idx->level));
pr_err("\tBranches:\n");
for (i = 0; i < n && i < c->fanout - 1; i++) {
const struct ubifs_branch *br;
br = ubifs_idx_branch(c, idx, i);
key_read(c, &br->key, &key);
pr_err("\t%d: LEB %d:%d len %d key %s\n",
i, le32_to_cpu(br->lnum), le32_to_cpu(br->offs),
le32_to_cpu(br->len),
dbg_snprintf_key(c, &key, key_buf,
DBG_KEY_BUF_LEN));
}
break;
}
case UBIFS_CS_NODE:
break;
case UBIFS_ORPH_NODE:
{
const struct ubifs_orph_node *orph = node;
pr_err("\tcommit number %llu\n",
(unsigned long long)
le64_to_cpu(orph->cmt_no) & LLONG_MAX);
pr_err("\tlast node flag %llu\n",
(unsigned long long)(le64_to_cpu(orph->cmt_no)) >> 63);
n = (le32_to_cpu(ch->len) - UBIFS_ORPH_NODE_SZ) >> 3;
pr_err("\t%d orphan inode numbers:\n", n);
(unsigned long long)le64_to_cpu(orph->inos[i]));
pr_err("node type %d was not recognized\n",
(int)ch->node_type);
}
spin_unlock(&dbg_lock);
}
void ubifs_dump_budget_req(const struct ubifs_budget_req *req)
pr_err("Budgeting request: new_ino %d, dirtied_ino %d\n",
pr_err("\tnew_ino_d %d, dirtied_ino_d %d\n",
req->new_ino_d, req->dirtied_ino_d);
pr_err("\tnew_page %d, dirtied_page %d\n",
pr_err("\tnew_dent %d, mod_dent %d\n",
pr_err("\tidx_growth %d\n", req->idx_growth);
pr_err("\tdata_growth %d dd_growth %d\n",
req->data_growth, req->dd_growth);
spin_unlock(&dbg_lock);
}
void ubifs_dump_lstats(const struct ubifs_lp_stats *lst)
pr_err("(pid %d) Lprops statistics: empty_lebs %d, idx_lebs %d\n",
current->pid, lst->empty_lebs, lst->idx_lebs);
pr_err("\ttaken_empty_lebs %d, total_free %lld, total_dirty %lld\n",
lst->taken_empty_lebs, lst->total_free, lst->total_dirty);
pr_err("\ttotal_used %lld, total_dark %lld, total_dead %lld\n",
lst->total_used, lst->total_dark, lst->total_dead);
void ubifs_dump_budg(struct ubifs_info *c, const struct ubifs_budg_info *bi)
{
int i;
struct rb_node *rb;
struct ubifs_bud *bud;
struct ubifs_gced_idx_leb *idx_gc;
long long available, outstanding, free;
spin_lock(&c->space_lock);
pr_err("(pid %d) Budgeting info: data budget sum %lld, total budget sum %lld\n",
current->pid, bi->data_growth + bi->dd_growth,
bi->data_growth + bi->dd_growth + bi->idx_growth);
pr_err("\tbudg_data_growth %lld, budg_dd_growth %lld, budg_idx_growth %lld\n",
bi->data_growth, bi->dd_growth, bi->idx_growth);
pr_err("\tmin_idx_lebs %d, old_idx_sz %llu, uncommitted_idx %lld\n",
bi->min_idx_lebs, bi->old_idx_sz, bi->uncommitted_idx);
pr_err("\tpage_budget %d, inode_budget %d, dent_budget %d\n",
bi->page_budget, bi->inode_budget, bi->dent_budget);
pr_err("\tnospace %u, nospace_rp %u\n", bi->nospace, bi->nospace_rp);
pr_err("\tdark_wm %d, dead_wm %d, max_idx_node_sz %d\n",
c->dark_wm, c->dead_wm, c->max_idx_node_sz);
if (bi != &c->bi)
/*
* If we are dumping saved budgeting data, do not print
* additional information which is about the current state, not
* the old one which corresponded to the saved budgeting data.
*/
goto out_unlock;
pr_err("\tfreeable_cnt %d, calc_idx_sz %lld, idx_gc_cnt %d\n",
c->freeable_cnt, c->calc_idx_sz, c->idx_gc_cnt);
pr_err("\tdirty_pg_cnt %ld, dirty_zn_cnt %ld, clean_zn_cnt %ld\n",
atomic_long_read(&c->dirty_zn_cnt),
atomic_long_read(&c->clean_zn_cnt));
pr_err("\tgc_lnum %d, ihead_lnum %d\n", c->gc_lnum, c->ihead_lnum);
/* If we are in R/O mode, journal heads do not exist */
if (c->jheads)
for (i = 0; i < c->jhead_cnt; i++)
pr_err("\tjhead %s\t LEB %d\n",
dbg_jhead(c->jheads[i].wbuf.jhead),
c->jheads[i].wbuf.lnum);
for (rb = rb_first(&c->buds); rb; rb = rb_next(rb)) {
bud = rb_entry(rb, struct ubifs_bud, rb);
pr_err("\tbud LEB %d\n", bud->lnum);
}
list_for_each_entry(bud, &c->old_buds, list)
pr_err("\told bud LEB %d\n", bud->lnum);
list_for_each_entry(idx_gc, &c->idx_gc, list)
pr_err("\tGC'ed idx LEB %d unmap %d\n",
pr_err("\tcommit state %d\n", c->cmt_state);
available = ubifs_calc_available(c, c->bi.min_idx_lebs);
outstanding = c->bi.data_growth + c->bi.dd_growth;
free = ubifs_get_free_space_nolock(c);
pr_err("Budgeting predictions:\n");
pr_err("\tavailable: %lld, outstanding %lld, free %lld\n",
spin_unlock(&c->space_lock);
void ubifs_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp)
int i, spc, dark = 0, dead = 0;
struct rb_node *rb;
struct ubifs_bud *bud;
spc = lp->free + lp->dirty;
if (spc < c->dead_wm)
dead = spc;
else
dark = ubifs_calc_dark(c, spc);
if (lp->flags & LPROPS_INDEX)
pr_err("LEB %-7d free %-8d dirty %-8d used %-8d free + dirty %-8d flags %#x (",
lp->lnum, lp->free, lp->dirty, c->leb_size - spc, spc,
lp->flags);
pr_err("LEB %-7d free %-8d dirty %-8d used %-8d free + dirty %-8d dark %-4d dead %-4d nodes fit %-3d flags %#-4x (",
lp->lnum, lp->free, lp->dirty, c->leb_size - spc, spc,
dark, dead, (int)(spc / UBIFS_MAX_NODE_SZ), lp->flags);
if (lp->flags & LPROPS_TAKEN) {
if (lp->flags & LPROPS_INDEX)
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
} else {
const char *s;
if (lp->flags & LPROPS_INDEX) {
switch (lp->flags & LPROPS_CAT_MASK) {
case LPROPS_DIRTY_IDX:
s = "dirty index";
break;
case LPROPS_FRDI_IDX:
s = "freeable index";
break;
default:
s = "index";
}
} else {
switch (lp->flags & LPROPS_CAT_MASK) {
case LPROPS_UNCAT:
s = "not categorized";
break;
case LPROPS_DIRTY:
s = "dirty";
break;
case LPROPS_FREE:
s = "free";
break;
case LPROPS_EMPTY:
s = "empty";
break;
case LPROPS_FREEABLE:
s = "freeable";
break;
default:
s = NULL;
break;
}
}
}
for (rb = rb_first((struct rb_root *)&c->buds); rb; rb = rb_next(rb)) {
bud = rb_entry(rb, struct ubifs_bud, rb);
if (bud->lnum == lp->lnum) {
int head = 0;
for (i = 0; i < c->jhead_cnt; i++) {
/*
* Note, if we are in R/O mode or in the middle
* of mounting/re-mounting, the write-buffers do
* not exist.
*/
if (c->jheads &&
lp->lnum == c->jheads[i].wbuf.lnum) {
pr_cont(", jhead %s", dbg_jhead(i));
dbg_jhead(bud->jhead));
}
}
if (lp->lnum == c->gc_lnum)
pr_cont(", GC LEB");
pr_cont(")\n");
void ubifs_dump_lprops(struct ubifs_info *c)
{
int lnum, err;
struct ubifs_lprops lp;
struct ubifs_lp_stats lst;
pr_err("(pid %d) start dumping LEB properties\n", current->pid);
for (lnum = c->main_first; lnum < c->leb_cnt; lnum++) {
err = ubifs_read_one_lp(c, lnum, &lp);
if (err)
ubifs_err("cannot read lprops for LEB %d", lnum);
pr_err("(pid %d) finish dumping LEB properties\n", current->pid);
void ubifs_dump_lpt_info(struct ubifs_info *c)
{
int i;
spin_lock(&dbg_lock);
pr_err("(pid %d) dumping LPT information\n", current->pid);
pr_err("\tlpt_sz: %lld\n", c->lpt_sz);
pr_err("\tpnode_sz: %d\n", c->pnode_sz);
pr_err("\tnnode_sz: %d\n", c->nnode_sz);
pr_err("\tltab_sz: %d\n", c->ltab_sz);
pr_err("\tlsave_sz: %d\n", c->lsave_sz);
pr_err("\tbig_lpt: %d\n", c->big_lpt);
pr_err("\tlpt_hght: %d\n", c->lpt_hght);
pr_err("\tpnode_cnt: %d\n", c->pnode_cnt);
pr_err("\tnnode_cnt: %d\n", c->nnode_cnt);
pr_err("\tdirty_pn_cnt: %d\n", c->dirty_pn_cnt);
pr_err("\tdirty_nn_cnt: %d\n", c->dirty_nn_cnt);
pr_err("\tlsave_cnt: %d\n", c->lsave_cnt);
pr_err("\tspace_bits: %d\n", c->space_bits);
pr_err("\tlpt_lnum_bits: %d\n", c->lpt_lnum_bits);
pr_err("\tlpt_offs_bits: %d\n", c->lpt_offs_bits);
pr_err("\tlpt_spc_bits: %d\n", c->lpt_spc_bits);
pr_err("\tpcnt_bits: %d\n", c->pcnt_bits);
pr_err("\tlnum_bits: %d\n", c->lnum_bits);
pr_err("\tLPT root is at %d:%d\n", c->lpt_lnum, c->lpt_offs);
pr_err("\tLPT head is at %d:%d\n",
c->nhead_lnum, c->nhead_offs);
pr_err("\tLPT ltab is at %d:%d\n", c->ltab_lnum, c->ltab_offs);
pr_err("\tLPT lsave is at %d:%d\n",
c->lsave_lnum, c->lsave_offs);
for (i = 0; i < c->lpt_lebs; i++)
pr_err("\tLPT LEB %d free %d dirty %d tgc %d cmt %d\n",
i + c->lpt_first, c->ltab[i].free, c->ltab[i].dirty,
c->ltab[i].tgc, c->ltab[i].cmt);
spin_unlock(&dbg_lock);
}
void ubifs_dump_sleb(const struct ubifs_info *c,
const struct ubifs_scan_leb *sleb, int offs)
{
struct ubifs_scan_node *snod;
pr_err("(pid %d) start dumping scanned data from LEB %d:%d\n",
current->pid, sleb->lnum, offs);
list_for_each_entry(snod, &sleb->nodes, list) {
cond_resched();
pr_err("Dumping node at LEB %d:%d len %d\n",
void ubifs_dump_leb(const struct ubifs_info *c, int lnum)
{
struct ubifs_scan_leb *sleb;
struct ubifs_scan_node *snod;
pr_err("(pid %d) start dumping LEB %d\n", current->pid, lnum);
buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
if (!buf) {
ubifs_err("cannot allocate memory for dumping LEB %d", lnum);
return;
}
sleb = ubifs_scan(c, lnum, 0, buf, 0);
if (IS_ERR(sleb)) {
ubifs_err("scan error %d", (int)PTR_ERR(sleb));
pr_err("LEB %d has %d nodes ending at %d\n", lnum,
sleb->nodes_cnt, sleb->endpt);
list_for_each_entry(snod, &sleb->nodes, list) {
cond_resched();
pr_err("Dumping node at LEB %d:%d len %d\n", lnum,
pr_err("(pid %d) finish dumping LEB %d\n", current->pid, lnum);
void ubifs_dump_znode(const struct ubifs_info *c,
const struct ubifs_znode *znode)
{
int n;
const struct ubifs_zbranch *zbr;
spin_lock(&dbg_lock);
if (znode->parent)
zbr = &znode->parent->zbranch[znode->iip];
else
zbr = &c->zroot;
pr_err("znode %p, LEB %d:%d len %d parent %p iip %d level %d child_cnt %d flags %lx\n",
znode, zbr->lnum, zbr->offs, zbr->len, znode->parent, znode->iip,
znode->level, znode->child_cnt, znode->flags);
if (znode->child_cnt <= 0 || znode->child_cnt > c->fanout) {
spin_unlock(&dbg_lock);
return;
}
for (n = 0; n < znode->child_cnt; n++) {
zbr = &znode->zbranch[n];
if (znode->level > 0)
pr_err("\t%d: znode %p LEB %d:%d len %d key %s\n",
n, zbr->znode, zbr->lnum, zbr->offs, zbr->len,
dbg_snprintf_key(c, &zbr->key, key_buf,
DBG_KEY_BUF_LEN));
pr_err("\t%d: LNC %p LEB %d:%d len %d key %s\n",
n, zbr->znode, zbr->lnum, zbr->offs, zbr->len,
dbg_snprintf_key(c, &zbr->key, key_buf,
DBG_KEY_BUF_LEN));
}
spin_unlock(&dbg_lock);
}
void ubifs_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat)
pr_err("(pid %d) start dumping heap cat %d (%d elements)\n",
for (i = 0; i < heap->cnt; i++) {
struct ubifs_lprops *lprops = heap->arr[i];
pr_err("\t%d. LEB %d hpos %d free %d dirty %d flags %d\n",
i, lprops->lnum, lprops->hpos, lprops->free,
lprops->dirty, lprops->flags);
pr_err("(pid %d) finish dumping heap\n", current->pid);
void ubifs_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
struct ubifs_nnode *parent, int iip)
pr_err("(pid %d) dumping pnode:\n", current->pid);
pr_err("\taddress %zx parent %zx cnext %zx\n",
(size_t)pnode, (size_t)parent, (size_t)pnode->cnext);
pr_err("\tflags %lu iip %d level %d num %d\n",
pnode->flags, iip, pnode->level, pnode->num);
for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
struct ubifs_lprops *lp = &pnode->lprops[i];
pr_err("\t%d: free %d dirty %d flags %d lnum %d\n",
i, lp->free, lp->dirty, lp->flags, lp->lnum);
}
}
void ubifs_dump_tnc(struct ubifs_info *c)
{
struct ubifs_znode *znode;
int level;
pr_err("\n");
pr_err("(pid %d) start dumping TNC tree\n", current->pid);
znode = ubifs_tnc_levelorder_next(c->zroot.znode, NULL);
level = znode->level;
pr_err("== Level %d ==\n", level);
while (znode) {
if (level != znode->level) {
level = znode->level;
pr_err("== Level %d ==\n", level);
znode = ubifs_tnc_levelorder_next(c->zroot.znode, znode);
}
pr_err("(pid %d) finish dumping TNC tree\n", current->pid);
}
static int dump_znode(struct ubifs_info *c, struct ubifs_znode *znode,
void *priv)
{
* ubifs_dump_index - dump the on-flash index.
* @c: UBIFS file-system description object
*
* This function dumps whole UBIFS indexing B-tree, unlike 'ubifs_dump_tnc()'
* which dumps only in-memory znodes and does not read znodes which from flash.
*/
void ubifs_dump_index(struct ubifs_info *c)
{
dbg_walk_index(c, NULL, dump_znode, NULL);
}
/**
* dbg_save_space_info - save information about flash space.
* @c: UBIFS file-system description object
*
* This function saves information about UBIFS free space, dirty space, etc, in
* order to check it later.
*/
void dbg_save_space_info(struct ubifs_info *c)
{
struct ubifs_debug_info *d = c->dbg;
int freeable_cnt;
memcpy(&d->saved_lst, &c->lst, sizeof(struct ubifs_lp_stats));
memcpy(&d->saved_bi, &c->bi, sizeof(struct ubifs_budg_info));
d->saved_idx_gc_cnt = c->idx_gc_cnt;
/*
* We use a dirty hack here and zero out @c->freeable_cnt, because it
* affects the free space calculations, and UBIFS might not know about
* all freeable eraseblocks. Indeed, we know about freeable eraseblocks
* only when we read their lprops, and we do this only lazily, upon the
* need. So at any given point of time @c->freeable_cnt might be not
* exactly accurate.
*
* Just one example about the issue we hit when we did not zero
* @c->freeable_cnt.
* 1. The file-system is mounted R/O, c->freeable_cnt is %0. We save the
* amount of free space in @d->saved_free
* 2. We re-mount R/W, which makes UBIFS to read the "lsave"
* information from flash, where we cache LEBs from various
* categories ('ubifs_remount_fs()' -> 'ubifs_lpt_init()'
* -> 'lpt_init_wr()' -> 'read_lsave()' -> 'ubifs_lpt_lookup()'
* -> 'ubifs_get_pnode()' -> 'update_cats()'
* -> 'ubifs_add_to_cat()').
* 3. Lsave contains a freeable eraseblock, and @c->freeable_cnt
* becomes %1.
* 4. We calculate the amount of free space when the re-mount is
* finished in 'dbg_check_space_info()' and it does not match
* @d->saved_free.