diff options
Diffstat (limited to 'fs/udf/inode.c')
| -rw-r--r-- | fs/udf/inode.c | 581 | 
1 files changed, 350 insertions, 231 deletions
diff --git a/fs/udf/inode.c b/fs/udf/inode.c index ae21a0e59e9..c8461551e10 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -49,10 +49,10 @@ MODULE_LICENSE("GPL");  static mode_t udf_convert_permissions(struct fileEntry *);  static int udf_update_inode(struct inode *, int);  static void udf_fill_inode(struct inode *, struct buffer_head *); -static struct buffer_head *inode_getblk(struct inode *, long, int *, +static struct buffer_head *inode_getblk(struct inode *, sector_t, int *,  	long *, int *); -static int8_t udf_insert_aext(struct inode *, kernel_lb_addr, int, -	kernel_lb_addr, uint32_t, struct buffer_head *); +static int8_t udf_insert_aext(struct inode *, struct extent_position, +	kernel_lb_addr, uint32_t);  static void udf_split_extents(struct inode *, int *, int, int,  	kernel_long_ad [EXTENT_MERGE_SIZE], int *);  static void udf_prealloc_extents(struct inode *, int, int, @@ -61,7 +61,7 @@ static void udf_merge_extents(struct inode *,  	 kernel_long_ad [EXTENT_MERGE_SIZE], int *);  static void udf_update_extents(struct inode *,  	kernel_long_ad [EXTENT_MERGE_SIZE], int, int, -	kernel_lb_addr, uint32_t, struct buffer_head **); +	struct extent_position *);  static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int);  /* @@ -194,10 +194,11 @@ void udf_expand_file_adinicb(struct inode * inode, int newsize, int * err)  struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int *err)  {  	int newblock; -	struct buffer_head *sbh = NULL, *dbh = NULL; -	kernel_lb_addr bloc, eloc; -	uint32_t elen, extoffset; +	struct buffer_head *dbh = NULL; +	kernel_lb_addr eloc; +	uint32_t elen;  	uint8_t alloctype; +	struct extent_position epos;  	struct udf_fileident_bh sfibh, dfibh;  	loff_t f_pos = udf_ext0_offset(inode) >> 2; @@ -237,16 +238,16 @@ struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int  	mark_buffer_dirty_inode(dbh, inode);  	sfibh.soffset = sfibh.eoffset = (f_pos & ((inode->i_sb->s_blocksize - 1) >> 2)) << 2; -	sbh = sfibh.sbh = sfibh.ebh = NULL; +	sfibh.sbh = sfibh.ebh = NULL;  	dfibh.soffset = dfibh.eoffset = 0;  	dfibh.sbh = dfibh.ebh = dbh;  	while ( (f_pos < size) )  	{  		UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB; -		sfi = udf_fileident_read(inode, &f_pos, &sfibh, &cfi, NULL, NULL, NULL, NULL, NULL, NULL); +		sfi = udf_fileident_read(inode, &f_pos, &sfibh, &cfi, NULL, NULL, NULL, NULL);  		if (!sfi)  		{ -			udf_release_data(dbh); +			brelse(dbh);  			return NULL;  		}  		UDF_I_ALLOCTYPE(inode) = alloctype; @@ -258,7 +259,7 @@ struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int  			sfi->fileIdent + le16_to_cpu(sfi->lengthOfImpUse)))  		{  			UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB; -			udf_release_data(dbh); +			brelse(dbh);  			return NULL;  		}  	} @@ -266,16 +267,17 @@ struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int  	memset(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), 0, UDF_I_LENALLOC(inode));  	UDF_I_LENALLOC(inode) = 0; -	bloc = UDF_I_LOCATION(inode);  	eloc.logicalBlockNum = *block;  	eloc.partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;  	elen = inode->i_size;  	UDF_I_LENEXTENTS(inode) = elen; -	extoffset = udf_file_entry_alloc_offset(inode); -	udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &sbh, 0); +	epos.bh = NULL; +	epos.block = UDF_I_LOCATION(inode); +	epos.offset = udf_file_entry_alloc_offset(inode); +	udf_add_aext(inode, &epos, eloc, elen, 0);  	/* UniqueID stuff */ -	udf_release_data(sbh); +	brelse(epos.bh);  	mark_inode_dirty(inode);  	return dbh;  } @@ -354,53 +356,153 @@ udf_getblk(struct inode *inode, long block, int create, int *err)  	return NULL;  } -static struct buffer_head * inode_getblk(struct inode * inode, long block, +/* Extend the file by 'blocks' blocks, return the number of extents added */ +int udf_extend_file(struct inode *inode, struct extent_position *last_pos, +	kernel_long_ad *last_ext, sector_t blocks) +{ +	sector_t add; +	int count = 0, fake = !(last_ext->extLength & UDF_EXTENT_LENGTH_MASK); +	struct super_block *sb = inode->i_sb; +	kernel_lb_addr prealloc_loc = {0, 0}; +	int prealloc_len = 0; + +	/* The previous extent is fake and we should not extend by anything +	 * - there's nothing to do... */ +	if (!blocks && fake) +		return 0; +	/* Round the last extent up to a multiple of block size */ +	if (last_ext->extLength & (sb->s_blocksize - 1)) { +		last_ext->extLength = +			(last_ext->extLength & UDF_EXTENT_FLAG_MASK) | +			(((last_ext->extLength & UDF_EXTENT_LENGTH_MASK) + +				sb->s_blocksize - 1) & ~(sb->s_blocksize - 1)); +		UDF_I_LENEXTENTS(inode) = +			(UDF_I_LENEXTENTS(inode) + sb->s_blocksize - 1) & +				~(sb->s_blocksize - 1); +	} +	/* Last extent are just preallocated blocks? */ +	if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) == EXT_NOT_RECORDED_ALLOCATED) { +		/* Save the extent so that we can reattach it to the end */ +		prealloc_loc = last_ext->extLocation; +		prealloc_len = last_ext->extLength; +		/* Mark the extent as a hole */ +		last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | +			(last_ext->extLength & UDF_EXTENT_LENGTH_MASK); +		last_ext->extLocation.logicalBlockNum = 0; +       		last_ext->extLocation.partitionReferenceNum = 0; +	} +	/* Can we merge with the previous extent? */ +	if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) == EXT_NOT_RECORDED_NOT_ALLOCATED) { +		add = ((1<<30) - sb->s_blocksize - (last_ext->extLength & +			UDF_EXTENT_LENGTH_MASK)) >> sb->s_blocksize_bits; +		if (add > blocks) +			add = blocks; +		blocks -= add; +		last_ext->extLength += add << sb->s_blocksize_bits; +	} + +	if (fake) { +		udf_add_aext(inode, last_pos, last_ext->extLocation, +			last_ext->extLength, 1); +		count++; +	} +	else +		udf_write_aext(inode, last_pos, last_ext->extLocation, last_ext->extLength, 1); +	/* Managed to do everything necessary? */ +	if (!blocks) +		goto out; + +	/* All further extents will be NOT_RECORDED_NOT_ALLOCATED */ +	last_ext->extLocation.logicalBlockNum = 0; +       	last_ext->extLocation.partitionReferenceNum = 0; +	add = (1 << (30-sb->s_blocksize_bits)) - 1; +	last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | (add << sb->s_blocksize_bits); +	/* Create enough extents to cover the whole hole */ +	while (blocks > add) { +		blocks -= add; +		if (udf_add_aext(inode, last_pos, last_ext->extLocation, +			last_ext->extLength, 1) == -1) +			return -1; +		count++; +	} +	if (blocks) { +		last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | +			(blocks << sb->s_blocksize_bits); +		if (udf_add_aext(inode, last_pos, last_ext->extLocation, +			last_ext->extLength, 1) == -1) +			return -1; +		count++; +	} +out: +	/* Do we have some preallocated blocks saved? */ +	if (prealloc_len) { +		if (udf_add_aext(inode, last_pos, prealloc_loc, prealloc_len, 1) == -1) +			return -1; +		last_ext->extLocation = prealloc_loc; +		last_ext->extLength = prealloc_len; +		count++; +	} +	/* last_pos should point to the last written extent... */ +	if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT) +		last_pos->offset -= sizeof(short_ad); +	else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG) +		last_pos->offset -= sizeof(long_ad); +	else +		return -1; +	return count; +} + +static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,  	int *err, long *phys, int *new)  { -	struct buffer_head *pbh = NULL, *cbh = NULL, *nbh = NULL, *result = NULL; +	static sector_t last_block; +	struct buffer_head *result = NULL;  	kernel_long_ad laarr[EXTENT_MERGE_SIZE]; -	uint32_t pextoffset = 0, cextoffset = 0, nextoffset = 0; +	struct extent_position prev_epos, cur_epos, next_epos;  	int count = 0, startnum = 0, endnum = 0;  	uint32_t elen = 0; -	kernel_lb_addr eloc, pbloc, cbloc, nbloc; +	kernel_lb_addr eloc;  	int c = 1; -	uint64_t lbcount = 0, b_off = 0; -	uint32_t newblocknum, newblock, offset = 0; +	loff_t lbcount = 0, b_off = 0; +	uint32_t newblocknum, newblock; +	sector_t offset = 0;  	int8_t etype;  	int goal = 0, pgoal = UDF_I_LOCATION(inode).logicalBlockNum; -	char lastblock = 0; +	int lastblock = 0; -	pextoffset = cextoffset = nextoffset = udf_file_entry_alloc_offset(inode); -	b_off = (uint64_t)block << inode->i_sb->s_blocksize_bits; -	pbloc = cbloc = nbloc = UDF_I_LOCATION(inode); +	prev_epos.offset = udf_file_entry_alloc_offset(inode); +	prev_epos.block = UDF_I_LOCATION(inode); +	prev_epos.bh = NULL; +	cur_epos = next_epos = prev_epos; +	b_off = (loff_t)block << inode->i_sb->s_blocksize_bits;  	/* find the extent which contains the block we are looking for.         alternate between laarr[0] and laarr[1] for locations of the         current extent, and the previous extent */  	do  	{ -		if (pbh != cbh) +		if (prev_epos.bh != cur_epos.bh)  		{ -			udf_release_data(pbh); -			atomic_inc(&cbh->b_count); -			pbh = cbh; +			brelse(prev_epos.bh); +			get_bh(cur_epos.bh); +			prev_epos.bh = cur_epos.bh;  		} -		if (cbh != nbh) +		if (cur_epos.bh != next_epos.bh)  		{ -			udf_release_data(cbh); -			atomic_inc(&nbh->b_count); -			cbh = nbh; +			brelse(cur_epos.bh); +			get_bh(next_epos.bh); +			cur_epos.bh = next_epos.bh;  		}  		lbcount += elen; -		pbloc = cbloc; -		cbloc = nbloc; +		prev_epos.block = cur_epos.block; +		cur_epos.block = next_epos.block; -		pextoffset = cextoffset; -		cextoffset = nextoffset; +		prev_epos.offset = cur_epos.offset; +		cur_epos.offset = next_epos.offset; -		if ((etype = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1)) == -1) +		if ((etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 1)) == -1)  			break;  		c = !c; @@ -418,6 +520,8 @@ static struct buffer_head * inode_getblk(struct inode * inode, long block,  	b_off -= lbcount;  	offset = b_off >> inode->i_sb->s_blocksize_bits; +	/* Move into indirect extent if we are at a pointer to it */ +	udf_next_aext(inode, &prev_epos, &eloc, &elen, 0);  	/* if the extent is allocated and recorded, return the block         if the extent is not a multiple of the blocksize, round up */ @@ -429,54 +533,77 @@ static struct buffer_head * inode_getblk(struct inode * inode, long block,  			elen = EXT_RECORDED_ALLOCATED |  				((elen + inode->i_sb->s_blocksize - 1) &  				~(inode->i_sb->s_blocksize - 1)); -			etype = udf_write_aext(inode, nbloc, &cextoffset, eloc, elen, nbh, 1); +			etype = udf_write_aext(inode, &cur_epos, eloc, elen, 1);  		} -		udf_release_data(pbh); -		udf_release_data(cbh); -		udf_release_data(nbh); +		brelse(prev_epos.bh); +		brelse(cur_epos.bh); +		brelse(next_epos.bh);  		newblock = udf_get_lb_pblock(inode->i_sb, eloc, offset);  		*phys = newblock;  		return NULL;  	} +	last_block = block; +	/* Are we beyond EOF? */  	if (etype == -1)  	{ -		endnum = startnum = ((count > 1) ? 1 : count); -		if (laarr[c].extLength & (inode->i_sb->s_blocksize - 1)) -		{ -			laarr[c].extLength = -				(laarr[c].extLength & UDF_EXTENT_FLAG_MASK) | -				(((laarr[c].extLength & UDF_EXTENT_LENGTH_MASK) + -					inode->i_sb->s_blocksize - 1) & -				~(inode->i_sb->s_blocksize - 1)); -			UDF_I_LENEXTENTS(inode) = -				(UDF_I_LENEXTENTS(inode) + inode->i_sb->s_blocksize - 1) & -					~(inode->i_sb->s_blocksize - 1); +		int ret; + +		if (count) { +			if (c) +				laarr[0] = laarr[1]; +			startnum = 1; +		} +		else { +			/* Create a fake extent when there's not one */ +			memset(&laarr[0].extLocation, 0x00, sizeof(kernel_lb_addr)); +			laarr[0].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED; +			/* Will udf_extend_file() create real extent from a fake one? */ +			startnum = (offset > 0); +		} +		/* Create extents for the hole between EOF and offset */ +		ret = udf_extend_file(inode, &prev_epos, laarr, offset); +		if (ret == -1) { +			brelse(prev_epos.bh); +			brelse(cur_epos.bh); +			brelse(next_epos.bh); +			/* We don't really know the error here so we just make +			 * something up */ +			*err = -ENOSPC; +			return NULL;  		} -		c = !c; -		laarr[c].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | -			((offset + 1) << inode->i_sb->s_blocksize_bits); -		memset(&laarr[c].extLocation, 0x00, sizeof(kernel_lb_addr)); -		count ++; -		endnum ++; +		c = 0; +		offset = 0; +		count += ret; +		/* We are not covered by a preallocated extent? */ +		if ((laarr[0].extLength & UDF_EXTENT_FLAG_MASK) != EXT_NOT_RECORDED_ALLOCATED) { +			/* Is there any real extent? - otherwise we overwrite +			 * the fake one... */ +			if (count) +				c = !c; +			laarr[c].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | +				inode->i_sb->s_blocksize; +			memset(&laarr[c].extLocation, 0x00, sizeof(kernel_lb_addr)); +			count ++; +			endnum ++; +		} +		endnum = c+1;  		lastblock = 1;  	} -	else +	else {  		endnum = startnum = ((count > 2) ? 2 : count); -	/* if the current extent is in position 0, swap it with the previous */ -	if (!c && count != 1) -	{ -		laarr[2] = laarr[0]; -		laarr[0] = laarr[1]; -		laarr[1] = laarr[2]; -		c = 1; -	} +		/* if the current extent is in position 0, swap it with the previous */ +		if (!c && count != 1) +		{ +			laarr[2] = laarr[0]; +			laarr[0] = laarr[1]; +			laarr[1] = laarr[2]; +			c = 1; +		} -	/* if the current block is located in a extent, read the next extent */ -	if (etype != -1) -	{ -		if ((etype = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 0)) != -1) +		/* if the current block is located in an extent, read the next extent */ +		if ((etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 0)) != -1)  		{  			laarr[c+1].extLength = (etype << 30) | elen;  			laarr[c+1].extLocation = eloc; @@ -484,11 +611,10 @@ static struct buffer_head * inode_getblk(struct inode * inode, long block,  			startnum ++;  			endnum ++;  		} -		else +		else {  			lastblock = 1; +		}  	} -	udf_release_data(cbh); -	udf_release_data(nbh);  	/* if the current extent is not recorded but allocated, get the  		block in the extent corresponding to the requested block */ @@ -508,7 +634,7 @@ static struct buffer_head * inode_getblk(struct inode * inode, long block,  		if (!(newblocknum = udf_new_block(inode->i_sb, inode,  			UDF_I_LOCATION(inode).partitionReferenceNum, goal, err)))  		{ -			udf_release_data(pbh); +			brelse(prev_epos.bh);  			*err = -ENOSPC;  			return NULL;  		} @@ -529,11 +655,11 @@ static struct buffer_head * inode_getblk(struct inode * inode, long block,  	udf_merge_extents(inode, laarr, &endnum);  	/* write back the new extents, inserting new extents if the new number -       of extents is greater than the old number, and deleting extents if -       the new number of extents is less than the old number */ -	udf_update_extents(inode, laarr, startnum, endnum, pbloc, pextoffset, &pbh); +	of extents is greater than the old number, and deleting extents if +	the new number of extents is less than the old number */ +	udf_update_extents(inode, laarr, startnum, endnum, &prev_epos); -	udf_release_data(pbh); +	brelse(prev_epos.bh);  	if (!(newblock = udf_get_pblock(inode->i_sb, newblocknum,  		UDF_I_LOCATION(inode).partitionReferenceNum, 0))) @@ -795,7 +921,7 @@ static void udf_merge_extents(struct inode *inode,  static void udf_update_extents(struct inode *inode,  	kernel_long_ad laarr[EXTENT_MERGE_SIZE], int startnum, int endnum, -	kernel_lb_addr pbloc, uint32_t pextoffset, struct buffer_head **pbh) +	struct extent_position *epos)  {  	int start = 0, i;  	kernel_lb_addr tmploc; @@ -804,28 +930,26 @@ static void udf_update_extents(struct inode *inode,  	if (startnum > endnum)  	{  		for (i=0; i<(startnum-endnum); i++) -		{ -			udf_delete_aext(inode, pbloc, pextoffset, laarr[i].extLocation, -				laarr[i].extLength, *pbh); -		} +			udf_delete_aext(inode, *epos, laarr[i].extLocation, +				laarr[i].extLength);  	}  	else if (startnum < endnum)  	{  		for (i=0; i<(endnum-startnum); i++)  		{ -			udf_insert_aext(inode, pbloc, pextoffset, laarr[i].extLocation, -				laarr[i].extLength, *pbh); -			udf_next_aext(inode, &pbloc, &pextoffset, &laarr[i].extLocation, -				&laarr[i].extLength, pbh, 1); +			udf_insert_aext(inode, *epos, laarr[i].extLocation, +				laarr[i].extLength); +			udf_next_aext(inode, epos, &laarr[i].extLocation, +				&laarr[i].extLength, 1);  			start ++;  		}  	}  	for (i=start; i<endnum; i++)  	{ -		udf_next_aext(inode, &pbloc, &pextoffset, &tmploc, &tmplen, pbh, 0); -		udf_write_aext(inode, pbloc, &pextoffset, laarr[i].extLocation, -			laarr[i].extLength, *pbh, 1); +		udf_next_aext(inode, epos, &tmploc, &tmplen, 0); +		udf_write_aext(inode, epos, laarr[i].extLocation, +			laarr[i].extLength, 1);  	}  } @@ -931,7 +1055,7 @@ __udf_read_inode(struct inode *inode)  	{  		printk(KERN_ERR "udf: udf_read_inode(ino %ld) failed ident=%d\n",  			inode->i_ino, ident); -		udf_release_data(bh); +		brelse(bh);  		make_bad_inode(inode);  		return;  	} @@ -960,35 +1084,36 @@ __udf_read_inode(struct inode *inode)  						ident == TAG_IDENT_EFE)  					{  						memcpy(&UDF_I_LOCATION(inode), &loc, sizeof(kernel_lb_addr)); -						udf_release_data(bh); -						udf_release_data(ibh); -						udf_release_data(nbh); +						brelse(bh); +						brelse(ibh); +						brelse(nbh);  						__udf_read_inode(inode);  						return;  					}  					else  					{ -						udf_release_data(nbh); -						udf_release_data(ibh); +						brelse(nbh); +						brelse(ibh);  					}  				}  				else -					udf_release_data(ibh); +					brelse(ibh);  			}  		}  		else -			udf_release_data(ibh); +			brelse(ibh);  	}  	else if (le16_to_cpu(fe->icbTag.strategyType) != 4)  	{  		printk(KERN_ERR "udf: unsupported strategy type: %d\n",  			le16_to_cpu(fe->icbTag.strategyType)); -		udf_release_data(bh); +		brelse(bh);  		make_bad_inode(inode);  		return;  	}  	udf_fill_inode(inode, bh); -	udf_release_data(bh); + +	brelse(bh);  }  static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) @@ -1331,7 +1456,7 @@ udf_update_inode(struct inode *inode, int do_sync)  				use->descTag.tagChecksum += ((uint8_t *)&(use->descTag))[i];  		mark_buffer_dirty(bh); -		udf_release_data(bh); +		brelse(bh);  		return err;  	} @@ -1520,7 +1645,7 @@ udf_update_inode(struct inode *inode, int do_sync)  			err = -EIO;  		}  	} -	udf_release_data(bh); +	brelse(bh);  	return err;  } @@ -1556,8 +1681,8 @@ udf_iget(struct super_block *sb, kernel_lb_addr ino)  	return NULL;  } -int8_t udf_add_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset, -	kernel_lb_addr eloc, uint32_t elen, struct buffer_head **bh, int inc) +int8_t udf_add_aext(struct inode *inode, struct extent_position *epos, +	kernel_lb_addr eloc, uint32_t elen, int inc)  {  	int adsize;  	short_ad *sad = NULL; @@ -1566,10 +1691,10 @@ int8_t udf_add_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset,  	int8_t etype;  	uint8_t *ptr; -	if (!*bh) -		ptr = UDF_I_DATA(inode) + *extoffset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode); +	if (!epos->bh) +		ptr = UDF_I_DATA(inode) + epos->offset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode);  	else -		ptr = (*bh)->b_data + *extoffset; +		ptr = epos->bh->b_data + epos->offset;  	if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)  		adsize = sizeof(short_ad); @@ -1578,20 +1703,20 @@ int8_t udf_add_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset,  	else  		return -1; -	if (*extoffset + (2 * adsize) > inode->i_sb->s_blocksize) +	if (epos->offset + (2 * adsize) > inode->i_sb->s_blocksize)  	{  		char *sptr, *dptr;  		struct buffer_head *nbh;  		int err, loffset; -		kernel_lb_addr obloc = *bloc; +		kernel_lb_addr obloc = epos->block; -		if (!(bloc->logicalBlockNum = udf_new_block(inode->i_sb, NULL, +		if (!(epos->block.logicalBlockNum = udf_new_block(inode->i_sb, NULL,  			obloc.partitionReferenceNum, obloc.logicalBlockNum, &err)))  		{  			return -1;  		}  		if (!(nbh = udf_tgetblk(inode->i_sb, udf_get_lb_pblock(inode->i_sb, -			*bloc, 0)))) +			epos->block, 0))))  		{  			return -1;  		} @@ -1604,25 +1729,25 @@ int8_t udf_add_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset,  		aed = (struct allocExtDesc *)(nbh->b_data);  		if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT))  			aed->previousAllocExtLocation = cpu_to_le32(obloc.logicalBlockNum); -		if (*extoffset + adsize > inode->i_sb->s_blocksize) +		if (epos->offset + adsize > inode->i_sb->s_blocksize)  		{ -			loffset = *extoffset; +			loffset = epos->offset;  			aed->lengthAllocDescs = cpu_to_le32(adsize);  			sptr = ptr - adsize;  			dptr = nbh->b_data + sizeof(struct allocExtDesc);  			memcpy(dptr, sptr, adsize); -			*extoffset = sizeof(struct allocExtDesc) + adsize; +			epos->offset = sizeof(struct allocExtDesc) + adsize;  		}  		else  		{ -			loffset = *extoffset + adsize; +			loffset = epos->offset + adsize;  			aed->lengthAllocDescs = cpu_to_le32(0);  			sptr = ptr; -			*extoffset = sizeof(struct allocExtDesc); +			epos->offset = sizeof(struct allocExtDesc); -			if (*bh) +			if (epos->bh)  			{ -				aed = (struct allocExtDesc *)(*bh)->b_data; +				aed = (struct allocExtDesc *)epos->bh->b_data;  				aed->lengthAllocDescs =  					cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);  			} @@ -1634,10 +1759,10 @@ int8_t udf_add_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset,  		}  		if (UDF_SB_UDFREV(inode->i_sb) >= 0x0200)  			udf_new_tag(nbh->b_data, TAG_IDENT_AED, 3, 1, -				bloc->logicalBlockNum, sizeof(tag)); +				epos->block.logicalBlockNum, sizeof(tag));  		else  			udf_new_tag(nbh->b_data, TAG_IDENT_AED, 2, 1, -				bloc->logicalBlockNum, sizeof(tag)); +				epos->block.logicalBlockNum, sizeof(tag));  		switch (UDF_I_ALLOCTYPE(inode))  		{  			case ICBTAG_FLAG_AD_SHORT: @@ -1646,7 +1771,7 @@ int8_t udf_add_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset,  				sad->extLength = cpu_to_le32(  					EXT_NEXT_EXTENT_ALLOCDECS |  					inode->i_sb->s_blocksize); -				sad->extPosition = cpu_to_le32(bloc->logicalBlockNum); +				sad->extPosition = cpu_to_le32(epos->block.logicalBlockNum);  				break;  			}  			case ICBTAG_FLAG_AD_LONG: @@ -1655,60 +1780,57 @@ int8_t udf_add_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset,  				lad->extLength = cpu_to_le32(  					EXT_NEXT_EXTENT_ALLOCDECS |  					inode->i_sb->s_blocksize); -				lad->extLocation = cpu_to_lelb(*bloc); +				lad->extLocation = cpu_to_lelb(epos->block);  				memset(lad->impUse, 0x00, sizeof(lad->impUse));  				break;  			}  		} -		if (*bh) +		if (epos->bh)  		{  			if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) -				udf_update_tag((*bh)->b_data, loffset); +				udf_update_tag(epos->bh->b_data, loffset);  			else -				udf_update_tag((*bh)->b_data, sizeof(struct allocExtDesc)); -			mark_buffer_dirty_inode(*bh, inode); -			udf_release_data(*bh); +				udf_update_tag(epos->bh->b_data, sizeof(struct allocExtDesc)); +			mark_buffer_dirty_inode(epos->bh, inode); +			brelse(epos->bh);  		}  		else  			mark_inode_dirty(inode); -		*bh = nbh; +		epos->bh = nbh;  	} -	etype = udf_write_aext(inode, *bloc, extoffset, eloc, elen, *bh, inc); +	etype = udf_write_aext(inode, epos, eloc, elen, inc); -	if (!*bh) +	if (!epos->bh)  	{  		UDF_I_LENALLOC(inode) += adsize;  		mark_inode_dirty(inode);  	}  	else  	{ -		aed = (struct allocExtDesc *)(*bh)->b_data; +		aed = (struct allocExtDesc *)epos->bh->b_data;  		aed->lengthAllocDescs =  			cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);  		if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) -			udf_update_tag((*bh)->b_data, *extoffset + (inc ? 0 : adsize)); +			udf_update_tag(epos->bh->b_data, epos->offset + (inc ? 0 : adsize));  		else -			udf_update_tag((*bh)->b_data, sizeof(struct allocExtDesc)); -		mark_buffer_dirty_inode(*bh, inode); +			udf_update_tag(epos->bh->b_data, sizeof(struct allocExtDesc)); +		mark_buffer_dirty_inode(epos->bh, inode);  	}  	return etype;  } -int8_t udf_write_aext(struct inode *inode, kernel_lb_addr bloc, int *extoffset, -    kernel_lb_addr eloc, uint32_t elen, struct buffer_head *bh, int inc) +int8_t udf_write_aext(struct inode *inode, struct extent_position *epos, +    kernel_lb_addr eloc, uint32_t elen, int inc)  {  	int adsize;  	uint8_t *ptr; -	if (!bh) -		ptr = UDF_I_DATA(inode) + *extoffset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode); +	if (!epos->bh) +		ptr = UDF_I_DATA(inode) + epos->offset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode);  	else -	{ -		ptr = bh->b_data + *extoffset; -		atomic_inc(&bh->b_count); -	} +		ptr = epos->bh->b_data + epos->offset;  	switch (UDF_I_ALLOCTYPE(inode))  	{ @@ -1733,40 +1855,39 @@ int8_t udf_write_aext(struct inode *inode, kernel_lb_addr bloc, int *extoffset,  			return -1;  	} -	if (bh) +	if (epos->bh)  	{  		if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)  		{ -			struct allocExtDesc *aed = (struct allocExtDesc *)(bh)->b_data; -			udf_update_tag((bh)->b_data, +			struct allocExtDesc *aed = (struct allocExtDesc *)epos->bh->b_data; +			udf_update_tag(epos->bh->b_data,  				le32_to_cpu(aed->lengthAllocDescs) + sizeof(struct allocExtDesc));  		} -		mark_buffer_dirty_inode(bh, inode); -		udf_release_data(bh); +		mark_buffer_dirty_inode(epos->bh, inode);  	}  	else  		mark_inode_dirty(inode);  	if (inc) -		*extoffset += adsize; +		epos->offset += adsize;  	return (elen >> 30);  } -int8_t udf_next_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset, -	kernel_lb_addr *eloc, uint32_t *elen, struct buffer_head **bh, int inc) +int8_t udf_next_aext(struct inode *inode, struct extent_position *epos, +	kernel_lb_addr *eloc, uint32_t *elen, int inc)  {  	int8_t etype; -	while ((etype = udf_current_aext(inode, bloc, extoffset, eloc, elen, bh, inc)) == +	while ((etype = udf_current_aext(inode, epos, eloc, elen, inc)) ==  		(EXT_NEXT_EXTENT_ALLOCDECS >> 30))  	{ -		*bloc = *eloc; -		*extoffset = sizeof(struct allocExtDesc); -		udf_release_data(*bh); -		if (!(*bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, *bloc, 0)))) +		epos->block = *eloc; +		epos->offset = sizeof(struct allocExtDesc); +		brelse(epos->bh); +		if (!(epos->bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, epos->block, 0))))  		{  			udf_debug("reading block %d failed!\n", -				udf_get_lb_pblock(inode->i_sb, *bloc, 0)); +				udf_get_lb_pblock(inode->i_sb, epos->block, 0));  			return -1;  		}  	} @@ -1774,26 +1895,26 @@ int8_t udf_next_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset,  	return etype;  } -int8_t udf_current_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset, -	kernel_lb_addr *eloc, uint32_t *elen, struct buffer_head **bh, int inc) +int8_t udf_current_aext(struct inode *inode, struct extent_position *epos, +	kernel_lb_addr *eloc, uint32_t *elen, int inc)  {  	int alen;  	int8_t etype;  	uint8_t *ptr; -	if (!*bh) +	if (!epos->bh)  	{ -		if (!(*extoffset)) -			*extoffset = udf_file_entry_alloc_offset(inode); -		ptr = UDF_I_DATA(inode) + *extoffset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode); +		if (!epos->offset) +			epos->offset = udf_file_entry_alloc_offset(inode); +		ptr = UDF_I_DATA(inode) + epos->offset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode);  		alen = udf_file_entry_alloc_offset(inode) + UDF_I_LENALLOC(inode);  	}  	else  	{ -		if (!(*extoffset)) -			*extoffset = sizeof(struct allocExtDesc); -		ptr = (*bh)->b_data + *extoffset; -		alen = sizeof(struct allocExtDesc) + le32_to_cpu(((struct allocExtDesc *)(*bh)->b_data)->lengthAllocDescs); +		if (!epos->offset) +			epos->offset = sizeof(struct allocExtDesc); +		ptr = epos->bh->b_data + epos->offset; +		alen = sizeof(struct allocExtDesc) + le32_to_cpu(((struct allocExtDesc *)epos->bh->b_data)->lengthAllocDescs);  	}  	switch (UDF_I_ALLOCTYPE(inode)) @@ -1802,7 +1923,7 @@ int8_t udf_current_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffse  		{  			short_ad *sad; -			if (!(sad = udf_get_fileshortad(ptr, alen, extoffset, inc))) +			if (!(sad = udf_get_fileshortad(ptr, alen, &epos->offset, inc)))  				return -1;  			etype = le32_to_cpu(sad->extLength) >> 30; @@ -1815,7 +1936,7 @@ int8_t udf_current_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffse  		{  			long_ad *lad; -			if (!(lad = udf_get_filelongad(ptr, alen, extoffset, inc))) +			if (!(lad = udf_get_filelongad(ptr, alen, &epos->offset, inc)))  				return -1;  			etype = le32_to_cpu(lad->extLength) >> 30; @@ -1834,41 +1955,40 @@ int8_t udf_current_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffse  }  static int8_t -udf_insert_aext(struct inode *inode, kernel_lb_addr bloc, int extoffset, -		kernel_lb_addr neloc, uint32_t nelen, struct buffer_head *bh) +udf_insert_aext(struct inode *inode, struct extent_position epos, +		kernel_lb_addr neloc, uint32_t nelen)  {  	kernel_lb_addr oeloc;  	uint32_t oelen;  	int8_t etype; -	if (bh) -		atomic_inc(&bh->b_count); +	if (epos.bh) +		get_bh(epos.bh); -	while ((etype = udf_next_aext(inode, &bloc, &extoffset, &oeloc, &oelen, &bh, 0)) != -1) +	while ((etype = udf_next_aext(inode, &epos, &oeloc, &oelen, 0)) != -1)  	{ -		udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 1); +		udf_write_aext(inode, &epos, neloc, nelen, 1);  		neloc = oeloc;  		nelen = (etype << 30) | oelen;  	} -	udf_add_aext(inode, &bloc, &extoffset, neloc, nelen, &bh, 1); -	udf_release_data(bh); +	udf_add_aext(inode, &epos, neloc, nelen, 1); +	brelse(epos.bh);  	return (nelen >> 30);  } -int8_t udf_delete_aext(struct inode *inode, kernel_lb_addr nbloc, int nextoffset, -	kernel_lb_addr eloc, uint32_t elen, struct buffer_head *nbh) +int8_t udf_delete_aext(struct inode *inode, struct extent_position epos, +	kernel_lb_addr eloc, uint32_t elen)  { -	struct buffer_head *obh; -	kernel_lb_addr obloc; -	int oextoffset, adsize; +	struct extent_position oepos; +	int adsize;  	int8_t etype;  	struct allocExtDesc *aed; -	if (nbh) +	if (epos.bh)  	{ -		atomic_inc(&nbh->b_count); -		atomic_inc(&nbh->b_count); +		get_bh(epos.bh); +		get_bh(epos.bh);  	}  	if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT) @@ -1878,80 +1998,77 @@ int8_t udf_delete_aext(struct inode *inode, kernel_lb_addr nbloc, int nextoffset  	else  		adsize = 0; -	obh = nbh; -	obloc = nbloc; -	oextoffset = nextoffset; - -	if (udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1) == -1) +	oepos = epos; +	if (udf_next_aext(inode, &epos, &eloc, &elen, 1) == -1)  		return -1; -	while ((etype = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1)) != -1) +	while ((etype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1)  	{ -		udf_write_aext(inode, obloc, &oextoffset, eloc, (etype << 30) | elen, obh, 1); -		if (obh != nbh) +		udf_write_aext(inode, &oepos, eloc, (etype << 30) | elen, 1); +		if (oepos.bh != epos.bh)  		{ -			obloc = nbloc; -			udf_release_data(obh); -			atomic_inc(&nbh->b_count); -			obh = nbh; -			oextoffset = nextoffset - adsize; +			oepos.block = epos.block; +			brelse(oepos.bh); +			get_bh(epos.bh); +			oepos.bh = epos.bh; +			oepos.offset = epos.offset - adsize;  		}  	}  	memset(&eloc, 0x00, sizeof(kernel_lb_addr));  	elen = 0; -	if (nbh != obh) +	if (epos.bh != oepos.bh)  	{ -		udf_free_blocks(inode->i_sb, inode, nbloc, 0, 1); -		udf_write_aext(inode, obloc, &oextoffset, eloc, elen, obh, 1); -		udf_write_aext(inode, obloc, &oextoffset, eloc, elen, obh, 1); -		if (!obh) +		udf_free_blocks(inode->i_sb, inode, epos.block, 0, 1); +		udf_write_aext(inode, &oepos, eloc, elen, 1); +		udf_write_aext(inode, &oepos, eloc, elen, 1); +		if (!oepos.bh)  		{  			UDF_I_LENALLOC(inode) -= (adsize * 2);  			mark_inode_dirty(inode);  		}  		else  		{ -			aed = (struct allocExtDesc *)(obh)->b_data; +			aed = (struct allocExtDesc *)oepos.bh->b_data;  			aed->lengthAllocDescs =  				cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - (2*adsize));  			if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) -				udf_update_tag((obh)->b_data, oextoffset - (2*adsize)); +				udf_update_tag(oepos.bh->b_data, oepos.offset - (2*adsize));  			else -				udf_update_tag((obh)->b_data, sizeof(struct allocExtDesc)); -			mark_buffer_dirty_inode(obh, inode); +				udf_update_tag(oepos.bh->b_data, sizeof(struct allocExtDesc)); +			mark_buffer_dirty_inode(oepos.bh, inode);  		}  	}  	else  	{ -		udf_write_aext(inode, obloc, &oextoffset, eloc, elen, obh, 1); -		if (!obh) +		udf_write_aext(inode, &oepos, eloc, elen, 1); +		if (!oepos.bh)  		{  			UDF_I_LENALLOC(inode) -= adsize;  			mark_inode_dirty(inode);  		}  		else  		{ -			aed = (struct allocExtDesc *)(obh)->b_data; +			aed = (struct allocExtDesc *)oepos.bh->b_data;  			aed->lengthAllocDescs =  				cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - adsize);  			if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) -				udf_update_tag((obh)->b_data, oextoffset - adsize); +				udf_update_tag(oepos.bh->b_data, epos.offset - adsize);  			else -				udf_update_tag((obh)->b_data, sizeof(struct allocExtDesc)); -			mark_buffer_dirty_inode(obh, inode); +				udf_update_tag(oepos.bh->b_data, sizeof(struct allocExtDesc)); +			mark_buffer_dirty_inode(oepos.bh, inode);  		}  	} -	udf_release_data(nbh); -	udf_release_data(obh); +	brelse(epos.bh); +	brelse(oepos.bh);  	return (elen >> 30);  } -int8_t inode_bmap(struct inode *inode, int block, kernel_lb_addr *bloc, uint32_t *extoffset, -	kernel_lb_addr *eloc, uint32_t *elen, uint32_t *offset, struct buffer_head **bh) +int8_t inode_bmap(struct inode *inode, sector_t block, struct extent_position *pos, +	kernel_lb_addr *eloc, uint32_t *elen, sector_t *offset)  { -	uint64_t lbcount = 0, bcount = (uint64_t)block << inode->i_sb->s_blocksize_bits; +	loff_t lbcount = 0, bcount = (loff_t)block << inode->i_sb->s_blocksize_bits;  	int8_t etype;  	if (block < 0) @@ -1960,42 +2077,44 @@ int8_t inode_bmap(struct inode *inode, int block, kernel_lb_addr *bloc, uint32_t  		return -1;  	} -	*extoffset = 0; +	pos->offset = 0; +	pos->block = UDF_I_LOCATION(inode); +	pos->bh = NULL;  	*elen = 0; -	*bloc = UDF_I_LOCATION(inode);  	do  	{ -		if ((etype = udf_next_aext(inode, bloc, extoffset, eloc, elen, bh, 1)) == -1) +		if ((etype = udf_next_aext(inode, pos, eloc, elen, 1)) == -1)  		{ -			*offset = bcount - lbcount; +			*offset = (bcount - lbcount) >> inode->i_sb->s_blocksize_bits;  			UDF_I_LENEXTENTS(inode) = lbcount;  			return -1;  		}  		lbcount += *elen;  	} while (lbcount <= bcount); -	*offset = bcount + *elen - lbcount; +	*offset = (bcount + *elen - lbcount) >> inode->i_sb->s_blocksize_bits;  	return etype;  } -long udf_block_map(struct inode *inode, long block) +long udf_block_map(struct inode *inode, sector_t block)  { -	kernel_lb_addr eloc, bloc; -	uint32_t offset, extoffset, elen; -	struct buffer_head *bh = NULL; +	kernel_lb_addr eloc; +	uint32_t elen; +	sector_t offset; +	struct extent_position epos = { NULL, 0, { 0, 0}};  	int ret;  	lock_kernel(); -	if (inode_bmap(inode, block, &bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30)) -		ret = udf_get_lb_pblock(inode->i_sb, eloc, offset >> inode->i_sb->s_blocksize_bits); +	if (inode_bmap(inode, block, &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30)) +		ret = udf_get_lb_pblock(inode->i_sb, eloc, offset);  	else  		ret = 0;  	unlock_kernel(); -	udf_release_data(bh); +	brelse(epos.bh);  	if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_VARCONV))  		return udf_fixed_to_variable(ret);  | 
