Blame view

fs/udf/truncate.c 8.9 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
  /*
   * truncate.c
   *
   * PURPOSE
   *	Truncate handling routines for the OSTA-UDF(tm) filesystem.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
   * COPYRIGHT
   *	This file is distributed under the terms of the GNU General Public
   *	License (GPL). Copies of the GPL can be obtained from:
   *		ftp://prep.ai.mit.edu/pub/gnu/GPL
   *	Each contributing author retains all rights to their own work.
   *
   *  (C) 1999-2004 Ben Fennema
   *  (C) 1999 Stelias Computing Inc
   *
   * HISTORY
   *
   *  02/24/99 blf  Created.
   *
   */
  
  #include "udfdecl.h"
  #include <linux/fs.h>
  #include <linux/mm.h>
  #include <linux/udf_fs.h>
  #include <linux/buffer_head.h>
  
  #include "udf_i.h"
  #include "udf_sb.h"
cb00ea352   Cyrill Gorcunov   UDF: coding style...
30
31
32
  static void extent_trunc(struct inode *inode, struct extent_position *epos,
  			 kernel_lb_addr eloc, int8_t etype, uint32_t elen,
  			 uint32_t nelen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
  {
28de7948a   Cyrill Gorcunov   UDF: coding style...
34
35
36
37
38
  	kernel_lb_addr neloc = {};
  	int last_block = (elen + inode->i_sb->s_blocksize - 1) >>
  		inode->i_sb->s_blocksize_bits;
  	int first_block = (nelen + inode->i_sb->s_blocksize - 1) >>
  		inode->i_sb->s_blocksize_bits;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39

cb00ea352   Cyrill Gorcunov   UDF: coding style...
40
41
42
43
  	if (nelen) {
  		if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
  			udf_free_blocks(inode->i_sb, inode, eloc, 0,
  					last_block);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
  			etype = (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30);
cb00ea352   Cyrill Gorcunov   UDF: coding style...
45
  		} else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
48
  			neloc = eloc;
  		nelen = (etype << 30) | nelen;
  	}
cb00ea352   Cyrill Gorcunov   UDF: coding style...
49
  	if (elen != nelen) {
ff116fc8d   Jan Kara   UDF: introduce st...
50
  		udf_write_aext(inode, epos, neloc, nelen, 0);
cb00ea352   Cyrill Gorcunov   UDF: coding style...
51
  		if (last_block - first_block > 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
54
55
  			if (etype == (EXT_RECORDED_ALLOCATED >> 30))
  				mark_inode_dirty(inode);
  
  			if (etype != (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
cb00ea352   Cyrill Gorcunov   UDF: coding style...
56
57
58
  				udf_free_blocks(inode->i_sb, inode, eloc,
  						first_block,
  						last_block - first_block);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
60
61
  		}
  	}
  }
74584ae50   Jan Kara   udf: fix possible...
62
63
64
65
66
  /*
   * Truncate the last extent to match i_size. This function assumes
   * that preallocation extent is already truncated.
   */
  void udf_truncate_tail_extent(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
  {
28de7948a   Cyrill Gorcunov   UDF: coding style...
68
  	struct extent_position epos = {};
ff116fc8d   Jan Kara   UDF: introduce st...
69
70
  	kernel_lb_addr eloc;
  	uint32_t elen, nelen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
  	uint64_t lbcount = 0;
  	int8_t etype = -1, netype;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
75
  	int adsize;
  
  	if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB ||
74584ae50   Jan Kara   udf: fix possible...
76
77
78
79
  	    inode->i_size == UDF_I_LENEXTENTS(inode))
  		return;
  	/* Are we going to delete the file anyway? */
  	if (inode->i_nlink == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
82
83
84
85
86
  
  	if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
  		adsize = sizeof(short_ad);
  	else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG)
  		adsize = sizeof(long_ad);
  	else
74584ae50   Jan Kara   udf: fix possible...
87
  		BUG();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88

ff116fc8d   Jan Kara   UDF: introduce st...
89
  	/* Find the last extent in the file */
cb00ea352   Cyrill Gorcunov   UDF: coding style...
90
  	while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
92
  		etype = netype;
  		lbcount += elen;
74584ae50   Jan Kara   udf: fix possible...
93
94
95
96
97
98
99
100
101
102
103
104
  		if (lbcount > inode->i_size) {
  			if (lbcount - inode->i_size >= inode->i_sb->s_blocksize)
  				printk(KERN_WARNING
  				       "udf_truncate_tail_extent(): Too long "
  				       "extent after EOF in inode %u: i_size: "
  				       "%Ld lbcount: %Ld extent %u+%u
  ",
  				       (unsigned)inode->i_ino,
  				       (long long)inode->i_size,
  				       (long long)lbcount,
  				       (unsigned)eloc.logicalBlockNum,
  				       (unsigned)elen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
  			nelen = elen - (lbcount - inode->i_size);
ff116fc8d   Jan Kara   UDF: introduce st...
106
107
108
  			epos.offset -= adsize;
  			extent_trunc(inode, &epos, eloc, etype, elen, nelen);
  			epos.offset += adsize;
74584ae50   Jan Kara   udf: fix possible...
109
110
111
112
113
114
  			if (udf_next_aext(inode, &epos, &eloc, &elen, 1) != -1)
  				printk(KERN_ERR "udf_truncate_tail_extent(): "
  				       "Extent after EOF in inode %u.
  ",
  				       (unsigned)inode->i_ino);
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
116
  		}
  	}
74584ae50   Jan Kara   udf: fix possible...
117
118
119
120
121
122
123
124
  	/* This inode entry is in-memory only and thus we don't have to mark
  	 * the inode dirty */
  	UDF_I_LENEXTENTS(inode) = inode->i_size;
  	brelse(epos.bh);
  }
  
  void udf_discard_prealloc(struct inode *inode)
  {
cb00ea352   Cyrill Gorcunov   UDF: coding style...
125
  	struct extent_position epos = { NULL, 0, {0, 0} };
74584ae50   Jan Kara   udf: fix possible...
126
127
128
129
130
131
132
  	kernel_lb_addr eloc;
  	uint32_t elen;
  	uint64_t lbcount = 0;
  	int8_t etype = -1, netype;
  	int adsize;
  
  	if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB ||
cb00ea352   Cyrill Gorcunov   UDF: coding style...
133
  	    inode->i_size == UDF_I_LENEXTENTS(inode))
74584ae50   Jan Kara   udf: fix possible...
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
  		return;
  
  	if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
  		adsize = sizeof(short_ad);
  	else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG)
  		adsize = sizeof(long_ad);
  	else
  		adsize = 0;
  
  	epos.block = UDF_I_LOCATION(inode);
  
  	/* Find the last extent in the file */
  	while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) {
  		etype = netype;
  		lbcount += elen;
  	}
ff116fc8d   Jan Kara   UDF: introduce st...
150
151
  	if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
  		epos.offset -= adsize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
  		lbcount -= elen;
ff116fc8d   Jan Kara   UDF: introduce st...
153
  		extent_trunc(inode, &epos, eloc, etype, elen, 0);
74584ae50   Jan Kara   udf: fix possible...
154
  		if (!epos.bh) {
cb00ea352   Cyrill Gorcunov   UDF: coding style...
155
  			UDF_I_LENALLOC(inode) =
28de7948a   Cyrill Gorcunov   UDF: coding style...
156
  				epos.offset - udf_file_entry_alloc_offset(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
  			mark_inode_dirty(inode);
74584ae50   Jan Kara   udf: fix possible...
158
  		} else {
cb00ea352   Cyrill Gorcunov   UDF: coding style...
159
  			struct allocExtDesc *aed =
28de7948a   Cyrill Gorcunov   UDF: coding style...
160
  				(struct allocExtDesc *)(epos.bh->b_data);
cb00ea352   Cyrill Gorcunov   UDF: coding style...
161
  			aed->lengthAllocDescs =
28de7948a   Cyrill Gorcunov   UDF: coding style...
162
163
164
165
  				cpu_to_le32(epos.offset -
  					    sizeof(struct allocExtDesc));
  			if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
  			    UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
ff116fc8d   Jan Kara   UDF: introduce st...
166
  				udf_update_tag(epos.bh->b_data, epos.offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
  			else
cb00ea352   Cyrill Gorcunov   UDF: coding style...
168
169
  				udf_update_tag(epos.bh->b_data,
  					       sizeof(struct allocExtDesc));
ff116fc8d   Jan Kara   UDF: introduce st...
170
  			mark_buffer_dirty_inode(epos.bh, inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
172
  		}
  	}
74584ae50   Jan Kara   udf: fix possible...
173
174
  	/* This inode entry is in-memory only and thus we don't have to mark
  	 * the inode dirty */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
  	UDF_I_LENEXTENTS(inode) = lbcount;
3bf25cb40   Jan Kara   udf: use get_bh()
176
  	brelse(epos.bh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
  }
cb00ea352   Cyrill Gorcunov   UDF: coding style...
178
  void udf_truncate_extents(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
  {
ff116fc8d   Jan Kara   UDF: introduce st...
180
  	struct extent_position epos;
28de7948a   Cyrill Gorcunov   UDF: coding style...
181
  	kernel_lb_addr eloc, neloc = {};
ff116fc8d   Jan Kara   UDF: introduce st...
182
  	uint32_t elen, nelen = 0, indirect_ext_len = 0, lenalloc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
  	int8_t etype;
31170b6ad   Jan Kara   udf: support file...
184
185
  	struct super_block *sb = inode->i_sb;
  	sector_t first_block = inode->i_size >> sb->s_blocksize_bits, offset;
60448b1d6   Jan Kara   udf: use sector_t...
186
  	loff_t byte_offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
188
189
190
191
192
193
  	int adsize;
  
  	if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
  		adsize = sizeof(short_ad);
  	else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG)
  		adsize = sizeof(long_ad);
  	else
ff116fc8d   Jan Kara   UDF: introduce st...
194
  		BUG();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195

ff116fc8d   Jan Kara   UDF: introduce st...
196
  	etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset);
28de7948a   Cyrill Gorcunov   UDF: coding style...
197
198
  	byte_offset = (offset << sb->s_blocksize_bits) +
  		(inode->i_size & (sb->s_blocksize - 1));
cb00ea352   Cyrill Gorcunov   UDF: coding style...
199
  	if (etype != -1) {
ff116fc8d   Jan Kara   UDF: introduce st...
200
201
202
  		epos.offset -= adsize;
  		extent_trunc(inode, &epos, eloc, etype, elen, byte_offset);
  		epos.offset += adsize;
60448b1d6   Jan Kara   udf: use sector_t...
203
  		if (byte_offset)
ff116fc8d   Jan Kara   UDF: introduce st...
204
  			lenalloc = epos.offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
  		else
ff116fc8d   Jan Kara   UDF: introduce st...
206
  			lenalloc = epos.offset - adsize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207

ff116fc8d   Jan Kara   UDF: introduce st...
208
  		if (!epos.bh)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209
210
211
  			lenalloc -= udf_file_entry_alloc_offset(inode);
  		else
  			lenalloc -= sizeof(struct allocExtDesc);
28de7948a   Cyrill Gorcunov   UDF: coding style...
212
  		while ((etype = udf_current_aext(inode, &epos, &eloc, &elen, 0)) != -1) {
cb00ea352   Cyrill Gorcunov   UDF: coding style...
213
  			if (etype == (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) {
ff116fc8d   Jan Kara   UDF: introduce st...
214
  				udf_write_aext(inode, &epos, neloc, nelen, 0);
cb00ea352   Cyrill Gorcunov   UDF: coding style...
215
  				if (indirect_ext_len) {
ff116fc8d   Jan Kara   UDF: introduce st...
216
217
218
  					/* We managed to free all extents in the
  					 * indirect extent - free it too */
  					if (!epos.bh)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
  						BUG();
cb00ea352   Cyrill Gorcunov   UDF: coding style...
220
221
222
223
  					udf_free_blocks(sb, inode, epos.block,
  							0, indirect_ext_len);
  				} else {
  					if (!epos.bh) {
28de7948a   Cyrill Gorcunov   UDF: coding style...
224
  						UDF_I_LENALLOC(inode) = lenalloc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
  						mark_inode_dirty(inode);
cb00ea352   Cyrill Gorcunov   UDF: coding style...
226
227
  					} else {
  						struct allocExtDesc *aed =
28de7948a   Cyrill Gorcunov   UDF: coding style...
228
  							(struct allocExtDesc *)(epos.bh->b_data);
cb00ea352   Cyrill Gorcunov   UDF: coding style...
229
230
  						aed->lengthAllocDescs =
  						    cpu_to_le32(lenalloc);
28de7948a   Cyrill Gorcunov   UDF: coding style...
231
232
233
234
235
  						if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) ||
  						    UDF_SB_UDFREV(sb) >= 0x0201)
  							udf_update_tag(epos.bh->b_data,
  								       lenalloc +
  								       sizeof(struct allocExtDesc));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236
  						else
28de7948a   Cyrill Gorcunov   UDF: coding style...
237
238
239
  							udf_update_tag(epos.bh->b_data,
  								       sizeof(struct allocExtDesc));
  						mark_buffer_dirty_inode(epos.bh, inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
241
  					}
  				}
ff116fc8d   Jan Kara   UDF: introduce st...
242
243
244
  				brelse(epos.bh);
  				epos.offset = sizeof(struct allocExtDesc);
  				epos.block = eloc;
28de7948a   Cyrill Gorcunov   UDF: coding style...
245
  				epos.bh = udf_tread(sb, udf_get_lb_pblock(sb, eloc, 0));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
  				if (elen)
28de7948a   Cyrill Gorcunov   UDF: coding style...
247
248
  					indirect_ext_len = (elen + sb->s_blocksize -1) >>
  						sb->s_blocksize_bits;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
  				else
ff116fc8d   Jan Kara   UDF: introduce st...
250
  					indirect_ext_len = 1;
cb00ea352   Cyrill Gorcunov   UDF: coding style...
251
  			} else {
28de7948a   Cyrill Gorcunov   UDF: coding style...
252
  				extent_trunc(inode, &epos, eloc, etype, elen, 0);
ff116fc8d   Jan Kara   UDF: introduce st...
253
  				epos.offset += adsize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
255
  			}
  		}
cb00ea352   Cyrill Gorcunov   UDF: coding style...
256
  		if (indirect_ext_len) {
ff116fc8d   Jan Kara   UDF: introduce st...
257
  			if (!epos.bh)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
  				BUG();
cb00ea352   Cyrill Gorcunov   UDF: coding style...
259
260
261
262
  			udf_free_blocks(sb, inode, epos.block, 0,
  					indirect_ext_len);
  		} else {
  			if (!epos.bh) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
264
  				UDF_I_LENALLOC(inode) = lenalloc;
  				mark_inode_dirty(inode);
cb00ea352   Cyrill Gorcunov   UDF: coding style...
265
266
267
  			} else {
  				struct allocExtDesc *aed =
  				    (struct allocExtDesc *)(epos.bh->b_data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
  				aed->lengthAllocDescs = cpu_to_le32(lenalloc);
28de7948a   Cyrill Gorcunov   UDF: coding style...
269
270
  				if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) ||
  				    UDF_SB_UDFREV(sb) >= 0x0201)
cb00ea352   Cyrill Gorcunov   UDF: coding style...
271
  					udf_update_tag(epos.bh->b_data,
28de7948a   Cyrill Gorcunov   UDF: coding style...
272
  						       lenalloc + sizeof(struct allocExtDesc));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
  				else
cb00ea352   Cyrill Gorcunov   UDF: coding style...
274
  					udf_update_tag(epos.bh->b_data,
28de7948a   Cyrill Gorcunov   UDF: coding style...
275
  						       sizeof(struct allocExtDesc));
ff116fc8d   Jan Kara   UDF: introduce st...
276
  				mark_buffer_dirty_inode(epos.bh, inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
278
  			}
  		}
cb00ea352   Cyrill Gorcunov   UDF: coding style...
279
280
  	} else if (inode->i_size) {
  		if (byte_offset) {
31170b6ad   Jan Kara   udf: support file...
281
  			kernel_long_ad extent;
00a2b0f6d   Jan Kara   Fix possible UDF ...
282
283
284
  			/*
  			 *  OK, there is not extent covering inode->i_size and
  			 *  no extent above inode->i_size => truncate is
31170b6ad   Jan Kara   udf: support file...
285
  			 *  extending the file by 'offset' blocks.
00a2b0f6d   Jan Kara   Fix possible UDF ...
286
  			 */
28de7948a   Cyrill Gorcunov   UDF: coding style...
287
288
289
  			if ((!epos.bh &&
  			     epos.offset == udf_file_entry_alloc_offset(inode)) ||
  			    (epos.bh && epos.offset == sizeof(struct allocExtDesc))) {
31170b6ad   Jan Kara   udf: support file...
290
291
292
293
  				/* File has no extents at all or has empty last
  				 * indirect extent! Create a fake extent... */
  				extent.extLocation.logicalBlockNum = 0;
  				extent.extLocation.partitionReferenceNum = 0;
28de7948a   Cyrill Gorcunov   UDF: coding style...
294
  				extent.extLength = EXT_NOT_RECORDED_NOT_ALLOCATED;
cb00ea352   Cyrill Gorcunov   UDF: coding style...
295
  			} else {
ff116fc8d   Jan Kara   UDF: introduce st...
296
  				epos.offset -= adsize;
31170b6ad   Jan Kara   udf: support file...
297
  				etype = udf_next_aext(inode, &epos,
cb00ea352   Cyrill Gorcunov   UDF: coding style...
298
299
  						      &extent.extLocation,
  						      &extent.extLength, 0);
31170b6ad   Jan Kara   udf: support file...
300
  				extent.extLength |= etype << 30;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
  			}
cb00ea352   Cyrill Gorcunov   UDF: coding style...
302
  			udf_extend_file(inode, &epos, &extent,
28de7948a   Cyrill Gorcunov   UDF: coding style...
303
  					offset + ((inode->i_size & (sb->s_blocksize - 1)) != 0));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304
305
306
  		}
  	}
  	UDF_I_LENEXTENTS(inode) = inode->i_size;
3bf25cb40   Jan Kara   udf: use get_bh()
307
  	brelse(epos.bh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
  }