Commit cfe4c1b2 authored by Jan Kara's avatar Jan Kara

udf: Fix preallocation discarding at indirect extent boundary

When preallocation extent is the first one in the extent block, the
code would corrupt extent tree header instead. Fix the problem and use
udf_delete_aext() for deleting extent to avoid some code duplication.

CC: stable@vger.kernel.org
Signed-off-by: default avatarJan Kara <jack@suse.cz>
parent 7868f930
...@@ -120,60 +120,41 @@ void udf_truncate_tail_extent(struct inode *inode) ...@@ -120,60 +120,41 @@ void udf_truncate_tail_extent(struct inode *inode)
void udf_discard_prealloc(struct inode *inode) void udf_discard_prealloc(struct inode *inode)
{ {
struct extent_position epos = { NULL, 0, {0, 0} }; struct extent_position epos = {};
struct extent_position prev_epos = {};
struct kernel_lb_addr eloc; struct kernel_lb_addr eloc;
uint32_t elen; uint32_t elen;
uint64_t lbcount = 0; uint64_t lbcount = 0;
int8_t etype = -1, netype; int8_t etype = -1, netype;
int adsize;
struct udf_inode_info *iinfo = UDF_I(inode); struct udf_inode_info *iinfo = UDF_I(inode);
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB || if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB ||
inode->i_size == iinfo->i_lenExtents) inode->i_size == iinfo->i_lenExtents)
return; return;
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
adsize = 0;
epos.block = iinfo->i_location; epos.block = iinfo->i_location;
/* Find the last extent in the file */ /* Find the last extent in the file */
while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) { while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 0)) != -1) {
etype = netype; brelse(prev_epos.bh);
prev_epos = epos;
if (prev_epos.bh)
get_bh(prev_epos.bh);
etype = udf_next_aext(inode, &epos, &eloc, &elen, 1);
lbcount += elen; lbcount += elen;
} }
if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) { if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
epos.offset -= adsize;
lbcount -= elen; lbcount -= elen;
extent_trunc(inode, &epos, &eloc, etype, elen, 0); udf_delete_aext(inode, prev_epos);
if (!epos.bh) { udf_free_blocks(inode->i_sb, inode, &eloc, 0,
iinfo->i_lenAlloc = DIV_ROUND_UP(elen, 1 << inode->i_blkbits));
epos.offset -
udf_file_entry_alloc_offset(inode);
mark_inode_dirty(inode);
} else {
struct allocExtDesc *aed =
(struct allocExtDesc *)(epos.bh->b_data);
aed->lengthAllocDescs =
cpu_to_le32(epos.offset -
sizeof(struct allocExtDesc));
if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
UDF_SB(inode->i_sb)->s_udfrev >= 0x0201)
udf_update_tag(epos.bh->b_data, epos.offset);
else
udf_update_tag(epos.bh->b_data,
sizeof(struct allocExtDesc));
mark_buffer_dirty_inode(epos.bh, inode);
}
} }
/* This inode entry is in-memory only and thus we don't have to mark /* This inode entry is in-memory only and thus we don't have to mark
* the inode dirty */ * the inode dirty */
iinfo->i_lenExtents = lbcount; iinfo->i_lenExtents = lbcount;
brelse(epos.bh); brelse(epos.bh);
brelse(prev_epos.bh);
} }
static void udf_update_alloc_ext_desc(struct inode *inode, static void udf_update_alloc_ext_desc(struct inode *inode,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment