Commit e8183c24 authored by Tomas Janousek's avatar Tomas Janousek Committed by Jan Kara

udf: Fix regression in UDF anchor block detection

In some cases it could happen that some block passed test in
udf_check_anchor_block() even though udf_read_tagged() refused to read it later
(e.g. because checksum was not correct).  This patch makes
udf_check_anchor_block() use udf_read_tagged() so that the checking is
stricter.

This fixes the regression (certain disks unmountable) caused by commit
423cf6dc.
Signed-off-by: default avatarTomas Janousek <tomi@nomi.cz>
Signed-off-by: default avatarJan Kara <jack@suse.cz>
parent e4f3ec06
...@@ -682,38 +682,26 @@ static int udf_vrs(struct super_block *sb, int silent) ...@@ -682,38 +682,26 @@ static int udf_vrs(struct super_block *sb, int silent)
/* /*
* Check whether there is an anchor block in the given block * Check whether there is an anchor block in the given block
*/ */
static int udf_check_anchor_block(struct super_block *sb, sector_t block, static int udf_check_anchor_block(struct super_block *sb, sector_t block)
bool varconv)
{ {
struct buffer_head *bh = NULL; struct buffer_head *bh;
tag *t;
uint16_t ident; uint16_t ident;
uint32_t location;
if (varconv) { if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV) &&
if (udf_fixed_to_variable(block) >= udf_fixed_to_variable(block) >=
sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits) sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits)
return 0; return 0;
bh = sb_bread(sb, udf_fixed_to_variable(block));
}
else
bh = sb_bread(sb, block);
bh = udf_read_tagged(sb, block, block, &ident);
if (!bh) if (!bh)
return 0; return 0;
t = (tag *)bh->b_data;
ident = le16_to_cpu(t->tagIdent);
location = le32_to_cpu(t->tagLocation);
brelse(bh); brelse(bh);
if (ident != TAG_IDENT_AVDP)
return 0; return ident == TAG_IDENT_AVDP;
return location == block;
} }
/* Search for an anchor volume descriptor pointer */ /* Search for an anchor volume descriptor pointer */
static sector_t udf_scan_anchors(struct super_block *sb, bool varconv, static sector_t udf_scan_anchors(struct super_block *sb, sector_t lastblock)
sector_t lastblock)
{ {
sector_t last[6]; sector_t last[6];
int i; int i;
...@@ -739,7 +727,7 @@ static sector_t udf_scan_anchors(struct super_block *sb, bool varconv, ...@@ -739,7 +727,7 @@ static sector_t udf_scan_anchors(struct super_block *sb, bool varconv,
sb->s_blocksize_bits) sb->s_blocksize_bits)
continue; continue;
if (udf_check_anchor_block(sb, last[i], varconv)) { if (udf_check_anchor_block(sb, last[i])) {
sbi->s_anchor[0] = last[i]; sbi->s_anchor[0] = last[i];
sbi->s_anchor[1] = last[i] - 256; sbi->s_anchor[1] = last[i] - 256;
return last[i]; return last[i];
...@@ -748,17 +736,17 @@ static sector_t udf_scan_anchors(struct super_block *sb, bool varconv, ...@@ -748,17 +736,17 @@ static sector_t udf_scan_anchors(struct super_block *sb, bool varconv,
if (last[i] < 256) if (last[i] < 256)
continue; continue;
if (udf_check_anchor_block(sb, last[i] - 256, varconv)) { if (udf_check_anchor_block(sb, last[i] - 256)) {
sbi->s_anchor[1] = last[i] - 256; sbi->s_anchor[1] = last[i] - 256;
return last[i]; return last[i];
} }
} }
if (udf_check_anchor_block(sb, sbi->s_session + 256, varconv)) { if (udf_check_anchor_block(sb, sbi->s_session + 256)) {
sbi->s_anchor[0] = sbi->s_session + 256; sbi->s_anchor[0] = sbi->s_session + 256;
return last[0]; return last[0];
} }
if (udf_check_anchor_block(sb, sbi->s_session + 512, varconv)) { if (udf_check_anchor_block(sb, sbi->s_session + 512)) {
sbi->s_anchor[0] = sbi->s_session + 512; sbi->s_anchor[0] = sbi->s_session + 512;
return last[0]; return last[0];
} }
...@@ -780,23 +768,24 @@ static void udf_find_anchor(struct super_block *sb) ...@@ -780,23 +768,24 @@ static void udf_find_anchor(struct super_block *sb)
int i; int i;
struct udf_sb_info *sbi = UDF_SB(sb); struct udf_sb_info *sbi = UDF_SB(sb);
lastblock = udf_scan_anchors(sb, 0, sbi->s_last_block); lastblock = udf_scan_anchors(sb, sbi->s_last_block);
if (lastblock) if (lastblock)
goto check_anchor; goto check_anchor;
/* No anchor found? Try VARCONV conversion of block numbers */ /* No anchor found? Try VARCONV conversion of block numbers */
UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
/* Firstly, we try to not convert number of the last block */ /* Firstly, we try to not convert number of the last block */
lastblock = udf_scan_anchors(sb, 1, lastblock = udf_scan_anchors(sb,
udf_variable_to_fixed(sbi->s_last_block)); udf_variable_to_fixed(sbi->s_last_block));
if (lastblock) { if (lastblock)
UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
goto check_anchor; goto check_anchor;
}
/* Secondly, we try with converted number of the last block */ /* Secondly, we try with converted number of the last block */
lastblock = udf_scan_anchors(sb, 1, sbi->s_last_block); lastblock = udf_scan_anchors(sb, sbi->s_last_block);
if (lastblock) if (!lastblock) {
UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); /* VARCONV didn't help. Clear it. */
UDF_CLEAR_FLAG(sb, UDF_FLAG_VARCONV);
}
check_anchor: check_anchor:
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment