Skip to content

Commit cfe4c1b

Browse files
committed
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: [email protected] Signed-off-by: Jan Kara <[email protected]>
1 parent 7868f93 commit cfe4c1b

File tree

1 file changed

+13
-32
lines changed

1 file changed

+13
-32
lines changed

fs/udf/truncate.c

Lines changed: 13 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -120,60 +120,41 @@ void udf_truncate_tail_extent(struct inode *inode)
120120

121121
void udf_discard_prealloc(struct inode *inode)
122122
{
123-
struct extent_position epos = { NULL, 0, {0, 0} };
123+
struct extent_position epos = {};
124+
struct extent_position prev_epos = {};
124125
struct kernel_lb_addr eloc;
125126
uint32_t elen;
126127
uint64_t lbcount = 0;
127128
int8_t etype = -1, netype;
128-
int adsize;
129129
struct udf_inode_info *iinfo = UDF_I(inode);
130130

131131
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB ||
132132
inode->i_size == iinfo->i_lenExtents)
133133
return;
134134

135-
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
136-
adsize = sizeof(struct short_ad);
137-
else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
138-
adsize = sizeof(struct long_ad);
139-
else
140-
adsize = 0;
141-
142135
epos.block = iinfo->i_location;
143136

144137
/* Find the last extent in the file */
145-
while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) {
146-
etype = netype;
138+
while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 0)) != -1) {
139+
brelse(prev_epos.bh);
140+
prev_epos = epos;
141+
if (prev_epos.bh)
142+
get_bh(prev_epos.bh);
143+
144+
etype = udf_next_aext(inode, &epos, &eloc, &elen, 1);
147145
lbcount += elen;
148146
}
149147
if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
150-
epos.offset -= adsize;
151148
lbcount -= elen;
152-
extent_trunc(inode, &epos, &eloc, etype, elen, 0);
153-
if (!epos.bh) {
154-
iinfo->i_lenAlloc =
155-
epos.offset -
156-
udf_file_entry_alloc_offset(inode);
157-
mark_inode_dirty(inode);
158-
} else {
159-
struct allocExtDesc *aed =
160-
(struct allocExtDesc *)(epos.bh->b_data);
161-
aed->lengthAllocDescs =
162-
cpu_to_le32(epos.offset -
163-
sizeof(struct allocExtDesc));
164-
if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
165-
UDF_SB(inode->i_sb)->s_udfrev >= 0x0201)
166-
udf_update_tag(epos.bh->b_data, epos.offset);
167-
else
168-
udf_update_tag(epos.bh->b_data,
169-
sizeof(struct allocExtDesc));
170-
mark_buffer_dirty_inode(epos.bh, inode);
171-
}
149+
udf_delete_aext(inode, prev_epos);
150+
udf_free_blocks(inode->i_sb, inode, &eloc, 0,
151+
DIV_ROUND_UP(elen, 1 << inode->i_blkbits));
172152
}
173153
/* This inode entry is in-memory only and thus we don't have to mark
174154
* the inode dirty */
175155
iinfo->i_lenExtents = lbcount;
176156
brelse(epos.bh);
157+
brelse(prev_epos.bh);
177158
}
178159

179160
static void udf_update_alloc_ext_desc(struct inode *inode,

0 commit comments

Comments
 (0)