4 * Copyright (C) 1991, 1992 Linus Torvalds
6 * Copyright (C) 1996 Gertjan van Wingerde (gertjan@cs.vu.nl)
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
)
44 struct buffer_head
* bh
;
49 for (i
= DIRECT_BLOCK
; i
< 7 ; i
++) {
50 p
= i
+ inode
->u
.minix_i
.u
.i1_data
;
53 bh
= get_hash_table(inode
->i_dev
,tmp
,BLOCK_SIZE
);
54 if (i
< DIRECT_BLOCK
) {
58 if ((bh
&& DATA_BUFFER_USED(bh
)) || tmp
!= *p
) {
64 mark_inode_dirty(inode
);
66 minix_free_block(inode
,tmp
);
71 static int V1_trunc_indirect(struct inode
* inode
, int offset
, unsigned short * p
)
73 struct buffer_head
* bh
;
75 struct buffer_head
* ind_bh
;
82 ind_bh
= bread(inode
->i_dev
, tmp
, BLOCK_SIZE
);
92 for (i
= INDIRECT_BLOCK(offset
) ; i
< 512 ; i
++) {
95 if (i
< INDIRECT_BLOCK(offset
))
97 ind
= i
+(unsigned short *) ind_bh
->b_data
;
101 bh
= get_hash_table(inode
->i_dev
,tmp
,BLOCK_SIZE
);
102 if (i
< INDIRECT_BLOCK(offset
)) {
106 if ((bh
&& DATA_BUFFER_USED(bh
)) || tmp
!= *ind
) {
112 mark_buffer_dirty(ind_bh
);
114 minix_free_block(inode
,tmp
);
116 ind
= (unsigned short *) ind_bh
->b_data
;
117 for (i
= 0; i
< 512; i
++)
121 if (atomic_read(&ind_bh
->b_count
) != 1)
126 minix_free_block(inode
,tmp
);
133 static int V1_trunc_dindirect(struct inode
* inode
, int offset
, unsigned short *p
)
136 struct buffer_head
* dind_bh
;
137 unsigned short * dind
;
142 dind_bh
= bread(inode
->i_dev
, tmp
, BLOCK_SIZE
);
152 for (i
= V1_DINDIRECT_BLOCK(offset
) ; i
< 512 ; i
++) {
155 if (i
< V1_DINDIRECT_BLOCK(offset
))
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
++)
166 if (atomic_read(&dind_bh
->b_count
) != 1)
171 mark_inode_dirty(inode
);
172 minix_free_block(inode
,tmp
);
179 static void V1_minix_truncate(struct inode
* inode
)
183 if (!(S_ISREG(inode
->i_mode
) || S_ISDIR(inode
->i_mode
) ||
184 S_ISLNK(inode
->i_mode
)))
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);
192 current
->counter
= 0;
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
)
205 struct buffer_head
* bh
;
210 for (i
= DIRECT_BLOCK
; i
< 7 ; i
++) {
211 p
= (unsigned long *) inode
->u
.minix_i
.u
.i2_data
+ i
;
214 bh
= get_hash_table(inode
->i_dev
,tmp
,BLOCK_SIZE
);
215 if (i
< DIRECT_BLOCK
) {
219 if ((bh
&& DATA_BUFFER_USED(bh
)) || tmp
!= *p
) {
225 mark_inode_dirty(inode
);
227 minix_free_block(inode
,tmp
);
232 static int V2_trunc_indirect(struct inode
* inode
, int offset
, unsigned long * p
)
234 struct buffer_head
* bh
;
236 struct buffer_head
* ind_bh
;
243 ind_bh
= bread(inode
->i_dev
, tmp
, BLOCK_SIZE
);
253 for (i
= INDIRECT_BLOCK(offset
) ; i
< 256 ; i
++) {
256 if (i
< INDIRECT_BLOCK(offset
))
258 ind
= i
+(unsigned long *) ind_bh
->b_data
;
262 bh
= get_hash_table(inode
->i_dev
,tmp
,BLOCK_SIZE
);
263 if (i
< INDIRECT_BLOCK(offset
)) {
267 if ((bh
&& DATA_BUFFER_USED(bh
)) || tmp
!= *ind
) {
273 mark_buffer_dirty(ind_bh
);
275 minix_free_block(inode
,tmp
);
277 ind
= (unsigned long *) ind_bh
->b_data
;
278 for (i
= 0; i
< 256; i
++)
282 if (atomic_read(&ind_bh
->b_count
) != 1)
287 minix_free_block(inode
,tmp
);
294 static int V2_trunc_dindirect(struct inode
* inode
, int offset
, unsigned long *p
)
297 struct buffer_head
* dind_bh
;
298 unsigned long * dind
;
303 dind_bh
= bread(inode
->i_dev
, tmp
, BLOCK_SIZE
);
313 for (i
= V2_DINDIRECT_BLOCK(offset
) ; i
< 256 ; i
++) {
316 if (i
< V2_DINDIRECT_BLOCK(offset
))
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
++)
327 if (atomic_read(&dind_bh
->b_count
) != 1)
332 mark_inode_dirty(inode
);
333 minix_free_block(inode
,tmp
);
340 static int V2_trunc_tindirect(struct inode
* inode
, int offset
, unsigned long * p
)
343 struct buffer_head
* tind_bh
;
344 unsigned long * tind
;
349 tind_bh
= bread(inode
->i_dev
, tmp
, BLOCK_SIZE
);
359 for (i
= TINDIRECT_BLOCK(offset
) ; i
< 256 ; i
++) {
362 if (i
< TINDIRECT_BLOCK(offset
))
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
++)
373 if (atomic_read(&tind_bh
->b_count
) != 1)
378 mark_inode_dirty(inode
);
379 minix_free_block(inode
,tmp
);
386 static void V2_minix_truncate(struct inode
* inode
)
390 if (!(S_ISREG(inode
->i_mode
) || S_ISDIR(inode
->i_mode
) ||
391 S_ISLNK(inode
->i_mode
)))
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);
403 run_task_queue(&tq_disk
);
404 current
->policy
|= SCHED_YIELD
;
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
);
419 V2_minix_truncate(inode
);