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: Adrian Hunter <ext-adrian.hunter@nokia.com>
bulk_read read more in one go to take advantage of flash
media that read faster sequentially
no_bulk_read (*) do not bulk-read
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
* @lnum: logical eraseblock number
* @offs: offset within the logical eraseblock
* @quiet: print no messages
* @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
*
* This function checks node magic number and CRC checksum. This function also
* validates node length to prevent UBIFS from becoming crazy when an attacker
* or magic.
*/
int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
* or magic.
*/
int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
+ int offs, int quiet, int chk_crc)
{
int err = -EINVAL, type, node_len;
uint32_t crc, node_crc, magic;
{
int err = -EINVAL, type, node_len;
uint32_t crc, node_crc, magic;
node_len > c->ranges[type].max_len)
goto out_len;
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) {
crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
node_crc = le32_to_cpu(ch->crc);
if (crc != node_crc) {
- 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;
if (err) {
ubifs_err("expected node type %d", type);
return err;
- 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;
if (err) {
ubifs_err("expected node type %d", type);
return err;
dbg_scan("scanning %s", dbg_ntype(ch->node_type));
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) {
return SCANNED_A_CORRUPT_NODE;
if (ch->node_type == UBIFS_PAD_NODE) {
else if (c->mount_opts.bulk_read == 1)
seq_printf(s, ",no_bulk_read");
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");
+
* Opt_norm_unmount: run a journal commit before un-mounting
* Opt_bulk_read: enable bulk-reads
* Opt_no_bulk_read: disable bulk-reads
* 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 {
* Opt_err: just end of array marker
*/
enum {
Opt_norm_unmount,
Opt_bulk_read,
Opt_no_bulk_read,
Opt_norm_unmount,
Opt_bulk_read,
Opt_no_bulk_read,
+ Opt_chk_data_crc,
+ Opt_no_chk_data_crc,
{Opt_norm_unmount, "norm_unmount"},
{Opt_bulk_read, "bulk_read"},
{Opt_no_bulk_read, "no_bulk_read"},
{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"},
c->mount_opts.bulk_read = 1;
c->bulk_read = 0;
break;
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);
default:
ubifs_err("unrecognized mount option \"%s\" "
"or missing value", p);
+ c->always_chk_crc = 1;
+
err = ubifs_read_superblock(c);
if (err)
goto out_free;
err = ubifs_read_superblock(c);
if (err)
goto out_free;
+ 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)
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)
mutex_lock(&c->umount_mutex);
c->remounting_rw = 1;
mutex_lock(&c->umount_mutex);
c->remounting_rw = 1;
/* Check for enough free space */
if (ubifs_calc_available(c, c->min_idx_lebs) <= 0) {
/* Check for enough free space */
if (ubifs_calc_available(c, c->min_idx_lebs) <= 0) {
c->bgt = NULL;
ubifs_err("cannot spawn \"%s\", error %d",
c->bgt_name, err);
c->bgt = NULL;
ubifs_err("cannot spawn \"%s\", error %d",
c->bgt_name, err);
}
wake_up_process(c->bgt);
c->orph_buf = vmalloc(c->leb_size);
}
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;
/* Check for enough log space */
lnum = c->lhead_lnum + 1;
dbg_gen("re-mounted read-write");
c->vfs_sb->s_flags &= ~MS_RDONLY;
c->remounting_rw = 0;
dbg_gen("re-mounted read-write");
c->vfs_sb->s_flags &= ~MS_RDONLY;
c->remounting_rw = 0;
mutex_unlock(&c->umount_mutex);
return 0;
mutex_unlock(&c->umount_mutex);
return 0;
c->ileb_buf = NULL;
ubifs_lpt_free(c, 1);
c->remounting_rw = 0;
c->ileb_buf = NULL;
ubifs_lpt_free(c, 1);
c->remounting_rw = 0;
mutex_unlock(&c->umount_mutex);
return err;
}
mutex_unlock(&c->umount_mutex);
return err;
}
if (node_len != len)
return 0;
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)
crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
node_crc = le32_to_cpu(ch->crc);
if (crc != node_crc)
- 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;
if (err) {
ubifs_err("expected node type %d", UBIFS_DATA_NODE);
goto out;
* struct ubifs_mount_opts - UBIFS-specific mount options information.
* @unmount_mode: selected unmount mode (%0 default, %1 normal, %2 fast)
* @bulk_read: enable bulk-reads
* struct ubifs_mount_opts - UBIFS-specific mount options information.
* @unmount_mode: selected unmount mode (%0 default, %1 normal, %2 fast)
* @bulk_read: enable bulk-reads
+ * @chk_data_crc: check CRCs when reading data nodes
*/
struct ubifs_mount_opts {
unsigned int unmount_mode:2;
unsigned int bulk_read:2;
*/
struct ubifs_mount_opts {
unsigned int unmount_mode:2;
unsigned int bulk_read:2;
+ unsigned int chk_data_crc:2;
* @bulk_read: enable bulk-reads
* @bulk_read_buf_size: buffer size for bulk-reads
*
* @bulk_read: enable bulk-reads
* @bulk_read_buf_size: buffer size for bulk-reads
*
+ * @no_chk_data_crc: do not check CRCs when reading data nodes (except during
+ * recovery)
+ *
* @dirty_pg_cnt: number of dirty pages (not used)
* @dirty_zn_cnt: number of dirty znodes
* @clean_zn_cnt: number of clean znodes
* @dirty_pg_cnt: number of dirty pages (not used)
* @dirty_zn_cnt: number of dirty znodes
* @clean_zn_cnt: number of clean znodes
* @rcvrd_mst_node: recovered master node to write when mounting ro to rw
* @size_tree: inode size information for recovery
* @remounting_rw: set while remounting from ro to rw (sb flags have MS_RDONLY)
* @rcvrd_mst_node: recovered master node to write when mounting ro to rw
* @size_tree: inode size information for recovery
* @remounting_rw: set while remounting from ro to rw (sb flags have MS_RDONLY)
+ * @always_chk_crc: always check CRCs (while mounting and remounting rw)
* @mount_opts: UBIFS-specific mount options
*
* @dbg_buf: a buffer of LEB size used for debugging purposes
* @mount_opts: UBIFS-specific mount options
*
* @dbg_buf: a buffer of LEB size used for debugging purposes
int bulk_read;
int bulk_read_buf_size;
int bulk_read;
int bulk_read_buf_size;
atomic_long_t dirty_pg_cnt;
atomic_long_t dirty_zn_cnt;
atomic_long_t clean_zn_cnt;
atomic_long_t dirty_pg_cnt;
atomic_long_t dirty_zn_cnt;
atomic_long_t clean_zn_cnt;
struct ubifs_mst_node *rcvrd_mst_node;
struct rb_root size_tree;
int remounting_rw;
struct ubifs_mst_node *rcvrd_mst_node;
struct rb_root size_tree;
int remounting_rw;
struct ubifs_mount_opts mount_opts;
#ifdef CONFIG_UBIFS_FS_DEBUG
struct ubifs_mount_opts mount_opts;
#ifdef CONFIG_UBIFS_FS_DEBUG
int ubifs_write_node(struct ubifs_info *c, void *node, int len, int lnum,
int offs, int dtype);
int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
int ubifs_write_node(struct ubifs_info *c, void *node, int len, int lnum,
int offs, int dtype);
int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
+ int offs, int quiet, int chk_crc);
void ubifs_prepare_node(struct ubifs_info *c, void *buf, int len, int pad);
void ubifs_prep_grp_node(struct ubifs_info *c, void *node, int len, int last);
int ubifs_io_init(struct ubifs_info *c);
void ubifs_prepare_node(struct ubifs_info *c, void *buf, int len, int pad);
void ubifs_prep_grp_node(struct ubifs_info *c, void *node, int len, int last);
int ubifs_io_init(struct ubifs_info *c);