- pre5:
[davej-history.git] / fs / minix / truncate.c
blob3f9f2cb857c04bd4aeff4151cf23100e0ab172ba
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 (atomic_read(&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 bforget(bh);
66 minix_free_block(inode,tmp);
68 return retry;
71 static int V1_trunc_indirect(struct inode * inode, int offset, unsigned short * p)
73 struct buffer_head * bh;
74 int i, tmp;
75 struct buffer_head * ind_bh;
76 unsigned short * ind;
77 int retry = 0;
79 tmp = *p;
80 if (!tmp)
81 return 0;
82 ind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
83 if (tmp != *p) {
84 brelse(ind_bh);
85 return 1;
87 if (!ind_bh) {
88 *p = 0;
89 return 0;
91 repeat:
92 for (i = INDIRECT_BLOCK(offset) ; i < 512 ; i++) {
93 if (i < 0)
94 i = 0;
95 if (i < INDIRECT_BLOCK(offset))
96 goto repeat;
97 ind = i+(unsigned short *) ind_bh->b_data;
98 tmp = *ind;
99 if (!tmp)
100 continue;
101 bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
102 if (i < INDIRECT_BLOCK(offset)) {
103 brelse(bh);
104 goto repeat;
106 if ((bh && DATA_BUFFER_USED(bh)) || tmp != *ind) {
107 retry = 1;
108 brelse(bh);
109 continue;
111 *ind = 0;
112 mark_buffer_dirty(ind_bh);
113 bforget(bh);
114 minix_free_block(inode,tmp);
116 ind = (unsigned short *) ind_bh->b_data;
117 for (i = 0; i < 512; i++)
118 if (*(ind++))
119 break;
120 if (i >= 512) {
121 if (atomic_read(&ind_bh->b_count) != 1)
122 retry = 1;
123 else {
124 tmp = *p;
125 *p = 0;
126 minix_free_block(inode,tmp);
129 brelse(ind_bh);
130 return retry;
133 static int V1_trunc_dindirect(struct inode * inode, int offset, unsigned short *p)
135 int i, tmp;
136 struct buffer_head * dind_bh;
137 unsigned short * dind;
138 int retry = 0;
140 if (!(tmp = *p))
141 return 0;
142 dind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
143 if (tmp != *p) {
144 brelse(dind_bh);
145 return 1;
147 if (!dind_bh) {
148 *p = 0;
149 return 0;
151 repeat:
152 for (i = V1_DINDIRECT_BLOCK(offset) ; i < 512 ; i ++) {
153 if (i < 0)
154 i = 0;
155 if (i < V1_DINDIRECT_BLOCK(offset))
156 goto repeat;
157 dind = i+(unsigned short *) dind_bh->b_data;
158 retry |= V1_trunc_indirect(inode,offset+(i<<9),dind);
159 mark_buffer_dirty(dind_bh);
161 dind = (unsigned short *) dind_bh->b_data;
162 for (i = 0; i < 512; i++)
163 if (*(dind++))
164 break;
165 if (i >= 512) {
166 if (atomic_read(&dind_bh->b_count) != 1)
167 retry = 1;
168 else {
169 tmp = *p;
170 *p = 0;
171 mark_inode_dirty(inode);
172 minix_free_block(inode,tmp);
175 brelse(dind_bh);
176 return retry;
179 static void V1_minix_truncate(struct inode * inode)
181 int retry;
183 if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
184 S_ISLNK(inode->i_mode)))
185 return;
186 while (1) {
187 retry = V1_trunc_direct(inode);
188 retry |= V1_trunc_indirect(inode, 7, inode->u.minix_i.u.i1_data + 7);
189 retry |= V1_trunc_dindirect(inode, 7+512, inode->u.minix_i.u.i1_data + 8);
190 if (!retry)
191 break;
192 current->counter = 0;
193 schedule();
195 inode->i_mtime = inode->i_ctime = CURRENT_TIME;
196 mark_inode_dirty(inode);
200 * The functions for minix V2 fs truncation.
202 static int V2_trunc_direct(struct inode * inode)
204 unsigned long * p;
205 struct buffer_head * bh;
206 int i, tmp;
207 int retry = 0;
209 repeat:
210 for (i = DIRECT_BLOCK ; i < 7 ; i++) {
211 p = (unsigned long *) inode->u.minix_i.u.i2_data + i;
212 if (!(tmp = *p))
213 continue;
214 bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
215 if (i < DIRECT_BLOCK) {
216 brelse(bh);
217 goto repeat;
219 if ((bh && DATA_BUFFER_USED(bh)) || tmp != *p) {
220 retry = 1;
221 brelse(bh);
222 continue;
224 *p = 0;
225 mark_inode_dirty(inode);
226 bforget(bh);
227 minix_free_block(inode,tmp);
229 return retry;
232 static int V2_trunc_indirect(struct inode * inode, int offset, unsigned long * p)
234 struct buffer_head * bh;
235 int i, tmp;
236 struct buffer_head * ind_bh;
237 unsigned long * ind;
238 int retry = 0;
240 tmp = *p;
241 if (!tmp)
242 return 0;
243 ind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
244 if (tmp != *p) {
245 brelse(ind_bh);
246 return 1;
248 if (!ind_bh) {
249 *p = 0;
250 return 0;
252 repeat:
253 for (i = INDIRECT_BLOCK(offset) ; i < 256 ; i++) {
254 if (i < 0)
255 i = 0;
256 if (i < INDIRECT_BLOCK(offset))
257 goto repeat;
258 ind = i+(unsigned long *) ind_bh->b_data;
259 tmp = *ind;
260 if (!tmp)
261 continue;
262 bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
263 if (i < INDIRECT_BLOCK(offset)) {
264 brelse(bh);
265 goto repeat;
267 if ((bh && DATA_BUFFER_USED(bh)) || tmp != *ind) {
268 retry = 1;
269 brelse(bh);
270 continue;
272 *ind = 0;
273 mark_buffer_dirty(ind_bh);
274 bforget(bh);
275 minix_free_block(inode,tmp);
277 ind = (unsigned long *) ind_bh->b_data;
278 for (i = 0; i < 256; i++)
279 if (*(ind++))
280 break;
281 if (i >= 256) {
282 if (atomic_read(&ind_bh->b_count) != 1)
283 retry = 1;
284 else {
285 tmp = *p;
286 *p = 0;
287 minix_free_block(inode,tmp);
290 brelse(ind_bh);
291 return retry;
294 static int V2_trunc_dindirect(struct inode * inode, int offset, unsigned long *p)
296 int i, tmp;
297 struct buffer_head * dind_bh;
298 unsigned long * dind;
299 int retry = 0;
301 if (!(tmp = *p))
302 return 0;
303 dind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
304 if (tmp != *p) {
305 brelse(dind_bh);
306 return 1;
308 if (!dind_bh) {
309 *p = 0;
310 return 0;
312 repeat:
313 for (i = V2_DINDIRECT_BLOCK(offset) ; i < 256 ; i ++) {
314 if (i < 0)
315 i = 0;
316 if (i < V2_DINDIRECT_BLOCK(offset))
317 goto repeat;
318 dind = i+(unsigned long *) dind_bh->b_data;
319 retry |= V2_trunc_indirect(inode,offset+(i<<8),dind);
320 mark_buffer_dirty(dind_bh);
322 dind = (unsigned long *) dind_bh->b_data;
323 for (i = 0; i < 256; i++)
324 if (*(dind++))
325 break;
326 if (i >= 256) {
327 if (atomic_read(&dind_bh->b_count) != 1)
328 retry = 1;
329 else {
330 tmp = *p;
331 *p = 0;
332 mark_inode_dirty(inode);
333 minix_free_block(inode,tmp);
336 brelse(dind_bh);
337 return retry;
340 static int V2_trunc_tindirect(struct inode * inode, int offset, unsigned long * p)
342 int i, tmp;
343 struct buffer_head * tind_bh;
344 unsigned long * tind;
345 int retry = 0;
347 if (!(tmp = *p))
348 return 0;
349 tind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
350 if (tmp != *p) {
351 brelse(tind_bh);
352 return 1;
354 if (!tind_bh) {
355 *p = 0;
356 return 0;
358 repeat:
359 for (i = TINDIRECT_BLOCK(offset) ; i < 256 ; i ++) {
360 if (i < 0)
361 i = 0;
362 if (i < TINDIRECT_BLOCK(offset))
363 goto repeat;
364 tind = i+(unsigned long *) tind_bh->b_data;
365 retry |= V2_trunc_dindirect(inode,offset+(i<<8),tind);
366 mark_buffer_dirty(tind_bh);
368 tind = (unsigned long *) tind_bh->b_data;
369 for (i = 0; i < 256; i++)
370 if (*(tind++))
371 break;
372 if (i >= 256) {
373 if (atomic_read(&tind_bh->b_count) != 1)
374 retry = 1;
375 else {
376 tmp = *p;
377 *p = 0;
378 mark_inode_dirty(inode);
379 minix_free_block(inode,tmp);
382 brelse(tind_bh);
383 return retry;
386 static void V2_minix_truncate(struct inode * inode)
388 int retry;
390 if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
391 S_ISLNK(inode->i_mode)))
392 return;
393 while (1) {
394 retry = V2_trunc_direct(inode);
395 retry |= V2_trunc_indirect(inode,7,
396 (unsigned long *) inode->u.minix_i.u.i2_data + 7);
397 retry |= V2_trunc_dindirect(inode, 7+256,
398 (unsigned long *) inode->u.minix_i.u.i2_data + 8);
399 retry |= V2_trunc_tindirect(inode, 7+256+256*256,
400 (unsigned long *) inode->u.minix_i.u.i2_data + 9);
401 if (!retry)
402 break;
403 run_task_queue(&tq_disk);
404 current->policy |= SCHED_YIELD;
405 schedule();
407 inode->i_mtime = inode->i_ctime = CURRENT_TIME;
408 mark_inode_dirty(inode);
412 * The function that is called for file truncation.
414 void minix_truncate(struct inode * inode)
416 if (INODE_VERSION(inode) == MINIX_V1)
417 V1_minix_truncate(inode);
418 else
419 V2_minix_truncate(inode);