diff options
Diffstat (limited to 'fs/udf/super.c')
| -rw-r--r-- | fs/udf/super.c | 54 | 
1 files changed, 43 insertions, 11 deletions
diff --git a/fs/udf/super.c b/fs/udf/super.c index 91219385691..3286db047a4 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -76,6 +76,9 @@  #define UDF_DEFAULT_BLOCKSIZE 2048 +#define VSD_FIRST_SECTOR_OFFSET		32768 +#define VSD_MAX_SECTOR_OFFSET		0x800000 +  enum { UDF_MAX_LINKS = 0xffff };  /* These are the "meat" - everything else is stuffing */ @@ -172,7 +175,7 @@ static void init_once(void *foo)  	inode_init_once(&ei->vfs_inode);  } -static int init_inodecache(void) +static int __init init_inodecache(void)  {  	udf_inode_cachep = kmem_cache_create("udf_inode_cache",  					     sizeof(struct udf_inode_info), @@ -502,6 +505,7 @@ static int udf_parse_options(char *options, struct udf_options *uopt,  	while ((p = strsep(&options, ",")) != NULL) {  		substring_t args[MAX_OPT_ARGS];  		int token; +		unsigned n;  		if (!*p)  			continue; @@ -513,7 +517,10 @@ static int udf_parse_options(char *options, struct udf_options *uopt,  		case Opt_bs:  			if (match_int(&args[0], &option))  				return 0; -			uopt->blocksize = option; +			n = option; +			if (n != 512 && n != 1024 && n != 2048 && n != 4096) +				return 0; +			uopt->blocksize = n;  			uopt->flags |= (1 << UDF_FLAG_BLOCKSIZE_SET);  			break;  		case Opt_unhide: @@ -643,6 +650,7 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options)  	int error = 0;  	struct logicalVolIntegrityDescImpUse *lvidiu = udf_sb_lvidiu(sb); +	sync_filesystem(sb);  	if (lvidiu) {  		int write_rev = le16_to_cpu(lvidiu->minUDFWriteRev);  		if (write_rev > UDF_MAX_WRITE_VERSION && !(*flags & MS_RDONLY)) @@ -685,7 +693,7 @@ out_unlock:  static loff_t udf_check_vsd(struct super_block *sb)  {  	struct volStructDesc *vsd = NULL; -	loff_t sector = 32768; +	loff_t sector = VSD_FIRST_SECTOR_OFFSET;  	int sectorsize;  	struct buffer_head *bh = NULL;  	int nsr02 = 0; @@ -703,8 +711,18 @@ static loff_t udf_check_vsd(struct super_block *sb)  	udf_debug("Starting at sector %u (%ld byte sectors)\n",  		  (unsigned int)(sector >> sb->s_blocksize_bits),  		  sb->s_blocksize); -	/* Process the sequence (if applicable) */ -	for (; !nsr02 && !nsr03; sector += sectorsize) { +	/* Process the sequence (if applicable). The hard limit on the sector +	 * offset is arbitrary, hopefully large enough so that all valid UDF +	 * filesystems will be recognised. There is no mention of an upper +	 * bound to the size of the volume recognition area in the standard. +	 *  The limit will prevent the code to read all the sectors of a +	 * specially crafted image (like a bluray disc full of CD001 sectors), +	 * potentially causing minutes or even hours of uninterruptible I/O +	 * activity. This actually happened with uninitialised SSD partitions +	 * (all 0xFF) before the check for the limit and all valid IDs were +	 * added */ +	for (; !nsr02 && !nsr03 && sector < VSD_MAX_SECTOR_OFFSET; +	     sector += sectorsize) {  		/* Read a block */  		bh = udf_tread(sb, sector >> sb->s_blocksize_bits);  		if (!bh) @@ -714,10 +732,7 @@ static loff_t udf_check_vsd(struct super_block *sb)  		vsd = (struct volStructDesc *)(bh->b_data +  					      (sector & (sb->s_blocksize - 1))); -		if (vsd->stdIdent[0] == 0) { -			brelse(bh); -			break; -		} else if (!strncmp(vsd->stdIdent, VSD_STD_ID_CD001, +		if (!strncmp(vsd->stdIdent, VSD_STD_ID_CD001,  				    VSD_STD_ID_LEN)) {  			switch (vsd->structType) {  			case 0: @@ -753,6 +768,17 @@ static loff_t udf_check_vsd(struct super_block *sb)  		else if (!strncmp(vsd->stdIdent, VSD_STD_ID_NSR03,  				    VSD_STD_ID_LEN))  			nsr03 = sector; +		else if (!strncmp(vsd->stdIdent, VSD_STD_ID_BOOT2, +				    VSD_STD_ID_LEN)) +			; /* nothing */ +		else if (!strncmp(vsd->stdIdent, VSD_STD_ID_CDW02, +				    VSD_STD_ID_LEN)) +			; /* nothing */ +		else { +			/* invalid id : end of volume recognition area */ +			brelse(bh); +			break; +		}  		brelse(bh);  	} @@ -760,7 +786,8 @@ static loff_t udf_check_vsd(struct super_block *sb)  		return nsr03;  	else if (nsr02)  		return nsr02; -	else if (sector - (sbi->s_session << sb->s_blocksize_bits) == 32768) +	else if (!bh && sector - (sbi->s_session << sb->s_blocksize_bits) == +			VSD_FIRST_SECTOR_OFFSET)  		return -1;  	else  		return 0; @@ -1270,6 +1297,9 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block)  	 * PHYSICAL partitions are already set up  	 */  	type1_idx = i; +#ifdef UDFFS_DEBUG +	map = NULL; /* supress 'maybe used uninitialized' warning */ +#endif  	for (i = 0; i < sbi->s_partitions; i++) {  		map = &sbi->s_partmaps[i]; @@ -1891,7 +1921,9 @@ static int udf_load_vrs(struct super_block *sb, struct udf_options *uopt,  			return 0;  		}  		if (nsr_off == -1) -			udf_debug("Failed to read byte 32768. Assuming open disc. Skipping validity check\n"); +			udf_debug("Failed to read sector at offset %d. " +				  "Assuming open disc. Skipping validity " +				  "check\n", VSD_FIRST_SECTOR_OFFSET);  		if (!sbi->s_last_block)  			sbi->s_last_block = udf_get_last_block(sb);  	} else {  | 
