|
|
@@ -470,13 +470,15 @@ static struct buffer_head *udf_getblk(struct inode *inode, udf_pblk_t block,
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
-/* Extend the file by 'blocks' blocks, return the number of extents added */
|
|
|
+/* Extend the file with new blocks totaling 'new_block_bytes',
|
|
|
+ * return the number of extents added
|
|
|
+ */
|
|
|
static int udf_do_extend_file(struct inode *inode,
|
|
|
struct extent_position *last_pos,
|
|
|
struct kernel_long_ad *last_ext,
|
|
|
- sector_t blocks)
|
|
|
+ loff_t new_block_bytes)
|
|
|
{
|
|
|
- sector_t add;
|
|
|
+ uint32_t add;
|
|
|
int count = 0, fake = !(last_ext->extLength & UDF_EXTENT_LENGTH_MASK);
|
|
|
struct super_block *sb = inode->i_sb;
|
|
|
struct kernel_lb_addr prealloc_loc = {};
|
|
|
@@ -486,7 +488,7 @@ static int udf_do_extend_file(struct inode *inode,
|
|
|
|
|
|
/* The previous extent is fake and we should not extend by anything
|
|
|
* - there's nothing to do... */
|
|
|
- if (!blocks && fake)
|
|
|
+ if (!new_block_bytes && fake)
|
|
|
return 0;
|
|
|
|
|
|
iinfo = UDF_I(inode);
|
|
|
@@ -517,13 +519,12 @@ static int udf_do_extend_file(struct inode *inode,
|
|
|
/* 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;
|
|
|
+ add = (1 << 30) - sb->s_blocksize -
|
|
|
+ (last_ext->extLength & UDF_EXTENT_LENGTH_MASK);
|
|
|
+ if (add > new_block_bytes)
|
|
|
+ add = new_block_bytes;
|
|
|
+ new_block_bytes -= add;
|
|
|
+ last_ext->extLength += add;
|
|
|
}
|
|
|
|
|
|
if (fake) {
|
|
|
@@ -544,28 +545,27 @@ static int udf_do_extend_file(struct inode *inode,
|
|
|
}
|
|
|
|
|
|
/* Managed to do everything necessary? */
|
|
|
- if (!blocks)
|
|
|
+ if (!new_block_bytes)
|
|
|
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);
|
|
|
+ add = (1 << 30) - sb->s_blocksize;
|
|
|
+ last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | add;
|
|
|
|
|
|
/* Create enough extents to cover the whole hole */
|
|
|
- while (blocks > add) {
|
|
|
- blocks -= add;
|
|
|
+ while (new_block_bytes > add) {
|
|
|
+ new_block_bytes -= add;
|
|
|
err = udf_add_aext(inode, last_pos, &last_ext->extLocation,
|
|
|
last_ext->extLength, 1);
|
|
|
if (err)
|
|
|
return err;
|
|
|
count++;
|
|
|
}
|
|
|
- if (blocks) {
|
|
|
+ if (new_block_bytes) {
|
|
|
last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
|
|
|
- (blocks << sb->s_blocksize_bits);
|
|
|
+ new_block_bytes;
|
|
|
err = udf_add_aext(inode, last_pos, &last_ext->extLocation,
|
|
|
last_ext->extLength, 1);
|
|
|
if (err)
|
|
|
@@ -596,6 +596,24 @@ out:
|
|
|
return count;
|
|
|
}
|
|
|
|
|
|
+/* Extend the final block of the file to final_block_len bytes */
|
|
|
+static void udf_do_extend_final_block(struct inode *inode,
|
|
|
+ struct extent_position *last_pos,
|
|
|
+ struct kernel_long_ad *last_ext,
|
|
|
+ uint32_t final_block_len)
|
|
|
+{
|
|
|
+ struct super_block *sb = inode->i_sb;
|
|
|
+ uint32_t added_bytes;
|
|
|
+
|
|
|
+ added_bytes = final_block_len -
|
|
|
+ (last_ext->extLength & (sb->s_blocksize - 1));
|
|
|
+ last_ext->extLength += added_bytes;
|
|
|
+ UDF_I(inode)->i_lenExtents += added_bytes;
|
|
|
+
|
|
|
+ udf_write_aext(inode, last_pos, &last_ext->extLocation,
|
|
|
+ last_ext->extLength, 1);
|
|
|
+}
|
|
|
+
|
|
|
static int udf_extend_file(struct inode *inode, loff_t newsize)
|
|
|
{
|
|
|
|
|
|
@@ -605,10 +623,12 @@ static int udf_extend_file(struct inode *inode, loff_t newsize)
|
|
|
int8_t etype;
|
|
|
struct super_block *sb = inode->i_sb;
|
|
|
sector_t first_block = newsize >> sb->s_blocksize_bits, offset;
|
|
|
+ unsigned long partial_final_block;
|
|
|
int adsize;
|
|
|
struct udf_inode_info *iinfo = UDF_I(inode);
|
|
|
struct kernel_long_ad extent;
|
|
|
- int err;
|
|
|
+ int err = 0;
|
|
|
+ int within_final_block;
|
|
|
|
|
|
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
|
|
|
adsize = sizeof(struct short_ad);
|
|
|
@@ -618,18 +638,8 @@ static int udf_extend_file(struct inode *inode, loff_t newsize)
|
|
|
BUG();
|
|
|
|
|
|
etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset);
|
|
|
+ within_final_block = (etype != -1);
|
|
|
|
|
|
- /* 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
|
|
|
@@ -643,7 +653,22 @@ static int udf_extend_file(struct inode *inode, loff_t newsize)
|
|
|
&extent.extLength, 0);
|
|
|
extent.extLength |= etype << 30;
|
|
|
}
|
|
|
- err = udf_do_extend_file(inode, &epos, &extent, offset);
|
|
|
+
|
|
|
+ partial_final_block = newsize & (sb->s_blocksize - 1);
|
|
|
+
|
|
|
+ /* File has extent covering the new size (could happen when extending
|
|
|
+ * inside a block)?
|
|
|
+ */
|
|
|
+ if (within_final_block) {
|
|
|
+ /* Extending file within the last file block */
|
|
|
+ udf_do_extend_final_block(inode, &epos, &extent,
|
|
|
+ partial_final_block);
|
|
|
+ } else {
|
|
|
+ loff_t add = ((loff_t)offset << sb->s_blocksize_bits) |
|
|
|
+ partial_final_block;
|
|
|
+ err = udf_do_extend_file(inode, &epos, &extent, add);
|
|
|
+ }
|
|
|
+
|
|
|
if (err < 0)
|
|
|
goto out;
|
|
|
err = 0;
|
|
|
@@ -745,6 +770,7 @@ static sector_t inode_getblk(struct inode *inode, sector_t block,
|
|
|
/* Are we beyond EOF? */
|
|
|
if (etype == -1) {
|
|
|
int ret;
|
|
|
+ loff_t hole_len;
|
|
|
isBeyondEOF = true;
|
|
|
if (count) {
|
|
|
if (c)
|
|
|
@@ -760,7 +786,8 @@ static sector_t inode_getblk(struct inode *inode, sector_t block,
|
|
|
startnum = (offset > 0);
|
|
|
}
|
|
|
/* Create extents for the hole between EOF and offset */
|
|
|
- ret = udf_do_extend_file(inode, &prev_epos, laarr, offset);
|
|
|
+ hole_len = (loff_t)offset << inode->i_blkbits;
|
|
|
+ ret = udf_do_extend_file(inode, &prev_epos, laarr, hole_len);
|
|
|
if (ret < 0) {
|
|
|
*err = ret;
|
|
|
newblock = 0;
|