diff options
| author | Thomas Gleixner <tglx@linutronix.de> | 2011-05-14 12:06:36 +0200 | 
|---|---|---|
| committer | Thomas Gleixner <tglx@linutronix.de> | 2011-05-14 12:06:36 +0200 | 
| commit | a18f22a968de17b29f2310cdb7ba69163e65ec15 (patch) | |
| tree | a7d56d88fad5e444d7661484109758a2f436129e /fs/udf | |
| parent | a1c57e0fec53defe745e64417eacdbd3618c3e66 (diff) | |
| parent | 798778b8653f64b7b2162ac70eca10367cff6ce8 (diff) | |
Merge branch 'consolidate-clksrc-i8253' of master.kernel.org:~rmk/linux-2.6-arm into timers/clocksource
Conflicts:
	arch/ia64/kernel/cyclone.c
	arch/mips/kernel/i8253.c
	arch/x86/kernel/i8253.c
Reason: Resolve conflicts so further cleanups do not conflict further
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'fs/udf')
| -rw-r--r-- | fs/udf/balloc.c | 11 | ||||
| -rw-r--r-- | fs/udf/file.c | 8 | ||||
| -rw-r--r-- | fs/udf/inode.c | 240 | ||||
| -rw-r--r-- | fs/udf/namei.c | 18 | ||||
| -rw-r--r-- | fs/udf/truncate.c | 146 | ||||
| -rw-r--r-- | fs/udf/udfdecl.h | 12 | 
6 files changed, 250 insertions, 185 deletions
diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c index 306ee39ef2c3..95518a9f589e 100644 --- a/fs/udf/balloc.c +++ b/fs/udf/balloc.c @@ -27,11 +27,10 @@  #include "udf_i.h"  #include "udf_sb.h" -#define udf_clear_bit(nr, addr) ext2_clear_bit(nr, addr) -#define udf_set_bit(nr, addr) ext2_set_bit(nr, addr) -#define udf_test_bit(nr, addr) ext2_test_bit(nr, addr) -#define udf_find_next_one_bit(addr, size, offset) \ -		ext2_find_next_bit(addr, size, offset) +#define udf_clear_bit	__test_and_clear_bit_le +#define udf_set_bit	__test_and_set_bit_le +#define udf_test_bit	test_bit_le +#define udf_find_next_one_bit	find_next_bit_le  static int read_block_bitmap(struct super_block *sb,  			     struct udf_bitmap *bitmap, unsigned int block, @@ -297,7 +296,7 @@ repeat:  				break;  			}  		} else { -			bit = udf_find_next_one_bit((char *)bh->b_data, +			bit = udf_find_next_one_bit(bh->b_data,  						    sb->s_blocksize << 3,  						    group_start << 3);  			if (bit < sb->s_blocksize << 3) diff --git a/fs/udf/file.c b/fs/udf/file.c index 89c78486cbbe..2a346bb1d9f5 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -98,7 +98,6 @@ static int udf_adinicb_write_end(struct file *file,  const struct address_space_operations udf_adinicb_aops = {  	.readpage	= udf_adinicb_readpage,  	.writepage	= udf_adinicb_writepage, -	.sync_page	= block_sync_page,  	.write_begin = simple_write_begin,  	.write_end = udf_adinicb_write_end,  }; @@ -123,8 +122,8 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,  		if (inode->i_sb->s_blocksize <  				(udf_file_entry_alloc_offset(inode) +  						pos + count)) { -			udf_expand_file_adinicb(inode, pos + count, &err); -			if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { +			err = udf_expand_file_adinicb(inode); +			if (err) {  				udf_debug("udf_expand_adinicb: err=%d\n", err);  				up_write(&iinfo->i_data_sem);  				return err; @@ -237,7 +236,7 @@ static int udf_setattr(struct dentry *dentry, struct iattr *attr)  	if ((attr->ia_valid & ATTR_SIZE) &&  	    attr->ia_size != i_size_read(inode)) { -		error = vmtruncate(inode, attr->ia_size); +		error = udf_setsize(inode, attr->ia_size);  		if (error)  			return error;  	} @@ -249,5 +248,4 @@ static int udf_setattr(struct dentry *dentry, struct iattr *attr)  const struct inode_operations udf_file_inode_operations = {  	.setattr		= udf_setattr, -	.truncate		= udf_truncate,  }; diff --git a/fs/udf/inode.c b/fs/udf/inode.c index c6a2e782b97b..1d1358ed80c1 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -73,14 +73,12 @@ void udf_evict_inode(struct inode *inode)  	struct udf_inode_info *iinfo = UDF_I(inode);  	int want_delete = 0; -	truncate_inode_pages(&inode->i_data, 0); -  	if (!inode->i_nlink && !is_bad_inode(inode)) {  		want_delete = 1; -		inode->i_size = 0; -		udf_truncate(inode); +		udf_setsize(inode, 0);  		udf_update_inode(inode, IS_SYNC(inode)); -	} +	} else +		truncate_inode_pages(&inode->i_data, 0);  	invalidate_inode_buffers(inode);  	end_writeback(inode);  	if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB && @@ -117,9 +115,18 @@ static int udf_write_begin(struct file *file, struct address_space *mapping,  	ret = block_write_begin(mapping, pos, len, flags, pagep, udf_get_block);  	if (unlikely(ret)) { -		loff_t isize = mapping->host->i_size; -		if (pos + len > isize) -			vmtruncate(mapping->host, isize); +		struct inode *inode = mapping->host; +		struct udf_inode_info *iinfo = UDF_I(inode); +		loff_t isize = inode->i_size; + +		if (pos + len > isize) { +			truncate_pagecache(inode, pos + len, isize); +			if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { +				down_write(&iinfo->i_data_sem); +				udf_truncate_extents(inode); +				up_write(&iinfo->i_data_sem); +			} +		}  	}  	return ret; @@ -133,36 +140,36 @@ static sector_t udf_bmap(struct address_space *mapping, sector_t block)  const struct address_space_operations udf_aops = {  	.readpage	= udf_readpage,  	.writepage	= udf_writepage, -	.sync_page	= block_sync_page,  	.write_begin		= udf_write_begin,  	.write_end		= generic_write_end,  	.bmap		= udf_bmap,  }; -void udf_expand_file_adinicb(struct inode *inode, int newsize, int *err) +int udf_expand_file_adinicb(struct inode *inode)  {  	struct page *page;  	char *kaddr;  	struct udf_inode_info *iinfo = UDF_I(inode); +	int err;  	struct writeback_control udf_wbc = {  		.sync_mode = WB_SYNC_NONE,  		.nr_to_write = 1,  	}; -	/* from now on we have normal address_space methods */ -	inode->i_data.a_ops = &udf_aops; -  	if (!iinfo->i_lenAlloc) {  		if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD))  			iinfo->i_alloc_type = ICBTAG_FLAG_AD_SHORT;  		else  			iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG; +		/* from now on we have normal address_space methods */ +		inode->i_data.a_ops = &udf_aops;  		mark_inode_dirty(inode); -		return; +		return 0;  	} -	page = grab_cache_page(inode->i_mapping, 0); -	BUG_ON(!PageLocked(page)); +	page = find_or_create_page(inode->i_mapping, 0, GFP_NOFS); +	if (!page) +		return -ENOMEM;  	if (!PageUptodate(page)) {  		kaddr = kmap(page); @@ -181,11 +188,24 @@ void udf_expand_file_adinicb(struct inode *inode, int newsize, int *err)  		iinfo->i_alloc_type = ICBTAG_FLAG_AD_SHORT;  	else  		iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG; - -	inode->i_data.a_ops->writepage(page, &udf_wbc); +	/* from now on we have normal address_space methods */ +	inode->i_data.a_ops = &udf_aops; +	err = inode->i_data.a_ops->writepage(page, &udf_wbc); +	if (err) { +		/* Restore everything back so that we don't lose data... */ +		lock_page(page); +		kaddr = kmap(page); +		memcpy(iinfo->i_ext.i_data + iinfo->i_lenEAttr, kaddr, +		       inode->i_size); +		kunmap(page); +		unlock_page(page); +		iinfo->i_alloc_type = ICBTAG_FLAG_AD_IN_ICB; +		inode->i_data.a_ops = &udf_adinicb_aops; +	}  	page_cache_release(page); -  	mark_inode_dirty(inode); + +	return err;  }  struct buffer_head *udf_expand_dir_adinicb(struct inode *inode, int *block, @@ -348,8 +368,10 @@ static struct buffer_head *udf_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, -		    struct kernel_long_ad *last_ext, sector_t blocks) +static int udf_do_extend_file(struct inode *inode, +			      struct extent_position *last_pos, +			      struct kernel_long_ad *last_ext, +			      sector_t blocks)  {  	sector_t add;  	int count = 0, fake = !(last_ext->extLength & UDF_EXTENT_LENGTH_MASK); @@ -357,6 +379,7 @@ int udf_extend_file(struct inode *inode, struct extent_position *last_pos,  	struct kernel_lb_addr prealloc_loc = {};  	int prealloc_len = 0;  	struct udf_inode_info *iinfo; +	int err;  	/* The previous extent is fake and we should not extend by anything  	 * - there's nothing to do... */ @@ -422,26 +445,29 @@ int udf_extend_file(struct inode *inode, struct extent_position *last_pos,  	/* 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; +		err = udf_add_aext(inode, last_pos, &last_ext->extLocation, +				   last_ext->extLength, 1); +		if (err) +			return err;  		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; +		err = udf_add_aext(inode, last_pos, &last_ext->extLocation, +				   last_ext->extLength, 1); +		if (err) +			return err;  		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; +		err = udf_add_aext(inode, last_pos, &prealloc_loc, +				   prealloc_len, 1); +		if (err) +			return err;  		last_ext->extLocation = prealloc_loc;  		last_ext->extLength = prealloc_len;  		count++; @@ -453,11 +479,68 @@ out:  	else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)  		last_pos->offset -= sizeof(struct long_ad);  	else -		return -1; +		return -EIO;  	return count;  } +static int udf_extend_file(struct inode *inode, loff_t newsize) +{ + +	struct extent_position epos; +	struct kernel_lb_addr eloc; +	uint32_t elen; +	int8_t etype; +	struct super_block *sb = inode->i_sb; +	sector_t first_block = newsize >> sb->s_blocksize_bits, offset; +	int adsize; +	struct udf_inode_info *iinfo = UDF_I(inode); +	struct kernel_long_ad extent; +	int err; + +	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) +		adsize = sizeof(struct short_ad); +	else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG) +		adsize = sizeof(struct long_ad); +	else +		BUG(); + +	etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset); + +	/* File has extent covering the new size (could happen when extending +	 * inside a block)? */ +	if (etype != -1) +		return 0; +	if (newsize & (sb->s_blocksize - 1)) +		offset++; +	/* Extended file just to the boundary of the last file block? */ +	if (offset == 0) +		return 0; + +	/* Truncate is extending the file by 'offset' blocks */ +	if ((!epos.bh && epos.offset == udf_file_entry_alloc_offset(inode)) || +	    (epos.bh && epos.offset == sizeof(struct allocExtDesc))) { +		/* File has no extents at all or has empty last +		 * indirect extent! Create a fake extent... */ +		extent.extLocation.logicalBlockNum = 0; +		extent.extLocation.partitionReferenceNum = 0; +		extent.extLength = EXT_NOT_RECORDED_NOT_ALLOCATED; +	} else { +		epos.offset -= adsize; +		etype = udf_next_aext(inode, &epos, &extent.extLocation, +				      &extent.extLength, 0); +		extent.extLength |= etype << 30; +	} +	err = udf_do_extend_file(inode, &epos, &extent, offset); +	if (err < 0) +		goto out; +	err = 0; +	iinfo->i_lenExtents = newsize; +out: +	brelse(epos.bh); +	return err; +} +  static struct buffer_head *inode_getblk(struct inode *inode, sector_t block,  					int *err, sector_t *phys, int *new)  { @@ -540,7 +623,7 @@ static struct buffer_head *inode_getblk(struct inode *inode, sector_t block,  			elen = EXT_RECORDED_ALLOCATED |  				((elen + inode->i_sb->s_blocksize - 1) &  				 ~(inode->i_sb->s_blocksize - 1)); -			etype = udf_write_aext(inode, &cur_epos, &eloc, elen, 1); +			udf_write_aext(inode, &cur_epos, &eloc, elen, 1);  		}  		brelse(prev_epos.bh);  		brelse(cur_epos.bh); @@ -564,19 +647,17 @@ static struct buffer_head *inode_getblk(struct inode *inode, sector_t block,  			memset(&laarr[0].extLocation, 0x00,  				sizeof(struct kernel_lb_addr));  			laarr[0].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED; -			/* Will udf_extend_file() create real extent from +			/* Will udf_do_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) { +		ret = udf_do_extend_file(inode, &prev_epos, laarr, offset); +		if (ret < 0) {  			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; +			*err = ret;  			return NULL;  		}  		c = 0; @@ -1005,52 +1086,66 @@ struct buffer_head *udf_bread(struct inode *inode, int block,  	return NULL;  } -void udf_truncate(struct inode *inode) +int udf_setsize(struct inode *inode, loff_t newsize)  { -	int offset;  	int err;  	struct udf_inode_info *iinfo; +	int bsize = 1 << inode->i_blkbits;  	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||  	      S_ISLNK(inode->i_mode))) -		return; +		return -EINVAL;  	if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) -		return; +		return -EPERM;  	iinfo = UDF_I(inode); -	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { +	if (newsize > inode->i_size) {  		down_write(&iinfo->i_data_sem); -		if (inode->i_sb->s_blocksize < -				(udf_file_entry_alloc_offset(inode) + -				 inode->i_size)) { -			udf_expand_file_adinicb(inode, inode->i_size, &err); -			if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { -				inode->i_size = iinfo->i_lenAlloc; -				up_write(&iinfo->i_data_sem); -				return; +		if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { +			if (bsize < +			    (udf_file_entry_alloc_offset(inode) + newsize)) { +				err = udf_expand_file_adinicb(inode); +				if (err) { +					up_write(&iinfo->i_data_sem); +					return err; +				}  			} else -				udf_truncate_extents(inode); -		} else { -			offset = inode->i_size & (inode->i_sb->s_blocksize - 1); -			memset(iinfo->i_ext.i_data + iinfo->i_lenEAttr + offset, -				0x00, inode->i_sb->s_blocksize - -				offset - udf_file_entry_alloc_offset(inode)); -			iinfo->i_lenAlloc = inode->i_size; +				iinfo->i_lenAlloc = newsize; +		} +		err = udf_extend_file(inode, newsize); +		if (err) { +			up_write(&iinfo->i_data_sem); +			return err;  		} +		truncate_setsize(inode, newsize);  		up_write(&iinfo->i_data_sem);  	} else { -		block_truncate_page(inode->i_mapping, inode->i_size, -				    udf_get_block); +		if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { +			down_write(&iinfo->i_data_sem); +			memset(iinfo->i_ext.i_data + iinfo->i_lenEAttr + newsize, +			       0x00, bsize - newsize - +			       udf_file_entry_alloc_offset(inode)); +			iinfo->i_lenAlloc = newsize; +			truncate_setsize(inode, newsize); +			up_write(&iinfo->i_data_sem); +			goto update_time; +		} +		err = block_truncate_page(inode->i_mapping, newsize, +					  udf_get_block); +		if (err) +			return err;  		down_write(&iinfo->i_data_sem); +		truncate_setsize(inode, newsize);  		udf_truncate_extents(inode);  		up_write(&iinfo->i_data_sem);  	} - +update_time:  	inode->i_mtime = inode->i_ctime = current_fs_time(inode->i_sb);  	if (IS_SYNC(inode))  		udf_sync_inode(inode);  	else  		mark_inode_dirty(inode); +	return 0;  }  static void __udf_read_inode(struct inode *inode) @@ -1637,14 +1732,13 @@ struct inode *udf_iget(struct super_block *sb, struct kernel_lb_addr *ino)  	return NULL;  } -int8_t udf_add_aext(struct inode *inode, struct extent_position *epos, -		    struct kernel_lb_addr *eloc, uint32_t elen, int inc) +int udf_add_aext(struct inode *inode, struct extent_position *epos, +		 struct kernel_lb_addr *eloc, uint32_t elen, int inc)  {  	int adsize;  	struct short_ad *sad = NULL;  	struct long_ad *lad = NULL;  	struct allocExtDesc *aed; -	int8_t etype;  	uint8_t *ptr;  	struct udf_inode_info *iinfo = UDF_I(inode); @@ -1660,7 +1754,7 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,  	else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)  		adsize = sizeof(struct long_ad);  	else -		return -1; +		return -EIO;  	if (epos->offset + (2 * adsize) > inode->i_sb->s_blocksize) {  		unsigned char *sptr, *dptr; @@ -1672,12 +1766,12 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,  						obloc.partitionReferenceNum,  						obloc.logicalBlockNum, &err);  		if (!epos->block.logicalBlockNum) -			return -1; +			return -ENOSPC;  		nbh = udf_tgetblk(inode->i_sb, udf_get_lb_pblock(inode->i_sb,  								 &epos->block,  								 0));  		if (!nbh) -			return -1; +			return -EIO;  		lock_buffer(nbh);  		memset(nbh->b_data, 0x00, inode->i_sb->s_blocksize);  		set_buffer_uptodate(nbh); @@ -1746,7 +1840,7 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,  		epos->bh = nbh;  	} -	etype = udf_write_aext(inode, epos, eloc, elen, inc); +	udf_write_aext(inode, epos, eloc, elen, inc);  	if (!epos->bh) {  		iinfo->i_lenAlloc += adsize; @@ -1764,11 +1858,11 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,  		mark_buffer_dirty_inode(epos->bh, inode);  	} -	return etype; +	return 0;  } -int8_t udf_write_aext(struct inode *inode, struct extent_position *epos, -		      struct kernel_lb_addr *eloc, uint32_t elen, int inc) +void udf_write_aext(struct inode *inode, struct extent_position *epos, +		    struct kernel_lb_addr *eloc, uint32_t elen, int inc)  {  	int adsize;  	uint8_t *ptr; @@ -1798,7 +1892,7 @@ int8_t udf_write_aext(struct inode *inode, struct extent_position *epos,  		adsize = sizeof(struct long_ad);  		break;  	default: -		return -1; +		return;  	}  	if (epos->bh) { @@ -1817,8 +1911,6 @@ int8_t udf_write_aext(struct inode *inode, struct extent_position *epos,  	if (inc)  		epos->offset += adsize; - -	return (elen >> 30);  }  int8_t udf_next_aext(struct inode *inode, struct extent_position *epos, diff --git a/fs/udf/namei.c b/fs/udf/namei.c index 2be0f9eb86d2..f1dce848ef96 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -32,6 +32,8 @@  #include <linux/crc-itu-t.h>  #include <linux/exportfs.h> +enum { UDF_MAX_LINKS = 0xffff }; +  static inline int udf_match(int len1, const unsigned char *name1, int len2,  			    const unsigned char *name2)  { @@ -650,7 +652,7 @@ static int udf_mkdir(struct inode *dir, struct dentry *dentry, int mode)  	struct udf_inode_info *iinfo;  	err = -EMLINK; -	if (dir->i_nlink >= (256 << sizeof(dir->i_nlink)) - 1) +	if (dir->i_nlink >= UDF_MAX_LINKS)  		goto out;  	err = -EIO; @@ -1034,9 +1036,8 @@ static int udf_link(struct dentry *old_dentry, struct inode *dir,  	struct fileIdentDesc cfi, *fi;  	int err; -	if (inode->i_nlink >= (256 << sizeof(inode->i_nlink)) - 1) { +	if (inode->i_nlink >= UDF_MAX_LINKS)  		return -EMLINK; -	}  	fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);  	if (!fi) { @@ -1131,9 +1132,7 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,  			goto end_rename;  		retval = -EMLINK; -		if (!new_inode && -			new_dir->i_nlink >= -				(256 << sizeof(new_dir->i_nlink)) - 1) +		if (!new_inode && new_dir->i_nlink >= UDF_MAX_LINKS)  			goto end_rename;  	}  	if (!nfi) { @@ -1287,8 +1286,13 @@ static int udf_encode_fh(struct dentry *de, __u32 *fh, int *lenp,  	struct fid *fid = (struct fid *)fh;  	int type = FILEID_UDF_WITHOUT_PARENT; -	if (len < 3 || (connectable && len < 5)) +	if (connectable && (len < 5)) { +		*lenp = 5;  		return 255; +	} else if (len < 3) { +		*lenp = 3; +		return 255; +	}  	*lenp = 3;  	fid->udf.block = location.logicalBlockNum; diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c index 225527cdc885..8424308db4b4 100644 --- a/fs/udf/truncate.c +++ b/fs/udf/truncate.c @@ -197,6 +197,11 @@ static void udf_update_alloc_ext_desc(struct inode *inode,  	mark_buffer_dirty_inode(epos->bh, inode);  } +/* + * Truncate extents of inode to inode->i_size. This function can be used only + * for making file shorter. For making file longer, udf_extend_file() has to + * be used. + */  void udf_truncate_extents(struct inode *inode)  {  	struct extent_position epos; @@ -219,96 +224,65 @@ void udf_truncate_extents(struct inode *inode)  	etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset);  	byte_offset = (offset << sb->s_blocksize_bits) +  		(inode->i_size & (sb->s_blocksize - 1)); -	if (etype != -1) { -		epos.offset -= adsize; -		extent_trunc(inode, &epos, &eloc, etype, elen, byte_offset); -		epos.offset += adsize; -		if (byte_offset) -			lenalloc = epos.offset; -		else -			lenalloc = epos.offset - adsize; - -		if (!epos.bh) -			lenalloc -= udf_file_entry_alloc_offset(inode); -		else -			lenalloc -= sizeof(struct allocExtDesc); - -		while ((etype = udf_current_aext(inode, &epos, &eloc, -						 &elen, 0)) != -1) { -			if (etype == (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) { -				udf_write_aext(inode, &epos, &neloc, nelen, 0); -				if (indirect_ext_len) { -					/* We managed to free all extents in the -					 * indirect extent - free it too */ -					BUG_ON(!epos.bh); -					udf_free_blocks(sb, inode, &epos.block, -							0, indirect_ext_len); -				} else if (!epos.bh) { -					iinfo->i_lenAlloc = lenalloc; -					mark_inode_dirty(inode); -				} else -					udf_update_alloc_ext_desc(inode, -							&epos, lenalloc); -				brelse(epos.bh); -				epos.offset = sizeof(struct allocExtDesc); -				epos.block = eloc; -				epos.bh = udf_tread(sb, -						udf_get_lb_pblock(sb, &eloc, 0)); -				if (elen) -					indirect_ext_len = -						(elen + sb->s_blocksize - 1) >> -						sb->s_blocksize_bits; -				else -					indirect_ext_len = 1; -			} else { -				extent_trunc(inode, &epos, &eloc, etype, -					     elen, 0); -				epos.offset += adsize; -			} -		} +	if (etype == -1) { +		/* We should extend the file? */ +		WARN_ON(byte_offset); +		return; +	} +	epos.offset -= adsize; +	extent_trunc(inode, &epos, &eloc, etype, elen, byte_offset); +	epos.offset += adsize; +	if (byte_offset) +		lenalloc = epos.offset; +	else +		lenalloc = epos.offset - adsize; -		if (indirect_ext_len) { -			BUG_ON(!epos.bh); -			udf_free_blocks(sb, inode, &epos.block, 0, -					indirect_ext_len); -		} else if (!epos.bh) { -			iinfo->i_lenAlloc = lenalloc; -			mark_inode_dirty(inode); -		} else -			udf_update_alloc_ext_desc(inode, &epos, lenalloc); -	} else if (inode->i_size) { -		if (byte_offset) { -			struct kernel_long_ad extent; +	if (!epos.bh) +		lenalloc -= udf_file_entry_alloc_offset(inode); +	else +		lenalloc -= sizeof(struct allocExtDesc); -			/* -			 *  OK, there is not extent covering inode->i_size and -			 *  no extent above inode->i_size => truncate is -			 *  extending the file by 'offset' blocks. -			 */ -			if ((!epos.bh && -			     epos.offset == -					udf_file_entry_alloc_offset(inode)) || -			    (epos.bh && epos.offset == -						sizeof(struct allocExtDesc))) { -				/* File has no extents at all or has empty last -				 * indirect extent! Create a fake extent... */ -				extent.extLocation.logicalBlockNum = 0; -				extent.extLocation.partitionReferenceNum = 0; -				extent.extLength = -					EXT_NOT_RECORDED_NOT_ALLOCATED; -			} else { -				epos.offset -= adsize; -				etype = udf_next_aext(inode, &epos, -						      &extent.extLocation, -						      &extent.extLength, 0); -				extent.extLength |= etype << 30; -			} -			udf_extend_file(inode, &epos, &extent, -					offset + -					((inode->i_size & -						(sb->s_blocksize - 1)) != 0)); +	while ((etype = udf_current_aext(inode, &epos, &eloc, +					 &elen, 0)) != -1) { +		if (etype == (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) { +			udf_write_aext(inode, &epos, &neloc, nelen, 0); +			if (indirect_ext_len) { +				/* We managed to free all extents in the +				 * indirect extent - free it too */ +				BUG_ON(!epos.bh); +				udf_free_blocks(sb, inode, &epos.block, +						0, indirect_ext_len); +			} else if (!epos.bh) { +				iinfo->i_lenAlloc = lenalloc; +				mark_inode_dirty(inode); +			} else +				udf_update_alloc_ext_desc(inode, +						&epos, lenalloc); +			brelse(epos.bh); +			epos.offset = sizeof(struct allocExtDesc); +			epos.block = eloc; +			epos.bh = udf_tread(sb, +					udf_get_lb_pblock(sb, &eloc, 0)); +			if (elen) +				indirect_ext_len = +					(elen + sb->s_blocksize - 1) >> +					sb->s_blocksize_bits; +			else +				indirect_ext_len = 1; +		} else { +			extent_trunc(inode, &epos, &eloc, etype, elen, 0); +			epos.offset += adsize;  		}  	} + +	if (indirect_ext_len) { +		BUG_ON(!epos.bh); +		udf_free_blocks(sb, inode, &epos.block, 0, indirect_ext_len); +	} else if (!epos.bh) { +		iinfo->i_lenAlloc = lenalloc; +		mark_inode_dirty(inode); +	} else +		udf_update_alloc_ext_desc(inode, &epos, lenalloc);  	iinfo->i_lenExtents = inode->i_size;  	brelse(epos.bh); diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index eba48209f9f3..dbd52d4b5eed 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -136,22 +136,20 @@ extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *,  extern long udf_ioctl(struct file *, unsigned int, unsigned long);  /* inode.c */  extern struct inode *udf_iget(struct super_block *, struct kernel_lb_addr *); -extern void udf_expand_file_adinicb(struct inode *, int, int *); +extern int udf_expand_file_adinicb(struct inode *);  extern struct buffer_head *udf_expand_dir_adinicb(struct inode *, int *, int *);  extern struct buffer_head *udf_bread(struct inode *, int, int, int *); -extern void udf_truncate(struct inode *); +extern int udf_setsize(struct inode *, loff_t);  extern void udf_read_inode(struct inode *);  extern void udf_evict_inode(struct inode *);  extern int udf_write_inode(struct inode *, struct writeback_control *wbc);  extern long udf_block_map(struct inode *, sector_t); -extern int udf_extend_file(struct inode *, struct extent_position *, -			   struct kernel_long_ad *, sector_t);  extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *,  			 struct kernel_lb_addr *, uint32_t *, sector_t *); -extern int8_t udf_add_aext(struct inode *, struct extent_position *, +extern int udf_add_aext(struct inode *, struct extent_position *, +			struct kernel_lb_addr *, uint32_t, int); +extern void udf_write_aext(struct inode *, struct extent_position *,  			   struct kernel_lb_addr *, uint32_t, int); -extern int8_t udf_write_aext(struct inode *, struct extent_position *, -			     struct kernel_lb_addr *, uint32_t, int);  extern int8_t udf_delete_aext(struct inode *, struct extent_position,  			      struct kernel_lb_addr, uint32_t);  extern int8_t udf_next_aext(struct inode *, struct extent_position *,  | 
