1 // SPDX-License-Identifier: GPL-2.0
3 * linux/fs/sysv/itree.c
5 * Handling of indirect blocks' trees.
9 #include <linux/buffer_head.h>
10 #include <linux/mount.h>
11 #include <linux/string.h>
14 enum {DIRECT
= 10, DEPTH
= 4}; /* Have triple indirect */
16 static inline void dirty_indirect(struct buffer_head
*bh
, struct inode
*inode
)
18 mark_buffer_dirty_inode(bh
, inode
);
20 sync_dirty_buffer(bh
);
23 static int block_to_path(struct inode
*inode
, long block
, int offsets
[DEPTH
])
25 struct super_block
*sb
= inode
->i_sb
;
26 struct sysv_sb_info
*sbi
= SYSV_SB(sb
);
27 int ptrs_bits
= sbi
->s_ind_per_block_bits
;
28 unsigned long indirect_blocks
= sbi
->s_ind_per_block
,
29 double_blocks
= sbi
->s_ind_per_block_2
;
33 printk("sysv_block_map: block < 0\n");
34 } else if (block
< DIRECT
) {
36 } else if ( (block
-= DIRECT
) < indirect_blocks
) {
37 offsets
[n
++] = DIRECT
;
39 } else if ((block
-= indirect_blocks
) < double_blocks
) {
40 offsets
[n
++] = DIRECT
+1;
41 offsets
[n
++] = block
>> ptrs_bits
;
42 offsets
[n
++] = block
& (indirect_blocks
- 1);
43 } else if (((block
-= double_blocks
) >> (ptrs_bits
* 2)) < indirect_blocks
) {
44 offsets
[n
++] = DIRECT
+2;
45 offsets
[n
++] = block
>> (ptrs_bits
* 2);
46 offsets
[n
++] = (block
>> ptrs_bits
) & (indirect_blocks
- 1);
47 offsets
[n
++] = block
& (indirect_blocks
- 1);
54 static inline int block_to_cpu(struct sysv_sb_info
*sbi
, sysv_zone_t nr
)
56 return sbi
->s_block_base
+ fs32_to_cpu(sbi
, nr
);
62 struct buffer_head
*bh
;
65 static DEFINE_RWLOCK(pointers_lock
);
67 static inline void add_chain(Indirect
*p
, struct buffer_head
*bh
, sysv_zone_t
*v
)
73 static inline int verify_chain(Indirect
*from
, Indirect
*to
)
75 while (from
<= to
&& from
->key
== *from
->p
)
80 static inline sysv_zone_t
*block_end(struct buffer_head
*bh
)
82 return (sysv_zone_t
*)((char*)bh
->b_data
+ bh
->b_size
);
86 * Requires read_lock(&pointers_lock) or write_lock(&pointers_lock)
88 static Indirect
*get_branch(struct inode
*inode
,
94 struct super_block
*sb
= inode
->i_sb
;
96 struct buffer_head
*bh
;
99 add_chain(chain
, NULL
, SYSV_I(inode
)->i_data
+ *offsets
);
103 int block
= block_to_cpu(SYSV_SB(sb
), p
->key
);
104 bh
= sb_bread(sb
, block
);
107 if (!verify_chain(chain
, p
))
109 add_chain(++p
, bh
, (sysv_zone_t
*)bh
->b_data
+ *++offsets
);
125 static int alloc_branch(struct inode
*inode
,
130 int blocksize
= inode
->i_sb
->s_blocksize
;
134 branch
[0].key
= sysv_new_block(inode
->i_sb
);
135 if (branch
[0].key
) for (n
= 1; n
< num
; n
++) {
136 struct buffer_head
*bh
;
138 /* Allocate the next block */
139 branch
[n
].key
= sysv_new_block(inode
->i_sb
);
143 * Get buffer_head for parent block, zero it out and set
144 * the pointer to new one, then send parent to disk.
146 parent
= block_to_cpu(SYSV_SB(inode
->i_sb
), branch
[n
-1].key
);
147 bh
= sb_getblk(inode
->i_sb
, parent
);
149 memset(bh
->b_data
, 0, blocksize
);
151 branch
[n
].p
= (sysv_zone_t
*) bh
->b_data
+ offsets
[n
];
152 *branch
[n
].p
= branch
[n
].key
;
153 set_buffer_uptodate(bh
);
155 dirty_indirect(bh
, inode
);
160 /* Allocation failed, free what we already allocated */
161 for (i
= 1; i
< n
; i
++)
162 bforget(branch
[i
].bh
);
163 for (i
= 0; i
< n
; i
++)
164 sysv_free_block(inode
->i_sb
, branch
[i
].key
);
168 static inline int splice_branch(struct inode
*inode
,
175 /* Verify that place we are splicing to is still there and vacant */
176 write_lock(&pointers_lock
);
177 if (!verify_chain(chain
, where
-1) || *where
->p
)
179 *where
->p
= where
->key
;
180 write_unlock(&pointers_lock
);
182 inode
->i_ctime
= current_time(inode
);
184 /* had we spliced it onto indirect block? */
186 dirty_indirect(where
->bh
, inode
);
189 sysv_sync_inode(inode
);
191 mark_inode_dirty(inode
);
195 write_unlock(&pointers_lock
);
196 for (i
= 1; i
< num
; i
++)
197 bforget(where
[i
].bh
);
198 for (i
= 0; i
< num
; i
++)
199 sysv_free_block(inode
->i_sb
, where
[i
].key
);
203 static int get_block(struct inode
*inode
, sector_t iblock
, struct buffer_head
*bh_result
, int create
)
207 Indirect chain
[DEPTH
];
208 struct super_block
*sb
= inode
->i_sb
;
211 int depth
= block_to_path(inode
, iblock
, offsets
);
217 read_lock(&pointers_lock
);
218 partial
= get_branch(inode
, depth
, offsets
, chain
, &err
);
219 read_unlock(&pointers_lock
);
221 /* Simplest case - block found, no allocation needed */
224 map_bh(bh_result
, sb
, block_to_cpu(SYSV_SB(sb
),
225 chain
[depth
-1].key
));
226 /* Clean up and exit */
227 partial
= chain
+depth
-1; /* the whole chain */
231 /* Next simple case - plain lookup or failed read of indirect block */
232 if (!create
|| err
== -EIO
) {
234 while (partial
> chain
) {
243 * Indirect block might be removed by truncate while we were
244 * reading it. Handling of that case (forget what we've got and
245 * reread) is taken out of the main path.
250 left
= (chain
+ depth
) - partial
;
251 err
= alloc_branch(inode
, left
, offsets
+(partial
-chain
), partial
);
255 if (splice_branch(inode
, chain
, partial
, left
) < 0)
258 set_buffer_new(bh_result
);
262 while (partial
> chain
) {
269 static inline int all_zeroes(sysv_zone_t
*p
, sysv_zone_t
*q
)
277 static Indirect
*find_shared(struct inode
*inode
,
283 Indirect
*partial
, *p
;
287 for (k
= depth
; k
> 1 && !offsets
[k
-1]; k
--)
290 write_lock(&pointers_lock
);
291 partial
= get_branch(inode
, k
, offsets
, chain
, &err
);
293 partial
= chain
+ k
-1;
295 * If the branch acquired continuation since we've looked at it -
296 * fine, it should all survive and (new) top doesn't belong to us.
298 if (!partial
->key
&& *partial
->p
) {
299 write_unlock(&pointers_lock
);
302 for (p
=partial
; p
>chain
&& all_zeroes((sysv_zone_t
*)p
->bh
->b_data
,p
->p
); p
--)
305 * OK, we've found the last block that must survive. The rest of our
306 * branch should be detached before unlocking. However, if that rest
307 * of branch is all ours and does not grow immediately from the inode
308 * it's easier to cheat and just decrement partial->p.
310 if (p
== chain
+ k
- 1 && p
> chain
) {
316 write_unlock(&pointers_lock
);
318 while (partial
> p
) {
326 static inline void free_data(struct inode
*inode
, sysv_zone_t
*p
, sysv_zone_t
*q
)
328 for ( ; p
< q
; p
++) {
332 sysv_free_block(inode
->i_sb
, nr
);
333 mark_inode_dirty(inode
);
338 static void free_branches(struct inode
*inode
, sysv_zone_t
*p
, sysv_zone_t
*q
, int depth
)
340 struct buffer_head
* bh
;
341 struct super_block
*sb
= inode
->i_sb
;
344 for ( ; p
< q
; p
++) {
350 block
= block_to_cpu(SYSV_SB(sb
), nr
);
351 bh
= sb_bread(sb
, block
);
354 free_branches(inode
, (sysv_zone_t
*)bh
->b_data
,
355 block_end(bh
), depth
);
357 sysv_free_block(sb
, nr
);
358 mark_inode_dirty(inode
);
361 free_data(inode
, p
, q
);
364 void sysv_truncate (struct inode
* inode
)
366 sysv_zone_t
*i_data
= SYSV_I(inode
)->i_data
;
368 Indirect chain
[DEPTH
];
375 if (!(S_ISREG(inode
->i_mode
) || S_ISDIR(inode
->i_mode
) ||
376 S_ISLNK(inode
->i_mode
)))
379 blocksize
= inode
->i_sb
->s_blocksize
;
380 iblock
= (inode
->i_size
+ blocksize
-1)
381 >> inode
->i_sb
->s_blocksize_bits
;
383 block_truncate_page(inode
->i_mapping
, inode
->i_size
, get_block
);
385 n
= block_to_path(inode
, iblock
, offsets
);
390 free_data(inode
, i_data
+offsets
[0], i_data
+ DIRECT
);
394 partial
= find_shared(inode
, n
, offsets
, chain
, &nr
);
395 /* Kill the top of shared branch (already detached) */
397 if (partial
== chain
)
398 mark_inode_dirty(inode
);
400 dirty_indirect(partial
->bh
, inode
);
401 free_branches(inode
, &nr
, &nr
+1, (chain
+n
-1) - partial
);
403 /* Clear the ends of indirect blocks on the shared branch */
404 while (partial
> chain
) {
405 free_branches(inode
, partial
->p
+ 1, block_end(partial
->bh
),
406 (chain
+n
-1) - partial
);
407 dirty_indirect(partial
->bh
, inode
);
408 brelse (partial
->bh
);
412 /* Kill the remaining (whole) subtrees (== subtrees deeper than...) */
414 nr
= i_data
[DIRECT
+ n
- 1];
416 i_data
[DIRECT
+ n
- 1] = 0;
417 mark_inode_dirty(inode
);
418 free_branches(inode
, &nr
, &nr
+1, n
);
422 inode
->i_mtime
= inode
->i_ctime
= current_time(inode
);
424 sysv_sync_inode (inode
);
426 mark_inode_dirty(inode
);
429 static unsigned sysv_nblocks(struct super_block
*s
, loff_t size
)
431 struct sysv_sb_info
*sbi
= SYSV_SB(s
);
432 int ptrs_bits
= sbi
->s_ind_per_block_bits
;
433 unsigned blocks
, res
, direct
= DIRECT
, i
= DEPTH
;
434 blocks
= (size
+ s
->s_blocksize
- 1) >> s
->s_blocksize_bits
;
436 while (--i
&& blocks
> direct
) {
437 blocks
= ((blocks
- direct
- 1) >> ptrs_bits
) + 1;
444 int sysv_getattr(const struct path
*path
, struct kstat
*stat
,
445 u32 request_mask
, unsigned int flags
)
447 struct super_block
*s
= path
->dentry
->d_sb
;
448 generic_fillattr(d_inode(path
->dentry
), stat
);
449 stat
->blocks
= (s
->s_blocksize
/ 512) * sysv_nblocks(s
, stat
->size
);
450 stat
->blksize
= s
->s_blocksize
;
454 static int sysv_writepage(struct page
*page
, struct writeback_control
*wbc
)
456 return block_write_full_page(page
,get_block
,wbc
);
459 static int sysv_readpage(struct file
*file
, struct page
*page
)
461 return block_read_full_page(page
,get_block
);
464 int sysv_prepare_chunk(struct page
*page
, loff_t pos
, unsigned len
)
466 return __block_write_begin(page
, pos
, len
, get_block
);
469 static void sysv_write_failed(struct address_space
*mapping
, loff_t to
)
471 struct inode
*inode
= mapping
->host
;
473 if (to
> inode
->i_size
) {
474 truncate_pagecache(inode
, inode
->i_size
);
475 sysv_truncate(inode
);
479 static int sysv_write_begin(struct file
*file
, struct address_space
*mapping
,
480 loff_t pos
, unsigned len
, unsigned flags
,
481 struct page
**pagep
, void **fsdata
)
485 ret
= block_write_begin(mapping
, pos
, len
, flags
, pagep
, get_block
);
487 sysv_write_failed(mapping
, pos
+ len
);
492 static sector_t
sysv_bmap(struct address_space
*mapping
, sector_t block
)
494 return generic_block_bmap(mapping
,block
,get_block
);
497 const struct address_space_operations sysv_aops
= {
498 .readpage
= sysv_readpage
,
499 .writepage
= sysv_writepage
,
500 .write_begin
= sysv_write_begin
,
501 .write_end
= generic_write_end
,