Blame view

fs/udf/truncate.c 7.88 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
   * 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>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
26
27
28
  #include <linux/buffer_head.h>
  
  #include "udf_i.h"
  #include "udf_sb.h"
cb00ea352   Cyrill Gorcunov   UDF: coding style...
29
  static void extent_trunc(struct inode *inode, struct extent_position *epos,
97e961fdb   Pekka Enberg   Fix the udf code ...
30
  			 struct kernel_lb_addr *eloc, int8_t etype, uint32_t elen,
cb00ea352   Cyrill Gorcunov   UDF: coding style...
31
  			 uint32_t nelen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
  {
5ca4e4be8   Pekka Enberg   Remove struct typ...
33
  	struct kernel_lb_addr neloc = {};
28de7948a   Cyrill Gorcunov   UDF: coding style...
34
35
36
37
  	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
38

cb00ea352   Cyrill Gorcunov   UDF: coding style...
39
40
41
42
  	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
43
  			etype = (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30);
cb00ea352   Cyrill Gorcunov   UDF: coding style...
44
  		} else
97e961fdb   Pekka Enberg   Fix the udf code ...
45
  			neloc = *eloc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
  		nelen = (etype << 30) | nelen;
  	}
cb00ea352   Cyrill Gorcunov   UDF: coding style...
48
  	if (elen != nelen) {
97e961fdb   Pekka Enberg   Fix the udf code ...
49
  		udf_write_aext(inode, epos, &neloc, nelen, 0);
cb00ea352   Cyrill Gorcunov   UDF: coding style...
50
  		if (last_block - first_block > 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
52
53
54
  			if (etype == (EXT_RECORDED_ALLOCATED >> 30))
  				mark_inode_dirty(inode);
  
  			if (etype != (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
cb00ea352   Cyrill Gorcunov   UDF: coding style...
55
56
57
  				udf_free_blocks(inode->i_sb, inode, eloc,
  						first_block,
  						last_block - first_block);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
60
  		}
  	}
  }
74584ae50   Jan Kara   udf: fix possible...
61
62
63
64
65
  /*
   * 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
66
  {
28de7948a   Cyrill Gorcunov   UDF: coding style...
67
  	struct extent_position epos = {};
5ca4e4be8   Pekka Enberg   Remove struct typ...
68
  	struct kernel_lb_addr eloc;
ff116fc8d   Jan Kara   UDF: introduce st...
69
  	uint32_t elen, nelen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
  	uint64_t lbcount = 0;
  	int8_t etype = -1, netype;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
  	int adsize;
48d6d8ff7   Marcin Slusarz   udf: cache struct...
73
  	struct udf_inode_info *iinfo = UDF_I(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74

48d6d8ff7   Marcin Slusarz   udf: cache struct...
75
76
  	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB ||
  	    inode->i_size == iinfo->i_lenExtents)
74584ae50   Jan Kara   udf: fix possible...
77
78
79
  		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

48d6d8ff7   Marcin Slusarz   udf: cache struct...
82
  	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
5ca4e4be8   Pekka Enberg   Remove struct typ...
83
  		adsize = sizeof(struct short_ad);
48d6d8ff7   Marcin Slusarz   udf: cache struct...
84
  	else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
5ca4e4be8   Pekka Enberg   Remove struct typ...
85
  		adsize = sizeof(struct long_ad);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
  	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
  		if (lbcount > inode->i_size) {
  			if (lbcount - inode->i_size >= inode->i_sb->s_blocksize)
78ace70c4   Joe Perches   udf: Convert prin...
95
96
97
98
99
100
101
102
  				udf_warn(inode->i_sb,
  					 "Too long extent after EOF in inode %u: i_size: %lld lbcount: %lld 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
103
  			nelen = elen - (lbcount - inode->i_size);
ff116fc8d   Jan Kara   UDF: introduce st...
104
  			epos.offset -= adsize;
97e961fdb   Pekka Enberg   Fix the udf code ...
105
  			extent_trunc(inode, &epos, &eloc, etype, elen, nelen);
ff116fc8d   Jan Kara   UDF: introduce st...
106
  			epos.offset += adsize;
74584ae50   Jan Kara   udf: fix possible...
107
  			if (udf_next_aext(inode, &epos, &eloc, &elen, 1) != -1)
78ace70c4   Joe Perches   udf: Convert prin...
108
109
110
111
  				udf_err(inode->i_sb,
  					"Extent after EOF in inode %u
  ",
  					(unsigned)inode->i_ino);
74584ae50   Jan Kara   udf: fix possible...
112
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
114
  		}
  	}
74584ae50   Jan Kara   udf: fix possible...
115
116
  	/* This inode entry is in-memory only and thus we don't have to mark
  	 * the inode dirty */
48d6d8ff7   Marcin Slusarz   udf: cache struct...
117
  	iinfo->i_lenExtents = inode->i_size;
74584ae50   Jan Kara   udf: fix possible...
118
119
120
121
122
  	brelse(epos.bh);
  }
  
  void udf_discard_prealloc(struct inode *inode)
  {
cb00ea352   Cyrill Gorcunov   UDF: coding style...
123
  	struct extent_position epos = { NULL, 0, {0, 0} };
5ca4e4be8   Pekka Enberg   Remove struct typ...
124
  	struct kernel_lb_addr eloc;
74584ae50   Jan Kara   udf: fix possible...
125
126
127
128
  	uint32_t elen;
  	uint64_t lbcount = 0;
  	int8_t etype = -1, netype;
  	int adsize;
48d6d8ff7   Marcin Slusarz   udf: cache struct...
129
  	struct udf_inode_info *iinfo = UDF_I(inode);
74584ae50   Jan Kara   udf: fix possible...
130

48d6d8ff7   Marcin Slusarz   udf: cache struct...
131
132
  	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB ||
  	    inode->i_size == iinfo->i_lenExtents)
74584ae50   Jan Kara   udf: fix possible...
133
  		return;
48d6d8ff7   Marcin Slusarz   udf: cache struct...
134
  	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
5ca4e4be8   Pekka Enberg   Remove struct typ...
135
  		adsize = sizeof(struct short_ad);
48d6d8ff7   Marcin Slusarz   udf: cache struct...
136
  	else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
5ca4e4be8   Pekka Enberg   Remove struct typ...
137
  		adsize = sizeof(struct long_ad);
74584ae50   Jan Kara   udf: fix possible...
138
139
  	else
  		adsize = 0;
48d6d8ff7   Marcin Slusarz   udf: cache struct...
140
  	epos.block = iinfo->i_location;
74584ae50   Jan Kara   udf: fix possible...
141
142
143
144
145
146
  
  	/* 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...
147
148
  	if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
  		epos.offset -= adsize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
  		lbcount -= elen;
97e961fdb   Pekka Enberg   Fix the udf code ...
150
  		extent_trunc(inode, &epos, &eloc, etype, elen, 0);
74584ae50   Jan Kara   udf: fix possible...
151
  		if (!epos.bh) {
48d6d8ff7   Marcin Slusarz   udf: cache struct...
152
  			iinfo->i_lenAlloc =
4b11111ab   Marcin Slusarz   udf: fix coding s...
153
154
  				epos.offset -
  				udf_file_entry_alloc_offset(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
  			mark_inode_dirty(inode);
74584ae50   Jan Kara   udf: fix possible...
156
  		} else {
cb00ea352   Cyrill Gorcunov   UDF: coding style...
157
  			struct allocExtDesc *aed =
28de7948a   Cyrill Gorcunov   UDF: coding style...
158
  				(struct allocExtDesc *)(epos.bh->b_data);
cb00ea352   Cyrill Gorcunov   UDF: coding style...
159
  			aed->lengthAllocDescs =
28de7948a   Cyrill Gorcunov   UDF: coding style...
160
161
162
  				cpu_to_le32(epos.offset -
  					    sizeof(struct allocExtDesc));
  			if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
6c79e987d   Marcin Slusarz   udf: remove some ...
163
  			    UDF_SB(inode->i_sb)->s_udfrev >= 0x0201)
ff116fc8d   Jan Kara   UDF: introduce st...
164
  				udf_update_tag(epos.bh->b_data, epos.offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
  			else
cb00ea352   Cyrill Gorcunov   UDF: coding style...
166
167
  				udf_update_tag(epos.bh->b_data,
  					       sizeof(struct allocExtDesc));
ff116fc8d   Jan Kara   UDF: introduce st...
168
  			mark_buffer_dirty_inode(epos.bh, inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
  		}
  	}
74584ae50   Jan Kara   udf: fix possible...
171
172
  	/* This inode entry is in-memory only and thus we don't have to mark
  	 * the inode dirty */
48d6d8ff7   Marcin Slusarz   udf: cache struct...
173
  	iinfo->i_lenExtents = lbcount;
3bf25cb40   Jan Kara   udf: use get_bh()
174
  	brelse(epos.bh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
  }
456390de4   marcin.slusarz@gmail.com   udf: truncate: cr...
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
  static void udf_update_alloc_ext_desc(struct inode *inode,
  				      struct extent_position *epos,
  				      u32 lenalloc)
  {
  	struct super_block *sb = inode->i_sb;
  	struct udf_sb_info *sbi = UDF_SB(sb);
  
  	struct allocExtDesc *aed = (struct allocExtDesc *) (epos->bh->b_data);
  	int len = sizeof(struct allocExtDesc);
  
  	aed->lengthAllocDescs =	cpu_to_le32(lenalloc);
  	if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) || sbi->s_udfrev >= 0x0201)
  		len += lenalloc;
  
  	udf_update_tag(epos->bh->b_data, len);
  	mark_buffer_dirty_inode(epos->bh, inode);
  }
7e49b6f24   Jan Kara   udf: Convert UDF ...
193
194
195
196
197
  /*
   * Truncate extents of inode to inode->i_size. This function can be used only
   * for making file shorter. For making file longer, udf_extend_file() has to
   * be used.
   */
cb00ea352   Cyrill Gorcunov   UDF: coding style...
198
  void udf_truncate_extents(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
  {
ff116fc8d   Jan Kara   UDF: introduce st...
200
  	struct extent_position epos;
5ca4e4be8   Pekka Enberg   Remove struct typ...
201
  	struct kernel_lb_addr eloc, neloc = {};
ff116fc8d   Jan Kara   UDF: introduce st...
202
  	uint32_t elen, nelen = 0, indirect_ext_len = 0, lenalloc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
  	int8_t etype;
31170b6ad   Jan Kara   udf: support file...
204
205
  	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...
206
  	loff_t byte_offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
  	int adsize;
48d6d8ff7   Marcin Slusarz   udf: cache struct...
208
  	struct udf_inode_info *iinfo = UDF_I(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209

48d6d8ff7   Marcin Slusarz   udf: cache struct...
210
  	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
5ca4e4be8   Pekka Enberg   Remove struct typ...
211
  		adsize = sizeof(struct short_ad);
48d6d8ff7   Marcin Slusarz   udf: cache struct...
212
  	else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
5ca4e4be8   Pekka Enberg   Remove struct typ...
213
  		adsize = sizeof(struct long_ad);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214
  	else
ff116fc8d   Jan Kara   UDF: introduce st...
215
  		BUG();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216

ff116fc8d   Jan Kara   UDF: introduce st...
217
  	etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset);
28de7948a   Cyrill Gorcunov   UDF: coding style...
218
219
  	byte_offset = (offset << sb->s_blocksize_bits) +
  		(inode->i_size & (sb->s_blocksize - 1));
7e49b6f24   Jan Kara   udf: Convert UDF ...
220
221
222
223
224
225
226
227
228
229
230
231
  	if (etype == -1) {
  		/* We should extend the file? */
  		WARN_ON(byte_offset);
  		return;
  	}
  	epos.offset -= adsize;
  	extent_trunc(inode, &epos, &eloc, etype, elen, byte_offset);
  	epos.offset += adsize;
  	if (byte_offset)
  		lenalloc = epos.offset;
  	else
  		lenalloc = epos.offset - adsize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232

7e49b6f24   Jan Kara   udf: Convert UDF ...
233
234
235
236
  	if (!epos.bh)
  		lenalloc -= udf_file_entry_alloc_offset(inode);
  	else
  		lenalloc -= sizeof(struct allocExtDesc);
31170b6ad   Jan Kara   udf: support file...
237

7e49b6f24   Jan Kara   udf: Convert UDF ...
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
  	while ((etype = udf_current_aext(inode, &epos, &eloc,
  					 &elen, 0)) != -1) {
  		if (etype == (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) {
  			udf_write_aext(inode, &epos, &neloc, nelen, 0);
  			if (indirect_ext_len) {
  				/* We managed to free all extents in the
  				 * indirect extent - free it too */
  				BUG_ON(!epos.bh);
  				udf_free_blocks(sb, inode, &epos.block,
  						0, indirect_ext_len);
  			} else if (!epos.bh) {
  				iinfo->i_lenAlloc = lenalloc;
  				mark_inode_dirty(inode);
  			} else
  				udf_update_alloc_ext_desc(inode,
  						&epos, lenalloc);
  			brelse(epos.bh);
  			epos.offset = sizeof(struct allocExtDesc);
  			epos.block = eloc;
  			epos.bh = udf_tread(sb,
  					udf_get_lb_pblock(sb, &eloc, 0));
  			if (elen)
  				indirect_ext_len =
  					(elen + sb->s_blocksize - 1) >>
  					sb->s_blocksize_bits;
  			else
  				indirect_ext_len = 1;
  		} else {
  			extent_trunc(inode, &epos, &eloc, etype, elen, 0);
  			epos.offset += adsize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
269
  		}
  	}
7e49b6f24   Jan Kara   udf: Convert UDF ...
270
271
272
273
274
275
276
277
278
  
  	if (indirect_ext_len) {
  		BUG_ON(!epos.bh);
  		udf_free_blocks(sb, inode, &epos.block, 0, indirect_ext_len);
  	} else if (!epos.bh) {
  		iinfo->i_lenAlloc = lenalloc;
  		mark_inode_dirty(inode);
  	} else
  		udf_update_alloc_ext_desc(inode, &epos, lenalloc);
48d6d8ff7   Marcin Slusarz   udf: cache struct...
279
  	iinfo->i_lenExtents = inode->i_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280

3bf25cb40   Jan Kara   udf: use get_bh()
281
  	brelse(epos.bh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
  }