xref: /openbmc/linux/fs/udf/truncate.c (revision a1e58bbd)
1 /*
2  * truncate.c
3  *
4  * PURPOSE
5  *	Truncate handling routines for the OSTA-UDF(tm) filesystem.
6  *
7  * COPYRIGHT
8  *	This file is distributed under the terms of the GNU General Public
9  *	License (GPL). Copies of the GPL can be obtained from:
10  *		ftp://prep.ai.mit.edu/pub/gnu/GPL
11  *	Each contributing author retains all rights to their own work.
12  *
13  *  (C) 1999-2004 Ben Fennema
14  *  (C) 1999 Stelias Computing Inc
15  *
16  * HISTORY
17  *
18  *  02/24/99 blf  Created.
19  *
20  */
21 
22 #include "udfdecl.h"
23 #include <linux/fs.h>
24 #include <linux/mm.h>
25 #include <linux/udf_fs.h>
26 #include <linux/buffer_head.h>
27 
28 #include "udf_i.h"
29 #include "udf_sb.h"
30 
31 static void extent_trunc(struct inode *inode, struct extent_position *epos,
32 			 kernel_lb_addr eloc, int8_t etype, uint32_t elen,
33 			 uint32_t nelen)
34 {
35 	kernel_lb_addr neloc = {};
36 	int last_block = (elen + inode->i_sb->s_blocksize - 1) >>
37 		inode->i_sb->s_blocksize_bits;
38 	int first_block = (nelen + inode->i_sb->s_blocksize - 1) >>
39 		inode->i_sb->s_blocksize_bits;
40 
41 	if (nelen) {
42 		if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
43 			udf_free_blocks(inode->i_sb, inode, eloc, 0,
44 					last_block);
45 			etype = (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30);
46 		} else
47 			neloc = eloc;
48 		nelen = (etype << 30) | nelen;
49 	}
50 
51 	if (elen != nelen) {
52 		udf_write_aext(inode, epos, neloc, nelen, 0);
53 		if (last_block - first_block > 0) {
54 			if (etype == (EXT_RECORDED_ALLOCATED >> 30))
55 				mark_inode_dirty(inode);
56 
57 			if (etype != (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
58 				udf_free_blocks(inode->i_sb, inode, eloc,
59 						first_block,
60 						last_block - first_block);
61 		}
62 	}
63 }
64 
65 /*
66  * Truncate the last extent to match i_size. This function assumes
67  * that preallocation extent is already truncated.
68  */
69 void udf_truncate_tail_extent(struct inode *inode)
70 {
71 	struct extent_position epos = {};
72 	kernel_lb_addr eloc;
73 	uint32_t elen, nelen;
74 	uint64_t lbcount = 0;
75 	int8_t etype = -1, netype;
76 	int adsize;
77 	struct udf_inode_info *iinfo = UDF_I(inode);
78 
79 	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB ||
80 	    inode->i_size == iinfo->i_lenExtents)
81 		return;
82 	/* Are we going to delete the file anyway? */
83 	if (inode->i_nlink == 0)
84 		return;
85 
86 	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
87 		adsize = sizeof(short_ad);
88 	else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
89 		adsize = sizeof(long_ad);
90 	else
91 		BUG();
92 
93 	/* Find the last extent in the file */
94 	while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) {
95 		etype = netype;
96 		lbcount += elen;
97 		if (lbcount > inode->i_size) {
98 			if (lbcount - inode->i_size >= inode->i_sb->s_blocksize)
99 				printk(KERN_WARNING
100 				       "udf_truncate_tail_extent(): Too long "
101 				       "extent after EOF in inode %u: i_size: "
102 				       "%Ld lbcount: %Ld extent %u+%u\n",
103 				       (unsigned)inode->i_ino,
104 				       (long long)inode->i_size,
105 				       (long long)lbcount,
106 				       (unsigned)eloc.logicalBlockNum,
107 				       (unsigned)elen);
108 			nelen = elen - (lbcount - inode->i_size);
109 			epos.offset -= adsize;
110 			extent_trunc(inode, &epos, eloc, etype, elen, nelen);
111 			epos.offset += adsize;
112 			if (udf_next_aext(inode, &epos, &eloc, &elen, 1) != -1)
113 				printk(KERN_ERR "udf_truncate_tail_extent(): "
114 				       "Extent after EOF in inode %u.\n",
115 				       (unsigned)inode->i_ino);
116 			break;
117 		}
118 	}
119 	/* This inode entry is in-memory only and thus we don't have to mark
120 	 * the inode dirty */
121 	iinfo->i_lenExtents = inode->i_size;
122 	brelse(epos.bh);
123 }
124 
125 void udf_discard_prealloc(struct inode *inode)
126 {
127 	struct extent_position epos = { NULL, 0, {0, 0} };
128 	kernel_lb_addr eloc;
129 	uint32_t elen;
130 	uint64_t lbcount = 0;
131 	int8_t etype = -1, netype;
132 	int adsize;
133 	struct udf_inode_info *iinfo = UDF_I(inode);
134 
135 	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB ||
136 	    inode->i_size == iinfo->i_lenExtents)
137 		return;
138 
139 	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
140 		adsize = sizeof(short_ad);
141 	else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
142 		adsize = sizeof(long_ad);
143 	else
144 		adsize = 0;
145 
146 	epos.block = iinfo->i_location;
147 
148 	/* Find the last extent in the file */
149 	while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) {
150 		etype = netype;
151 		lbcount += elen;
152 	}
153 	if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
154 		epos.offset -= adsize;
155 		lbcount -= elen;
156 		extent_trunc(inode, &epos, eloc, etype, elen, 0);
157 		if (!epos.bh) {
158 			iinfo->i_lenAlloc =
159 				epos.offset -
160 				udf_file_entry_alloc_offset(inode);
161 			mark_inode_dirty(inode);
162 		} else {
163 			struct allocExtDesc *aed =
164 				(struct allocExtDesc *)(epos.bh->b_data);
165 			aed->lengthAllocDescs =
166 				cpu_to_le32(epos.offset -
167 					    sizeof(struct allocExtDesc));
168 			if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
169 			    UDF_SB(inode->i_sb)->s_udfrev >= 0x0201)
170 				udf_update_tag(epos.bh->b_data, epos.offset);
171 			else
172 				udf_update_tag(epos.bh->b_data,
173 					       sizeof(struct allocExtDesc));
174 			mark_buffer_dirty_inode(epos.bh, inode);
175 		}
176 	}
177 	/* This inode entry is in-memory only and thus we don't have to mark
178 	 * the inode dirty */
179 	iinfo->i_lenExtents = lbcount;
180 	brelse(epos.bh);
181 }
182 
183 void udf_truncate_extents(struct inode *inode)
184 {
185 	struct extent_position epos;
186 	kernel_lb_addr eloc, neloc = {};
187 	uint32_t elen, nelen = 0, indirect_ext_len = 0, lenalloc;
188 	int8_t etype;
189 	struct super_block *sb = inode->i_sb;
190 	struct udf_sb_info *sbi = UDF_SB(sb);
191 	sector_t first_block = inode->i_size >> sb->s_blocksize_bits, offset;
192 	loff_t byte_offset;
193 	int adsize;
194 	struct udf_inode_info *iinfo = UDF_I(inode);
195 
196 	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
197 		adsize = sizeof(short_ad);
198 	else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
199 		adsize = sizeof(long_ad);
200 	else
201 		BUG();
202 
203 	etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset);
204 	byte_offset = (offset << sb->s_blocksize_bits) +
205 		(inode->i_size & (sb->s_blocksize - 1));
206 	if (etype != -1) {
207 		epos.offset -= adsize;
208 		extent_trunc(inode, &epos, eloc, etype, elen, byte_offset);
209 		epos.offset += adsize;
210 		if (byte_offset)
211 			lenalloc = epos.offset;
212 		else
213 			lenalloc = epos.offset - adsize;
214 
215 		if (!epos.bh)
216 			lenalloc -= udf_file_entry_alloc_offset(inode);
217 		else
218 			lenalloc -= sizeof(struct allocExtDesc);
219 
220 		while ((etype = udf_current_aext(inode, &epos, &eloc,
221 						 &elen, 0)) != -1) {
222 			if (etype == (EXT_NEXT_EXTENT_ALLOCDECS >> 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 */
227 					if (!epos.bh)
228 						BUG();
229 					udf_free_blocks(sb, inode, epos.block,
230 							0, indirect_ext_len);
231 				} else {
232 					if (!epos.bh) {
233 						iinfo->i_lenAlloc =
234 								lenalloc;
235 						mark_inode_dirty(inode);
236 					} else {
237 						struct allocExtDesc *aed =
238 							(struct allocExtDesc *)
239 							(epos.bh->b_data);
240 						int len =
241 						    sizeof(struct allocExtDesc);
242 
243 						aed->lengthAllocDescs =
244 						    cpu_to_le32(lenalloc);
245 						if (!UDF_QUERY_FLAG(sb,
246 							UDF_FLAG_STRICT) ||
247 						    sbi->s_udfrev >= 0x0201)
248 							len += lenalloc;
249 
250 						udf_update_tag(epos.bh->b_data,
251 								len);
252 						mark_buffer_dirty_inode(
253 								epos.bh, inode);
254 					}
255 				}
256 				brelse(epos.bh);
257 				epos.offset = sizeof(struct allocExtDesc);
258 				epos.block = eloc;
259 				epos.bh = udf_tread(sb,
260 						udf_get_lb_pblock(sb, eloc, 0));
261 				if (elen)
262 					indirect_ext_len =
263 						(elen + sb->s_blocksize - 1) >>
264 						sb->s_blocksize_bits;
265 				else
266 					indirect_ext_len = 1;
267 			} else {
268 				extent_trunc(inode, &epos, eloc, etype,
269 					     elen, 0);
270 				epos.offset += adsize;
271 			}
272 		}
273 
274 		if (indirect_ext_len) {
275 			if (!epos.bh)
276 				BUG();
277 			udf_free_blocks(sb, inode, epos.block, 0,
278 					indirect_ext_len);
279 		} else {
280 			if (!epos.bh) {
281 				iinfo->i_lenAlloc = lenalloc;
282 				mark_inode_dirty(inode);
283 			} else {
284 				struct allocExtDesc *aed =
285 				    (struct allocExtDesc *)(epos.bh->b_data);
286 				aed->lengthAllocDescs = cpu_to_le32(lenalloc);
287 				if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) ||
288 				    sbi->s_udfrev >= 0x0201)
289 					udf_update_tag(epos.bh->b_data,
290 						lenalloc +
291 						sizeof(struct allocExtDesc));
292 				else
293 					udf_update_tag(epos.bh->b_data,
294 						sizeof(struct allocExtDesc));
295 				mark_buffer_dirty_inode(epos.bh, inode);
296 			}
297 		}
298 	} else if (inode->i_size) {
299 		if (byte_offset) {
300 			kernel_long_ad extent;
301 
302 			/*
303 			 *  OK, there is not extent covering inode->i_size and
304 			 *  no extent above inode->i_size => truncate is
305 			 *  extending the file by 'offset' blocks.
306 			 */
307 			if ((!epos.bh &&
308 			     epos.offset ==
309 					udf_file_entry_alloc_offset(inode)) ||
310 			    (epos.bh && epos.offset ==
311 						sizeof(struct allocExtDesc))) {
312 				/* File has no extents at all or has empty last
313 				 * indirect extent! Create a fake extent... */
314 				extent.extLocation.logicalBlockNum = 0;
315 				extent.extLocation.partitionReferenceNum = 0;
316 				extent.extLength =
317 					EXT_NOT_RECORDED_NOT_ALLOCATED;
318 			} else {
319 				epos.offset -= adsize;
320 				etype = udf_next_aext(inode, &epos,
321 						      &extent.extLocation,
322 						      &extent.extLength, 0);
323 				extent.extLength |= etype << 30;
324 			}
325 			udf_extend_file(inode, &epos, &extent,
326 					offset +
327 					((inode->i_size &
328 						(sb->s_blocksize - 1)) != 0));
329 		}
330 	}
331 	iinfo->i_lenExtents = inode->i_size;
332 
333 	brelse(epos.bh);
334 }
335