Skip to content

Commit 63dbbd8

Browse files
jankaragregkh
authored andcommitted
udf: Fix preallocation discarding at indirect extent boundary
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>
1 parent 79a97f0 commit 63dbbd8

1 file changed

Lines changed: 13 additions & 32 deletions

File tree

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)