1 // SPDX-License-Identifier: GPL-2.0-only
6 * Truncate handling routines for the OSTA-UDF(tm) filesystem.
9 * (C) 1999-2004 Ben Fennema
10 * (C) 1999 Stelias Computing Inc
14 * 02/24/99 blf Created.
25 static void extent_trunc(struct inode
*inode
, struct extent_position
*epos
,
26 struct kernel_lb_addr
*eloc
, int8_t etype
, uint32_t elen
,
29 struct kernel_lb_addr neloc
= {};
30 int last_block
= (elen
+ inode
->i_sb
->s_blocksize
- 1) >>
31 inode
->i_sb
->s_blocksize_bits
;
32 int first_block
= (nelen
+ inode
->i_sb
->s_blocksize
- 1) >>
33 inode
->i_sb
->s_blocksize_bits
;
36 if (etype
== (EXT_NOT_RECORDED_ALLOCATED
>> 30)) {
37 udf_free_blocks(inode
->i_sb
, inode
, eloc
, 0,
39 etype
= (EXT_NOT_RECORDED_NOT_ALLOCATED
>> 30);
42 nelen
= (etype
<< 30) | nelen
;
46 udf_write_aext(inode
, epos
, &neloc
, nelen
, 0);
47 if (last_block
> first_block
) {
48 if (etype
== (EXT_RECORDED_ALLOCATED
>> 30))
49 mark_inode_dirty(inode
);
51 if (etype
!= (EXT_NOT_RECORDED_NOT_ALLOCATED
>> 30))
52 udf_free_blocks(inode
->i_sb
, inode
, eloc
,
54 last_block
- first_block
);
60 * Truncate the last extent to match i_size. This function assumes
61 * that preallocation extent is already truncated.
63 void udf_truncate_tail_extent(struct inode
*inode
)
65 struct extent_position epos
= {};
66 struct kernel_lb_addr eloc
;
69 int8_t etype
= -1, netype
;
71 struct udf_inode_info
*iinfo
= UDF_I(inode
);
73 if (iinfo
->i_alloc_type
== ICBTAG_FLAG_AD_IN_ICB
||
74 inode
->i_size
== iinfo
->i_lenExtents
)
76 /* Are we going to delete the file anyway? */
77 if (inode
->i_nlink
== 0)
80 if (iinfo
->i_alloc_type
== ICBTAG_FLAG_AD_SHORT
)
81 adsize
= sizeof(struct short_ad
);
82 else if (iinfo
->i_alloc_type
== ICBTAG_FLAG_AD_LONG
)
83 adsize
= sizeof(struct long_ad
);
87 /* Find the last extent in the file */
88 while ((netype
= udf_next_aext(inode
, &epos
, &eloc
, &elen
, 1)) != -1) {
91 if (lbcount
> inode
->i_size
) {
92 if (lbcount
- inode
->i_size
>= inode
->i_sb
->s_blocksize
)
94 "Too long extent after EOF in inode %u: i_size: %lld lbcount: %lld extent %u+%u\n",
95 (unsigned)inode
->i_ino
,
96 (long long)inode
->i_size
,
98 (unsigned)eloc
.logicalBlockNum
,
100 nelen
= elen
- (lbcount
- inode
->i_size
);
101 epos
.offset
-= adsize
;
102 extent_trunc(inode
, &epos
, &eloc
, etype
, elen
, nelen
);
103 epos
.offset
+= adsize
;
104 if (udf_next_aext(inode
, &epos
, &eloc
, &elen
, 1) != -1)
106 "Extent after EOF in inode %u\n",
107 (unsigned)inode
->i_ino
);
111 /* This inode entry is in-memory only and thus we don't have to mark
113 iinfo
->i_lenExtents
= inode
->i_size
;
117 void udf_discard_prealloc(struct inode
*inode
)
119 struct extent_position epos
= {};
120 struct extent_position prev_epos
= {};
121 struct kernel_lb_addr eloc
;
123 uint64_t lbcount
= 0;
125 struct udf_inode_info
*iinfo
= UDF_I(inode
);
126 int bsize
= i_blocksize(inode
);
128 if (iinfo
->i_alloc_type
== ICBTAG_FLAG_AD_IN_ICB
||
129 ALIGN(inode
->i_size
, bsize
) == ALIGN(iinfo
->i_lenExtents
, bsize
))
132 epos
.block
= iinfo
->i_location
;
134 /* Find the last extent in the file */
135 while (udf_next_aext(inode
, &epos
, &eloc
, &elen
, 0) != -1) {
136 brelse(prev_epos
.bh
);
139 get_bh(prev_epos
.bh
);
141 etype
= udf_next_aext(inode
, &epos
, &eloc
, &elen
, 1);
144 if (etype
== (EXT_NOT_RECORDED_ALLOCATED
>> 30)) {
146 udf_delete_aext(inode
, prev_epos
);
147 udf_free_blocks(inode
->i_sb
, inode
, &eloc
, 0,
148 DIV_ROUND_UP(elen
, bsize
));
150 /* This inode entry is in-memory only and thus we don't have to mark
152 iinfo
->i_lenExtents
= lbcount
;
154 brelse(prev_epos
.bh
);
157 static void udf_update_alloc_ext_desc(struct inode
*inode
,
158 struct extent_position
*epos
,
161 struct super_block
*sb
= inode
->i_sb
;
162 struct udf_sb_info
*sbi
= UDF_SB(sb
);
164 struct allocExtDesc
*aed
= (struct allocExtDesc
*) (epos
->bh
->b_data
);
165 int len
= sizeof(struct allocExtDesc
);
167 aed
->lengthAllocDescs
= cpu_to_le32(lenalloc
);
168 if (!UDF_QUERY_FLAG(sb
, UDF_FLAG_STRICT
) || sbi
->s_udfrev
>= 0x0201)
171 udf_update_tag(epos
->bh
->b_data
, len
);
172 mark_buffer_dirty_inode(epos
->bh
, inode
);
176 * Truncate extents of inode to inode->i_size. This function can be used only
177 * for making file shorter. For making file longer, udf_extend_file() has to
180 int udf_truncate_extents(struct inode
*inode
)
182 struct extent_position epos
;
183 struct kernel_lb_addr eloc
, neloc
= {};
184 uint32_t elen
, nelen
= 0, indirect_ext_len
= 0, lenalloc
;
186 struct super_block
*sb
= inode
->i_sb
;
187 sector_t first_block
= inode
->i_size
>> sb
->s_blocksize_bits
, offset
;
190 struct udf_inode_info
*iinfo
= UDF_I(inode
);
192 if (iinfo
->i_alloc_type
== ICBTAG_FLAG_AD_SHORT
)
193 adsize
= sizeof(struct short_ad
);
194 else if (iinfo
->i_alloc_type
== ICBTAG_FLAG_AD_LONG
)
195 adsize
= sizeof(struct long_ad
);
199 etype
= inode_bmap(inode
, first_block
, &epos
, &eloc
, &elen
, &offset
);
200 byte_offset
= (offset
<< sb
->s_blocksize_bits
) +
201 (inode
->i_size
& (sb
->s_blocksize
- 1));
203 /* We should extend the file? */
204 WARN_ON(byte_offset
);
207 epos
.offset
-= adsize
;
208 extent_trunc(inode
, &epos
, &eloc
, etype
, elen
, byte_offset
);
209 epos
.offset
+= adsize
;
211 lenalloc
= epos
.offset
;
213 lenalloc
= epos
.offset
- adsize
;
216 lenalloc
-= udf_file_entry_alloc_offset(inode
);
218 lenalloc
-= sizeof(struct allocExtDesc
);
220 while ((etype
= udf_current_aext(inode
, &epos
, &eloc
,
222 if (etype
== (EXT_NEXT_EXTENT_ALLOCDESCS
>> 30)) {
223 udf_write_aext(inode
, &epos
, &neloc
, nelen
, 0);
224 if (indirect_ext_len
) {
225 /* We managed to free all extents in the
226 * indirect extent - free it too */
228 udf_free_blocks(sb
, NULL
, &epos
.block
,
229 0, indirect_ext_len
);
230 } else if (!epos
.bh
) {
231 iinfo
->i_lenAlloc
= lenalloc
;
232 mark_inode_dirty(inode
);
234 udf_update_alloc_ext_desc(inode
,
237 epos
.offset
= sizeof(struct allocExtDesc
);
239 epos
.bh
= sb_bread(sb
,
240 udf_get_lb_pblock(sb
, &eloc
, 0));
241 /* Error reading indirect block? */
246 (elen
+ sb
->s_blocksize
- 1) >>
247 sb
->s_blocksize_bits
;
249 indirect_ext_len
= 1;
251 extent_trunc(inode
, &epos
, &eloc
, etype
, elen
, 0);
252 epos
.offset
+= adsize
;
256 if (indirect_ext_len
) {
258 udf_free_blocks(sb
, NULL
, &epos
.block
, 0, indirect_ext_len
);
259 } else if (!epos
.bh
) {
260 iinfo
->i_lenAlloc
= lenalloc
;
261 mark_inode_dirty(inode
);
263 udf_update_alloc_ext_desc(inode
, &epos
, lenalloc
);
264 iinfo
->i_lenExtents
= inode
->i_size
;