OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [before_ORP/] [uclinux/] [uClinux-2.0.x/] [fs/] [minix/] [truncate.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 *  linux/fs/truncate.c
3
 *
4
 *  Copyright (C) 1991, 1992  Linus Torvalds
5
 *
6
 *  Copyright (C) 1996  Gertjan van Wingerde (gertjan@cs.vu.nl)
7
 *      Minix V2 fs support.
8
 */
9
 
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>
15
 
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)
21
 
22
/*
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...
25
 *
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...
30
 *
31
 * The new code handles normal truncates (size = 0) as well as the more
32
 * general case (size = XXX). I hope.
33
 */
34
 
35
/*
36
 * The functions for minix V1 fs truncation.
37
 */
38
static int V1_trunc_direct(struct inode * inode)
39
{
40
        unsigned short * p;
41
        struct buffer_head * bh;
42
        int i, tmp;
43
        int retry = 0;
44
 
45
repeat:
46
        for (i = DIRECT_BLOCK ; i < 7 ; i++) {
47
                p = i + inode->u.minix_i.u.i1_data;
48
                if (!(tmp = *p))
49
                        continue;
50
                bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
51
                if (i < DIRECT_BLOCK) {
52
                        brelse(bh);
53
                        goto repeat;
54
                }
55
                if ((bh && bh->b_count != 1) || tmp != *p) {
56
                        retry = 1;
57
                        brelse(bh);
58
                        continue;
59
                }
60
                *p = 0;
61
                inode->i_dirt = 1;
62
                if (bh) {
63
                        mark_buffer_clean(bh);
64
                        brelse(bh);
65
                }
66
                minix_free_block(inode->i_sb,tmp);
67
        }
68
        return retry;
69
}
70
 
71
static int V1_trunc_indirect(struct inode * inode, int offset, unsigned short * p)
72
{
73
        struct buffer_head * bh;
74
        int i, tmp;
75
        struct buffer_head * ind_bh;
76
        unsigned short * ind;
77
        int retry = 0;
78
 
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;
86
        }
87
        if (!ind_bh) {
88
                *p = 0;
89
                return 0;
90
        }
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;
105
                }
106
                if ((bh && bh->b_count != 1) || tmp != *ind) {
107
                        retry = 1;
108
                        brelse(bh);
109
                        continue;
110
                }
111
                *ind = 0;
112
                mark_buffer_dirty(ind_bh, 1);
113
                brelse(bh);
114
                minix_free_block(inode->i_sb,tmp);
115
        }
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 (ind_bh->b_count != 1)
122
                        retry = 1;
123
                else {
124
                        tmp = *p;
125
                        *p = 0;
126
                        minix_free_block(inode->i_sb,tmp);
127
                }
128
        brelse(ind_bh);
129
        return retry;
130
}
131
 
132
static int V1_trunc_dindirect(struct inode * inode, int offset, unsigned short *p)
133
{
134
        int i, tmp;
135
        struct buffer_head * dind_bh;
136
        unsigned short * dind;
137
        int retry = 0;
138
 
139
        if (!(tmp = *p))
140
                return 0;
141
        dind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
142
        if (tmp != *p) {
143
                brelse(dind_bh);
144
                return 1;
145
        }
146
        if (!dind_bh) {
147
                *p = 0;
148
                return 0;
149
        }
150
repeat:
151
        for (i = V1_DINDIRECT_BLOCK(offset) ; i < 512 ; i ++) {
152
                if (i < 0)
153
                        i = 0;
154
                if (i < V1_DINDIRECT_BLOCK(offset))
155
                        goto repeat;
156
                dind = i+(unsigned short *) dind_bh->b_data;
157
                retry |= V1_trunc_indirect(inode,offset+(i<<9),dind);
158
                mark_buffer_dirty(dind_bh, 1);
159
        }
160
        dind = (unsigned short *) dind_bh->b_data;
161
        for (i = 0; i < 512; i++)
162
                if (*(dind++))
163
                        break;
164
        if (i >= 512)
165
                if (dind_bh->b_count != 1)
166
                        retry = 1;
167
                else {
168
                        tmp = *p;
169
                        *p = 0;
170
                        inode->i_dirt = 1;
171
                        minix_free_block(inode->i_sb,tmp);
172
                }
173
        brelse(dind_bh);
174
        return retry;
175
}
176
 
177
void V1_minix_truncate(struct inode * inode)
178
{
179
        int retry;
180
 
181
        if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
182
             S_ISLNK(inode->i_mode)))
183
                return;
184
        while (1) {
185
                retry = V1_trunc_direct(inode);
186
                retry |= V1_trunc_indirect(inode, 7, inode->u.minix_i.u.i1_data + 7);
187
                retry |= V1_trunc_dindirect(inode, 7+512, inode->u.minix_i.u.i1_data + 8);
188
                if (!retry)
189
                        break;
190
                current->counter = 0;
191
                schedule();
192
        }
193
        inode->i_mtime = inode->i_ctime = CURRENT_TIME;
194
        inode->i_dirt = 1;
195
}
196
 
197
/*
198
 * The functions for minix V2 fs truncation.
199
 */
200
static int V2_trunc_direct(struct inode * inode)
201
{
202
        unsigned long * p;
203
        struct buffer_head * bh;
204
        int i, tmp;
205
        int retry = 0;
206
 
207
repeat:
208
        for (i = DIRECT_BLOCK ; i < 7 ; i++) {
209
                p = (unsigned long *) inode->u.minix_i.u.i2_data + i;
210
                if (!(tmp = *p))
211
                        continue;
212
                bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
213
                if (i < DIRECT_BLOCK) {
214
                        brelse(bh);
215
                        goto repeat;
216
                }
217
                if ((bh && bh->b_count != 1) || tmp != *p) {
218
                        retry = 1;
219
                        brelse(bh);
220
                        continue;
221
                }
222
                *p = 0;
223
                inode->i_dirt = 1;
224
                if (bh) {
225
                        mark_buffer_clean(bh);
226
                        brelse(bh);
227
                }
228
                minix_free_block(inode->i_sb,tmp);
229
        }
230
        return retry;
231
}
232
 
233
static int V2_trunc_indirect(struct inode * inode, int offset, unsigned long * p)
234
{
235
        struct buffer_head * bh;
236
        int i, tmp;
237
        struct buffer_head * ind_bh;
238
        unsigned long * ind;
239
        int retry = 0;
240
 
241
        tmp = *p;
242
        if (!tmp)
243
                return 0;
244
        ind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
245
        if (tmp != *p) {
246
                brelse(ind_bh);
247
                return 1;
248
        }
249
        if (!ind_bh) {
250
                *p = 0;
251
                return 0;
252
        }
253
repeat:
254
        for (i = INDIRECT_BLOCK(offset) ; i < 256 ; i++) {
255
                if (i < 0)
256
                        i = 0;
257
                if (i < INDIRECT_BLOCK(offset))
258
                        goto repeat;
259
                ind = i+(unsigned long *) ind_bh->b_data;
260
                tmp = *ind;
261
                if (!tmp)
262
                        continue;
263
                bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
264
                if (i < INDIRECT_BLOCK(offset)) {
265
                        brelse(bh);
266
                        goto repeat;
267
                }
268
                if ((bh && bh->b_count != 1) || tmp != *ind) {
269
                        retry = 1;
270
                        brelse(bh);
271
                        continue;
272
                }
273
                *ind = 0;
274
                mark_buffer_dirty(ind_bh, 1);
275
                brelse(bh);
276
                minix_free_block(inode->i_sb,tmp);
277
        }
278
        ind = (unsigned long *) ind_bh->b_data;
279
        for (i = 0; i < 256; i++)
280
                if (*(ind++))
281
                        break;
282
        if (i >= 256)
283
                if (ind_bh->b_count != 1)
284
                        retry = 1;
285
                else {
286
                        tmp = *p;
287
                        *p = 0;
288
                        minix_free_block(inode->i_sb,tmp);
289
                }
290
        brelse(ind_bh);
291
        return retry;
292
}
293
 
294
static int V2_trunc_dindirect(struct inode * inode, int offset, unsigned long *p)
295
{
296
        int i, tmp;
297
        struct buffer_head * dind_bh;
298
        unsigned long * dind;
299
        int retry = 0;
300
 
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;
307
        }
308
        if (!dind_bh) {
309
                *p = 0;
310
                return 0;
311
        }
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, 1);
321
        }
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 (dind_bh->b_count != 1)
328
                        retry = 1;
329
                else {
330
                        tmp = *p;
331
                        *p = 0;
332
                        inode->i_dirt = 1;
333
                        minix_free_block(inode->i_sb,tmp);
334
                }
335
        brelse(dind_bh);
336
        return retry;
337
}
338
 
339
static int V2_trunc_tindirect(struct inode * inode, int offset, unsigned long * p)
340
{
341
        int i, tmp;
342
        struct buffer_head * tind_bh;
343
        unsigned long * tind;
344
        int retry = 0;
345
 
346
        if (!(tmp = *p))
347
                return 0;
348
        tind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
349
        if (tmp != *p) {
350
                brelse(tind_bh);
351
                return 1;
352
        }
353
        if (!tind_bh) {
354
                *p = 0;
355
                return 0;
356
        }
357
repeat:
358
        for (i = TINDIRECT_BLOCK(offset) ; i < 256 ; i ++) {
359
                if (i < 0)
360
                        i = 0;
361
                if (i < TINDIRECT_BLOCK(offset))
362
                        goto repeat;
363
                tind = i+(unsigned long *) tind_bh->b_data;
364
                retry |= V2_trunc_dindirect(inode,offset+(i<<8),tind);
365
                mark_buffer_dirty(tind_bh, 1);
366
        }
367
        tind = (unsigned long *) tind_bh->b_data;
368
        for (i = 0; i < 256; i++)
369
                if (*(tind++))
370
                        break;
371
        if (i >= 256)
372
                if (tind_bh->b_count != 1)
373
                        retry = 1;
374
                else {
375
                        tmp = *p;
376
                        *p = 0;
377
                        inode->i_dirt = 1;
378
                        minix_free_block(inode->i_sb,tmp);
379
                }
380
        brelse(tind_bh);
381
        return retry;
382
}
383
 
384
static void V2_minix_truncate(struct inode * inode)
385
{
386
        int retry;
387
 
388
        if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
389
             S_ISLNK(inode->i_mode)))
390
                return;
391
        while (1) {
392
                retry = V2_trunc_direct(inode);
393
                retry |= V2_trunc_indirect(inode,7,
394
                        (unsigned long *) inode->u.minix_i.u.i2_data + 7);
395
                retry |= V2_trunc_dindirect(inode, 7+256,
396
                        (unsigned long *) inode->u.minix_i.u.i2_data + 8);
397
                retry |= V2_trunc_tindirect(inode, 7+256+256*256,
398
                        (unsigned long *) inode->u.minix_i.u.i2_data + 9);
399
                if (!retry)
400
                        break;
401
                current->counter = 0;
402
                schedule();
403
        }
404
        inode->i_mtime = inode->i_ctime = CURRENT_TIME;
405
        inode->i_dirt = 1;
406
}
407
 
408
/*
409
 * The function that is called for file truncation.
410
 */
411
void minix_truncate(struct inode * inode)
412
{
413
        if (INODE_VERSION(inode) == MINIX_V1)
414
                V1_minix_truncate(inode);
415
        else
416
                V2_minix_truncate(inode);
417
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.