Commit 66ccf961 authored by Jan Kara's avatar Jan Kara Committed by Greg Kroah-Hartman

udf: Standardize return values in mount sequence

commit d759bfa4 upstream.

Change all function used in filesystem discovery during mount to user
standard kernel return values - -errno on error, 0 on success instead
of 1 on failure and 0 on success. This allows us to pass error number
(not just failure / success) so we can abort device scanning earlier
in case of errors like EIO or ENOMEM . Also we will be able to return
EROFS in case writeable mount is requested but writing isn't supported.
Signed-off-by: default avatarJan Kara <jack@suse.cz>
Cc: Hui Wang <hui.wang@canonical.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 7b7b9915
...@@ -843,27 +843,38 @@ static int udf_find_fileset(struct super_block *sb, ...@@ -843,27 +843,38 @@ static int udf_find_fileset(struct super_block *sb,
return 1; return 1;
} }
/*
* Load primary Volume Descriptor Sequence
*
* Return <0 on error, 0 on success. -EAGAIN is special meaning next sequence
* should be tried.
*/
static int udf_load_pvoldesc(struct super_block *sb, sector_t block) static int udf_load_pvoldesc(struct super_block *sb, sector_t block)
{ {
struct primaryVolDesc *pvoldesc; struct primaryVolDesc *pvoldesc;
struct ustr *instr, *outstr; struct ustr *instr, *outstr;
struct buffer_head *bh; struct buffer_head *bh;
uint16_t ident; uint16_t ident;
int ret = 1; int ret = -ENOMEM;
instr = kmalloc(sizeof(struct ustr), GFP_NOFS); instr = kmalloc(sizeof(struct ustr), GFP_NOFS);
if (!instr) if (!instr)
return 1; return -ENOMEM;
outstr = kmalloc(sizeof(struct ustr), GFP_NOFS); outstr = kmalloc(sizeof(struct ustr), GFP_NOFS);
if (!outstr) if (!outstr)
goto out1; goto out1;
bh = udf_read_tagged(sb, block, block, &ident); bh = udf_read_tagged(sb, block, block, &ident);
if (!bh) if (!bh) {
ret = -EAGAIN;
goto out2; goto out2;
}
BUG_ON(ident != TAG_IDENT_PVD); if (ident != TAG_IDENT_PVD) {
ret = -EIO;
goto out_bh;
}
pvoldesc = (struct primaryVolDesc *)bh->b_data; pvoldesc = (struct primaryVolDesc *)bh->b_data;
...@@ -889,8 +900,9 @@ static int udf_load_pvoldesc(struct super_block *sb, sector_t block) ...@@ -889,8 +900,9 @@ static int udf_load_pvoldesc(struct super_block *sb, sector_t block)
if (udf_CS0toUTF8(outstr, instr)) if (udf_CS0toUTF8(outstr, instr))
udf_debug("volSetIdent[] = '%s'\n", outstr->u_name); udf_debug("volSetIdent[] = '%s'\n", outstr->u_name);
brelse(bh);
ret = 0; ret = 0;
out_bh:
brelse(bh);
out2: out2:
kfree(outstr); kfree(outstr);
out1: out1:
...@@ -947,7 +959,7 @@ static int udf_load_metadata_files(struct super_block *sb, int partition) ...@@ -947,7 +959,7 @@ static int udf_load_metadata_files(struct super_block *sb, int partition)
if (mdata->s_mirror_fe == NULL) { if (mdata->s_mirror_fe == NULL) {
udf_err(sb, "Both metadata and mirror metadata inode efe can not found\n"); udf_err(sb, "Both metadata and mirror metadata inode efe can not found\n");
goto error_exit; return -EIO;
} }
} }
...@@ -964,23 +976,18 @@ static int udf_load_metadata_files(struct super_block *sb, int partition) ...@@ -964,23 +976,18 @@ static int udf_load_metadata_files(struct super_block *sb, int partition)
addr.logicalBlockNum, addr.partitionReferenceNum); addr.logicalBlockNum, addr.partitionReferenceNum);
mdata->s_bitmap_fe = udf_iget(sb, &addr); mdata->s_bitmap_fe = udf_iget(sb, &addr);
if (mdata->s_bitmap_fe == NULL) { if (mdata->s_bitmap_fe == NULL) {
if (sb->s_flags & MS_RDONLY) if (sb->s_flags & MS_RDONLY)
udf_warn(sb, "bitmap inode efe not found but it's ok since the disc is mounted read-only\n"); udf_warn(sb, "bitmap inode efe not found but it's ok since the disc is mounted read-only\n");
else { else {
udf_err(sb, "bitmap inode efe not found and attempted read-write mount\n"); udf_err(sb, "bitmap inode efe not found and attempted read-write mount\n");
goto error_exit; return -EIO;
} }
} }
} }
udf_debug("udf_load_metadata_files Ok\n"); udf_debug("udf_load_metadata_files Ok\n");
return 0; return 0;
error_exit:
return 1;
} }
static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh, static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh,
...@@ -1069,7 +1076,7 @@ static int udf_fill_partdesc_info(struct super_block *sb, ...@@ -1069,7 +1076,7 @@ static int udf_fill_partdesc_info(struct super_block *sb,
if (!map->s_uspace.s_table) { if (!map->s_uspace.s_table) {
udf_debug("cannot load unallocSpaceTable (part %d)\n", udf_debug("cannot load unallocSpaceTable (part %d)\n",
p_index); p_index);
return 1; return -EIO;
} }
map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_TABLE; map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_TABLE;
udf_debug("unallocSpaceTable (part %d) @ %ld\n", udf_debug("unallocSpaceTable (part %d) @ %ld\n",
...@@ -1079,7 +1086,7 @@ static int udf_fill_partdesc_info(struct super_block *sb, ...@@ -1079,7 +1086,7 @@ static int udf_fill_partdesc_info(struct super_block *sb,
if (phd->unallocSpaceBitmap.extLength) { if (phd->unallocSpaceBitmap.extLength) {
struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, p_index); struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, p_index);
if (!bitmap) if (!bitmap)
return 1; return -ENOMEM;
map->s_uspace.s_bitmap = bitmap; map->s_uspace.s_bitmap = bitmap;
bitmap->s_extPosition = le32_to_cpu( bitmap->s_extPosition = le32_to_cpu(
phd->unallocSpaceBitmap.extPosition); phd->unallocSpaceBitmap.extPosition);
...@@ -1102,7 +1109,7 @@ static int udf_fill_partdesc_info(struct super_block *sb, ...@@ -1102,7 +1109,7 @@ static int udf_fill_partdesc_info(struct super_block *sb,
if (!map->s_fspace.s_table) { if (!map->s_fspace.s_table) {
udf_debug("cannot load freedSpaceTable (part %d)\n", udf_debug("cannot load freedSpaceTable (part %d)\n",
p_index); p_index);
return 1; return -EIO;
} }
map->s_partition_flags |= UDF_PART_FLAG_FREED_TABLE; map->s_partition_flags |= UDF_PART_FLAG_FREED_TABLE;
...@@ -1113,7 +1120,7 @@ static int udf_fill_partdesc_info(struct super_block *sb, ...@@ -1113,7 +1120,7 @@ static int udf_fill_partdesc_info(struct super_block *sb,
if (phd->freedSpaceBitmap.extLength) { if (phd->freedSpaceBitmap.extLength) {
struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, p_index); struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, p_index);
if (!bitmap) if (!bitmap)
return 1; return -ENOMEM;
map->s_fspace.s_bitmap = bitmap; map->s_fspace.s_bitmap = bitmap;
bitmap->s_extPosition = le32_to_cpu( bitmap->s_extPosition = le32_to_cpu(
phd->freedSpaceBitmap.extPosition); phd->freedSpaceBitmap.extPosition);
...@@ -1165,7 +1172,7 @@ static int udf_load_vat(struct super_block *sb, int p_index, int type1_index) ...@@ -1165,7 +1172,7 @@ static int udf_load_vat(struct super_block *sb, int p_index, int type1_index)
udf_find_vat_block(sb, p_index, type1_index, blocks - 1); udf_find_vat_block(sb, p_index, type1_index, blocks - 1);
} }
if (!sbi->s_vat_inode) if (!sbi->s_vat_inode)
return 1; return -EIO;
if (map->s_partition_type == UDF_VIRTUAL_MAP15) { if (map->s_partition_type == UDF_VIRTUAL_MAP15) {
map->s_type_specific.s_virtual.s_start_offset = 0; map->s_type_specific.s_virtual.s_start_offset = 0;
...@@ -1177,7 +1184,7 @@ static int udf_load_vat(struct super_block *sb, int p_index, int type1_index) ...@@ -1177,7 +1184,7 @@ static int udf_load_vat(struct super_block *sb, int p_index, int type1_index)
pos = udf_block_map(sbi->s_vat_inode, 0); pos = udf_block_map(sbi->s_vat_inode, 0);
bh = sb_bread(sb, pos); bh = sb_bread(sb, pos);
if (!bh) if (!bh)
return 1; return -EIO;
vat20 = (struct virtualAllocationTable20 *)bh->b_data; vat20 = (struct virtualAllocationTable20 *)bh->b_data;
} else { } else {
vat20 = (struct virtualAllocationTable20 *) vat20 = (struct virtualAllocationTable20 *)
...@@ -1195,6 +1202,12 @@ static int udf_load_vat(struct super_block *sb, int p_index, int type1_index) ...@@ -1195,6 +1202,12 @@ static int udf_load_vat(struct super_block *sb, int p_index, int type1_index)
return 0; return 0;
} }
/*
* Load partition descriptor block
*
* Returns <0 on error, 0 on success, -EAGAIN is special - try next descriptor
* sequence.
*/
static int udf_load_partdesc(struct super_block *sb, sector_t block) static int udf_load_partdesc(struct super_block *sb, sector_t block)
{ {
struct buffer_head *bh; struct buffer_head *bh;
...@@ -1204,13 +1217,15 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block) ...@@ -1204,13 +1217,15 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block)
int i, type1_idx; int i, type1_idx;
uint16_t partitionNumber; uint16_t partitionNumber;
uint16_t ident; uint16_t ident;
int ret = 0; int ret;
bh = udf_read_tagged(sb, block, block, &ident); bh = udf_read_tagged(sb, block, block, &ident);
if (!bh) if (!bh)
return 1; return -EAGAIN;
if (ident != TAG_IDENT_PD) if (ident != TAG_IDENT_PD) {
ret = 0;
goto out_bh; goto out_bh;
}
p = (struct partitionDesc *)bh->b_data; p = (struct partitionDesc *)bh->b_data;
partitionNumber = le16_to_cpu(p->partitionNumber); partitionNumber = le16_to_cpu(p->partitionNumber);
...@@ -1229,10 +1244,13 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block) ...@@ -1229,10 +1244,13 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block)
if (i >= sbi->s_partitions) { if (i >= sbi->s_partitions) {
udf_debug("Partition (%d) not found in partition map\n", udf_debug("Partition (%d) not found in partition map\n",
partitionNumber); partitionNumber);
ret = 0;
goto out_bh; goto out_bh;
} }
ret = udf_fill_partdesc_info(sb, p, i); ret = udf_fill_partdesc_info(sb, p, i);
if (ret < 0)
goto out_bh;
/* /*
* Now rescan for VIRTUAL or METADATA partitions when SPARABLE and * Now rescan for VIRTUAL or METADATA partitions when SPARABLE and
...@@ -1249,23 +1267,25 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block) ...@@ -1249,23 +1267,25 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block)
break; break;
} }
if (i >= sbi->s_partitions) if (i >= sbi->s_partitions) {
ret = 0;
goto out_bh; goto out_bh;
}
ret = udf_fill_partdesc_info(sb, p, i); ret = udf_fill_partdesc_info(sb, p, i);
if (ret) if (ret < 0)
goto out_bh; goto out_bh;
if (map->s_partition_type == UDF_METADATA_MAP25) { if (map->s_partition_type == UDF_METADATA_MAP25) {
ret = udf_load_metadata_files(sb, i); ret = udf_load_metadata_files(sb, i);
if (ret) { if (ret < 0) {
udf_err(sb, "error loading MetaData partition map %d\n", udf_err(sb, "error loading MetaData partition map %d\n",
i); i);
goto out_bh; goto out_bh;
} }
} else { } else {
ret = udf_load_vat(sb, i, type1_idx); ret = udf_load_vat(sb, i, type1_idx);
if (ret) if (ret < 0)
goto out_bh; goto out_bh;
/* /*
* Mark filesystem read-only if we have a partition with * Mark filesystem read-only if we have a partition with
...@@ -1275,6 +1295,7 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block) ...@@ -1275,6 +1295,7 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block)
sb->s_flags |= MS_RDONLY; sb->s_flags |= MS_RDONLY;
pr_notice("Filesystem marked read-only because writing to pseudooverwrite partition is not implemented\n"); pr_notice("Filesystem marked read-only because writing to pseudooverwrite partition is not implemented\n");
} }
ret = 0;
out_bh: out_bh:
/* In case loading failed, we handle cleanup in udf_fill_super */ /* In case loading failed, we handle cleanup in udf_fill_super */
brelse(bh); brelse(bh);
...@@ -1340,11 +1361,11 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block, ...@@ -1340,11 +1361,11 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block,
uint16_t ident; uint16_t ident;
struct buffer_head *bh; struct buffer_head *bh;
unsigned int table_len; unsigned int table_len;
int ret = 0; int ret;
bh = udf_read_tagged(sb, block, block, &ident); bh = udf_read_tagged(sb, block, block, &ident);
if (!bh) if (!bh)
return 1; return -EAGAIN;
BUG_ON(ident != TAG_IDENT_LVD); BUG_ON(ident != TAG_IDENT_LVD);
lvd = (struct logicalVolDesc *)bh->b_data; lvd = (struct logicalVolDesc *)bh->b_data;
table_len = le32_to_cpu(lvd->mapTableLength); table_len = le32_to_cpu(lvd->mapTableLength);
...@@ -1352,7 +1373,7 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block, ...@@ -1352,7 +1373,7 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block,
udf_err(sb, "error loading logical volume descriptor: " udf_err(sb, "error loading logical volume descriptor: "
"Partition table too long (%u > %lu)\n", table_len, "Partition table too long (%u > %lu)\n", table_len,
sb->s_blocksize - sizeof(*lvd)); sb->s_blocksize - sizeof(*lvd));
ret = 1; ret = -EIO;
goto out_bh; goto out_bh;
} }
...@@ -1396,11 +1417,10 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block, ...@@ -1396,11 +1417,10 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block,
} else if (!strncmp(upm2->partIdent.ident, } else if (!strncmp(upm2->partIdent.ident,
UDF_ID_SPARABLE, UDF_ID_SPARABLE,
strlen(UDF_ID_SPARABLE))) { strlen(UDF_ID_SPARABLE))) {
if (udf_load_sparable_map(sb, map, ret = udf_load_sparable_map(sb, map,
(struct sparablePartitionMap *)gpm) < 0) { (struct sparablePartitionMap *)gpm);
ret = 1; if (ret < 0)
goto out_bh; goto out_bh;
}
} else if (!strncmp(upm2->partIdent.ident, } else if (!strncmp(upm2->partIdent.ident,
UDF_ID_METADATA, UDF_ID_METADATA,
strlen(UDF_ID_METADATA))) { strlen(UDF_ID_METADATA))) {
...@@ -1465,7 +1485,7 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block, ...@@ -1465,7 +1485,7 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block,
} }
if (lvd->integritySeqExt.extLength) if (lvd->integritySeqExt.extLength)
udf_load_logicalvolint(sb, leea_to_cpu(lvd->integritySeqExt)); udf_load_logicalvolint(sb, leea_to_cpu(lvd->integritySeqExt));
ret = 0;
out_bh: out_bh:
brelse(bh); brelse(bh);
return ret; return ret;
...@@ -1503,22 +1523,18 @@ static void udf_load_logicalvolint(struct super_block *sb, struct kernel_extent_ ...@@ -1503,22 +1523,18 @@ static void udf_load_logicalvolint(struct super_block *sb, struct kernel_extent_
} }
/* /*
* udf_process_sequence * Process a main/reserve volume descriptor sequence.
* * @block First block of first extent of the sequence.
* PURPOSE * @lastblock Lastblock of first extent of the sequence.
* Process a main/reserve volume descriptor sequence. * @fileset There we store extent containing root fileset
* *
* PRE-CONDITIONS * Returns <0 on error, 0 on success. -EAGAIN is special - try next descriptor
* sb Pointer to _locked_ superblock. * sequence
* block First block of first extent of the sequence.
* lastblock Lastblock of first extent of the sequence.
*
* HISTORY
* July 1, 1997 - Andrew E. Mileski
* Written, tested, and released.
*/ */
static noinline int udf_process_sequence(struct super_block *sb, long block, static noinline int udf_process_sequence(
long lastblock, struct kernel_lb_addr *fileset) struct super_block *sb,
sector_t block, sector_t lastblock,
struct kernel_lb_addr *fileset)
{ {
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
struct udf_vds_record vds[VDS_POS_LENGTH]; struct udf_vds_record vds[VDS_POS_LENGTH];
...@@ -1529,6 +1545,7 @@ static noinline int udf_process_sequence(struct super_block *sb, long block, ...@@ -1529,6 +1545,7 @@ static noinline int udf_process_sequence(struct super_block *sb, long block,
uint32_t vdsn; uint32_t vdsn;
uint16_t ident; uint16_t ident;
long next_s = 0, next_e = 0; long next_s = 0, next_e = 0;
int ret;
memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH); memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH);
...@@ -1543,7 +1560,7 @@ static noinline int udf_process_sequence(struct super_block *sb, long block, ...@@ -1543,7 +1560,7 @@ static noinline int udf_process_sequence(struct super_block *sb, long block,
udf_err(sb, udf_err(sb,
"Block %llu of volume descriptor sequence is corrupted or we could not read it\n", "Block %llu of volume descriptor sequence is corrupted or we could not read it\n",
(unsigned long long)block); (unsigned long long)block);
return 1; return -EAGAIN;
} }
/* Process each descriptor (ISO 13346 3/8.3-8.4) */ /* Process each descriptor (ISO 13346 3/8.3-8.4) */
...@@ -1616,14 +1633,19 @@ static noinline int udf_process_sequence(struct super_block *sb, long block, ...@@ -1616,14 +1633,19 @@ static noinline int udf_process_sequence(struct super_block *sb, long block,
*/ */
if (!vds[VDS_POS_PRIMARY_VOL_DESC].block) { if (!vds[VDS_POS_PRIMARY_VOL_DESC].block) {
udf_err(sb, "Primary Volume Descriptor not found!\n"); udf_err(sb, "Primary Volume Descriptor not found!\n");
return 1; return -EAGAIN;
}
ret = udf_load_pvoldesc(sb, vds[VDS_POS_PRIMARY_VOL_DESC].block);
if (ret < 0)
return ret;
if (vds[VDS_POS_LOGICAL_VOL_DESC].block) {
ret = udf_load_logicalvol(sb,
vds[VDS_POS_LOGICAL_VOL_DESC].block,
fileset);
if (ret < 0)
return ret;
} }
if (udf_load_pvoldesc(sb, vds[VDS_POS_PRIMARY_VOL_DESC].block))
return 1;
if (vds[VDS_POS_LOGICAL_VOL_DESC].block && udf_load_logicalvol(sb,
vds[VDS_POS_LOGICAL_VOL_DESC].block, fileset))
return 1;
if (vds[VDS_POS_PARTITION_DESC].block) { if (vds[VDS_POS_PARTITION_DESC].block) {
/* /*
...@@ -1632,19 +1654,27 @@ static noinline int udf_process_sequence(struct super_block *sb, long block, ...@@ -1632,19 +1654,27 @@ static noinline int udf_process_sequence(struct super_block *sb, long block,
*/ */
for (block = vds[VDS_POS_PARTITION_DESC].block; for (block = vds[VDS_POS_PARTITION_DESC].block;
block < vds[VDS_POS_TERMINATING_DESC].block; block < vds[VDS_POS_TERMINATING_DESC].block;
block++) block++) {
if (udf_load_partdesc(sb, block)) ret = udf_load_partdesc(sb, block);
return 1; if (ret < 0)
return ret;
}
} }
return 0; return 0;
} }
/*
* Load Volume Descriptor Sequence described by anchor in bh
*
* Returns <0 on error, 0 on success
*/
static int udf_load_sequence(struct super_block *sb, struct buffer_head *bh, static int udf_load_sequence(struct super_block *sb, struct buffer_head *bh,
struct kernel_lb_addr *fileset) struct kernel_lb_addr *fileset)
{ {
struct anchorVolDescPtr *anchor; struct anchorVolDescPtr *anchor;
long main_s, main_e, reserve_s, reserve_e; sector_t main_s, main_e, reserve_s, reserve_e;
int ret;
anchor = (struct anchorVolDescPtr *)bh->b_data; anchor = (struct anchorVolDescPtr *)bh->b_data;
...@@ -1662,18 +1692,26 @@ static int udf_load_sequence(struct super_block *sb, struct buffer_head *bh, ...@@ -1662,18 +1692,26 @@ static int udf_load_sequence(struct super_block *sb, struct buffer_head *bh,
/* Process the main & reserve sequences */ /* Process the main & reserve sequences */
/* responsible for finding the PartitionDesc(s) */ /* responsible for finding the PartitionDesc(s) */
if (!udf_process_sequence(sb, main_s, main_e, fileset)) ret = udf_process_sequence(sb, main_s, main_e, fileset);
return 1; if (ret != -EAGAIN)
udf_sb_free_partitions(sb); return ret;
if (!udf_process_sequence(sb, reserve_s, reserve_e, fileset))
return 1;
udf_sb_free_partitions(sb); udf_sb_free_partitions(sb);
return 0; ret = udf_process_sequence(sb, reserve_s, reserve_e, fileset);
if (ret < 0) {
udf_sb_free_partitions(sb);
/* No sequence was OK, return -EIO */
if (ret == -EAGAIN)
ret = -EIO;
}
return ret;
} }
/* /*
* Check whether there is an anchor block in the given block and * Check whether there is an anchor block in the given block and
* load Volume Descriptor Sequence if so. * load Volume Descriptor Sequence if so.
*
* Returns <0 on error, 0 on success, -EAGAIN is special - try next anchor
* 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,
struct kernel_lb_addr *fileset) struct kernel_lb_addr *fileset)
...@@ -1685,33 +1723,40 @@ static int udf_check_anchor_block(struct super_block *sb, sector_t block, ...@@ -1685,33 +1723,40 @@ static int udf_check_anchor_block(struct super_block *sb, sector_t block,
if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV) && if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV) &&
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 -EAGAIN;
bh = udf_read_tagged(sb, block, block, &ident); bh = udf_read_tagged(sb, block, block, &ident);
if (!bh) if (!bh)
return 0; return -EAGAIN;
if (ident != TAG_IDENT_AVDP) { if (ident != TAG_IDENT_AVDP) {
brelse(bh); brelse(bh);
return 0; return -EAGAIN;
} }
ret = udf_load_sequence(sb, bh, fileset); ret = udf_load_sequence(sb, bh, fileset);
brelse(bh); brelse(bh);
return ret; return ret;
} }
/* Search for an anchor volume descriptor pointer */ /*
static sector_t udf_scan_anchors(struct super_block *sb, sector_t lastblock, * Search for an anchor volume descriptor pointer.
struct kernel_lb_addr *fileset) *
* Returns < 0 on error, 0 on success. -EAGAIN is special - try next set
* of anchors.
*/
static int udf_scan_anchors(struct super_block *sb, sector_t *lastblock,
struct kernel_lb_addr *fileset)
{ {
sector_t last[6]; sector_t last[6];
int i; int i;
struct udf_sb_info *sbi = UDF_SB(sb); struct udf_sb_info *sbi = UDF_SB(sb);
int last_count = 0; int last_count = 0;
int ret;
/* First try user provided anchor */ /* First try user provided anchor */
if (sbi->s_anchor) { if (sbi->s_anchor) {
if (udf_check_anchor_block(sb, sbi->s_anchor, fileset)) ret = udf_check_anchor_block(sb, sbi->s_anchor, fileset);
return lastblock; if (ret != -EAGAIN)
return ret;
} }
/* /*
* according to spec, anchor is in either: * according to spec, anchor is in either:
...@@ -1720,39 +1765,46 @@ static sector_t udf_scan_anchors(struct super_block *sb, sector_t lastblock, ...@@ -1720,39 +1765,46 @@ static sector_t udf_scan_anchors(struct super_block *sb, sector_t lastblock,
* lastblock * lastblock
* however, if the disc isn't closed, it could be 512. * however, if the disc isn't closed, it could be 512.
*/ */
if (udf_check_anchor_block(sb, sbi->s_session + 256, fileset)) ret = udf_check_anchor_block(sb, sbi->s_session + 256, fileset);
return lastblock; if (ret != -EAGAIN)
return ret;
/* /*
* The trouble is which block is the last one. Drives often misreport * The trouble is which block is the last one. Drives often misreport
* this so we try various possibilities. * this so we try various possibilities.
*/ */
last[last_count++] = lastblock; last[last_count++] = *lastblock;
if (lastblock >= 1) if (*lastblock >= 1)
last[last_count++] = lastblock - 1; last[last_count++] = *lastblock - 1;
last[last_count++] = lastblock + 1; last[last_count++] = *lastblock + 1;
if (lastblock >= 2) if (*lastblock >= 2)
last[last_count++] = lastblock - 2; last[last_count++] = *lastblock - 2;
if (lastblock >= 150) if (*lastblock >= 150)
last[last_count++] = lastblock - 150; last[last_count++] = *lastblock - 150;
if (lastblock >= 152) if (*lastblock >= 152)
last[last_count++] = lastblock - 152; last[last_count++] = *lastblock - 152;
for (i = 0; i < last_count; i++) { for (i = 0; i < last_count; i++) {
if (last[i] >= sb->s_bdev->bd_inode->i_size >> if (last[i] >= sb->s_bdev->bd_inode->i_size >>
sb->s_blocksize_bits) sb->s_blocksize_bits)
continue; continue;
if (udf_check_anchor_block(sb, last[i], fileset)) ret = udf_check_anchor_block(sb, last[i], fileset);
return last[i]; if (ret != -EAGAIN) {
if (!ret)
*lastblock = last[i];
return ret;
}
if (last[i] < 256) if (last[i] < 256)
continue; continue;
if (udf_check_anchor_block(sb, last[i] - 256, fileset)) ret = udf_check_anchor_block(sb, last[i] - 256, fileset);
return last[i]; if (ret != -EAGAIN) {
if (!ret)
*lastblock = last[i];
return ret;
}
} }
/* Finally try block 512 in case media is open */ /* Finally try block 512 in case media is open */
if (udf_check_anchor_block(sb, sbi->s_session + 512, fileset)) return udf_check_anchor_block(sb, sbi->s_session + 512, fileset);
return last[0];
return 0;
} }
/* /*
...@@ -1760,54 +1812,59 @@ static sector_t udf_scan_anchors(struct super_block *sb, sector_t lastblock, ...@@ -1760,54 +1812,59 @@ static sector_t udf_scan_anchors(struct super_block *sb, sector_t lastblock,
* area specified by it. The function expects sbi->s_lastblock to be the last * area specified by it. The function expects sbi->s_lastblock to be the last
* block on the media. * block on the media.
* *
* Return 1 if ok, 0 if not found. * Return <0 on error, 0 if anchor found. -EAGAIN is special meaning anchor
* * was not found.
*/ */
static int udf_find_anchor(struct super_block *sb, static int udf_find_anchor(struct super_block *sb,
struct kernel_lb_addr *fileset) struct kernel_lb_addr *fileset)
{ {
sector_t lastblock;
struct udf_sb_info *sbi = UDF_SB(sb); struct udf_sb_info *sbi = UDF_SB(sb);
sector_t lastblock = sbi->s_last_block;
int ret;
lastblock = udf_scan_anchors(sb, sbi->s_last_block, fileset); ret = udf_scan_anchors(sb, &lastblock, fileset);
if (lastblock) if (ret != -EAGAIN)
goto out; goto out;
/* 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); UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
lastblock = udf_variable_to_fixed(sbi->s_last_block);
/* 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, ret = udf_scan_anchors(sb, &lastblock, fileset);
udf_variable_to_fixed(sbi->s_last_block), if (ret != -EAGAIN)
fileset);
if (lastblock)
goto out; goto out;
lastblock = sbi->s_last_block;
/* 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, sbi->s_last_block, fileset); ret = udf_scan_anchors(sb, &lastblock, fileset);
if (!lastblock) { if (ret < 0) {
/* VARCONV didn't help. Clear it. */ /* VARCONV didn't help. Clear it. */
UDF_CLEAR_FLAG(sb, UDF_FLAG_VARCONV); UDF_CLEAR_FLAG(sb, UDF_FLAG_VARCONV);
return 0;
} }
out: out:
sbi->s_last_block = lastblock; if (ret == 0)
return 1; sbi->s_last_block = lastblock;
return ret;
} }
/* /*
* Check Volume Structure Descriptor, find Anchor block and load Volume * Check Volume Structure Descriptor, find Anchor block and load Volume
* Descriptor Sequence * Descriptor Sequence.
*
* Returns < 0 on error, 0 on success. -EAGAIN is special meaning anchor
* block was not found.
*/ */
static int udf_load_vrs(struct super_block *sb, struct udf_options *uopt, static int udf_load_vrs(struct super_block *sb, struct udf_options *uopt,
int silent, struct kernel_lb_addr *fileset) int silent, struct kernel_lb_addr *fileset)
{ {
struct udf_sb_info *sbi = UDF_SB(sb); struct udf_sb_info *sbi = UDF_SB(sb);
loff_t nsr_off; loff_t nsr_off;
int ret;
if (!sb_set_blocksize(sb, uopt->blocksize)) { if (!sb_set_blocksize(sb, uopt->blocksize)) {
if (!silent) if (!silent)
udf_warn(sb, "Bad block size\n"); udf_warn(sb, "Bad block size\n");
return 0; return -EINVAL;
} }
sbi->s_last_block = uopt->lastblock; sbi->s_last_block = uopt->lastblock;
if (!uopt->novrs) { if (!uopt->novrs) {
...@@ -1828,12 +1885,13 @@ static int udf_load_vrs(struct super_block *sb, struct udf_options *uopt, ...@@ -1828,12 +1885,13 @@ static int udf_load_vrs(struct super_block *sb, struct udf_options *uopt,
/* Look for anchor block and load Volume Descriptor Sequence */ /* Look for anchor block and load Volume Descriptor Sequence */
sbi->s_anchor = uopt->anchor; sbi->s_anchor = uopt->anchor;
if (!udf_find_anchor(sb, fileset)) { ret = udf_find_anchor(sb, fileset);
if (!silent) if (ret < 0) {
if (!silent && ret == -EAGAIN)
udf_warn(sb, "No anchor found\n"); udf_warn(sb, "No anchor found\n");
return 0; return ret;
} }
return 1; return 0;
} }
static void udf_open_lvid(struct super_block *sb) static void udf_open_lvid(struct super_block *sb)
...@@ -1939,7 +1997,7 @@ u64 lvid_get_unique_id(struct super_block *sb) ...@@ -1939,7 +1997,7 @@ u64 lvid_get_unique_id(struct super_block *sb)
static int udf_fill_super(struct super_block *sb, void *options, int silent) static int udf_fill_super(struct super_block *sb, void *options, int silent)
{ {
int ret; int ret = -EINVAL;
struct inode *inode = NULL; struct inode *inode = NULL;
struct udf_options uopt; struct udf_options uopt;
struct kernel_lb_addr rootdir, fileset; struct kernel_lb_addr rootdir, fileset;
...@@ -2011,7 +2069,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) ...@@ -2011,7 +2069,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
} else { } else {
uopt.blocksize = bdev_logical_block_size(sb->s_bdev); uopt.blocksize = bdev_logical_block_size(sb->s_bdev);
ret = udf_load_vrs(sb, &uopt, silent, &fileset); ret = udf_load_vrs(sb, &uopt, silent, &fileset);
if (!ret && uopt.blocksize != UDF_DEFAULT_BLOCKSIZE) { if (ret == -EAGAIN && uopt.blocksize != UDF_DEFAULT_BLOCKSIZE) {
if (!silent) if (!silent)
pr_notice("Rescanning with blocksize %d\n", pr_notice("Rescanning with blocksize %d\n",
UDF_DEFAULT_BLOCKSIZE); UDF_DEFAULT_BLOCKSIZE);
...@@ -2021,8 +2079,11 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) ...@@ -2021,8 +2079,11 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
ret = udf_load_vrs(sb, &uopt, silent, &fileset); ret = udf_load_vrs(sb, &uopt, silent, &fileset);
} }
} }
if (!ret) { if (ret < 0) {
udf_warn(sb, "No partition found (1)\n"); if (ret == -EAGAIN) {
udf_warn(sb, "No partition found (1)\n");
ret = -EINVAL;
}
goto error_out; goto error_out;
} }
...@@ -2040,6 +2101,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) ...@@ -2040,6 +2101,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
udf_err(sb, "minUDFReadRev=%x (max is %x)\n", udf_err(sb, "minUDFReadRev=%x (max is %x)\n",
le16_to_cpu(lvidiu->minUDFReadRev), le16_to_cpu(lvidiu->minUDFReadRev),
UDF_MAX_READ_VERSION); UDF_MAX_READ_VERSION);
ret = -EINVAL;
goto error_out; goto error_out;
} else if (minUDFWriteRev > UDF_MAX_WRITE_VERSION) } else if (minUDFWriteRev > UDF_MAX_WRITE_VERSION)
sb->s_flags |= MS_RDONLY; sb->s_flags |= MS_RDONLY;
...@@ -2054,6 +2116,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) ...@@ -2054,6 +2116,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
if (!sbi->s_partitions) { if (!sbi->s_partitions) {
udf_warn(sb, "No partition found (2)\n"); udf_warn(sb, "No partition found (2)\n");
ret = -EINVAL;
goto error_out; goto error_out;
} }
...@@ -2065,6 +2128,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) ...@@ -2065,6 +2128,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
if (udf_find_fileset(sb, &fileset, &rootdir)) { if (udf_find_fileset(sb, &fileset, &rootdir)) {
udf_warn(sb, "No fileset found\n"); udf_warn(sb, "No fileset found\n");
ret = -EINVAL;
goto error_out; goto error_out;
} }
...@@ -2086,6 +2150,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) ...@@ -2086,6 +2150,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
if (!inode) { if (!inode) {
udf_err(sb, "Error in udf_iget, block=%d, partition=%d\n", udf_err(sb, "Error in udf_iget, block=%d, partition=%d\n",
rootdir.logicalBlockNum, rootdir.partitionReferenceNum); rootdir.logicalBlockNum, rootdir.partitionReferenceNum);
ret = -EIO;
goto error_out; goto error_out;
} }
...@@ -2093,6 +2158,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) ...@@ -2093,6 +2158,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
sb->s_root = d_make_root(inode); sb->s_root = d_make_root(inode);
if (!sb->s_root) { if (!sb->s_root) {
udf_err(sb, "Couldn't allocate root dentry\n"); udf_err(sb, "Couldn't allocate root dentry\n");
ret = -ENOMEM;
goto error_out; goto error_out;
} }
sb->s_maxbytes = MAX_LFS_FILESIZE; sb->s_maxbytes = MAX_LFS_FILESIZE;
...@@ -2113,7 +2179,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) ...@@ -2113,7 +2179,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
kfree(sbi); kfree(sbi);
sb->s_fs_info = NULL; sb->s_fs_info = NULL;
return -EINVAL; return ret;
} }
void _udf_err(struct super_block *sb, const char *function, void _udf_err(struct super_block *sb, const char *function,
......
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