Import 2.3.7pre3
[davej-history.git] / fs / minix / truncate.c
blob4718e092e48ada1438e8bb6472eb66f09653eb93
1 /*
2 * linux/fs/truncate.c
4 * Copyright (C) 1991, 1992 Linus Torvalds
6 * Copyright (C) 1996 Gertjan van Wingerde (gertjan@cs.vu.nl)
7 * Minix V2 fs support.
8 */
10 #include <linux/errno.h>
11 #include <linux/sched.h>
12 #include <linux/minix_fs.h>
13 #include <linux/stat.h>
14 #include <linux/fcntl.h>
16 #define DIRECT_BLOCK ((inode->i_size + 1023) >> 10)
17 #define INDIRECT_BLOCK(offset) (DIRECT_BLOCK-offset)
18 #define V1_DINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-offset)>>9)
19 #define V2_DINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-offset)>>8)
20 #define TINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-(offset))>>8)
23 * Truncate has the most races in the whole filesystem: coding it is
24 * a pain in the a**, especially as I don't do any locking.
26 * The code may look a bit weird, but that's just because I've tried to
27 * handle things like file-size changes in a somewhat graceful manner.
28 * Anyway, truncating a file at the same time somebody else writes to it
29 * is likely to result in pretty weird behaviour...
31 * The new code handles normal truncates (size = 0) as well as the more
32 * general case (size = XXX). I hope.
35 #define DATA_BUFFER_USED(bh) \
36 ((bh->b_count > 1) || buffer_locked(bh))
39 * The functions for minix V1 fs truncation.
41 static int V1_trunc_direct(struct inode * inode)
43 unsigned short * p;
44 struct buffer_head * bh;
45 int i, tmp;
46 int retry = 0;
48 repeat:
49 for (i = DIRECT_BLOCK ; i < 7 ; i++) {
50 p = i + inode->u.minix_i.u.i1_data;
51 if (!(tmp = *p))
52 continue;
53 bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
54 if (i < DIRECT_BLOCK) {
55 brelse(bh);
56 goto repeat;
58 if ((bh && DATA_BUFFER_USED(bh)) || tmp != *p) {
59 retry = 1;
60 brelse(bh);
61 continue;
63 *p = 0;
64 mark_inode_dirty(inode);
65 if (bh) {
66 mark_buffer_clean(bh);
67 brelse(bh);
69 minix_free_block(inode->i_sb,tmp);
71 return retry;
74 static int V1_trunc_indirect(struct inode * inode, int offset, unsigned short * p)
76 struct buffer_head * bh;
77 int i, tmp;
78 struct buffer_head * ind_bh;
79 unsigned short * ind;
80 int retry = 0;
82 tmp = *p;
83 if (!tmp)
84 return 0;
85 ind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
86 if (tmp != *p) {
87 brelse(ind_bh);
88 return 1;
90 if (!ind_bh) {
91 *p = 0;
92 return 0;
94 repeat:
95 for (i = INDIRECT_BLOCK(offset) ; i < 512 ; i++) {
96 if (i < 0)
97 i = 0;
98 if (i < INDIRECT_BLOCK(offset))
99 goto repeat;
100 ind = i+(unsigned short *) ind_bh->b_data;
101 tmp = *ind;
102 if (!tmp)
103 continue;
104 bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
105 if (i < INDIRECT_BLOCK(offset)) {
106 brelse(bh);
107 goto repeat;
109 if ((bh && DATA_BUFFER_USED(bh)) || tmp != *ind) {
110 retry = 1;
111 brelse(bh);
112 continue;
114 *ind = 0;
115 mark_buffer_dirty(ind_bh, 1);
116 brelse(bh);
117 minix_free_block(inode->i_sb,tmp);
119 ind = (unsigned short *) ind_bh->b_data;
120 for (i = 0; i < 512; i++)
121 if (*(ind++))
122 break;
123 if (i >= 512) {
124 if (ind_bh->b_count != 1)
125 retry = 1;
126 else {
127 tmp = *p;
128 *p = 0;
129 minix_free_block(inode->i_sb,tmp);
132 brelse(ind_bh);
133 return retry;
136 static int V1_trunc_dindirect(struct inode * inode, int offset, unsigned short *p)
138 int i, tmp;
139 struct buffer_head * dind_bh;
140 unsigned short * dind;
141 int retry = 0;
143 if (!(tmp = *p))
144 return 0;
145 dind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
146 if (tmp != *p) {
147 brelse(dind_bh);
148 return 1;
150 if (!dind_bh) {
151 *p = 0;
152 return 0;
154 repeat:
155 for (i = V1_DINDIRECT_BLOCK(offset) ; i < 512 ; i ++) {
156 if (i < 0)
157 i = 0;
158 if (i < V1_DINDIRECT_BLOCK(offset))
159 goto repeat;
160 dind = i+(unsigned short *) dind_bh->b_data;
161 retry |= V1_trunc_indirect(inode,offset+(i<<9),dind);
162 mark_buffer_dirty(dind_bh, 1);
164 dind = (unsigned short *) dind_bh->b_data;
165 for (i = 0; i < 512; i++)
166 if (*(dind++))
167 break;
168 if (i >= 512) {
169 if (dind_bh->b_count != 1)
170 retry = 1;
171 else {
172 tmp = *p;
173 *p = 0;
174 mark_inode_dirty(inode);
175 minix_free_block(inode->i_sb,tmp);
178 brelse(dind_bh);
179 return retry;
182 static void V1_minix_truncate(struct inode * inode)
184 int retry;
186 if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
187 S_ISLNK(inode->i_mode)))
188 return;
189 while (1) {
190 retry = V1_trunc_direct(inode);
191 retry |= V1_trunc_indirect(inode, 7, inode->u.minix_i.u.i1_data + 7);
192 retry |= V1_trunc_dindirect(inode, 7+512, inode->u.minix_i.u.i1_data + 8);
193 if (!retry)
194 break;
195 current->counter = 0;
196 schedule();
198 inode->i_mtime = inode->i_ctime = CURRENT_TIME;
199 mark_inode_dirty(inode);
203 * The functions for minix V2 fs truncation.
205 static int V2_trunc_direct(struct inode * inode)
207 unsigned long * p;
208 struct buffer_head * bh;
209 int i, tmp;
210 int retry = 0;
212 repeat:
213 for (i = DIRECT_BLOCK ; i < 7 ; i++) {
214 p = (unsigned long *) inode->u.minix_i.u.i2_data + i;
215 if (!(tmp = *p))
216 continue;
217 bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
218 if (i < DIRECT_BLOCK) {
219 brelse(bh);
220 goto repeat;
222 if ((bh && DATA_BUFFER_USED(bh)) || tmp != *p) {
223 retry = 1;
224 brelse(bh);
225 continue;
227 *p = 0;
228 mark_inode_dirty(inode);
229 if (bh) {
230 mark_buffer_clean(bh);
231 brelse(bh);
233 minix_free_block(inode->i_sb,tmp);
235 return retry;
238 static int V2_trunc_indirect(struct inode * inode, int offset, unsigned long * p)
240 struct buffer_head * bh;
241 int i, tmp;
242 struct buffer_head * ind_bh;
243 unsigned long * ind;
244 int retry = 0;
246 tmp = *p;
247 if (!tmp)
248 return 0;
249 ind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
250 if (tmp != *p) {
251 brelse(ind_bh);
252 return 1;
254 if (!ind_bh) {
255 *p = 0;
256 return 0;
258 repeat:
259 for (i = INDIRECT_BLOCK(offset) ; i < 256 ; i++) {
260 if (i < 0)
261 i = 0;
262 if (i < INDIRECT_BLOCK(offset))
263 goto repeat;
264 ind = i+(unsigned long *) ind_bh->b_data;
265 tmp = *ind;
266 if (!tmp)
267 continue;
268 bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
269 if (i < INDIRECT_BLOCK(offset)) {
270 brelse(bh);
271 goto repeat;
273 if ((bh && DATA_BUFFER_USED(bh)) || tmp != *ind) {
274 retry = 1;
275 brelse(bh);
276 continue;
278 *ind = 0;
279 mark_buffer_dirty(ind_bh, 1);
280 brelse(bh);
281 minix_free_block(inode->i_sb,tmp);
283 ind = (unsigned long *) ind_bh->b_data;
284 for (i = 0; i < 256; i++)
285 if (*(ind++))
286 break;
287 if (i >= 256) {
288 if (ind_bh->b_count != 1)
289 retry = 1;
290 else {
291 tmp = *p;
292 *p = 0;
293 minix_free_block(inode->i_sb,tmp);
296 brelse(ind_bh);
297 return retry;
300 static int V2_trunc_dindirect(struct inode * inode, int offset, unsigned long *p)
302 int i, tmp;
303 struct buffer_head * dind_bh;
304 unsigned long * dind;
305 int retry = 0;
307 if (!(tmp = *p))
308 return 0;
309 dind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
310 if (tmp != *p) {
311 brelse(dind_bh);
312 return 1;
314 if (!dind_bh) {
315 *p = 0;
316 return 0;
318 repeat:
319 for (i = V2_DINDIRECT_BLOCK(offset) ; i < 256 ; i ++) {
320 if (i < 0)
321 i = 0;
322 if (i < V2_DINDIRECT_BLOCK(offset))
323 goto repeat;
324 dind = i+(unsigned long *) dind_bh->b_data;
325 retry |= V2_trunc_indirect(inode,offset+(i<<8),dind);
326 mark_buffer_dirty(dind_bh, 1);
328 dind = (unsigned long *) dind_bh->b_data;
329 for (i = 0; i < 256; i++)
330 if (*(dind++))
331 break;
332 if (i >= 256) {
333 if (dind_bh->b_count != 1)
334 retry = 1;
335 else {
336 tmp = *p;
337 *p = 0;
338 mark_inode_dirty(inode);
339 minix_free_block(inode->i_sb,tmp);
342 brelse(dind_bh);
343 return retry;
346 static int V2_trunc_tindirect(struct inode * inode, int offset, unsigned long * p)
348 int i, tmp;
349 struct buffer_head * tind_bh;
350 unsigned long * tind;
351 int retry = 0;
353 if (!(tmp = *p))
354 return 0;
355 tind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
356 if (tmp != *p) {
357 brelse(tind_bh);
358 return 1;
360 if (!tind_bh) {
361 *p = 0;
362 return 0;
364 repeat:
365 for (i = TINDIRECT_BLOCK(offset) ; i < 256 ; i ++) {
366 if (i < 0)
367 i = 0;
368 if (i < TINDIRECT_BLOCK(offset))
369 goto repeat;
370 tind = i+(unsigned long *) tind_bh->b_data;
371 retry |= V2_trunc_dindirect(inode,offset+(i<<8),tind);
372 mark_buffer_dirty(tind_bh, 1);
374 tind = (unsigned long *) tind_bh->b_data;
375 for (i = 0; i < 256; i++)
376 if (*(tind++))
377 break;
378 if (i >= 256) {
379 if (tind_bh->b_count != 1)
380 retry = 1;
381 else {
382 tmp = *p;
383 *p = 0;
384 mark_inode_dirty(inode);
385 minix_free_block(inode->i_sb,tmp);
388 brelse(tind_bh);
389 return retry;
392 static void V2_minix_truncate(struct inode * inode)
394 int retry;
396 if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
397 S_ISLNK(inode->i_mode)))
398 return;
399 while (1) {
400 retry = V2_trunc_direct(inode);
401 retry |= V2_trunc_indirect(inode,7,
402 (unsigned long *) inode->u.minix_i.u.i2_data + 7);
403 retry |= V2_trunc_dindirect(inode, 7+256,
404 (unsigned long *) inode->u.minix_i.u.i2_data + 8);
405 retry |= V2_trunc_tindirect(inode, 7+256+256*256,
406 (unsigned long *) inode->u.minix_i.u.i2_data + 9);
407 if (!retry)
408 break;
409 current->counter = 0;
410 schedule();
412 inode->i_mtime = inode->i_ctime = CURRENT_TIME;
413 mark_inode_dirty(inode);
417 * The function that is called for file truncation.
419 void minix_truncate(struct inode * inode)
421 if (INODE_VERSION(inode) == MINIX_V1)
422 V1_minix_truncate(inode);
423 else
424 V2_minix_truncate(inode);