3052 lines · 82.5 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* * This file is part of UBIFS. * * Copyright (C) 2006-2008 Nokia Corporation * * 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/debugfs.h>#include <linux/math64.h>#include <linux/uaccess.h>#include <linux/random.h>#include <linux/ctype.h>#include "ubifs.h" static DEFINE_SPINLOCK(dbg_lock); 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));			break;		case UBIFS_DATA_KEY:			len -= snprintf(p, len, "(%lu, %s, %u)",					(unsigned long)key_inum(c, key),					get_key_type(type), key_block(c, key));			break;		case UBIFS_TRUN_KEY:			len -= snprintf(p, len, "(%lu, %s)",					(unsigned long)key_inum(c, key),					get_key_type(type));			break;		default:			len -= snprintf(p, len, "(bad key type: %#08x, %#08x)",					key->u32[0], key->u32[1]);		}	} else		len -= snprintf(p, len, "bad key format %d", c->key_fmt);	ubifs_assert(c, len > 0);	return p;} 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";	case UBIFS_AUTH_NODE:		return "auth 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,	       dbg_ntype(ch->node_type));	pr_err("\tgroup_type     %d (%s)\n", ch->group_type,	       dbg_gtype(ch->group_type));	pr_err("\tsqnum          %llu\n",	       (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 fscrypt_name nm = {0};	union ubifs_key key;	struct ubifs_dent_node *dent, *pdent = NULL;	int count = 2; 	pr_err("Dump in-memory inode:");	pr_err("\tinode          %llu\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));	pr_err("\tatime          %u.%u\n",	       (unsigned int) inode_get_atime_sec(inode),	       (unsigned int) inode_get_atime_nsec(inode));	pr_err("\tmtime          %u.%u\n",	       (unsigned int) inode_get_mtime_sec(inode),	       (unsigned int) inode_get_mtime_nsec(inode));	pr_err("\tctime          %u.%u\n",	       (unsigned int) inode_get_ctime_sec(inode),	       (unsigned int) inode_get_ctime_nsec(inode));	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->bulk_read);	pr_err("\tsynced_i_size  %llu\n",	       (unsigned long long)ui->synced_i_size);	pr_err("\tui_size        %llu\n",	       (unsigned long long)ui->ui_size);	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(c, !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));			break;		} 		pr_err("\t%d: inode %llu, type %s, len %d\n",		       count++, (unsigned long long) le64_to_cpu(dent->inum),		       get_dent_type(dent->type),		       le16_to_cpu(dent->nlen)); 		fname_name(&nm) = dent->name;		fname_len(&nm) = 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 node_len){	int i, n, type, safe_len, max_node_len, min_node_len;	union ubifs_key key;	const struct ubifs_ch *ch = node;	char key_buf[DBG_KEY_BUF_LEN]; 	/* 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;	} 	/* Skip dumping unknown type node */	type = ch->node_type;	if (type < 0 || type >= UBIFS_NODE_TYPES_CNT) {		pr_err("node type %d was not recognized\n", type);		return;	} 	spin_lock(&dbg_lock);	dump_ch(node); 	if (c->ranges[type].max_len == 0) {		max_node_len = min_node_len = c->ranges[type].len;	} else {		max_node_len = c->ranges[type].max_len;		min_node_len = c->ranges[type].min_len;	}	safe_len = le32_to_cpu(ch->len);	safe_len = safe_len > 0 ? safe_len : 0;	safe_len = min3(safe_len, max_node_len, node_len);	if (safe_len < min_node_len) {		pr_err("node len(%d) is too short for %s, left %d bytes:\n",		       safe_len, dbg_ntype(type),		       safe_len > UBIFS_CH_SZ ?		       safe_len - (int)UBIFS_CH_SZ : 0);		if (safe_len > UBIFS_CH_SZ)			print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 32, 1,				       (void *)node + UBIFS_CH_SZ,				       safe_len - UBIFS_CH_SZ, 0);		goto out_unlock;	}	if (safe_len != le32_to_cpu(ch->len))		pr_err("\ttruncated node length      %d\n", safe_len); 	switch (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("\tbig_lpt        %u\n",		       !!(sup_flags & UBIFS_FLG_BIGLPT));		pr_err("\tspace_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));		pr_err("\trp_size        %llu\n",		       (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);		pr_err("\tkey            %s\n",		       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));		pr_err("\tsize           %llu\n",		       (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));		pr_err("\tmtime          %lld.%u\n",		       (long long)le64_to_cpu(ino->mtime_sec),		       le32_to_cpu(ino->mtime_nsec));		pr_err("\tctime          %lld.%u\n",		       (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",		       (int)le16_to_cpu(ino->compr_type));		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);		pr_err("\tkey            %s\n",		       dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));		pr_err("\tinum           %llu\n",		       (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           "); 		if (nlen > UBIFS_MAX_NLEN ||		    nlen > safe_len - UBIFS_DENT_NODE_SZ)			pr_err("(bad name length, not printing, bad or corrupted node)");		else {			for (i = 0; i < nlen && dent->name[i]; i++)				pr_cont("%c", isprint(dent->name[i]) ?					dent->name[i] : '?');		}		pr_cont("\n"); 		break;	}	case UBIFS_DATA_NODE:	{		const struct ubifs_data_node *dn = node;

Lines 1–500 of 3052.