diff options
author | Jan Kara <jack@suse.cz> | 2007-05-08 00:35:21 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-08 11:15:21 -0700 |
commit | 31170b6ad4ebe6c43c1cc3b8112274cf59474de0 (patch) | |
tree | 25e19a70a323f18757c60a658d930b63e8e45124 /fs/udf/truncate.c | |
parent | 948b9b2c967c3bec6136b2dbb9e1c12f62e03efa (diff) | |
download | linux-31170b6ad4ebe6c43c1cc3b8112274cf59474de0.tar.bz2 |
udf: support files larger than 1G
Make UDF work correctly for files larger than 1GB. As no extent can be
longer than (1<<30)-blocksize bytes, we have to create several extents if a
big hole is being created. As a side-effect, we now don't discard
preallocated blocks when creating a hole.
Signed-off-by: Jan Kara <jack@suse.cz>
Acked-by: Christoph Hellwig <hch@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/udf/truncate.c')
-rw-r--r-- | fs/udf/truncate.c | 68 |
1 files changed, 22 insertions, 46 deletions
diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c index 0e328cdc9a45..77975ae291a5 100644 --- a/fs/udf/truncate.c +++ b/fs/udf/truncate.c @@ -130,7 +130,8 @@ void udf_truncate_extents(struct inode * inode) kernel_lb_addr eloc, neloc = { 0, 0 }; uint32_t elen, nelen = 0, indirect_ext_len = 0, lenalloc; int8_t etype; - sector_t first_block = inode->i_size >> inode->i_sb->s_blocksize_bits, offset; + struct super_block *sb = inode->i_sb; + sector_t first_block = inode->i_size >> sb->s_blocksize_bits, offset; loff_t byte_offset; int adsize; @@ -142,7 +143,7 @@ void udf_truncate_extents(struct inode * inode) BUG(); etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset); - byte_offset = (offset << inode->i_sb->s_blocksize_bits) + (inode->i_size & (inode->i_sb->s_blocksize-1)); + byte_offset = (offset << sb->s_blocksize_bits) + (inode->i_size & (sb->s_blocksize-1)); if (etype != -1) { epos.offset -= adsize; @@ -169,7 +170,7 @@ void udf_truncate_extents(struct inode * inode) * indirect extent - free it too */ if (!epos.bh) BUG(); - udf_free_blocks(inode->i_sb, inode, epos.block, 0, indirect_ext_len); + udf_free_blocks(sb, inode, epos.block, 0, indirect_ext_len); } else { @@ -182,7 +183,7 @@ void udf_truncate_extents(struct inode * inode) { struct allocExtDesc *aed = (struct allocExtDesc *)(epos.bh->b_data); aed->lengthAllocDescs = cpu_to_le32(lenalloc); - if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) + if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(sb) >= 0x0201) udf_update_tag(epos.bh->b_data, lenalloc + sizeof(struct allocExtDesc)); else @@ -193,11 +194,11 @@ void udf_truncate_extents(struct inode * inode) brelse(epos.bh); epos.offset = sizeof(struct allocExtDesc); epos.block = eloc; - epos.bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, eloc, 0)); + epos.bh = udf_tread(sb, udf_get_lb_pblock(sb, eloc, 0)); if (elen) indirect_ext_len = (elen + - inode->i_sb->s_blocksize - 1) >> - inode->i_sb->s_blocksize_bits; + sb->s_blocksize - 1) >> + sb->s_blocksize_bits; else indirect_ext_len = 1; } @@ -212,7 +213,7 @@ void udf_truncate_extents(struct inode * inode) { if (!epos.bh) BUG(); - udf_free_blocks(inode->i_sb, inode, epos.block, 0, indirect_ext_len); + udf_free_blocks(sb, inode, epos.block, 0, indirect_ext_len); } else { @@ -225,7 +226,7 @@ void udf_truncate_extents(struct inode * inode) { struct allocExtDesc *aed = (struct allocExtDesc *)(epos.bh->b_data); aed->lengthAllocDescs = cpu_to_le32(lenalloc); - if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) + if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(sb) >= 0x0201) udf_update_tag(epos.bh->b_data, lenalloc + sizeof(struct allocExtDesc)); else @@ -238,53 +239,28 @@ void udf_truncate_extents(struct inode * inode) { if (byte_offset) { + kernel_long_ad extent; + /* * OK, there is not extent covering inode->i_size and * no extent above inode->i_size => truncate is - * extending the file by 'offset'. + * 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! */ - memset(&eloc, 0x00, sizeof(kernel_lb_addr)); - elen = EXT_NOT_RECORDED_NOT_ALLOCATED | byte_offset; - udf_add_aext(inode, &epos, eloc, elen, 1); + /* 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, &eloc, &elen, 1); - - if (etype == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) - { - epos.offset -= adsize; - elen = EXT_NOT_RECORDED_NOT_ALLOCATED | (elen + byte_offset); - udf_write_aext(inode, &epos, eloc, elen, 0); - } - else if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) - { - kernel_lb_addr neloc = { 0, 0 }; - epos.offset -= adsize; - nelen = EXT_NOT_RECORDED_NOT_ALLOCATED | - ((elen + byte_offset + inode->i_sb->s_blocksize - 1) & - ~(inode->i_sb->s_blocksize - 1)); - udf_write_aext(inode, &epos, neloc, nelen, 1); - udf_add_aext(inode, &epos, eloc, (etype << 30) | elen, 1); - } - else - { - if (elen & (inode->i_sb->s_blocksize - 1)) - { - epos.offset -= adsize; - elen = EXT_RECORDED_ALLOCATED | - ((elen + inode->i_sb->s_blocksize - 1) & - ~(inode->i_sb->s_blocksize - 1)); - udf_write_aext(inode, &epos, eloc, elen, 1); - } - memset(&eloc, 0x00, sizeof(kernel_lb_addr)); - elen = EXT_NOT_RECORDED_NOT_ALLOCATED | byte_offset; - udf_add_aext(inode, &epos, eloc, elen, 1); - } + 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)); } } UDF_I_LENEXTENTS(inode) = inode->i_size; |