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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1628 jcastillo
/*
2
 *  linux/fs/sysv/truncate.c
3
 *
4
 *  minix/truncate.c
5
 *  Copyright (C) 1991, 1992  Linus Torvalds
6
 *
7
 *  coh/truncate.c
8
 *  Copyright (C) 1993  Pascal Haible, Bruno Haible
9
 *
10
 *  sysv/truncate.c
11
 *  Copyright (C) 1993  Bruno Haible
12
 */
13
 
14
#include <linux/sched.h>
15
#include <linux/fs.h>
16
#include <linux/sysv_fs.h>
17
#include <linux/stat.h>
18
 
19
 
20
/* Linus' implementation of truncate.
21
 * It doesn't need locking because it can tell from looking at bh->b_count
22
 * whether a given block is in use elsewhere.
23
 */
24
 
25
/*
26
 * Truncate has the most races in the whole filesystem: coding it is
27
 * a pain in the a**. Especially as I don't do any locking...
28
 *
29
 * The code may look a bit weird, but that's just because I've tried to
30
 * handle things like file-size changes in a somewhat graceful manner.
31
 * Anyway, truncating a file at the same time somebody else writes to it
32
 * is likely to result in pretty weird behaviour...
33
 *
34
 * The new code handles normal truncates (size = 0) as well as the more
35
 * general case (size = XXX). I hope.
36
 */
37
 
38
/* We throw away any data beyond inode->i_size. */
39
 
40
static int trunc_direct(struct inode * inode)
41
{
42
        struct super_block * sb;
43
        unsigned int i;
44
        unsigned long * p;
45
        unsigned long block;
46
        struct buffer_head * bh;
47
        int retry = 0;
48
 
49
        sb = inode->i_sb;
50
repeat:
51
        for (i = ((unsigned long) inode->i_size + sb->sv_block_size_1) >> sb->sv_block_size_bits; i < 10; i++) {
52
                p = inode->u.sysv_i.i_data + i;
53
                block = *p;
54
                if (!block)
55
                        continue;
56
                bh = sv_get_hash_table(sb, inode->i_dev, block);
57
                if ((i << sb->sv_block_size_bits) < inode->i_size) {
58
                        brelse(bh);
59
                        goto repeat;
60
                }
61
                if ((bh && bh->b_count != 1) || (block != *p)) {
62
                        retry = 1;
63
                        brelse(bh);
64
                        continue;
65
                }
66
                *p = 0;
67
                inode->i_dirt = 1;
68
                brelse(bh);
69
                sysv_free_block(sb,block);
70
        }
71
        return retry;
72
}
73
 
74
static int trunc_indirect(struct inode * inode, unsigned long offset, unsigned long * p, int convert, unsigned char * dirt)
75
{
76
        unsigned long indtmp, indblock;
77
        struct super_block * sb;
78
        struct buffer_head * indbh;
79
        unsigned int i;
80
        sysv_zone_t * ind;
81
        unsigned long tmp, block;
82
        struct buffer_head * bh;
83
        int retry = 0;
84
 
85
        indblock = indtmp = *p;
86
        if (convert)
87
                indblock = from_coh_ulong(indblock);
88
        if (!indblock)
89
                return 0;
90
        sb = inode->i_sb;
91
        indbh = sv_bread(sb, inode->i_dev, indblock);
92
        if (indtmp != *p) {
93
                brelse(indbh);
94
                return 1;
95
        }
96
        if (!indbh) {
97
                *p = 0;
98
                *dirt = 1;
99
                return 0;
100
        }
101
repeat:
102
        if (inode->i_size < offset)
103
                i = 0;
104
        else
105
                i = (inode->i_size - offset + sb->sv_block_size_1) >> sb->sv_block_size_bits;
106
        for (; i < sb->sv_ind_per_block; i++) {
107
                ind = ((sysv_zone_t *) indbh->b_data) + i;
108
                block = tmp = *ind;
109
                if (sb->sv_convert)
110
                        block = from_coh_ulong(block);
111
                if (!block)
112
                        continue;
113
                bh = sv_get_hash_table(sb, inode->i_dev, block);
114
                if ((i << sb->sv_block_size_bits) + offset < inode->i_size) {
115
                        brelse(bh);
116
                        goto repeat;
117
                }
118
                if ((bh && bh->b_count != 1) || (tmp != *ind)) {
119
                        retry = 1;
120
                        brelse(bh);
121
                        continue;
122
                }
123
                *ind = 0;
124
                mark_buffer_dirty(indbh, 1);
125
                brelse(bh);
126
                sysv_free_block(sb,block);
127
        }
128
        for (i = 0; i < sb->sv_ind_per_block; i++)
129
                if (((sysv_zone_t *) indbh->b_data)[i])
130
                        goto done;
131
        if ((indbh->b_count != 1) || (indtmp != *p)) {
132
                brelse(indbh);
133
                return 1;
134
        }
135
        *p = 0;
136
        *dirt = 1;
137
        sysv_free_block(sb,indblock);
138
done:
139
        brelse(indbh);
140
        return retry;
141
}
142
 
143
static int trunc_dindirect(struct inode * inode, unsigned long offset, unsigned long * p, int convert, unsigned char * dirt)
144
{
145
        unsigned long indtmp, indblock;
146
        struct super_block * sb;
147
        struct buffer_head * indbh;
148
        unsigned int i;
149
        sysv_zone_t * ind;
150
        unsigned long tmp, block;
151
        int retry = 0;
152
 
153
        indblock = indtmp = *p;
154
        if (convert)
155
                indblock = from_coh_ulong(indblock);
156
        if (!indblock)
157
                return 0;
158
        sb = inode->i_sb;
159
        indbh = sv_bread(sb, inode->i_dev, indblock);
160
        if (indtmp != *p) {
161
                brelse(indbh);
162
                return 1;
163
        }
164
        if (!indbh) {
165
                *p = 0;
166
                *dirt = 1;
167
                return 0;
168
        }
169
        if (inode->i_size < offset)
170
                i = 0;
171
        else
172
                i = (inode->i_size - offset + sb->sv_ind_per_block_block_size_1) >> sb->sv_ind_per_block_block_size_bits;
173
        for (; i < sb->sv_ind_per_block; i++) {
174
                unsigned char dirty = 0;
175
                ind = ((sysv_zone_t *) indbh->b_data) + i;
176
                block = tmp = *ind;
177
                if (sb->sv_convert)
178
                        block = from_coh_ulong(block);
179
                if (!block)
180
                        continue;
181
                retry |= trunc_indirect(inode,offset+(i<<sb->sv_ind_per_block_bits),ind,sb->sv_convert,&dirty);
182
                if (dirty)
183
                        mark_buffer_dirty(indbh, 1);
184
        }
185
        for (i = 0; i < sb->sv_ind_per_block; i++)
186
                if (((sysv_zone_t *) indbh->b_data)[i])
187
                        goto done;
188
        if ((indbh->b_count != 1) || (indtmp != *p)) {
189
                brelse(indbh);
190
                return 1;
191
        }
192
        *p = 0;
193
        *dirt = 1;
194
        sysv_free_block(sb,indblock);
195
done:
196
        brelse(indbh);
197
        return retry;
198
}
199
 
200
static int trunc_tindirect(struct inode * inode, unsigned long offset, unsigned long * p, int convert, unsigned char * dirt)
201
{
202
        unsigned long indtmp, indblock;
203
        struct super_block * sb;
204
        struct buffer_head * indbh;
205
        unsigned int i;
206
        sysv_zone_t * ind;
207
        unsigned long tmp, block;
208
        int retry = 0;
209
 
210
        indblock = indtmp = *p;
211
        if (convert)
212
                indblock = from_coh_ulong(indblock);
213
        if (!indblock)
214
                return 0;
215
        sb = inode->i_sb;
216
        indbh = sv_bread(sb, inode->i_dev, indblock);
217
        if (indtmp != *p) {
218
                brelse(indbh);
219
                return 1;
220
        }
221
        if (!indbh) {
222
                *p = 0;
223
                *dirt = 1;
224
                return 0;
225
        }
226
        if (inode->i_size < offset)
227
                i = 0;
228
        else
229
                i = (inode->i_size - offset + sb->sv_ind_per_block_2_block_size_1) >> sb->sv_ind_per_block_2_block_size_bits;
230
        for (; i < sb->sv_ind_per_block; i++) {
231
                unsigned char dirty = 0;
232
                ind = ((sysv_zone_t *) indbh->b_data) + i;
233
                block = tmp = *ind;
234
                if (sb->sv_convert)
235
                        block = from_coh_ulong(block);
236
                if (!block)
237
                        continue;
238
                retry |= trunc_dindirect(inode,offset+(i<<sb->sv_ind_per_block_2_bits),ind,sb->sv_convert,&dirty);
239
                if (dirty)
240
                        mark_buffer_dirty(indbh, 1);
241
        }
242
        for (i = 0; i < sb->sv_ind_per_block; i++)
243
                if (((sysv_zone_t *) indbh->b_data)[i])
244
                        goto done;
245
        if ((indbh->b_count != 1) || (indtmp != *p)) {
246
                brelse(indbh);
247
                return 1;
248
        }
249
        *p = 0;
250
        *dirt = 1;
251
        sysv_free_block(sb,indblock);
252
done:
253
        brelse(indbh);
254
        return retry;
255
}
256
 
257
static int trunc_all(struct inode * inode)
258
{
259
        struct super_block * sb;
260
 
261
        sb = inode->i_sb;
262
        return trunc_direct(inode)
263
             | trunc_indirect(inode,sb->sv_ind0_size,&inode->u.sysv_i.i_data[10],0,&inode->i_dirt)
264
             | trunc_dindirect(inode,sb->sv_ind1_size,&inode->u.sysv_i.i_data[11],0,&inode->i_dirt)
265
             | trunc_tindirect(inode,sb->sv_ind2_size,&inode->u.sysv_i.i_data[12],0,&inode->i_dirt);
266
}
267
 
268
 
269
void sysv_truncate(struct inode * inode)
270
{
271
        /* If this is called from sysv_put_inode, we needn't worry about
272
         * races as we are just losing the last reference to the inode.
273
         * If this is called from another place, let's hope it's a regular
274
         * file.
275
         * Truncating symbolic links is strange. We assume we don't truncate
276
         * a directory we are just modifying. We ensure we don't truncate
277
         * a regular file we are just writing to, by use of a lock.
278
         */
279
        if (S_ISLNK(inode->i_mode))
280
                printk("sysv_truncate: truncating symbolic link\n");
281
        else if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)))
282
                return;
283
        while (trunc_all(inode)) {
284
                current->counter = 0;
285
                schedule();
286
        }
287
        inode->i_mtime = inode->i_ctime = CURRENT_TIME;
288
        inode->i_dirt = 1;
289
}

powered by: WebSVN 2.1.0

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