Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2953e73f authored by Adrian Hunter's avatar Adrian Hunter Committed by Artem Bityutskiy
Browse files

UBIFS: add no_chk_data_crc mount option



UBIFS read performance can be improved by skipping the CRC
check when data nodes are read.  This option can be used if
the underlying media is considered to be highly reliable.
Note that CRCs are always checked for metadata.

Read speed on Arm platform with OneNAND goes from 19 MiB/s
to 27 MiB/s with data CRC checking disabled.

Signed-off-by: default avatarAdrian Hunter <ext-adrian.hunter@nokia.com>
parent 4793e7c5
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -89,6 +89,12 @@ fast_unmount do not commit on unmount; this option makes
bulk_read		read more in one go to take advantage of flash
			media that read faster sequentially
no_bulk_read (*)	do not bulk-read
no_chk_data_crc		skip checking of CRCs on data nodes in order to
			improve read performance. Use this option only
			if the flash media is highly reliable. The effect
			of this option is that corruption of the contents
			of a file can go unnoticed.
chk_data_crc (*)	do not skip checking CRCs on data nodes


Quick usage instructions
+8 −3
Original line number Diff line number Diff line
@@ -74,6 +74,7 @@ void ubifs_ro_mode(struct ubifs_info *c, int err)
 * @lnum: logical eraseblock number
 * @offs: offset within the logical eraseblock
 * @quiet: print no messages
 * @chk_crc: indicates whether to always check the CRC
 *
 * This function checks node magic number and CRC checksum. This function also
 * validates node length to prevent UBIFS from becoming crazy when an attacker
@@ -85,7 +86,7 @@ void ubifs_ro_mode(struct ubifs_info *c, int err)
 * or magic.
 */
int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
		     int offs, int quiet)
		     int offs, int quiet, int chk_crc)
{
	int err = -EINVAL, type, node_len;
	uint32_t crc, node_crc, magic;
@@ -121,6 +122,10 @@ int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
		   node_len > c->ranges[type].max_len)
		goto out_len;

	if (!chk_crc && type == UBIFS_DATA_NODE && !c->always_chk_crc)
		if (c->no_chk_data_crc)
			return 0;

	crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
	node_crc = le32_to_cpu(ch->crc);
	if (crc != node_crc) {
@@ -722,7 +727,7 @@ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
		goto out;
	}

	err = ubifs_check_node(c, buf, lnum, offs, 0);
	err = ubifs_check_node(c, buf, lnum, offs, 0, 0);
	if (err) {
		ubifs_err("expected node type %d", type);
		return err;
@@ -781,7 +786,7 @@ int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len,
		goto out;
	}

	err = ubifs_check_node(c, buf, lnum, offs, 0);
	err = ubifs_check_node(c, buf, lnum, offs, 0, 0);
	if (err) {
		ubifs_err("expected node type %d", type);
		return err;
+1 −1
Original line number Diff line number Diff line
@@ -87,7 +87,7 @@ int ubifs_scan_a_node(const struct ubifs_info *c, void *buf, int len, int lnum,

	dbg_scan("scanning %s", dbg_ntype(ch->node_type));

	if (ubifs_check_node(c, buf, lnum, offs, quiet))
	if (ubifs_check_node(c, buf, lnum, offs, quiet, 1))
		return SCANNED_A_CORRUPT_NODE;

	if (ch->node_type == UBIFS_PAD_NODE) {
+31 −3
Original line number Diff line number Diff line
@@ -406,6 +406,11 @@ static int ubifs_show_options(struct seq_file *s, struct vfsmount *mnt)
	else if (c->mount_opts.bulk_read == 1)
		seq_printf(s, ",no_bulk_read");

	if (c->mount_opts.chk_data_crc == 2)
		seq_printf(s, ",chk_data_crc");
	else if (c->mount_opts.chk_data_crc == 1)
		seq_printf(s, ",no_chk_data_crc");

	return 0;
}

@@ -859,6 +864,8 @@ static int check_volume_empty(struct ubifs_info *c)
 * Opt_norm_unmount: run a journal commit before un-mounting
 * Opt_bulk_read: enable bulk-reads
 * Opt_no_bulk_read: disable bulk-reads
 * Opt_chk_data_crc: check CRCs when reading data nodes
 * Opt_no_chk_data_crc: do not check CRCs when reading data nodes
 * Opt_err: just end of array marker
 */
enum {
@@ -866,6 +873,8 @@ enum {
	Opt_norm_unmount,
	Opt_bulk_read,
	Opt_no_bulk_read,
	Opt_chk_data_crc,
	Opt_no_chk_data_crc,
	Opt_err,
};

@@ -874,6 +883,8 @@ static match_table_t tokens = {
	{Opt_norm_unmount, "norm_unmount"},
	{Opt_bulk_read, "bulk_read"},
	{Opt_no_bulk_read, "no_bulk_read"},
	{Opt_chk_data_crc, "chk_data_crc"},
	{Opt_no_chk_data_crc, "no_chk_data_crc"},
	{Opt_err, NULL},
};

@@ -919,6 +930,14 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options,
			c->mount_opts.bulk_read = 1;
			c->bulk_read = 0;
			break;
		case Opt_chk_data_crc:
			c->mount_opts.chk_data_crc = 2;
			c->no_chk_data_crc = 0;
			break;
		case Opt_no_chk_data_crc:
			c->mount_opts.chk_data_crc = 1;
			c->no_chk_data_crc = 1;
			break;
		default:
			ubifs_err("unrecognized mount option \"%s\" "
				  "or missing value", p);
@@ -1027,6 +1046,8 @@ static int mount_ubifs(struct ubifs_info *c)
			goto out_free;
	}

	c->always_chk_crc = 1;

	err = ubifs_read_superblock(c);
	if (err)
		goto out_free;
@@ -1168,6 +1189,8 @@ static int mount_ubifs(struct ubifs_info *c)
	if (err)
		goto out_infos;

	c->always_chk_crc = 0;

	ubifs_msg("mounted UBI device %d, volume %d, name \"%s\"",
		  c->vi.ubi_num, c->vi.vol_id, c->vi.name);
	if (mounted_read_only)
@@ -1313,6 +1336,7 @@ static int ubifs_remount_rw(struct ubifs_info *c)

	mutex_lock(&c->umount_mutex);
	c->remounting_rw = 1;
	c->always_chk_crc = 1;

	/* Check for enough free space */
	if (ubifs_calc_available(c, c->min_idx_lebs) <= 0) {
@@ -1381,13 +1405,15 @@ static int ubifs_remount_rw(struct ubifs_info *c)
		c->bgt = NULL;
		ubifs_err("cannot spawn \"%s\", error %d",
			  c->bgt_name, err);
		return err;
		goto out;
	}
	wake_up_process(c->bgt);

	c->orph_buf = vmalloc(c->leb_size);
	if (!c->orph_buf)
		return -ENOMEM;
	if (!c->orph_buf) {
		err = -ENOMEM;
		goto out;
	}

	/* Check for enough log space */
	lnum = c->lhead_lnum + 1;
@@ -1414,6 +1440,7 @@ static int ubifs_remount_rw(struct ubifs_info *c)
	dbg_gen("re-mounted read-write");
	c->vfs_sb->s_flags &= ~MS_RDONLY;
	c->remounting_rw = 0;
	c->always_chk_crc = 0;
	mutex_unlock(&c->umount_mutex);
	return 0;

@@ -1429,6 +1456,7 @@ static int ubifs_remount_rw(struct ubifs_info *c)
	c->ileb_buf = NULL;
	ubifs_lpt_free(c, 1);
	c->remounting_rw = 0;
	c->always_chk_crc = 0;
	mutex_unlock(&c->umount_mutex);
	return err;
}
+5 −1
Original line number Diff line number Diff line
@@ -470,6 +470,10 @@ static int try_read_node(const struct ubifs_info *c, void *buf, int type,
	if (node_len != len)
		return 0;

	if (type == UBIFS_DATA_NODE && !c->always_chk_crc)
		if (c->no_chk_data_crc)
			return 0;

	crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
	node_crc = le32_to_cpu(ch->crc);
	if (crc != node_crc)
@@ -1687,7 +1691,7 @@ static int validate_data_node(struct ubifs_info *c, void *buf,
		goto out_err;
	}

	err = ubifs_check_node(c, buf, zbr->lnum, zbr->offs, 0);
	err = ubifs_check_node(c, buf, zbr->lnum, zbr->offs, 0, 0);
	if (err) {
		ubifs_err("expected node type %d", UBIFS_DATA_NODE);
		goto out;
Loading