2 * linux/fs/sysv/itree.c
4 * Handling of indirect blocks' trees.
8 #include <linux/buffer_head.h>
9 #include <linux/mount.h>
10 #include <linux/string.h>
13 enum {DIRECT
= 10, DEPTH
= 4}; /* Have triple indirect */
15 static inline void dirty_indirect(struct buffer_head
*bh
, struct inode
*inode
)
17 mark_buffer_dirty_inode(bh
, inode
);
19 sync_dirty_buffer(bh
);
22 static int block_to_path(struct inode
*inode
, long block
, int offsets
[DEPTH
])
24 struct super_block
*sb
= inode
->i_sb
;
25 struct sysv_sb_info
*sbi
= SYSV_SB(sb
);
26 int ptrs_bits
= sbi
->s_ind_per_block_bits
;
27 unsigned long indirect_blocks
= sbi
->s_ind_per_block
,
28 double_blocks
= sbi
->s_ind_per_block_2
;
32 printk("sysv_block_map: block < 0\n");
33 } else if (block
< DIRECT
) {
35 } else if ( (block
-= DIRECT
) < indirect_blocks
) {
36 offsets
[n
++] = DIRECT
;
38 } else if ((block
-= indirect_blocks
) < double_blocks
) {
39 offsets
[n
++] = DIRECT
+1;
40 offsets
[n
++] = block
>> ptrs_bits
;
41 offsets
[n
++] = block
& (indirect_blocks
- 1);
42 } else if (((block
-= double_blocks
) >> (ptrs_bits
* 2)) < indirect_blocks
) {
43 offsets
[n
++] = DIRECT
+2;
44 offsets
[n
++] = block
>> (ptrs_bits
* 2);
45 offsets
[n
++] = (block
>> ptrs_bits
) & (indirect_blocks
- 1);
46 offsets
[n
++] = block
& (indirect_blocks
- 1);
53 static inline int block_to_cpu(struct sysv_sb_info
*sbi
, sysv_zone_t nr
)
55 return sbi
->s_block_base
+ fs32_to_cpu(sbi
, nr
);
61 struct buffer_head
*bh
;
64 static DEFINE_RWLOCK(pointers_lock
);
66 static inline void add_chain(Indirect
*p
, struct buffer_head
*bh
, sysv_zone_t
*v
)
72 static inline int verify_chain(Indirect
*from
, Indirect
*to
)
74 while (from
<= to
&& from
->key
== *from
->p
)
79 static inline sysv_zone_t
*block_end(struct buffer_head
*bh
)
81 return (sysv_zone_t
*)((char*)bh
->b_data
+ bh
->b_size
);
85 * Requires read_lock(&pointers_lock) or write_lock(&pointers_lock)
87 static Indirect
*get_branch(struct inode
*inode
,
93 struct super_block
*sb
= inode
->i_sb
;
95 struct buffer_head
*bh
;
98 add_chain(chain
, NULL
, SYSV_I(inode
)->i_data
+ *offsets
);
102 int block
= block_to_cpu(SYSV_SB(sb
), p
->key
);
103 bh
= sb_bread(sb
, block
);
106 if (!verify_chain(chain
, p
))
108 add_chain(++p
, bh
, (sysv_zone_t
*)bh
->b_data
+ *++offsets
);
124 static int alloc_branch(struct inode
*inode
,
129 int blocksize
= inode
->i_sb
->s_blocksize
;
133 branch
[0].key
= sysv_new_block(inode
->i_sb
);
134 if (branch
[0].key
) for (n
= 1; n
< num
; n
++) {
135 struct buffer_head
*bh
;
137 /* Allocate the next block */
138 branch
[n
].key
= sysv_new_block(inode
->i_sb
);
142 * Get buffer_head for parent block, zero it out and set
143 * the pointer to new one, then send parent to disk.
145 parent
= block_to_cpu(SYSV_SB(inode
->i_sb
), branch
[n
-1].key
);
146 bh
= sb_getblk(inode
->i_sb
, parent
);
148 memset(bh
->b_data
, 0, blocksize
);
150 branch
[n
].p
= (sysv_zone_t
*) bh
->b_data
+ offsets
[n
];
151 *branch
[n
].p
= branch
[n
].key
;
152 set_buffer_uptodate(bh
);
154 dirty_indirect(bh
, inode
);
159 /* Allocation failed, free what we already allocated */
160 for (i
= 1; i
< n
; i
++)
161 bforget(branch
[i
].bh
);
162 for (i
= 0; i
< n
; i
++)
163 sysv_free_block(inode
->i_sb
, branch
[i
].key
);
167 static inline int splice_branch(struct inode
*inode
,
174 /* Verify that place we are splicing to is still there and vacant */
175 write_lock(&pointers_lock
);
176 if (!verify_chain(chain
, where
-1) || *where
->p
)
178 *where
->p
= where
->key
;
179 write_unlock(&pointers_lock
);
181 inode
->i_ctime
= CURRENT_TIME_SEC
;
183 /* had we spliced it onto indirect block? */
185 dirty_indirect(where
->bh
, inode
);
188 sysv_sync_inode(inode
);
190 mark_inode_dirty(inode
);
194 write_unlock(&pointers_lock
);
195 for (i
= 1; i
< num
; i
++)
196 bforget(where
[i
].bh
);
197 for (i
= 0; i
< num
; i
++)
198 sysv_free_block(inode
->i_sb
, where
[i
].key
);
202 static int get_block(struct inode
*inode
, sector_t iblock
, struct buffer_head
*bh_result
, int create
)
206 Indirect chain
[DEPTH
];
207 struct super_block
*sb
= inode
->i_sb
;
210 int depth
= block_to_path(inode
, iblock
, offsets
);
216 read_lock(&pointers_lock
);
217 partial
= get_branch(inode
, depth
, offsets
, chain
, &err
);
218 read_unlock(&pointers_lock
);
220 /* Simplest case - block found, no allocation needed */
223 map_bh(bh_result
, sb
, block_to_cpu(SYSV_SB(sb
),
224 chain
[depth
-1].key
));
225 /* Clean up and exit */
226 partial
= chain
+depth
-1; /* the whole chain */
230 /* Next simple case - plain lookup or failed read of indirect block */
231 if (!create
|| err
== -EIO
) {
233 while (partial
> chain
) {
242 * Indirect block might be removed by truncate while we were
243 * reading it. Handling of that case (forget what we've got and
244 * reread) is taken out of the main path.
249 left
= (chain
+ depth
) - partial
;
250 err
= alloc_branch(inode
, left
, offsets
+(partial
-chain
), partial
);
254 if (splice_branch(inode
, chain
, partial
, left
) < 0)
257 set_buffer_new(bh_result
);
261 while (partial
> chain
) {
268 static inline int all_zeroes(sysv_zone_t
*p
, sysv_zone_t
*q
)
276 static Indirect
*find_shared(struct inode
*inode
,
282 Indirect
*partial
, *p
;
286 for (k
= depth
; k
> 1 && !offsets
[k
-1]; k
--)
289 write_lock(&pointers_lock
);
290 partial
= get_branch(inode
, k
, offsets
, chain
, &err
);
292 partial
= chain
+ k
-1;
294 * If the branch acquired continuation since we've looked at it -
295 * fine, it should all survive and (new) top doesn't belong to us.
297 if (!partial
->key
&& *partial
->p
) {
298 write_unlock(&pointers_lock
);
301 for (p
=partial
; p
>chain
&& all_zeroes((sysv_zone_t
*)p
->bh
->b_data
,p
->p
); p
--)
304 * OK, we've found the last block that must survive. The rest of our
305 * branch should be detached before unlocking. However, if that rest
306 * of branch is all ours and does not grow immediately from the inode
307 * it's easier to cheat and just decrement partial->p.
309 if (p
== chain
+ k
- 1 && p
> chain
) {
315 write_unlock(&pointers_lock
);
317 while (partial
> p
) {
325 static inline void free_data(struct inode
*inode
, sysv_zone_t
*p
, sysv_zone_t
*q
)
327 for ( ; p
< q
; p
++) {
331 sysv_free_block(inode
->i_sb
, nr
);
332 mark_inode_dirty(inode
);
337 static void free_branches(struct inode
*inode
, sysv_zone_t
*p
, sysv_zone_t
*q
, int depth
)
339 struct buffer_head
* bh
;
340 struct super_block
*sb
= inode
->i_sb
;
343 for ( ; p
< q
; p
++) {
349 block
= block_to_cpu(SYSV_SB(sb
), nr
);
350 bh
= sb_bread(sb
, block
);
353 free_branches(inode
, (sysv_zone_t
*)bh
->b_data
,
354 block_end(bh
), depth
);
356 sysv_free_block(sb
, nr
);
357 mark_inode_dirty(inode
);
360 free_data(inode
, p
, q
);
363 void sysv_truncate (struct inode
* inode
)
365 sysv_zone_t
*i_data
= SYSV_I(inode
)->i_data
;
367 Indirect chain
[DEPTH
];
374 if (!(S_ISREG(inode
->i_mode
) || S_ISDIR(inode
->i_mode
) ||
375 S_ISLNK(inode
->i_mode
)))
378 blocksize
= inode
->i_sb
->s_blocksize
;
379 iblock
= (inode
->i_size
+ blocksize
-1)
380 >> inode
->i_sb
->s_blocksize_bits
;
382 block_truncate_page(inode
->i_mapping
, inode
->i_size
, get_block
);
384 n
= block_to_path(inode
, iblock
, offsets
);
389 free_data(inode
, i_data
+offsets
[0], i_data
+ DIRECT
);
393 partial
= find_shared(inode
, n
, offsets
, chain
, &nr
);
394 /* Kill the top of shared branch (already detached) */
396 if (partial
== chain
)
397 mark_inode_dirty(inode
);
399 dirty_indirect(partial
->bh
, inode
);
400 free_branches(inode
, &nr
, &nr
+1, (chain
+n
-1) - partial
);
402 /* Clear the ends of indirect blocks on the shared branch */
403 while (partial
> chain
) {
404 free_branches(inode
, partial
->p
+ 1, block_end(partial
->bh
),
405 (chain
+n
-1) - partial
);
406 dirty_indirect(partial
->bh
, inode
);
407 brelse (partial
->bh
);
411 /* Kill the remaining (whole) subtrees (== subtrees deeper than...) */
413 nr
= i_data
[DIRECT
+ n
- 1];
415 i_data
[DIRECT
+ n
- 1] = 0;
416 mark_inode_dirty(inode
);
417 free_branches(inode
, &nr
, &nr
+1, n
);
421 inode
->i_mtime
= inode
->i_ctime
= CURRENT_TIME_SEC
;
423 sysv_sync_inode (inode
);
425 mark_inode_dirty(inode
);
428 static unsigned sysv_nblocks(struct super_block
*s
, loff_t size
)
430 struct sysv_sb_info
*sbi
= SYSV_SB(s
);
431 int ptrs_bits
= sbi
->s_ind_per_block_bits
;
432 unsigned blocks
, res
, direct
= DIRECT
, i
= DEPTH
;
433 blocks
= (size
+ s
->s_blocksize
- 1) >> s
->s_blocksize_bits
;
435 while (--i
&& blocks
> direct
) {
436 blocks
= ((blocks
- direct
- 1) >> ptrs_bits
) + 1;
443 int sysv_getattr(struct vfsmount
*mnt
, struct dentry
*dentry
, struct kstat
*stat
)
445 struct super_block
*s
= dentry
->d_sb
;
446 generic_fillattr(dentry
->d_inode
, stat
);
447 stat
->blocks
= (s
->s_blocksize
/ 512) * sysv_nblocks(s
, stat
->size
);
448 stat
->blksize
= s
->s_blocksize
;
452 static int sysv_writepage(struct page
*page
, struct writeback_control
*wbc
)
454 return block_write_full_page(page
,get_block
,wbc
);
457 static int sysv_readpage(struct file
*file
, struct page
*page
)
459 return block_read_full_page(page
,get_block
);
462 int sysv_prepare_chunk(struct page
*page
, loff_t pos
, unsigned len
)
464 return __block_write_begin(page
, pos
, len
, get_block
);
467 static void sysv_write_failed(struct address_space
*mapping
, loff_t to
)
469 struct inode
*inode
= mapping
->host
;
471 if (to
> inode
->i_size
) {
472 truncate_pagecache(inode
, to
, inode
->i_size
);
473 sysv_truncate(inode
);
477 static int sysv_write_begin(struct file
*file
, struct address_space
*mapping
,
478 loff_t pos
, unsigned len
, unsigned flags
,
479 struct page
**pagep
, void **fsdata
)
483 ret
= block_write_begin(mapping
, pos
, len
, flags
, pagep
, get_block
);
485 sysv_write_failed(mapping
, pos
+ len
);
490 static sector_t
sysv_bmap(struct address_space
*mapping
, sector_t block
)
492 return generic_block_bmap(mapping
,block
,get_block
);
495 const struct address_space_operations sysv_aops
= {
496 .readpage
= sysv_readpage
,
497 .writepage
= sysv_writepage
,
498 .write_begin
= sysv_write_begin
,
499 .write_end
= generic_write_end
,