diff options
| -rw-r--r-- | Documentation/filesystems/ubifs.txt | 6 | ||||
| -rw-r--r-- | fs/ubifs/io.c | 11 | ||||
| -rw-r--r-- | fs/ubifs/scan.c | 2 | ||||
| -rw-r--r-- | fs/ubifs/super.c | 34 | ||||
| -rw-r--r-- | fs/ubifs/tnc.c | 6 | ||||
| -rw-r--r-- | fs/ubifs/ubifs.h | 11 |
6 files changed, 61 insertions, 9 deletions
diff --git a/Documentation/filesystems/ubifs.txt b/Documentation/filesystems/ubifs.txt index 340512c32506..dd84ea3c10da 100644 --- a/Documentation/filesystems/ubifs.txt +++ b/Documentation/filesystems/ubifs.txt | |||
| @@ -89,6 +89,12 @@ fast_unmount do not commit on unmount; this option makes | |||
| 89 | bulk_read read more in one go to take advantage of flash | 89 | bulk_read read more in one go to take advantage of flash |
| 90 | media that read faster sequentially | 90 | media that read faster sequentially |
| 91 | no_bulk_read (*) do not bulk-read | 91 | no_bulk_read (*) do not bulk-read |
| 92 | no_chk_data_crc skip checking of CRCs on data nodes in order to | ||
| 93 | improve read performance. Use this option only | ||
| 94 | if the flash media is highly reliable. The effect | ||
| 95 | of this option is that corruption of the contents | ||
| 96 | of a file can go unnoticed. | ||
| 97 | chk_data_crc (*) do not skip checking CRCs on data nodes | ||
| 92 | 98 | ||
| 93 | 99 | ||
| 94 | Quick usage instructions | 100 | Quick usage instructions |
diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c index 054363f2b207..40e2790b62ce 100644 --- a/fs/ubifs/io.c +++ b/fs/ubifs/io.c | |||
| @@ -74,6 +74,7 @@ void ubifs_ro_mode(struct ubifs_info *c, int err) | |||
| 74 | * @lnum: logical eraseblock number | 74 | * @lnum: logical eraseblock number |
| 75 | * @offs: offset within the logical eraseblock | 75 | * @offs: offset within the logical eraseblock |
| 76 | * @quiet: print no messages | 76 | * @quiet: print no messages |
| 77 | * @chk_crc: indicates whether to always check the CRC | ||
| 77 | * | 78 | * |
| 78 | * This function checks node magic number and CRC checksum. This function also | 79 | * This function checks node magic number and CRC checksum. This function also |
| 79 | * validates node length to prevent UBIFS from becoming crazy when an attacker | 80 | * 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) | |||
| 85 | * or magic. | 86 | * or magic. |
| 86 | */ | 87 | */ |
| 87 | int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum, | 88 | int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum, |
| 88 | int offs, int quiet) | 89 | int offs, int quiet, int chk_crc) |
| 89 | { | 90 | { |
| 90 | int err = -EINVAL, type, node_len; | 91 | int err = -EINVAL, type, node_len; |
| 91 | uint32_t crc, node_crc, magic; | 92 | uint32_t crc, node_crc, magic; |
| @@ -121,6 +122,10 @@ int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum, | |||
| 121 | node_len > c->ranges[type].max_len) | 122 | node_len > c->ranges[type].max_len) |
| 122 | goto out_len; | 123 | goto out_len; |
| 123 | 124 | ||
| 125 | if (!chk_crc && type == UBIFS_DATA_NODE && !c->always_chk_crc) | ||
| 126 | if (c->no_chk_data_crc) | ||
| 127 | return 0; | ||
| 128 | |||
| 124 | crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8); | 129 | crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8); |
| 125 | node_crc = le32_to_cpu(ch->crc); | 130 | node_crc = le32_to_cpu(ch->crc); |
| 126 | if (crc != node_crc) { | 131 | if (crc != node_crc) { |
| @@ -722,7 +727,7 @@ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len, | |||
| 722 | goto out; | 727 | goto out; |
| 723 | } | 728 | } |
| 724 | 729 | ||
| 725 | err = ubifs_check_node(c, buf, lnum, offs, 0); | 730 | err = ubifs_check_node(c, buf, lnum, offs, 0, 0); |
| 726 | if (err) { | 731 | if (err) { |
| 727 | ubifs_err("expected node type %d", type); | 732 | ubifs_err("expected node type %d", type); |
| 728 | return err; | 733 | return err; |
| @@ -781,7 +786,7 @@ int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len, | |||
| 781 | goto out; | 786 | goto out; |
| 782 | } | 787 | } |
| 783 | 788 | ||
| 784 | err = ubifs_check_node(c, buf, lnum, offs, 0); | 789 | err = ubifs_check_node(c, buf, lnum, offs, 0, 0); |
| 785 | if (err) { | 790 | if (err) { |
| 786 | ubifs_err("expected node type %d", type); | 791 | ubifs_err("expected node type %d", type); |
| 787 | return err; | 792 | return err; |
diff --git a/fs/ubifs/scan.c b/fs/ubifs/scan.c index acf5c5fffc60..0ed82479b44b 100644 --- a/fs/ubifs/scan.c +++ b/fs/ubifs/scan.c | |||
| @@ -87,7 +87,7 @@ int ubifs_scan_a_node(const struct ubifs_info *c, void *buf, int len, int lnum, | |||
| 87 | 87 | ||
| 88 | dbg_scan("scanning %s", dbg_ntype(ch->node_type)); | 88 | dbg_scan("scanning %s", dbg_ntype(ch->node_type)); |
| 89 | 89 | ||
| 90 | if (ubifs_check_node(c, buf, lnum, offs, quiet)) | 90 | if (ubifs_check_node(c, buf, lnum, offs, quiet, 1)) |
| 91 | return SCANNED_A_CORRUPT_NODE; | 91 | return SCANNED_A_CORRUPT_NODE; |
| 92 | 92 | ||
| 93 | if (ch->node_type == UBIFS_PAD_NODE) { | 93 | if (ch->node_type == UBIFS_PAD_NODE) { |
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index b1c57e8ee855..cf078b5cc88c 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c | |||
| @@ -406,6 +406,11 @@ static int ubifs_show_options(struct seq_file *s, struct vfsmount *mnt) | |||
| 406 | else if (c->mount_opts.bulk_read == 1) | 406 | else if (c->mount_opts.bulk_read == 1) |
| 407 | seq_printf(s, ",no_bulk_read"); | 407 | seq_printf(s, ",no_bulk_read"); |
| 408 | 408 | ||
| 409 | if (c->mount_opts.chk_data_crc == 2) | ||
| 410 | seq_printf(s, ",chk_data_crc"); | ||
| 411 | else if (c->mount_opts.chk_data_crc == 1) | ||
| 412 | seq_printf(s, ",no_chk_data_crc"); | ||
| 413 | |||
| 409 | return 0; | 414 | return 0; |
| 410 | } | 415 | } |
| 411 | 416 | ||
| @@ -859,6 +864,8 @@ static int check_volume_empty(struct ubifs_info *c) | |||
| 859 | * Opt_norm_unmount: run a journal commit before un-mounting | 864 | * Opt_norm_unmount: run a journal commit before un-mounting |
| 860 | * Opt_bulk_read: enable bulk-reads | 865 | * Opt_bulk_read: enable bulk-reads |
| 861 | * Opt_no_bulk_read: disable bulk-reads | 866 | * Opt_no_bulk_read: disable bulk-reads |
| 867 | * Opt_chk_data_crc: check CRCs when reading data nodes | ||
| 868 | * Opt_no_chk_data_crc: do not check CRCs when reading data nodes | ||
| 862 | * Opt_err: just end of array marker | 869 | * Opt_err: just end of array marker |
| 863 | */ | 870 | */ |
| 864 | enum { | 871 | enum { |
| @@ -866,6 +873,8 @@ enum { | |||
| 866 | Opt_norm_unmount, | 873 | Opt_norm_unmount, |
| 867 | Opt_bulk_read, | 874 | Opt_bulk_read, |
| 868 | Opt_no_bulk_read, | 875 | Opt_no_bulk_read, |
| 876 | Opt_chk_data_crc, | ||
| 877 | Opt_no_chk_data_crc, | ||
| 869 | Opt_err, | 878 | Opt_err, |
| 870 | }; | 879 | }; |
| 871 | 880 | ||
| @@ -874,6 +883,8 @@ static match_table_t tokens = { | |||
| 874 | {Opt_norm_unmount, "norm_unmount"}, | 883 | {Opt_norm_unmount, "norm_unmount"}, |
| 875 | {Opt_bulk_read, "bulk_read"}, | 884 | {Opt_bulk_read, "bulk_read"}, |
| 876 | {Opt_no_bulk_read, "no_bulk_read"}, | 885 | {Opt_no_bulk_read, "no_bulk_read"}, |
| 886 | {Opt_chk_data_crc, "chk_data_crc"}, | ||
| 887 | {Opt_no_chk_data_crc, "no_chk_data_crc"}, | ||
| 877 | {Opt_err, NULL}, | 888 | {Opt_err, NULL}, |
| 878 | }; | 889 | }; |
| 879 | 890 | ||
| @@ -919,6 +930,14 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options, | |||
| 919 | c->mount_opts.bulk_read = 1; | 930 | c->mount_opts.bulk_read = 1; |
| 920 | c->bulk_read = 0; | 931 | c->bulk_read = 0; |
| 921 | break; | 932 | break; |
| 933 | case Opt_chk_data_crc: | ||
| 934 | c->mount_opts.chk_data_crc = 2; | ||
| 935 | c->no_chk_data_crc = 0; | ||
| 936 | break; | ||
| 937 | case Opt_no_chk_data_crc: | ||
| 938 | c->mount_opts.chk_data_crc = 1; | ||
| 939 | c->no_chk_data_crc = 1; | ||
| 940 | break; | ||
| 922 | default: | 941 | default: |
| 923 | ubifs_err("unrecognized mount option \"%s\" " | 942 | ubifs_err("unrecognized mount option \"%s\" " |
| 924 | "or missing value", p); | 943 | "or missing value", p); |
| @@ -1027,6 +1046,8 @@ static int mount_ubifs(struct ubifs_info *c) | |||
| 1027 | goto out_free; | 1046 | goto out_free; |
| 1028 | } | 1047 | } |
| 1029 | 1048 | ||
| 1049 | c->always_chk_crc = 1; | ||
| 1050 | |||
| 1030 | err = ubifs_read_superblock(c); | 1051 | err = ubifs_read_superblock(c); |
| 1031 | if (err) | 1052 | if (err) |
| 1032 | goto out_free; | 1053 | goto out_free; |
| @@ -1168,6 +1189,8 @@ static int mount_ubifs(struct ubifs_info *c) | |||
| 1168 | if (err) | 1189 | if (err) |
| 1169 | goto out_infos; | 1190 | goto out_infos; |
| 1170 | 1191 | ||
| 1192 | c->always_chk_crc = 0; | ||
| 1193 | |||
| 1171 | ubifs_msg("mounted UBI device %d, volume %d, name \"%s\"", | 1194 | ubifs_msg("mounted UBI device %d, volume %d, name \"%s\"", |
| 1172 | c->vi.ubi_num, c->vi.vol_id, c->vi.name); | 1195 | c->vi.ubi_num, c->vi.vol_id, c->vi.name); |
| 1173 | if (mounted_read_only) | 1196 | if (mounted_read_only) |
| @@ -1313,6 +1336,7 @@ static int ubifs_remount_rw(struct ubifs_info *c) | |||
| 1313 | 1336 | ||
| 1314 | mutex_lock(&c->umount_mutex); | 1337 | mutex_lock(&c->umount_mutex); |
| 1315 | c->remounting_rw = 1; | 1338 | c->remounting_rw = 1; |
| 1339 | c->always_chk_crc = 1; | ||
| 1316 | 1340 | ||
| 1317 | /* Check for enough free space */ | 1341 | /* Check for enough free space */ |
| 1318 | if (ubifs_calc_available(c, c->min_idx_lebs) <= 0) { | 1342 | if (ubifs_calc_available(c, c->min_idx_lebs) <= 0) { |
| @@ -1381,13 +1405,15 @@ static int ubifs_remount_rw(struct ubifs_info *c) | |||
| 1381 | c->bgt = NULL; | 1405 | c->bgt = NULL; |
| 1382 | ubifs_err("cannot spawn \"%s\", error %d", | 1406 | ubifs_err("cannot spawn \"%s\", error %d", |
| 1383 | c->bgt_name, err); | 1407 | c->bgt_name, err); |
| 1384 | return err; | 1408 | goto out; |
| 1385 | } | 1409 | } |
| 1386 | wake_up_process(c->bgt); | 1410 | wake_up_process(c->bgt); |
| 1387 | 1411 | ||
| 1388 | c->orph_buf = vmalloc(c->leb_size); | 1412 | c->orph_buf = vmalloc(c->leb_size); |
| 1389 | if (!c->orph_buf) | 1413 | if (!c->orph_buf) { |
| 1390 | return -ENOMEM; | 1414 | err = -ENOMEM; |
| 1415 | goto out; | ||
| 1416 | } | ||
| 1391 | 1417 | ||
| 1392 | /* Check for enough log space */ | 1418 | /* Check for enough log space */ |
| 1393 | lnum = c->lhead_lnum + 1; | 1419 | lnum = c->lhead_lnum + 1; |
| @@ -1414,6 +1440,7 @@ static int ubifs_remount_rw(struct ubifs_info *c) | |||
| 1414 | dbg_gen("re-mounted read-write"); | 1440 | dbg_gen("re-mounted read-write"); |
| 1415 | c->vfs_sb->s_flags &= ~MS_RDONLY; | 1441 | c->vfs_sb->s_flags &= ~MS_RDONLY; |
| 1416 | c->remounting_rw = 0; | 1442 | c->remounting_rw = 0; |
| 1443 | c->always_chk_crc = 0; | ||
| 1417 | mutex_unlock(&c->umount_mutex); | 1444 | mutex_unlock(&c->umount_mutex); |
| 1418 | return 0; | 1445 | return 0; |
| 1419 | 1446 | ||
| @@ -1429,6 +1456,7 @@ out: | |||
| 1429 | c->ileb_buf = NULL; | 1456 | c->ileb_buf = NULL; |
| 1430 | ubifs_lpt_free(c, 1); | 1457 | ubifs_lpt_free(c, 1); |
| 1431 | c->remounting_rw = 0; | 1458 | c->remounting_rw = 0; |
| 1459 | c->always_chk_crc = 0; | ||
| 1432 | mutex_unlock(&c->umount_mutex); | 1460 | mutex_unlock(&c->umount_mutex); |
| 1433 | return err; | 1461 | return err; |
| 1434 | } | 1462 | } |
diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c index d279012d8dd5..66dc57100bdf 100644 --- a/fs/ubifs/tnc.c +++ b/fs/ubifs/tnc.c | |||
| @@ -470,6 +470,10 @@ static int try_read_node(const struct ubifs_info *c, void *buf, int type, | |||
| 470 | if (node_len != len) | 470 | if (node_len != len) |
| 471 | return 0; | 471 | return 0; |
| 472 | 472 | ||
| 473 | if (type == UBIFS_DATA_NODE && !c->always_chk_crc) | ||
| 474 | if (c->no_chk_data_crc) | ||
| 475 | return 0; | ||
| 476 | |||
| 473 | crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8); | 477 | crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8); |
| 474 | node_crc = le32_to_cpu(ch->crc); | 478 | node_crc = le32_to_cpu(ch->crc); |
| 475 | if (crc != node_crc) | 479 | if (crc != node_crc) |
| @@ -1687,7 +1691,7 @@ static int validate_data_node(struct ubifs_info *c, void *buf, | |||
| 1687 | goto out_err; | 1691 | goto out_err; |
| 1688 | } | 1692 | } |
| 1689 | 1693 | ||
| 1690 | err = ubifs_check_node(c, buf, zbr->lnum, zbr->offs, 0); | 1694 | err = ubifs_check_node(c, buf, zbr->lnum, zbr->offs, 0, 0); |
| 1691 | if (err) { | 1695 | if (err) { |
| 1692 | ubifs_err("expected node type %d", UBIFS_DATA_NODE); | 1696 | ubifs_err("expected node type %d", UBIFS_DATA_NODE); |
| 1693 | goto out; | 1697 | goto out; |
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index 8513239ea8a0..d6ae3f7b2b05 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h | |||
| @@ -894,10 +894,12 @@ struct ubifs_orphan { | |||
| 894 | * struct ubifs_mount_opts - UBIFS-specific mount options information. | 894 | * struct ubifs_mount_opts - UBIFS-specific mount options information. |
| 895 | * @unmount_mode: selected unmount mode (%0 default, %1 normal, %2 fast) | 895 | * @unmount_mode: selected unmount mode (%0 default, %1 normal, %2 fast) |
| 896 | * @bulk_read: enable bulk-reads | 896 | * @bulk_read: enable bulk-reads |
| 897 | * @chk_data_crc: check CRCs when reading data nodes | ||
| 897 | */ | 898 | */ |
| 898 | struct ubifs_mount_opts { | 899 | struct ubifs_mount_opts { |
| 899 | unsigned int unmount_mode:2; | 900 | unsigned int unmount_mode:2; |
| 900 | unsigned int bulk_read:2; | 901 | unsigned int bulk_read:2; |
| 902 | unsigned int chk_data_crc:2; | ||
| 901 | }; | 903 | }; |
| 902 | 904 | ||
| 903 | /** | 905 | /** |
| @@ -1001,6 +1003,9 @@ struct ubifs_mount_opts { | |||
| 1001 | * @bulk_read: enable bulk-reads | 1003 | * @bulk_read: enable bulk-reads |
| 1002 | * @bulk_read_buf_size: buffer size for bulk-reads | 1004 | * @bulk_read_buf_size: buffer size for bulk-reads |
| 1003 | * | 1005 | * |
| 1006 | * @no_chk_data_crc: do not check CRCs when reading data nodes (except during | ||
| 1007 | * recovery) | ||
| 1008 | * | ||
| 1004 | * @dirty_pg_cnt: number of dirty pages (not used) | 1009 | * @dirty_pg_cnt: number of dirty pages (not used) |
| 1005 | * @dirty_zn_cnt: number of dirty znodes | 1010 | * @dirty_zn_cnt: number of dirty znodes |
| 1006 | * @clean_zn_cnt: number of clean znodes | 1011 | * @clean_zn_cnt: number of clean znodes |
| @@ -1138,6 +1143,7 @@ struct ubifs_mount_opts { | |||
| 1138 | * @rcvrd_mst_node: recovered master node to write when mounting ro to rw | 1143 | * @rcvrd_mst_node: recovered master node to write when mounting ro to rw |
| 1139 | * @size_tree: inode size information for recovery | 1144 | * @size_tree: inode size information for recovery |
| 1140 | * @remounting_rw: set while remounting from ro to rw (sb flags have MS_RDONLY) | 1145 | * @remounting_rw: set while remounting from ro to rw (sb flags have MS_RDONLY) |
| 1146 | * @always_chk_crc: always check CRCs (while mounting and remounting rw) | ||
| 1141 | * @mount_opts: UBIFS-specific mount options | 1147 | * @mount_opts: UBIFS-specific mount options |
| 1142 | * | 1148 | * |
| 1143 | * @dbg_buf: a buffer of LEB size used for debugging purposes | 1149 | * @dbg_buf: a buffer of LEB size used for debugging purposes |
| @@ -1244,6 +1250,8 @@ struct ubifs_info { | |||
| 1244 | int bulk_read; | 1250 | int bulk_read; |
| 1245 | int bulk_read_buf_size; | 1251 | int bulk_read_buf_size; |
| 1246 | 1252 | ||
| 1253 | int no_chk_data_crc; | ||
| 1254 | |||
| 1247 | atomic_long_t dirty_pg_cnt; | 1255 | atomic_long_t dirty_pg_cnt; |
| 1248 | atomic_long_t dirty_zn_cnt; | 1256 | atomic_long_t dirty_zn_cnt; |
| 1249 | atomic_long_t clean_zn_cnt; | 1257 | atomic_long_t clean_zn_cnt; |
| @@ -1374,6 +1382,7 @@ struct ubifs_info { | |||
| 1374 | struct ubifs_mst_node *rcvrd_mst_node; | 1382 | struct ubifs_mst_node *rcvrd_mst_node; |
| 1375 | struct rb_root size_tree; | 1383 | struct rb_root size_tree; |
| 1376 | int remounting_rw; | 1384 | int remounting_rw; |
| 1385 | int always_chk_crc; | ||
| 1377 | struct ubifs_mount_opts mount_opts; | 1386 | struct ubifs_mount_opts mount_opts; |
| 1378 | 1387 | ||
| 1379 | #ifdef CONFIG_UBIFS_FS_DEBUG | 1388 | #ifdef CONFIG_UBIFS_FS_DEBUG |
| @@ -1416,7 +1425,7 @@ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len, | |||
| 1416 | int ubifs_write_node(struct ubifs_info *c, void *node, int len, int lnum, | 1425 | int ubifs_write_node(struct ubifs_info *c, void *node, int len, int lnum, |
| 1417 | int offs, int dtype); | 1426 | int offs, int dtype); |
| 1418 | int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum, | 1427 | int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum, |
| 1419 | int offs, int quiet); | 1428 | int offs, int quiet, int chk_crc); |
| 1420 | void ubifs_prepare_node(struct ubifs_info *c, void *buf, int len, int pad); | 1429 | void ubifs_prepare_node(struct ubifs_info *c, void *buf, int len, int pad); |
| 1421 | void ubifs_prep_grp_node(struct ubifs_info *c, void *node, int len, int last); | 1430 | void ubifs_prep_grp_node(struct ubifs_info *c, void *node, int len, int last); |
| 1422 | int ubifs_io_init(struct ubifs_info *c); | 1431 | int ubifs_io_init(struct ubifs_info *c); |
