This source file includes following definitions.
- trunc_direct
- trunc_indirect
- trunc_dindirect
- trunc_tindirect
- ext2_truncate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 #include <linux/errno.h>
16 #include <linux/fs.h>
17 #include <linux/ext2_fs.h>
18 #include <linux/fcntl.h>
19 #include <linux/sched.h>
20 #include <linux/stat.h>
21 #include <linux/locks.h>
22
23 #define clear_block(addr,size,value) \
24 __asm__("cld\n\t" \
25 "rep\n\t" \
26 "stosl" \
27 : \
28 :"a" (value), "c" (size / 4), "D" ((long) (addr)) \
29 :"cx", "di")
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 static int trunc_direct (struct inode * inode)
45 {
46 int i, tmp;
47 unsigned long * p;
48 struct buffer_head * bh;
49 int retry = 0;
50 int blocks = inode->i_sb->s_blocksize / 512;
51 #define DIRECT_BLOCK ((inode->i_size + inode->i_sb->s_blocksize - 1) / \
52 inode->i_sb->s_blocksize)
53 int direct_block = DIRECT_BLOCK;
54
55 repeat:
56 for (i = direct_block ; i < EXT2_NDIR_BLOCKS ; i++) {
57 p = inode->u.ext2_i.i_data + i;
58 tmp = *p;
59 if (!tmp)
60 continue;
61 if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL)
62 bh = getblk (inode->i_dev, tmp,
63 inode->i_sb->s_blocksize);
64 else
65 bh = get_hash_table (inode->i_dev, tmp,
66 inode->i_sb->s_blocksize);
67 if (i < direct_block) {
68 brelse (bh);
69 goto repeat;
70 }
71 if ((bh && bh->b_count != 1) || tmp != *p) {
72 retry = 1;
73 brelse (bh);
74 continue;
75 }
76 *p = 0;
77 inode->i_blocks -= blocks;
78 inode->i_dirt = 1;
79 if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) {
80 clear_block (bh->b_data, inode->i_sb->s_blocksize,
81 CURRENT_TIME);
82 bh->b_dirt = 1;
83 }
84 brelse (bh);
85 ext2_free_blocks (inode->i_sb, tmp, 1);
86 }
87 return retry;
88 }
89
90 static int trunc_indirect (struct inode * inode, int offset, unsigned long * p)
91 {
92 int i, tmp;
93 struct buffer_head * bh;
94 struct buffer_head * ind_bh;
95 unsigned long * ind;
96 int retry = 0;
97 int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
98 int blocks = inode->i_sb->s_blocksize / 512;
99 #define INDIRECT_BLOCK ((int)DIRECT_BLOCK - offset)
100 int indirect_block = INDIRECT_BLOCK;
101
102 tmp = *p;
103 if (!tmp)
104 return 0;
105 ind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
106 if (tmp != *p) {
107 brelse (ind_bh);
108 return 1;
109 }
110 if (!ind_bh) {
111 *p = 0;
112 return 0;
113 }
114 repeat:
115 for (i = indirect_block ; i < addr_per_block ; i++) {
116 if (i < 0)
117 i = 0;
118 if (i < indirect_block)
119 goto repeat;
120 ind = i + (unsigned long *) ind_bh->b_data;
121 tmp = *ind;
122 if (!tmp)
123 continue;
124 if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL)
125 bh = getblk (inode->i_dev, tmp,
126 inode->i_sb->s_blocksize);
127 else
128 bh = get_hash_table (inode->i_dev, tmp,
129 inode->i_sb->s_blocksize);
130 if (i < indirect_block) {
131 brelse (bh);
132 goto repeat;
133 }
134 if ((bh && bh->b_count != 1) || tmp != *ind) {
135 retry = 1;
136 brelse (bh);
137 continue;
138 }
139 *ind = 0;
140 ind_bh->b_dirt = 1;
141 if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) {
142 clear_block (bh->b_data, inode->i_sb->s_blocksize,
143 CURRENT_TIME);
144 bh->b_dirt = 1;
145 }
146 brelse (bh);
147 ext2_free_blocks (inode->i_sb, tmp, 1);
148 inode->i_blocks -= blocks;
149 inode->i_dirt = 1;
150 }
151 ind = (unsigned long *) ind_bh->b_data;
152 for (i = 0; i < addr_per_block; i++)
153 if (*(ind++))
154 break;
155 if (i >= addr_per_block)
156 if (ind_bh->b_count != 1)
157 retry = 1;
158 else {
159 tmp = *p;
160 *p = 0;
161 inode->i_blocks -= blocks;
162 inode->i_dirt = 1;
163 ext2_free_blocks (inode->i_sb, tmp, 1);
164 }
165 if (IS_SYNC(inode) && ind_bh->b_dirt) {
166 ll_rw_block (WRITE, 1, &ind_bh);
167 wait_on_buffer (ind_bh);
168 }
169 brelse (ind_bh);
170 return retry;
171 }
172
173 static int trunc_dindirect (struct inode * inode, int offset,
174 unsigned long * p)
175 {
176 int i, tmp;
177 struct buffer_head * dind_bh;
178 unsigned long * dind;
179 int retry = 0;
180 int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
181 int blocks = inode->i_sb->s_blocksize / 512;
182 #define DINDIRECT_BLOCK (((int)DIRECT_BLOCK - offset) / addr_per_block)
183 int dindirect_block = DINDIRECT_BLOCK;
184
185 tmp = *p;
186 if (!tmp)
187 return 0;
188 dind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
189 if (tmp != *p) {
190 brelse (dind_bh);
191 return 1;
192 }
193 if (!dind_bh) {
194 *p = 0;
195 return 0;
196 }
197 repeat:
198 for (i = dindirect_block ; i < addr_per_block ; i++) {
199 if (i < 0)
200 i = 0;
201 if (i < dindirect_block)
202 goto repeat;
203 dind = i + (unsigned long *) dind_bh->b_data;
204 tmp = *dind;
205 if (!tmp)
206 continue;
207 retry |= trunc_indirect (inode, offset + (i * addr_per_block),
208 dind);
209 dind_bh->b_dirt = 1;
210 }
211 dind = (unsigned long *) dind_bh->b_data;
212 for (i = 0; i < addr_per_block; i++)
213 if (*(dind++))
214 break;
215 if (i >= addr_per_block)
216 if (dind_bh->b_count != 1)
217 retry = 1;
218 else {
219 tmp = *p;
220 *p = 0;
221 inode->i_blocks -= blocks;
222 inode->i_dirt = 1;
223 ext2_free_blocks (inode->i_sb, tmp, 1);
224 }
225 if (IS_SYNC(inode) && dind_bh->b_dirt) {
226 ll_rw_block (WRITE, 1, &dind_bh);
227 wait_on_buffer (dind_bh);
228 }
229 brelse (dind_bh);
230 return retry;
231 }
232
233 static int trunc_tindirect (struct inode * inode)
234 {
235 int i, tmp;
236 struct buffer_head * tind_bh;
237 unsigned long * tind, * p;
238 int retry = 0;
239 int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
240 int blocks = inode->i_sb->s_blocksize / 512;
241 #define TINDIRECT_BLOCK (((int)DIRECT_BLOCK - (addr_per_block * addr_per_block + \
242 addr_per_block + EXT2_NDIR_BLOCKS)) / \
243 (addr_per_block * addr_per_block))
244 int tindirect_block = TINDIRECT_BLOCK;
245
246 p = inode->u.ext2_i.i_data + EXT2_TIND_BLOCK;
247 if (!(tmp = *p))
248 return 0;
249 tind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
250 if (tmp != *p) {
251 brelse (tind_bh);
252 return 1;
253 }
254 if (!tind_bh) {
255 *p = 0;
256 return 0;
257 }
258 repeat:
259 for (i = tindirect_block ; i < addr_per_block ; i++) {
260 if (i < 0)
261 i = 0;
262 if (i < tindirect_block)
263 goto repeat;
264 tind = i + (unsigned long *) tind_bh->b_data;
265 retry |= trunc_dindirect(inode, EXT2_NDIR_BLOCKS +
266 addr_per_block + (i + 1) * addr_per_block * addr_per_block,
267 tind);
268 tind_bh->b_dirt = 1;
269 }
270 tind = (unsigned long *) tind_bh->b_data;
271 for (i = 0; i < addr_per_block; i++)
272 if (*(tind++))
273 break;
274 if (i >= addr_per_block)
275 if (tind_bh->b_count != 1)
276 retry = 1;
277 else {
278 tmp = *p;
279 *p = 0;
280 inode->i_blocks -= blocks;
281 inode->i_dirt = 1;
282 ext2_free_blocks (inode->i_sb, tmp, 1);
283 }
284 if (IS_SYNC(inode) && tind_bh->b_dirt) {
285 ll_rw_block (WRITE, 1, &tind_bh);
286 wait_on_buffer (tind_bh);
287 }
288 brelse (tind_bh);
289 return retry;
290 }
291
292 void ext2_truncate (struct inode * inode)
293 {
294 int retry;
295
296 if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
297 S_ISLNK(inode->i_mode)))
298 return;
299 ext2_discard_prealloc(inode);
300 while (1) {
301 retry = trunc_direct(inode);
302 retry |= trunc_indirect (inode, EXT2_IND_BLOCK,
303 (unsigned long *) &inode->u.ext2_i.i_data[EXT2_IND_BLOCK]);
304 retry |= trunc_dindirect (inode, EXT2_IND_BLOCK +
305 EXT2_ADDR_PER_BLOCK(inode->i_sb),
306 (unsigned long *) &inode->u.ext2_i.i_data[EXT2_DIND_BLOCK]);
307 retry |= trunc_tindirect (inode);
308 if (!retry)
309 break;
310 if (IS_SYNC(inode) && inode->i_dirt)
311 ext2_sync_inode (inode);
312 current->counter = 0;
313 schedule ();
314 }
315 inode->i_mtime = inode->i_ctime = CURRENT_TIME;
316 inode->i_dirt = 1;
317 }