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 ((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 mark_buffer_clean(bh
);
69 minix_free_block(inode
->i_sb
,tmp
);
74 static int V1_trunc_indirect(struct inode
* inode
, int offset
, unsigned short * p
)
76 struct buffer_head
* bh
;
78 struct buffer_head
* ind_bh
;
85 ind_bh
= bread(inode
->i_dev
, tmp
, BLOCK_SIZE
);
95 for (i
= INDIRECT_BLOCK(offset
) ; i
< 512 ; i
++) {
98 if (i
< INDIRECT_BLOCK(offset
))
100 ind
= i
+(unsigned short *) ind_bh
->b_data
;
104 bh
= get_hash_table(inode
->i_dev
,tmp
,BLOCK_SIZE
);
105 if (i
< INDIRECT_BLOCK(offset
)) {
109 if ((bh
&& DATA_BUFFER_USED(bh
)) || tmp
!= *ind
) {
115 mark_buffer_dirty(ind_bh
, 1);
117 minix_free_block(inode
->i_sb
,tmp
);
119 ind
= (unsigned short *) ind_bh
->b_data
;
120 for (i
= 0; i
< 512; i
++)
124 if (ind_bh
->b_count
!= 1)
129 minix_free_block(inode
->i_sb
,tmp
);
136 static int V1_trunc_dindirect(struct inode
* inode
, int offset
, unsigned short *p
)
139 struct buffer_head
* dind_bh
;
140 unsigned short * dind
;
145 dind_bh
= bread(inode
->i_dev
, tmp
, BLOCK_SIZE
);
155 for (i
= V1_DINDIRECT_BLOCK(offset
) ; i
< 512 ; i
++) {
158 if (i
< V1_DINDIRECT_BLOCK(offset
))
160 dind
= i
+(unsigned short *) dind_bh
->b_data
;
161 retry
|= V1_trunc_indirect(inode
,offset
+(i
<<9),dind
);
162 mark_buffer_dirty(dind_bh
, 1);
164 dind
= (unsigned short *) dind_bh
->b_data
;
165 for (i
= 0; i
< 512; i
++)
169 if (dind_bh
->b_count
!= 1)
174 mark_inode_dirty(inode
);
175 minix_free_block(inode
->i_sb
,tmp
);
182 static void V1_minix_truncate(struct inode
* inode
)
186 if (!(S_ISREG(inode
->i_mode
) || S_ISDIR(inode
->i_mode
) ||
187 S_ISLNK(inode
->i_mode
)))
190 retry
= V1_trunc_direct(inode
);
191 retry
|= V1_trunc_indirect(inode
, 7, inode
->u
.minix_i
.u
.i1_data
+ 7);
192 retry
|= V1_trunc_dindirect(inode
, 7+512, inode
->u
.minix_i
.u
.i1_data
+ 8);
195 current
->counter
= 0;
198 inode
->i_mtime
= inode
->i_ctime
= CURRENT_TIME
;
199 mark_inode_dirty(inode
);
203 * The functions for minix V2 fs truncation.
205 static int V2_trunc_direct(struct inode
* inode
)
208 struct buffer_head
* bh
;
213 for (i
= DIRECT_BLOCK
; i
< 7 ; i
++) {
214 p
= (unsigned long *) inode
->u
.minix_i
.u
.i2_data
+ i
;
217 bh
= get_hash_table(inode
->i_dev
,tmp
,BLOCK_SIZE
);
218 if (i
< DIRECT_BLOCK
) {
222 if ((bh
&& DATA_BUFFER_USED(bh
)) || tmp
!= *p
) {
228 mark_inode_dirty(inode
);
230 mark_buffer_clean(bh
);
233 minix_free_block(inode
->i_sb
,tmp
);
238 static int V2_trunc_indirect(struct inode
* inode
, int offset
, unsigned long * p
)
240 struct buffer_head
* bh
;
242 struct buffer_head
* ind_bh
;
249 ind_bh
= bread(inode
->i_dev
, tmp
, BLOCK_SIZE
);
259 for (i
= INDIRECT_BLOCK(offset
) ; i
< 256 ; i
++) {
262 if (i
< INDIRECT_BLOCK(offset
))
264 ind
= i
+(unsigned long *) ind_bh
->b_data
;
268 bh
= get_hash_table(inode
->i_dev
,tmp
,BLOCK_SIZE
);
269 if (i
< INDIRECT_BLOCK(offset
)) {
273 if ((bh
&& DATA_BUFFER_USED(bh
)) || tmp
!= *ind
) {
279 mark_buffer_dirty(ind_bh
, 1);
281 minix_free_block(inode
->i_sb
,tmp
);
283 ind
= (unsigned long *) ind_bh
->b_data
;
284 for (i
= 0; i
< 256; i
++)
288 if (ind_bh
->b_count
!= 1)
293 minix_free_block(inode
->i_sb
,tmp
);
300 static int V2_trunc_dindirect(struct inode
* inode
, int offset
, unsigned long *p
)
303 struct buffer_head
* dind_bh
;
304 unsigned long * dind
;
309 dind_bh
= bread(inode
->i_dev
, tmp
, BLOCK_SIZE
);
319 for (i
= V2_DINDIRECT_BLOCK(offset
) ; i
< 256 ; i
++) {
322 if (i
< V2_DINDIRECT_BLOCK(offset
))
324 dind
= i
+(unsigned long *) dind_bh
->b_data
;
325 retry
|= V2_trunc_indirect(inode
,offset
+(i
<<8),dind
);
326 mark_buffer_dirty(dind_bh
, 1);
328 dind
= (unsigned long *) dind_bh
->b_data
;
329 for (i
= 0; i
< 256; i
++)
333 if (dind_bh
->b_count
!= 1)
338 mark_inode_dirty(inode
);
339 minix_free_block(inode
->i_sb
,tmp
);
346 static int V2_trunc_tindirect(struct inode
* inode
, int offset
, unsigned long * p
)
349 struct buffer_head
* tind_bh
;
350 unsigned long * tind
;
355 tind_bh
= bread(inode
->i_dev
, tmp
, BLOCK_SIZE
);
365 for (i
= TINDIRECT_BLOCK(offset
) ; i
< 256 ; i
++) {
368 if (i
< TINDIRECT_BLOCK(offset
))
370 tind
= i
+(unsigned long *) tind_bh
->b_data
;
371 retry
|= V2_trunc_dindirect(inode
,offset
+(i
<<8),tind
);
372 mark_buffer_dirty(tind_bh
, 1);
374 tind
= (unsigned long *) tind_bh
->b_data
;
375 for (i
= 0; i
< 256; i
++)
379 if (tind_bh
->b_count
!= 1)
384 mark_inode_dirty(inode
);
385 minix_free_block(inode
->i_sb
,tmp
);
392 static void V2_minix_truncate(struct inode
* inode
)
396 if (!(S_ISREG(inode
->i_mode
) || S_ISDIR(inode
->i_mode
) ||
397 S_ISLNK(inode
->i_mode
)))
400 retry
= V2_trunc_direct(inode
);
401 retry
|= V2_trunc_indirect(inode
,7,
402 (unsigned long *) inode
->u
.minix_i
.u
.i2_data
+ 7);
403 retry
|= V2_trunc_dindirect(inode
, 7+256,
404 (unsigned long *) inode
->u
.minix_i
.u
.i2_data
+ 8);
405 retry
|= V2_trunc_tindirect(inode
, 7+256+256*256,
406 (unsigned long *) inode
->u
.minix_i
.u
.i2_data
+ 9);
409 current
->counter
= 0;
412 inode
->i_mtime
= inode
->i_ctime
= CURRENT_TIME
;
413 mark_inode_dirty(inode
);
417 * The function that is called for file truncation.
419 void minix_truncate(struct inode
* inode
)
421 if (INODE_VERSION(inode
) == MINIX_V1
)
422 V1_minix_truncate(inode
);
424 V2_minix_truncate(inode
);