Skip to content

Commit

Permalink
udf: Fix preallocation discarding at indirect extent boundary
Browse files Browse the repository at this point in the history
commit cfe4c1b upstream.

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: Jan Kara <jack@suse.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
jankara authored and gregkh committed Dec 21, 2022
1 parent 79a97f0 commit 63dbbd8
Showing 1 changed file with 13 additions and 32 deletions.
45 changes: 13 additions & 32 deletions fs/udf/truncate.c
Expand Up @@ -120,60 +120,41 @@ void udf_truncate_tail_extent(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;
uint32_t elen;
uint64_t lbcount = 0;
int8_t etype = -1, netype;
int adsize;
struct udf_inode_info *iinfo = UDF_I(inode);

if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB ||
inode->i_size == iinfo->i_lenExtents)
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;

/* Find the last extent in the file */
while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) {
etype = netype;
while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 0)) != -1) {
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;
}
if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
epos.offset -= adsize;
lbcount -= elen;
extent_trunc(inode, &epos, &eloc, etype, elen, 0);
if (!epos.bh) {
iinfo->i_lenAlloc =
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);
}
udf_delete_aext(inode, prev_epos);
udf_free_blocks(inode->i_sb, inode, &eloc, 0,
DIV_ROUND_UP(elen, 1 << inode->i_blkbits));
}
/* This inode entry is in-memory only and thus we don't have to mark
* the inode dirty */
iinfo->i_lenExtents = lbcount;
brelse(epos.bh);
brelse(prev_epos.bh);
}

static void udf_update_alloc_ext_desc(struct inode *inode,
Expand Down

0 comments on commit 63dbbd8

Please sign in to comment.