UBIFS: fix no_chk_data_crc
When data CRC checking is disabled, UBIFS returns incorrect return code from the 'try_read_node()' function (0 instead of 1, which means CRC error), which make the caller re-read the data node again, but using a different code patch, so the second read is fine. Thus, we read the same node twice. And the result of this is that UBIFS is slower with no_chk_data_crc option than it is with chk_data_crc option. This patches fixes the problem. Reported-by: Reuben Dowle <Reuben.Dowle@navico.com> Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
This commit is contained in:
@@ -29,7 +29,7 @@
|
|||||||
* would have been wasted for padding to the nearest minimal I/O unit boundary.
|
* would have been wasted for padding to the nearest minimal I/O unit boundary.
|
||||||
* Instead, data first goes to the write-buffer and is flushed when the
|
* Instead, data first goes to the write-buffer and is flushed when the
|
||||||
* buffer is full or when it is not used for some time (by timer). This is
|
* buffer is full or when it is not used for some time (by timer). This is
|
||||||
* similarto the mechanism is used by JFFS2.
|
* similar to the mechanism is used by JFFS2.
|
||||||
*
|
*
|
||||||
* Write-buffers are defined by 'struct ubifs_wbuf' objects and protected by
|
* Write-buffers are defined by 'struct ubifs_wbuf' objects and protected by
|
||||||
* mutexes defined inside these objects. Since sometimes upper-level code
|
* mutexes defined inside these objects. Since sometimes upper-level code
|
||||||
@@ -75,7 +75,7 @@ void ubifs_ro_mode(struct ubifs_info *c, int err)
|
|||||||
* @lnum: logical eraseblock number
|
* @lnum: logical eraseblock number
|
||||||
* @offs: offset within the logical eraseblock
|
* @offs: offset within the logical eraseblock
|
||||||
* @quiet: print no messages
|
* @quiet: print no messages
|
||||||
* @chk_crc: indicates whether to always check the CRC
|
* @must_chk_crc: indicates whether to always check the CRC
|
||||||
*
|
*
|
||||||
* This function checks node magic number and CRC checksum. This function also
|
* This function checks node magic number and CRC checksum. This function also
|
||||||
* validates node length to prevent UBIFS from becoming crazy when an attacker
|
* validates node length to prevent UBIFS from becoming crazy when an attacker
|
||||||
@@ -83,11 +83,17 @@ void ubifs_ro_mode(struct ubifs_info *c, int err)
|
|||||||
* node length in the common header could cause UBIFS to read memory outside of
|
* node length in the common header could cause UBIFS to read memory outside of
|
||||||
* allocated buffer when checking the CRC checksum.
|
* allocated buffer when checking the CRC checksum.
|
||||||
*
|
*
|
||||||
* This function returns zero in case of success %-EUCLEAN in case of bad CRC
|
* This function may skip data nodes CRC checking if @c->no_chk_data_crc is
|
||||||
* or magic.
|
* true, which is controlled by corresponding UBIFS mount option. However, if
|
||||||
|
* @must_chk_crc is true, then @c->no_chk_data_crc is ignored and CRC is
|
||||||
|
* checked. Similarly, if @c->always_chk_crc is true, @c->no_chk_data_crc is
|
||||||
|
* ignored and CRC is checked.
|
||||||
|
*
|
||||||
|
* This function returns zero in case of success and %-EUCLEAN in case of bad
|
||||||
|
* CRC or magic.
|
||||||
*/
|
*/
|
||||||
int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
|
int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
|
||||||
int offs, int quiet, int chk_crc)
|
int offs, int quiet, int must_chk_crc)
|
||||||
{
|
{
|
||||||
int err = -EINVAL, type, node_len;
|
int err = -EINVAL, type, node_len;
|
||||||
uint32_t crc, node_crc, magic;
|
uint32_t crc, node_crc, magic;
|
||||||
@@ -123,9 +129,9 @@ int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
|
|||||||
node_len > c->ranges[type].max_len)
|
node_len > c->ranges[type].max_len)
|
||||||
goto out_len;
|
goto out_len;
|
||||||
|
|
||||||
if (!chk_crc && type == UBIFS_DATA_NODE && !c->always_chk_crc)
|
if (!must_chk_crc && type == UBIFS_DATA_NODE && !c->always_chk_crc &&
|
||||||
if (c->no_chk_data_crc)
|
c->no_chk_data_crc)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
|
crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
|
||||||
node_crc = le32_to_cpu(ch->crc);
|
node_crc = le32_to_cpu(ch->crc);
|
||||||
|
@@ -443,6 +443,11 @@ static int tnc_read_node_nm(struct ubifs_info *c, struct ubifs_zbranch *zbr,
|
|||||||
* This function performs that same function as ubifs_read_node except that
|
* This function performs that same function as ubifs_read_node except that
|
||||||
* it does not require that there is actually a node present and instead
|
* it does not require that there is actually a node present and instead
|
||||||
* the return code indicates if a node was read.
|
* the return code indicates if a node was read.
|
||||||
|
*
|
||||||
|
* Note, this function does not check CRC of data nodes if @c->no_chk_data_crc
|
||||||
|
* is true (it is controlled by corresponding mount option). However, if
|
||||||
|
* @c->always_chk_crc is true, @c->no_chk_data_crc is ignored and CRC is always
|
||||||
|
* checked.
|
||||||
*/
|
*/
|
||||||
static int try_read_node(const struct ubifs_info *c, void *buf, int type,
|
static int try_read_node(const struct ubifs_info *c, void *buf, int type,
|
||||||
int len, int lnum, int offs)
|
int len, int lnum, int offs)
|
||||||
@@ -470,9 +475,8 @@ static int try_read_node(const struct ubifs_info *c, void *buf, int type,
|
|||||||
if (node_len != len)
|
if (node_len != len)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (type == UBIFS_DATA_NODE && !c->always_chk_crc)
|
if (type == UBIFS_DATA_NODE && !c->always_chk_crc && c->no_chk_data_crc)
|
||||||
if (c->no_chk_data_crc)
|
return 1;
|
||||||
return 0;
|
|
||||||
|
|
||||||
crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
|
crc = crc32(UBIFS_CRC32_INIT, buf + 8, node_len - 8);
|
||||||
node_crc = le32_to_cpu(ch->crc);
|
node_crc = le32_to_cpu(ch->crc);
|
||||||
@@ -1506,7 +1510,7 @@ out:
|
|||||||
*
|
*
|
||||||
* Note, if the bulk-read buffer length (@bu->buf_len) is known, this function
|
* Note, if the bulk-read buffer length (@bu->buf_len) is known, this function
|
||||||
* makes sure bulk-read nodes fit the buffer. Otherwise, this function prepares
|
* makes sure bulk-read nodes fit the buffer. Otherwise, this function prepares
|
||||||
* maxumum possible amount of nodes for bulk-read.
|
* maximum possible amount of nodes for bulk-read.
|
||||||
*/
|
*/
|
||||||
int ubifs_tnc_get_bu_keys(struct ubifs_info *c, struct bu_info *bu)
|
int ubifs_tnc_get_bu_keys(struct ubifs_info *c, struct bu_info *bu)
|
||||||
{
|
{
|
||||||
|
@@ -1428,7 +1428,7 @@ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
|
|||||||
int ubifs_write_node(struct ubifs_info *c, void *node, int len, int lnum,
|
int ubifs_write_node(struct ubifs_info *c, void *node, int len, int lnum,
|
||||||
int offs, int dtype);
|
int offs, int dtype);
|
||||||
int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
|
int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
|
||||||
int offs, int quiet, int chk_crc);
|
int offs, int quiet, int must_chk_crc);
|
||||||
void ubifs_prepare_node(struct ubifs_info *c, void *buf, int len, int pad);
|
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);
|
void ubifs_prep_grp_node(struct ubifs_info *c, void *node, int len, int last);
|
||||||
int ubifs_io_init(struct ubifs_info *c);
|
int ubifs_io_init(struct ubifs_info *c);
|
||||||
|
Reference in New Issue
Block a user