18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* Generic part */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_citypedef struct {
58c2ecf20Sopenharmony_ci	block_t	*p;
68c2ecf20Sopenharmony_ci	block_t	key;
78c2ecf20Sopenharmony_ci	struct buffer_head *bh;
88c2ecf20Sopenharmony_ci} Indirect;
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_cistatic DEFINE_RWLOCK(pointers_lock);
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_cistatic inline void add_chain(Indirect *p, struct buffer_head *bh, block_t *v)
138c2ecf20Sopenharmony_ci{
148c2ecf20Sopenharmony_ci	p->key = *(p->p = v);
158c2ecf20Sopenharmony_ci	p->bh = bh;
168c2ecf20Sopenharmony_ci}
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistatic inline int verify_chain(Indirect *from, Indirect *to)
198c2ecf20Sopenharmony_ci{
208c2ecf20Sopenharmony_ci	while (from <= to && from->key == *from->p)
218c2ecf20Sopenharmony_ci		from++;
228c2ecf20Sopenharmony_ci	return (from > to);
238c2ecf20Sopenharmony_ci}
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic inline block_t *block_end(struct buffer_head *bh)
268c2ecf20Sopenharmony_ci{
278c2ecf20Sopenharmony_ci	return (block_t *)((char*)bh->b_data + bh->b_size);
288c2ecf20Sopenharmony_ci}
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic inline Indirect *get_branch(struct inode *inode,
318c2ecf20Sopenharmony_ci					int depth,
328c2ecf20Sopenharmony_ci					int *offsets,
338c2ecf20Sopenharmony_ci					Indirect chain[DEPTH],
348c2ecf20Sopenharmony_ci					int *err)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	struct super_block *sb = inode->i_sb;
378c2ecf20Sopenharmony_ci	Indirect *p = chain;
388c2ecf20Sopenharmony_ci	struct buffer_head *bh;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	*err = 0;
418c2ecf20Sopenharmony_ci	/* i_data is not going away, no lock needed */
428c2ecf20Sopenharmony_ci	add_chain (chain, NULL, i_data(inode) + *offsets);
438c2ecf20Sopenharmony_ci	if (!p->key)
448c2ecf20Sopenharmony_ci		goto no_block;
458c2ecf20Sopenharmony_ci	while (--depth) {
468c2ecf20Sopenharmony_ci		bh = sb_bread(sb, block_to_cpu(p->key));
478c2ecf20Sopenharmony_ci		if (!bh)
488c2ecf20Sopenharmony_ci			goto failure;
498c2ecf20Sopenharmony_ci		read_lock(&pointers_lock);
508c2ecf20Sopenharmony_ci		if (!verify_chain(chain, p))
518c2ecf20Sopenharmony_ci			goto changed;
528c2ecf20Sopenharmony_ci		add_chain(++p, bh, (block_t *)bh->b_data + *++offsets);
538c2ecf20Sopenharmony_ci		read_unlock(&pointers_lock);
548c2ecf20Sopenharmony_ci		if (!p->key)
558c2ecf20Sopenharmony_ci			goto no_block;
568c2ecf20Sopenharmony_ci	}
578c2ecf20Sopenharmony_ci	return NULL;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cichanged:
608c2ecf20Sopenharmony_ci	read_unlock(&pointers_lock);
618c2ecf20Sopenharmony_ci	brelse(bh);
628c2ecf20Sopenharmony_ci	*err = -EAGAIN;
638c2ecf20Sopenharmony_ci	goto no_block;
648c2ecf20Sopenharmony_cifailure:
658c2ecf20Sopenharmony_ci	*err = -EIO;
668c2ecf20Sopenharmony_cino_block:
678c2ecf20Sopenharmony_ci	return p;
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic int alloc_branch(struct inode *inode,
718c2ecf20Sopenharmony_ci			     int num,
728c2ecf20Sopenharmony_ci			     int *offsets,
738c2ecf20Sopenharmony_ci			     Indirect *branch)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	int n = 0;
768c2ecf20Sopenharmony_ci	int i;
778c2ecf20Sopenharmony_ci	int parent = minix_new_block(inode);
788c2ecf20Sopenharmony_ci	int err = -ENOSPC;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	branch[0].key = cpu_to_block(parent);
818c2ecf20Sopenharmony_ci	if (parent) for (n = 1; n < num; n++) {
828c2ecf20Sopenharmony_ci		struct buffer_head *bh;
838c2ecf20Sopenharmony_ci		/* Allocate the next block */
848c2ecf20Sopenharmony_ci		int nr = minix_new_block(inode);
858c2ecf20Sopenharmony_ci		if (!nr)
868c2ecf20Sopenharmony_ci			break;
878c2ecf20Sopenharmony_ci		branch[n].key = cpu_to_block(nr);
888c2ecf20Sopenharmony_ci		bh = sb_getblk(inode->i_sb, parent);
898c2ecf20Sopenharmony_ci		if (!bh) {
908c2ecf20Sopenharmony_ci			minix_free_block(inode, nr);
918c2ecf20Sopenharmony_ci			err = -ENOMEM;
928c2ecf20Sopenharmony_ci			break;
938c2ecf20Sopenharmony_ci		}
948c2ecf20Sopenharmony_ci		lock_buffer(bh);
958c2ecf20Sopenharmony_ci		memset(bh->b_data, 0, bh->b_size);
968c2ecf20Sopenharmony_ci		branch[n].bh = bh;
978c2ecf20Sopenharmony_ci		branch[n].p = (block_t*) bh->b_data + offsets[n];
988c2ecf20Sopenharmony_ci		*branch[n].p = branch[n].key;
998c2ecf20Sopenharmony_ci		set_buffer_uptodate(bh);
1008c2ecf20Sopenharmony_ci		unlock_buffer(bh);
1018c2ecf20Sopenharmony_ci		mark_buffer_dirty_inode(bh, inode);
1028c2ecf20Sopenharmony_ci		parent = nr;
1038c2ecf20Sopenharmony_ci	}
1048c2ecf20Sopenharmony_ci	if (n == num)
1058c2ecf20Sopenharmony_ci		return 0;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	/* Allocation failed, free what we already allocated */
1088c2ecf20Sopenharmony_ci	for (i = 1; i < n; i++)
1098c2ecf20Sopenharmony_ci		bforget(branch[i].bh);
1108c2ecf20Sopenharmony_ci	for (i = 0; i < n; i++)
1118c2ecf20Sopenharmony_ci		minix_free_block(inode, block_to_cpu(branch[i].key));
1128c2ecf20Sopenharmony_ci	return err;
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic inline int splice_branch(struct inode *inode,
1168c2ecf20Sopenharmony_ci				     Indirect chain[DEPTH],
1178c2ecf20Sopenharmony_ci				     Indirect *where,
1188c2ecf20Sopenharmony_ci				     int num)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	int i;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	write_lock(&pointers_lock);
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	/* Verify that place we are splicing to is still there and vacant */
1258c2ecf20Sopenharmony_ci	if (!verify_chain(chain, where-1) || *where->p)
1268c2ecf20Sopenharmony_ci		goto changed;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	*where->p = where->key;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	write_unlock(&pointers_lock);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	/* We are done with atomic stuff, now do the rest of housekeeping */
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	inode->i_ctime = current_time(inode);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	/* had we spliced it onto indirect block? */
1378c2ecf20Sopenharmony_ci	if (where->bh)
1388c2ecf20Sopenharmony_ci		mark_buffer_dirty_inode(where->bh, inode);
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	mark_inode_dirty(inode);
1418c2ecf20Sopenharmony_ci	return 0;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cichanged:
1448c2ecf20Sopenharmony_ci	write_unlock(&pointers_lock);
1458c2ecf20Sopenharmony_ci	for (i = 1; i < num; i++)
1468c2ecf20Sopenharmony_ci		bforget(where[i].bh);
1478c2ecf20Sopenharmony_ci	for (i = 0; i < num; i++)
1488c2ecf20Sopenharmony_ci		minix_free_block(inode, block_to_cpu(where[i].key));
1498c2ecf20Sopenharmony_ci	return -EAGAIN;
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic int get_block(struct inode * inode, sector_t block,
1538c2ecf20Sopenharmony_ci			struct buffer_head *bh, int create)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	int err = -EIO;
1568c2ecf20Sopenharmony_ci	int offsets[DEPTH];
1578c2ecf20Sopenharmony_ci	Indirect chain[DEPTH];
1588c2ecf20Sopenharmony_ci	Indirect *partial;
1598c2ecf20Sopenharmony_ci	int left;
1608c2ecf20Sopenharmony_ci	int depth = block_to_path(inode, block, offsets);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	if (depth == 0)
1638c2ecf20Sopenharmony_ci		goto out;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_cireread:
1668c2ecf20Sopenharmony_ci	partial = get_branch(inode, depth, offsets, chain, &err);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	/* Simplest case - block found, no allocation needed */
1698c2ecf20Sopenharmony_ci	if (!partial) {
1708c2ecf20Sopenharmony_cigot_it:
1718c2ecf20Sopenharmony_ci		map_bh(bh, inode->i_sb, block_to_cpu(chain[depth-1].key));
1728c2ecf20Sopenharmony_ci		/* Clean up and exit */
1738c2ecf20Sopenharmony_ci		partial = chain+depth-1; /* the whole chain */
1748c2ecf20Sopenharmony_ci		goto cleanup;
1758c2ecf20Sopenharmony_ci	}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	/* Next simple case - plain lookup or failed read of indirect block */
1788c2ecf20Sopenharmony_ci	if (!create || err == -EIO) {
1798c2ecf20Sopenharmony_cicleanup:
1808c2ecf20Sopenharmony_ci		while (partial > chain) {
1818c2ecf20Sopenharmony_ci			brelse(partial->bh);
1828c2ecf20Sopenharmony_ci			partial--;
1838c2ecf20Sopenharmony_ci		}
1848c2ecf20Sopenharmony_ciout:
1858c2ecf20Sopenharmony_ci		return err;
1868c2ecf20Sopenharmony_ci	}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	/*
1898c2ecf20Sopenharmony_ci	 * Indirect block might be removed by truncate while we were
1908c2ecf20Sopenharmony_ci	 * reading it. Handling of that case (forget what we've got and
1918c2ecf20Sopenharmony_ci	 * reread) is taken out of the main path.
1928c2ecf20Sopenharmony_ci	 */
1938c2ecf20Sopenharmony_ci	if (err == -EAGAIN)
1948c2ecf20Sopenharmony_ci		goto changed;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	left = (chain + depth) - partial;
1978c2ecf20Sopenharmony_ci	err = alloc_branch(inode, left, offsets+(partial-chain), partial);
1988c2ecf20Sopenharmony_ci	if (err)
1998c2ecf20Sopenharmony_ci		goto cleanup;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	if (splice_branch(inode, chain, partial, left) < 0)
2028c2ecf20Sopenharmony_ci		goto changed;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	set_buffer_new(bh);
2058c2ecf20Sopenharmony_ci	goto got_it;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_cichanged:
2088c2ecf20Sopenharmony_ci	while (partial > chain) {
2098c2ecf20Sopenharmony_ci		brelse(partial->bh);
2108c2ecf20Sopenharmony_ci		partial--;
2118c2ecf20Sopenharmony_ci	}
2128c2ecf20Sopenharmony_ci	goto reread;
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cistatic inline int all_zeroes(block_t *p, block_t *q)
2168c2ecf20Sopenharmony_ci{
2178c2ecf20Sopenharmony_ci	while (p < q)
2188c2ecf20Sopenharmony_ci		if (*p++)
2198c2ecf20Sopenharmony_ci			return 0;
2208c2ecf20Sopenharmony_ci	return 1;
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_cistatic Indirect *find_shared(struct inode *inode,
2248c2ecf20Sopenharmony_ci				int depth,
2258c2ecf20Sopenharmony_ci				int offsets[DEPTH],
2268c2ecf20Sopenharmony_ci				Indirect chain[DEPTH],
2278c2ecf20Sopenharmony_ci				block_t *top)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	Indirect *partial, *p;
2308c2ecf20Sopenharmony_ci	int k, err;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	*top = 0;
2338c2ecf20Sopenharmony_ci	for (k = depth; k > 1 && !offsets[k-1]; k--)
2348c2ecf20Sopenharmony_ci		;
2358c2ecf20Sopenharmony_ci	partial = get_branch(inode, k, offsets, chain, &err);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	write_lock(&pointers_lock);
2388c2ecf20Sopenharmony_ci	if (!partial)
2398c2ecf20Sopenharmony_ci		partial = chain + k-1;
2408c2ecf20Sopenharmony_ci	if (!partial->key && *partial->p) {
2418c2ecf20Sopenharmony_ci		write_unlock(&pointers_lock);
2428c2ecf20Sopenharmony_ci		goto no_top;
2438c2ecf20Sopenharmony_ci	}
2448c2ecf20Sopenharmony_ci	for (p=partial;p>chain && all_zeroes((block_t*)p->bh->b_data,p->p);p--)
2458c2ecf20Sopenharmony_ci		;
2468c2ecf20Sopenharmony_ci	if (p == chain + k - 1 && p > chain) {
2478c2ecf20Sopenharmony_ci		p->p--;
2488c2ecf20Sopenharmony_ci	} else {
2498c2ecf20Sopenharmony_ci		*top = *p->p;
2508c2ecf20Sopenharmony_ci		*p->p = 0;
2518c2ecf20Sopenharmony_ci	}
2528c2ecf20Sopenharmony_ci	write_unlock(&pointers_lock);
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	while(partial > p)
2558c2ecf20Sopenharmony_ci	{
2568c2ecf20Sopenharmony_ci		brelse(partial->bh);
2578c2ecf20Sopenharmony_ci		partial--;
2588c2ecf20Sopenharmony_ci	}
2598c2ecf20Sopenharmony_cino_top:
2608c2ecf20Sopenharmony_ci	return partial;
2618c2ecf20Sopenharmony_ci}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_cistatic inline void free_data(struct inode *inode, block_t *p, block_t *q)
2648c2ecf20Sopenharmony_ci{
2658c2ecf20Sopenharmony_ci	unsigned long nr;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	for ( ; p < q ; p++) {
2688c2ecf20Sopenharmony_ci		nr = block_to_cpu(*p);
2698c2ecf20Sopenharmony_ci		if (nr) {
2708c2ecf20Sopenharmony_ci			*p = 0;
2718c2ecf20Sopenharmony_ci			minix_free_block(inode, nr);
2728c2ecf20Sopenharmony_ci		}
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_cistatic void free_branches(struct inode *inode, block_t *p, block_t *q, int depth)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	struct buffer_head * bh;
2798c2ecf20Sopenharmony_ci	unsigned long nr;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	if (depth--) {
2828c2ecf20Sopenharmony_ci		for ( ; p < q ; p++) {
2838c2ecf20Sopenharmony_ci			nr = block_to_cpu(*p);
2848c2ecf20Sopenharmony_ci			if (!nr)
2858c2ecf20Sopenharmony_ci				continue;
2868c2ecf20Sopenharmony_ci			*p = 0;
2878c2ecf20Sopenharmony_ci			bh = sb_bread(inode->i_sb, nr);
2888c2ecf20Sopenharmony_ci			if (!bh)
2898c2ecf20Sopenharmony_ci				continue;
2908c2ecf20Sopenharmony_ci			free_branches(inode, (block_t*)bh->b_data,
2918c2ecf20Sopenharmony_ci				      block_end(bh), depth);
2928c2ecf20Sopenharmony_ci			bforget(bh);
2938c2ecf20Sopenharmony_ci			minix_free_block(inode, nr);
2948c2ecf20Sopenharmony_ci			mark_inode_dirty(inode);
2958c2ecf20Sopenharmony_ci		}
2968c2ecf20Sopenharmony_ci	} else
2978c2ecf20Sopenharmony_ci		free_data(inode, p, q);
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_cistatic inline void truncate (struct inode * inode)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	struct super_block *sb = inode->i_sb;
3038c2ecf20Sopenharmony_ci	block_t *idata = i_data(inode);
3048c2ecf20Sopenharmony_ci	int offsets[DEPTH];
3058c2ecf20Sopenharmony_ci	Indirect chain[DEPTH];
3068c2ecf20Sopenharmony_ci	Indirect *partial;
3078c2ecf20Sopenharmony_ci	block_t nr = 0;
3088c2ecf20Sopenharmony_ci	int n;
3098c2ecf20Sopenharmony_ci	int first_whole;
3108c2ecf20Sopenharmony_ci	long iblock;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	iblock = (inode->i_size + sb->s_blocksize -1) >> sb->s_blocksize_bits;
3138c2ecf20Sopenharmony_ci	block_truncate_page(inode->i_mapping, inode->i_size, get_block);
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	n = block_to_path(inode, iblock, offsets);
3168c2ecf20Sopenharmony_ci	if (!n)
3178c2ecf20Sopenharmony_ci		return;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	if (n == 1) {
3208c2ecf20Sopenharmony_ci		free_data(inode, idata+offsets[0], idata + DIRECT);
3218c2ecf20Sopenharmony_ci		first_whole = 0;
3228c2ecf20Sopenharmony_ci		goto do_indirects;
3238c2ecf20Sopenharmony_ci	}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	first_whole = offsets[0] + 1 - DIRECT;
3268c2ecf20Sopenharmony_ci	partial = find_shared(inode, n, offsets, chain, &nr);
3278c2ecf20Sopenharmony_ci	if (nr) {
3288c2ecf20Sopenharmony_ci		if (partial == chain)
3298c2ecf20Sopenharmony_ci			mark_inode_dirty(inode);
3308c2ecf20Sopenharmony_ci		else
3318c2ecf20Sopenharmony_ci			mark_buffer_dirty_inode(partial->bh, inode);
3328c2ecf20Sopenharmony_ci		free_branches(inode, &nr, &nr+1, (chain+n-1) - partial);
3338c2ecf20Sopenharmony_ci	}
3348c2ecf20Sopenharmony_ci	/* Clear the ends of indirect blocks on the shared branch */
3358c2ecf20Sopenharmony_ci	while (partial > chain) {
3368c2ecf20Sopenharmony_ci		free_branches(inode, partial->p + 1, block_end(partial->bh),
3378c2ecf20Sopenharmony_ci				(chain+n-1) - partial);
3388c2ecf20Sopenharmony_ci		mark_buffer_dirty_inode(partial->bh, inode);
3398c2ecf20Sopenharmony_ci		brelse (partial->bh);
3408c2ecf20Sopenharmony_ci		partial--;
3418c2ecf20Sopenharmony_ci	}
3428c2ecf20Sopenharmony_cido_indirects:
3438c2ecf20Sopenharmony_ci	/* Kill the remaining (whole) subtrees */
3448c2ecf20Sopenharmony_ci	while (first_whole < DEPTH-1) {
3458c2ecf20Sopenharmony_ci		nr = idata[DIRECT+first_whole];
3468c2ecf20Sopenharmony_ci		if (nr) {
3478c2ecf20Sopenharmony_ci			idata[DIRECT+first_whole] = 0;
3488c2ecf20Sopenharmony_ci			mark_inode_dirty(inode);
3498c2ecf20Sopenharmony_ci			free_branches(inode, &nr, &nr+1, first_whole+1);
3508c2ecf20Sopenharmony_ci		}
3518c2ecf20Sopenharmony_ci		first_whole++;
3528c2ecf20Sopenharmony_ci	}
3538c2ecf20Sopenharmony_ci	inode->i_mtime = inode->i_ctime = current_time(inode);
3548c2ecf20Sopenharmony_ci	mark_inode_dirty(inode);
3558c2ecf20Sopenharmony_ci}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_cistatic inline unsigned nblocks(loff_t size, struct super_block *sb)
3588c2ecf20Sopenharmony_ci{
3598c2ecf20Sopenharmony_ci	int k = sb->s_blocksize_bits - 10;
3608c2ecf20Sopenharmony_ci	unsigned blocks, res, direct = DIRECT, i = DEPTH;
3618c2ecf20Sopenharmony_ci	blocks = (size + sb->s_blocksize - 1) >> (BLOCK_SIZE_BITS + k);
3628c2ecf20Sopenharmony_ci	res = blocks;
3638c2ecf20Sopenharmony_ci	while (--i && blocks > direct) {
3648c2ecf20Sopenharmony_ci		blocks -= direct;
3658c2ecf20Sopenharmony_ci		blocks += sb->s_blocksize/sizeof(block_t) - 1;
3668c2ecf20Sopenharmony_ci		blocks /= sb->s_blocksize/sizeof(block_t);
3678c2ecf20Sopenharmony_ci		res += blocks;
3688c2ecf20Sopenharmony_ci		direct = 1;
3698c2ecf20Sopenharmony_ci	}
3708c2ecf20Sopenharmony_ci	return res;
3718c2ecf20Sopenharmony_ci}
372