Blame view

fs/ufs/truncate.c 12.7 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  /*
   *  linux/fs/ufs/truncate.c
   *
   * Copyright (C) 1998
   * Daniel Pirkl <daniel.pirkl@email.cz>
   * Charles University, Faculty of Mathematics and Physics
   *
   *  from
   *
   *  linux/fs/ext2/truncate.c
   *
   * Copyright (C) 1992, 1993, 1994, 1995
   * Remy Card (card@masi.ibp.fr)
   * Laboratoire MASI - Institut Blaise Pascal
   * Universite Pierre et Marie Curie (Paris VI)
   *
   *  from
   *
   *  linux/fs/minix/truncate.c
   *
   *  Copyright (C) 1991, 1992  Linus Torvalds
   *
   *  Big-endian to little-endian byte-swapping/bitmaps by
   *        David S. Miller (davem@caip.rutgers.edu), 1995
   */
  
  /*
   * Real random numbers for secure rm added 94/02/18
   * Idea from Pierre del Perugia <delperug@gla.ecoledoc.ibp.fr>
   */
09114eb8c   Evgeniy Dushistov   [PATCH] ufs: fix ...
31
  /*
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
32
33
   * Adoptation to use page cache and UFS2 write support by
   * Evgeniy Dushistov <dushistov@mail.ru>, 2006-2007
09114eb8c   Evgeniy Dushistov   [PATCH] ufs: fix ...
34
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
  #include <linux/errno.h>
  #include <linux/fs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
39
40
  #include <linux/fcntl.h>
  #include <linux/time.h>
  #include <linux/stat.h>
  #include <linux/string.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
43
  #include <linux/buffer_head.h>
  #include <linux/blkdev.h>
  #include <linux/sched.h>
e54205988   Mike Frysinger   drop linux/ufs_fs...
44
  #include "ufs_fs.h"
bcd6d4ecf   Christoph Hellwig   ufs: move non-lay...
45
  #include "ufs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
  #include "swab.h"
  #include "util.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
49
50
51
52
53
54
55
56
57
58
59
  /*
   * Secure deletion currently doesn't work. It interacts very badly
   * with buffers shared with memory mappings, and for that reason
   * can't be done in the truncate() routines. It should instead be
   * done separately in "release()" before calling the truncate routines
   * that will release the actual file blocks.
   *
   *		Linus
   */
  
  #define DIRECT_BLOCK ((inode->i_size + uspi->s_bsize - 1) >> uspi->s_bshift)
  #define DIRECT_FRAGMENT ((inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60

54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
61
  static int ufs_trunc_direct(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
64
65
  {
  	struct ufs_inode_info *ufsi = UFS_I(inode);
  	struct super_block * sb;
  	struct ufs_sb_private_info * uspi;
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
66
67
  	void *p;
  	u64 frag1, frag2, frag3, frag4, block1, block2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
  	unsigned frag_to_free, free_count;
09114eb8c   Evgeniy Dushistov   [PATCH] ufs: fix ...
69
  	unsigned i, tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
  	int retry;
  	
4b25a37e2   Evgeniy Dushistov   [PATCH] ufs: zero...
72
73
  	UFSD("ENTER: ino %lu
  ", inode->i_ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
75
76
77
78
79
80
81
82
  
  	sb = inode->i_sb;
  	uspi = UFS_SB(sb)->s_uspi;
  	
  	frag_to_free = 0;
  	free_count = 0;
  	retry = 0;
  	
  	frag1 = DIRECT_FRAGMENT;
1d5827235   Dan Carpenter   ufs: fix truncate...
83
  	frag4 = min_t(u64, UFS_NDIR_FRAGMENT, ufsi->i_lastfrag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
85
86
87
88
89
  	frag2 = ((frag1 & uspi->s_fpbmask) ? ((frag1 | uspi->s_fpbmask) + 1) : frag1);
  	frag3 = frag4 & ~uspi->s_fpbmask;
  	block1 = block2 = 0;
  	if (frag2 > frag3) {
  		frag2 = frag4;
  		frag3 = frag4 = 0;
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
90
  	} else if (frag2 < frag3) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
92
93
  		block1 = ufs_fragstoblks (frag2);
  		block2 = ufs_fragstoblks (frag3);
  	}
4b25a37e2   Evgeniy Dushistov   [PATCH] ufs: zero...
94
95
96
  	UFSD("ino %lu, frag1 %llu, frag2 %llu, block1 %llu, block2 %llu,"
  	     " frag3 %llu, frag4 %llu
  ", inode->i_ino,
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
97
98
99
  	     (unsigned long long)frag1, (unsigned long long)frag2,
  	     (unsigned long long)block1, (unsigned long long)block2,
  	     (unsigned long long)frag3, (unsigned long long)frag4);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
101
102
103
104
105
106
  
  	if (frag1 >= frag2)
  		goto next1;		
  
  	/*
  	 * Free first free fragments
  	 */
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
107
108
  	p = ufs_get_direct_data_ptr(uspi, ufsi, ufs_fragstoblks(frag1));
  	tmp = ufs_data_ptr_to_cpu(sb, p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
110
  	if (!tmp )
  		ufs_panic (sb, "ufs_trunc_direct", "internal error");
8682164a6   Evgeniy Dushistov   [PATCH] ufs: trun...
111
  	frag2 -= frag1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
  	frag1 = ufs_fragnum (frag1);
09114eb8c   Evgeniy Dushistov   [PATCH] ufs: fix ...
113

8682164a6   Evgeniy Dushistov   [PATCH] ufs: trun...
114
  	ufs_free_fragments(inode, tmp + frag1, frag2);
50aa4eb0b   Evgeniy Dushistov   [PATCH] ufs: i_bl...
115
  	mark_inode_dirty(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
117
118
119
120
121
122
  	frag_to_free = tmp + frag1;
  
  next1:
  	/*
  	 * Free whole blocks
  	 */
  	for (i = block1 ; i < block2; i++) {
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
123
124
  		p = ufs_get_direct_data_ptr(uspi, ufsi, i);
  		tmp = ufs_data_ptr_to_cpu(sb, p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
126
  		if (!tmp)
  			continue;
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
127
  		ufs_data_ptr_clear(uspi, p);
50aa4eb0b   Evgeniy Dushistov   [PATCH] ufs: i_bl...
128

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
130
131
132
133
134
135
136
137
138
  		if (free_count == 0) {
  			frag_to_free = tmp;
  			free_count = uspi->s_fpb;
  		} else if (free_count > 0 && frag_to_free == tmp - free_count)
  			free_count += uspi->s_fpb;
  		else {
  			ufs_free_blocks (inode, frag_to_free, free_count);
  			frag_to_free = tmp;
  			free_count = uspi->s_fpb;
  		}
50aa4eb0b   Evgeniy Dushistov   [PATCH] ufs: i_bl...
139
  		mark_inode_dirty(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
142
143
144
145
146
147
148
149
150
  	}
  	
  	if (free_count > 0)
  		ufs_free_blocks (inode, frag_to_free, free_count);
  
  	if (frag3 >= frag4)
  		goto next3;
  
  	/*
  	 * Free last free fragments
  	 */
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
151
152
  	p = ufs_get_direct_data_ptr(uspi, ufsi, ufs_fragstoblks(frag3));
  	tmp = ufs_data_ptr_to_cpu(sb, p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
155
  	if (!tmp )
  		ufs_panic(sb, "ufs_truncate_direct", "internal error");
  	frag4 = ufs_fragnum (frag4);
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
156
  	ufs_data_ptr_clear(uspi, p);
50aa4eb0b   Evgeniy Dushistov   [PATCH] ufs: i_bl...
157

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
  	ufs_free_fragments (inode, tmp, frag4);
50aa4eb0b   Evgeniy Dushistov   [PATCH] ufs: i_bl...
159
  	mark_inode_dirty(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
   next3:
4b25a37e2   Evgeniy Dushistov   [PATCH] ufs: zero...
161
162
  	UFSD("EXIT: ino %lu
  ", inode->i_ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
164
  	return retry;
  }
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
165
  static int ufs_trunc_indirect(struct inode *inode, u64 offset, void *p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
167
168
169
  {
  	struct super_block * sb;
  	struct ufs_sb_private_info * uspi;
  	struct ufs_buffer_head * ind_ubh;
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
170
171
172
  	void *ind;
  	u64 tmp, indirect_block, i, frag_to_free;
  	unsigned free_count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
  	int retry;
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
174
175
176
177
178
  	UFSD("ENTER: ino %lu, offset %llu, p: %p
  ",
  	     inode->i_ino, (unsigned long long)offset, p);
  
  	BUG_ON(!p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
180
181
182
183
184
185
186
  		
  	sb = inode->i_sb;
  	uspi = UFS_SB(sb)->s_uspi;
  
  	frag_to_free = 0;
  	free_count = 0;
  	retry = 0;
  	
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
187
  	tmp = ufs_data_ptr_to_cpu(sb, p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
189
190
  	if (!tmp)
  		return 0;
  	ind_ubh = ubh_bread(sb, tmp, uspi->s_bsize);
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
191
  	if (tmp != ufs_data_ptr_to_cpu(sb, p)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
193
194
195
  		ubh_brelse (ind_ubh);
  		return 1;
  	}
  	if (!ind_ubh) {
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
196
  		ufs_data_ptr_clear(uspi, p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197
198
199
200
201
  		return 0;
  	}
  
  	indirect_block = (DIRECT_BLOCK > offset) ? (DIRECT_BLOCK - offset) : 0;
  	for (i = indirect_block; i < uspi->s_apb; i++) {
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
202
203
  		ind = ubh_get_data_ptr(uspi, ind_ubh, i);
  		tmp = ufs_data_ptr_to_cpu(sb, ind);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
205
  		if (!tmp)
  			continue;
09114eb8c   Evgeniy Dushistov   [PATCH] ufs: fix ...
206

54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
207
  		ufs_data_ptr_clear(uspi, ind);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
210
211
212
213
214
215
216
217
218
  		ubh_mark_buffer_dirty(ind_ubh);
  		if (free_count == 0) {
  			frag_to_free = tmp;
  			free_count = uspi->s_fpb;
  		} else if (free_count > 0 && frag_to_free == tmp - free_count)
  			free_count += uspi->s_fpb;
  		else {
  			ufs_free_blocks (inode, frag_to_free, free_count);
  			frag_to_free = tmp;
  			free_count = uspi->s_fpb;
  		}
50aa4eb0b   Evgeniy Dushistov   [PATCH] ufs: i_bl...
219

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
  		mark_inode_dirty(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
222
223
224
225
226
  	}
  
  	if (free_count > 0) {
  		ufs_free_blocks (inode, frag_to_free, free_count);
  	}
  	for (i = 0; i < uspi->s_apb; i++)
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
227
228
  		if (!ufs_is_data_ptr_zero(uspi,
  					  ubh_get_data_ptr(uspi, ind_ubh, i)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
230
  			break;
  	if (i >= uspi->s_apb) {
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
231
232
  		tmp = ufs_data_ptr_to_cpu(sb, p);
  		ufs_data_ptr_clear(uspi, p);
50aa4eb0b   Evgeniy Dushistov   [PATCH] ufs: i_bl...
233

2061df0f8   Evgeniy Dushistov   [PATCH] ufs: ufs_...
234
  		ufs_free_blocks (inode, tmp, uspi->s_fpb);
50aa4eb0b   Evgeniy Dushistov   [PATCH] ufs: i_bl...
235
  		mark_inode_dirty(inode);
2061df0f8   Evgeniy Dushistov   [PATCH] ufs: ufs_...
236
237
  		ubh_bforget(ind_ubh);
  		ind_ubh = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
  	}
9cb569d60   Christoph Hellwig   remove SWRITE* I/...
239
240
  	if (IS_SYNC(inode) && ind_ubh && ubh_buffer_dirty(ind_ubh))
  		ubh_sync_block(ind_ubh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241
242
  	ubh_brelse (ind_ubh);
  	
4b25a37e2   Evgeniy Dushistov   [PATCH] ufs: zero...
243
244
  	UFSD("EXIT: ino %lu
  ", inode->i_ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
246
247
  	
  	return retry;
  }
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
248
  static int ufs_trunc_dindirect(struct inode *inode, u64 offset, void *p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
250
251
  {
  	struct super_block * sb;
  	struct ufs_sb_private_info * uspi;
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
252
253
254
  	struct ufs_buffer_head *dind_bh;
  	u64 i, tmp, dindirect_block;
  	void *dind;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
256
  	int retry = 0;
  	
4b25a37e2   Evgeniy Dushistov   [PATCH] ufs: zero...
257
258
  	UFSD("ENTER: ino %lu
  ", inode->i_ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
260
261
262
263
264
265
266
  	
  	sb = inode->i_sb;
  	uspi = UFS_SB(sb)->s_uspi;
  
  	dindirect_block = (DIRECT_BLOCK > offset) 
  		? ((DIRECT_BLOCK - offset) >> uspi->s_apbshift) : 0;
  	retry = 0;
  	
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
267
  	tmp = ufs_data_ptr_to_cpu(sb, p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
269
270
  	if (!tmp)
  		return 0;
  	dind_bh = ubh_bread(sb, tmp, uspi->s_bsize);
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
271
  	if (tmp != ufs_data_ptr_to_cpu(sb, p)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
273
274
275
  		ubh_brelse (dind_bh);
  		return 1;
  	}
  	if (!dind_bh) {
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
276
  		ufs_data_ptr_clear(uspi, p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
278
279
280
  		return 0;
  	}
  
  	for (i = dindirect_block ; i < uspi->s_apb ; i++) {
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
281
282
  		dind = ubh_get_data_ptr(uspi, dind_bh, i);
  		tmp = ufs_data_ptr_to_cpu(sb, dind);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
284
285
286
287
288
289
  		if (!tmp)
  			continue;
  		retry |= ufs_trunc_indirect (inode, offset + (i << uspi->s_apbshift), dind);
  		ubh_mark_buffer_dirty(dind_bh);
  	}
  
  	for (i = 0; i < uspi->s_apb; i++)
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
290
291
  		if (!ufs_is_data_ptr_zero(uspi,
  					  ubh_get_data_ptr(uspi, dind_bh, i)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
293
  			break;
  	if (i >= uspi->s_apb) {
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
294
295
  		tmp = ufs_data_ptr_to_cpu(sb, p);
  		ufs_data_ptr_clear(uspi, p);
50aa4eb0b   Evgeniy Dushistov   [PATCH] ufs: i_bl...
296
297
  
  		ufs_free_blocks(inode, tmp, uspi->s_fpb);
2061df0f8   Evgeniy Dushistov   [PATCH] ufs: ufs_...
298
  		mark_inode_dirty(inode);
2061df0f8   Evgeniy Dushistov   [PATCH] ufs: ufs_...
299
300
  		ubh_bforget(dind_bh);
  		dind_bh = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
  	}
9cb569d60   Christoph Hellwig   remove SWRITE* I/...
302
303
  	if (IS_SYNC(inode) && dind_bh && ubh_buffer_dirty(dind_bh))
  		ubh_sync_block(dind_bh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304
305
  	ubh_brelse (dind_bh);
  	
4b25a37e2   Evgeniy Dushistov   [PATCH] ufs: zero...
306
307
  	UFSD("EXIT: ino %lu
  ", inode->i_ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
309
310
  	
  	return retry;
  }
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
311
  static int ufs_trunc_tindirect(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
  {
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
313
314
  	struct super_block *sb = inode->i_sb;
  	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
  	struct ufs_inode_info *ufsi = UFS_I(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
  	struct ufs_buffer_head * tind_bh;
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
317
318
  	u64 tindirect_block, tmp, i;
  	void *tind, *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
320
  	int retry;
  	
4b25a37e2   Evgeniy Dushistov   [PATCH] ufs: zero...
321
322
  	UFSD("ENTER: ino %lu
  ", inode->i_ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
325
326
327
  	retry = 0;
  	
  	tindirect_block = (DIRECT_BLOCK > (UFS_NDADDR + uspi->s_apb + uspi->s_2apb))
  		? ((DIRECT_BLOCK - UFS_NDADDR - uspi->s_apb - uspi->s_2apb) >> uspi->s_2apbshift) : 0;
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
328
329
330
  
  	p = ufs_get_direct_data_ptr(uspi, ufsi, UFS_TIND_BLOCK);
  	if (!(tmp = ufs_data_ptr_to_cpu(sb, p)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
332
  		return 0;
  	tind_bh = ubh_bread (sb, tmp, uspi->s_bsize);
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
333
  	if (tmp != ufs_data_ptr_to_cpu(sb, p)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
334
335
336
337
  		ubh_brelse (tind_bh);
  		return 1;
  	}
  	if (!tind_bh) {
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
338
  		ufs_data_ptr_clear(uspi, p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
340
341
342
  		return 0;
  	}
  
  	for (i = tindirect_block ; i < uspi->s_apb ; i++) {
0465fc0a1   Evgeniy Dushistov   [PATCH] ufs2: tin...
343
  		tind = ubh_get_data_ptr(uspi, tind_bh, i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
346
347
348
  		retry |= ufs_trunc_dindirect(inode, UFS_NDADDR + 
  			uspi->s_apb + ((i + 1) << uspi->s_2apbshift), tind);
  		ubh_mark_buffer_dirty(tind_bh);
  	}
  	for (i = 0; i < uspi->s_apb; i++)
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
349
350
  		if (!ufs_is_data_ptr_zero(uspi,
  					  ubh_get_data_ptr(uspi, tind_bh, i)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
352
  			break;
  	if (i >= uspi->s_apb) {
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
353
354
  		tmp = ufs_data_ptr_to_cpu(sb, p);
  		ufs_data_ptr_clear(uspi, p);
50aa4eb0b   Evgeniy Dushistov   [PATCH] ufs: i_bl...
355
356
  
  		ufs_free_blocks(inode, tmp, uspi->s_fpb);
2061df0f8   Evgeniy Dushistov   [PATCH] ufs: ufs_...
357
  		mark_inode_dirty(inode);
2061df0f8   Evgeniy Dushistov   [PATCH] ufs: ufs_...
358
359
  		ubh_bforget(tind_bh);
  		tind_bh = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
  	}
9cb569d60   Christoph Hellwig   remove SWRITE* I/...
361
362
  	if (IS_SYNC(inode) && tind_bh && ubh_buffer_dirty(tind_bh))
  		ubh_sync_block(tind_bh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
364
  	ubh_brelse (tind_bh);
  	
4b25a37e2   Evgeniy Dushistov   [PATCH] ufs: zero...
365
366
  	UFSD("EXIT: ino %lu
  ", inode->i_ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
368
  	return retry;
  }
10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
369
370
  
  static int ufs_alloc_lastblock(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
  {
10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
372
  	int err = 0;
4b25a37e2   Evgeniy Dushistov   [PATCH] ufs: zero...
373
  	struct super_block *sb = inode->i_sb;
10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
374
  	struct address_space *mapping = inode->i_mapping;
4b25a37e2   Evgeniy Dushistov   [PATCH] ufs: zero...
375
  	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
376
377
  	unsigned i, end;
  	sector_t lastfrag;
10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
378
379
  	struct page *lastpage;
  	struct buffer_head *bh;
4b25a37e2   Evgeniy Dushistov   [PATCH] ufs: zero...
380
  	u64 phys64;
10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
381
382
  
  	lastfrag = (i_size_read(inode) + uspi->s_fsize - 1) >> uspi->s_fshift;
ecdc63948   Evgeniy Dushistov   [PATCH] ufs: trun...
383
  	if (!lastfrag)
10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
384
  		goto out;
ecdc63948   Evgeniy Dushistov   [PATCH] ufs: trun...
385

10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
386
387
388
389
390
391
392
393
394
395
396
397
398
  	lastfrag--;
  
  	lastpage = ufs_get_locked_page(mapping, lastfrag >>
  				       (PAGE_CACHE_SHIFT - inode->i_blkbits));
         if (IS_ERR(lastpage)) {
                 err = -EIO;
                 goto out;
         }
  
         end = lastfrag & ((1 << (PAGE_CACHE_SHIFT - inode->i_blkbits)) - 1);
         bh = page_buffers(lastpage);
         for (i = 0; i < end; ++i)
                 bh = bh->b_this_page;
ecdc63948   Evgeniy Dushistov   [PATCH] ufs: trun...
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
  
         err = ufs_getfrag_block(inode, lastfrag, bh, 1);
  
         if (unlikely(err))
  	       goto out_unlock;
  
         if (buffer_new(bh)) {
  	       clear_buffer_new(bh);
  	       unmap_underlying_metadata(bh->b_bdev,
  					 bh->b_blocknr);
  	       /*
  		* we do not zeroize fragment, because of
  		* if it maped to hole, it already contains zeroes
  		*/
  	       set_buffer_uptodate(bh);
  	       mark_buffer_dirty(bh);
  	       set_page_dirty(lastpage);
10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
416
         }
ecdc63948   Evgeniy Dushistov   [PATCH] ufs: trun...
417

4b25a37e2   Evgeniy Dushistov   [PATCH] ufs: zero...
418
419
420
421
422
423
424
425
426
427
428
429
430
431
         if (lastfrag >= UFS_IND_FRAGMENT) {
  	       end = uspi->s_fpb - ufs_fragnum(lastfrag) - 1;
  	       phys64 = bh->b_blocknr + 1;
  	       for (i = 0; i < end; ++i) {
  		       bh = sb_getblk(sb, i + phys64);
  		       lock_buffer(bh);
  		       memset(bh->b_data, 0, sb->s_blocksize);
  		       set_buffer_uptodate(bh);
  		       mark_buffer_dirty(bh);
  		       unlock_buffer(bh);
  		       sync_dirty_buffer(bh);
  		       brelse(bh);
  	       }
         }
10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
432
433
434
435
436
437
438
439
440
441
442
443
  out_unlock:
         ufs_put_locked_page(lastpage);
  out:
         return err;
  }
  
  int ufs_truncate(struct inode *inode, loff_t old_i_size)
  {
  	struct ufs_inode_info *ufsi = UFS_I(inode);
  	struct super_block *sb = inode->i_sb;
  	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
  	int retry, err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
444
  	
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
445
446
447
448
  	UFSD("ENTER: ino %lu, i_size: %llu, old_i_size: %llu
  ",
  	     inode->i_ino, (unsigned long long)i_size_read(inode),
  	     (unsigned long long)old_i_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449

10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
450
451
452
  	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
  	      S_ISLNK(inode->i_mode)))
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
  	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
454
  		return -EPERM;
ecdc63948   Evgeniy Dushistov   [PATCH] ufs: trun...
455
  	err = ufs_alloc_lastblock(inode);
10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
456

ecdc63948   Evgeniy Dushistov   [PATCH] ufs: trun...
457
458
459
  	if (err) {
  		i_size_write(inode, old_i_size);
  		goto out;
10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
460
  	}
09114eb8c   Evgeniy Dushistov   [PATCH] ufs: fix ...
461

10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
462
  	block_truncate_page(inode->i_mapping, inode->i_size, ufs_getfrag_block);
09114eb8c   Evgeniy Dushistov   [PATCH] ufs: fix ...
463

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464
465
  	while (1) {
  		retry = ufs_trunc_direct(inode);
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
466
467
468
469
470
471
  		retry |= ufs_trunc_indirect(inode, UFS_IND_BLOCK,
  					    ufs_get_direct_data_ptr(uspi, ufsi,
  								    UFS_IND_BLOCK));
  		retry |= ufs_trunc_dindirect(inode, UFS_IND_BLOCK + uspi->s_apb,
  					     ufs_get_direct_data_ptr(uspi, ufsi,
  								     UFS_DIND_BLOCK));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
473
474
475
476
  		retry |= ufs_trunc_tindirect (inode);
  		if (!retry)
  			break;
  		if (IS_SYNC(inode) && (inode->i_state & I_DIRTY))
  			ufs_sync_inode (inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
478
  		yield();
  	}
09114eb8c   Evgeniy Dushistov   [PATCH] ufs: fix ...
479

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
480
  	inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
ecdc63948   Evgeniy Dushistov   [PATCH] ufs: trun...
481
  	ufsi->i_lastfrag = DIRECT_FRAGMENT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
  	mark_inode_dirty(inode);
10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
483
484
485
486
  out:
  	UFSD("EXIT: err %d
  ", err);
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
  }
10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
488

311b9549e   Dmitry Monakhov   ufs: add ufs spec...
489
  int ufs_setattr(struct dentry *dentry, struct iattr *attr)
10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
490
491
492
493
494
495
496
497
  {
  	struct inode *inode = dentry->d_inode;
  	unsigned int ia_valid = attr->ia_valid;
  	int error;
  
  	error = inode_change_ok(inode, attr);
  	if (error)
  		return error;
12755627b   Dmitry Monakhov   quota: unify quot...
498
  	if (ia_valid & ATTR_SIZE && attr->ia_size != inode->i_size) {
10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
499
  		loff_t old_i_size = inode->i_size;
907f4554e   Christoph Hellwig   dquot: move dquot...
500

2c27c65ed   Christoph Hellwig   check ATTR_SIZE c...
501
502
  		/* XXX(truncate): truncate_setsize should be called last */
  		truncate_setsize(inode, attr->ia_size);
788257d61   Arnd Bergmann   ufs: remove the BKL
503
  		lock_ufs(inode->i_sb);
10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
504
  		error = ufs_truncate(inode, old_i_size);
788257d61   Arnd Bergmann   ufs: remove the BKL
505
  		unlock_ufs(inode->i_sb);
10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
506
507
508
  		if (error)
  			return error;
  	}
1025774ce   Christoph Hellwig   remove inode_setattr
509
510
511
512
  
  	setattr_copy(inode, attr);
  	mark_inode_dirty(inode);
  	return 0;
10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
513
  }
c5ef1c42c   Arjan van de Ven   [PATCH] mark stru...
514
  const struct inode_operations ufs_file_inode_operations = {
10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
515
516
  	.setattr = ufs_setattr,
  };