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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [fs/] [ext/] [truncate.c] - Blame information for rev 1628

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1628 jcastillo
/*
2
 *  linux/fs/ext/truncate.c
3
 *
4
 *  Copyright (C) 1992  Remy Card (card@masi.ibp.fr)
5
 *
6
 *  from
7
 *
8
 *  linux/fs/minix/truncate.c
9
 *
10
 *  Copyright (C) 1991, 1992  Linus Torvalds
11
 */
12
 
13
#include <linux/sched.h>
14
#include <linux/ext_fs.h>
15
#include <linux/stat.h>
16
#include <linux/fcntl.h>
17
#include <linux/errno.h>
18
 
19
/*
20
 * Truncate has the most races in the whole filesystem: coding it is
21
 * a pain in the a**. Especially as I don't do any locking...
22
 *
23
 * The code may look a bit weird, but that's just because I've tried to
24
 * handle things like file-size changes in a somewhat graceful manner.
25
 * Anyway, truncating a file at the same time somebody else writes to it
26
 * is likely to result in pretty weird behaviour...
27
 *
28
 * The new code handles normal truncates (size = 0) as well as the more
29
 * general case (size = XXX). I hope.
30
 */
31
 
32
static int trunc_direct(struct inode * inode)
33
{
34
        int i, tmp;
35
        unsigned long * p;
36
        struct buffer_head * bh;
37
        int retry = 0;
38
#define DIRECT_BLOCK ((inode->i_size + 1023) >> 10)
39
 
40
repeat:
41
        for (i = DIRECT_BLOCK ; i < 9 ; i++) {
42
                p = inode->u.ext_i.i_data+i;
43
                if (!(tmp = *p))
44
                        continue;
45
                bh = getblk(inode->i_dev,tmp,BLOCK_SIZE);
46
                if (i < DIRECT_BLOCK) {
47
                        brelse(bh);
48
                        goto repeat;
49
                }
50
                if ((bh && bh->b_count != 1) || tmp != *p) {
51
                        retry = 1;
52
                        brelse(bh);
53
                        continue;
54
                }
55
                *p = 0;
56
                inode->i_dirt = 1;
57
                brelse(bh);
58
                ext_free_block(inode->i_sb,tmp);
59
        }
60
        return retry;
61
}
62
 
63
static int trunc_indirect(struct inode * inode, int offset, unsigned long * p)
64
{
65
        int i, tmp;
66
        struct buffer_head * bh;
67
        struct buffer_head * ind_bh;
68
        unsigned long * ind;
69
        int retry = 0;
70
#define INDIRECT_BLOCK (DIRECT_BLOCK-offset)
71
 
72
        tmp = *p;
73
        if (!tmp)
74
                return 0;
75
        ind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
76
        if (tmp != *p) {
77
                brelse(ind_bh);
78
                return 1;
79
        }
80
        if (!ind_bh) {
81
                *p = 0;
82
                return 0;
83
        }
84
repeat:
85
        for (i = INDIRECT_BLOCK ; i < 256 ; i++) {
86
                if (i < 0)
87
                        i = 0;
88
                if (i < INDIRECT_BLOCK)
89
                        goto repeat;
90
                ind = i+(unsigned long *) ind_bh->b_data;
91
                tmp = *ind;
92
                if (!tmp)
93
                        continue;
94
                bh = getblk(inode->i_dev,tmp,BLOCK_SIZE);
95
                if (i < INDIRECT_BLOCK) {
96
                        brelse(bh);
97
                        goto repeat;
98
                }
99
                if ((bh && bh->b_count != 1) || tmp != *ind) {
100
                        retry = 1;
101
                        brelse(bh);
102
                        continue;
103
                }
104
                *ind = 0;
105
                mark_buffer_dirty(ind_bh, 1);
106
                brelse(bh);
107
                ext_free_block(inode->i_sb,tmp);
108
        }
109
        ind = (unsigned long *) ind_bh->b_data;
110
        for (i = 0; i < 256; i++)
111
                if (*(ind++))
112
                        break;
113
        if (i >= 256)
114
                if (ind_bh->b_count != 1)
115
                        retry = 1;
116
                else {
117
                        tmp = *p;
118
                        *p = 0;
119
                        inode->i_dirt = 1;
120
                        ext_free_block(inode->i_sb,tmp);
121
                }
122
        brelse(ind_bh);
123
        return retry;
124
}
125
 
126
static int trunc_dindirect(struct inode * inode, int offset, unsigned long * p)
127
{
128
        int i,tmp;
129
        struct buffer_head * dind_bh;
130
        unsigned long * dind;
131
        int retry = 0;
132
#define DINDIRECT_BLOCK ((DIRECT_BLOCK-offset)>>8)
133
 
134
        tmp = *p;
135
        if (!tmp)
136
                return 0;
137
        dind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
138
        if (tmp != *p) {
139
                brelse(dind_bh);
140
                return 1;
141
        }
142
        if (!dind_bh) {
143
                *p = 0;
144
                return 0;
145
        }
146
repeat:
147
        for (i = DINDIRECT_BLOCK ; i < 256 ; i ++) {
148
                if (i < 0)
149
                        i = 0;
150
                if (i < DINDIRECT_BLOCK)
151
                        goto repeat;
152
                dind = i+(unsigned long *) dind_bh->b_data;
153
                tmp = *dind;
154
                if (!tmp)
155
                        continue;
156
                retry |= trunc_indirect(inode,offset+(i<<8),dind);
157
                mark_buffer_dirty(dind_bh, 1);
158
        }
159
        dind = (unsigned long *) dind_bh->b_data;
160
        for (i = 0; i < 256; i++)
161
                if (*(dind++))
162
                        break;
163
        if (i >= 256)
164
                if (dind_bh->b_count != 1)
165
                        retry = 1;
166
                else {
167
                        tmp = *p;
168
                        *p = 0;
169
                        inode->i_dirt = 1;
170
                        ext_free_block(inode->i_sb,tmp);
171
                }
172
        brelse(dind_bh);
173
        return retry;
174
}
175
 
176
static int trunc_tindirect(struct inode * inode)
177
{
178
        int i,tmp;
179
        struct buffer_head * tind_bh;
180
        unsigned long * tind, * p;
181
        int retry = 0;
182
#define TINDIRECT_BLOCK ((DIRECT_BLOCK-(256*256+256+9))>>16)
183
 
184
        p = inode->u.ext_i.i_data+11;
185
        if (!(tmp = *p))
186
                return 0;
187
        tind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
188
        if (tmp != *p) {
189
                brelse(tind_bh);
190
                return 1;
191
        }
192
        if (!tind_bh) {
193
                *p = 0;
194
                return 0;
195
        }
196
repeat:
197
        for (i = TINDIRECT_BLOCK ; i < 256 ; i ++) {
198
                if (i < 0)
199
                        i = 0;
200
                if (i < TINDIRECT_BLOCK)
201
                        goto repeat;
202
                tind = i+(unsigned long *) tind_bh->b_data;
203
                retry |= trunc_dindirect(inode,9+256+256*256+(i<<16),tind);
204
                mark_buffer_dirty(tind_bh, 1);
205
        }
206
        tind = (unsigned long *) tind_bh->b_data;
207
        for (i = 0; i < 256; i++)
208
                if (*(tind++))
209
                        break;
210
        if (i >= 256)
211
                if (tind_bh->b_count != 1)
212
                        retry = 1;
213
                else {
214
                        tmp = *p;
215
                        *p = 0;
216
                        inode->i_dirt = 1;
217
                        ext_free_block(inode->i_sb,tmp);
218
                }
219
        brelse(tind_bh);
220
        return retry;
221
}
222
 
223
void ext_truncate(struct inode * inode)
224
{
225
        int retry;
226
 
227
        if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
228
             S_ISLNK(inode->i_mode)))
229
                return;
230
        while (1) {
231
                retry = trunc_direct(inode);
232
                retry |= trunc_indirect(inode,9,inode->u.ext_i.i_data+9);
233
                retry |= trunc_dindirect(inode,9+256,inode->u.ext_i.i_data+10);
234
                retry |= trunc_tindirect(inode);
235
                if (!retry)
236
                        break;
237
                current->counter = 0;
238
                schedule();
239
        }
240
        inode->i_mtime = inode->i_ctime = CURRENT_TIME;
241
        inode->i_dirt = 1;
242
}
243
 
244
/*
245
 * Called when a inode is released. Note that this is different
246
 * from ext_open: open gets called at every open, but release
247
 * gets called only when /all/ the files are closed.
248
 */
249
void ext_release(struct inode * inode, struct file * filp)
250
{
251
        printk("ext_release not implemented\n");
252
}

powered by: WebSVN 2.1.0

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