18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <linux/kernel.h>
38c2ecf20Sopenharmony_ci#include <linux/fs.h>
48c2ecf20Sopenharmony_ci#include <linux/buffer_head.h>
58c2ecf20Sopenharmony_ci#include <asm/div64.h>
68c2ecf20Sopenharmony_ci#include "omfs.h"
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ciunsigned long omfs_count_free(struct super_block *sb)
98c2ecf20Sopenharmony_ci{
108c2ecf20Sopenharmony_ci	unsigned int i;
118c2ecf20Sopenharmony_ci	unsigned long sum = 0;
128c2ecf20Sopenharmony_ci	struct omfs_sb_info *sbi = OMFS_SB(sb);
138c2ecf20Sopenharmony_ci	int nbits = sb->s_blocksize * 8;
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci	for (i = 0; i < sbi->s_imap_size; i++)
168c2ecf20Sopenharmony_ci		sum += nbits - bitmap_weight(sbi->s_imap[i], nbits);
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci	return sum;
198c2ecf20Sopenharmony_ci}
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/*
228c2ecf20Sopenharmony_ci *  Counts the run of zero bits starting at bit up to max.
238c2ecf20Sopenharmony_ci *  It handles the case where a run might spill over a buffer.
248c2ecf20Sopenharmony_ci *  Called with bitmap lock.
258c2ecf20Sopenharmony_ci */
268c2ecf20Sopenharmony_cistatic int count_run(unsigned long **addr, int nbits,
278c2ecf20Sopenharmony_ci		int addrlen, int bit, int max)
288c2ecf20Sopenharmony_ci{
298c2ecf20Sopenharmony_ci	int count = 0;
308c2ecf20Sopenharmony_ci	int x;
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	for (; addrlen > 0; addrlen--, addr++) {
338c2ecf20Sopenharmony_ci		x = find_next_bit(*addr, nbits, bit);
348c2ecf20Sopenharmony_ci		count += x - bit;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci		if (x < nbits || count > max)
378c2ecf20Sopenharmony_ci			return min(count, max);
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci		bit = 0;
408c2ecf20Sopenharmony_ci	}
418c2ecf20Sopenharmony_ci	return min(count, max);
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci/*
458c2ecf20Sopenharmony_ci * Sets or clears the run of count bits starting with bit.
468c2ecf20Sopenharmony_ci * Called with bitmap lock.
478c2ecf20Sopenharmony_ci */
488c2ecf20Sopenharmony_cistatic int set_run(struct super_block *sb, int map,
498c2ecf20Sopenharmony_ci		int nbits, int bit, int count, int set)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	int i;
528c2ecf20Sopenharmony_ci	int err;
538c2ecf20Sopenharmony_ci	struct buffer_head *bh;
548c2ecf20Sopenharmony_ci	struct omfs_sb_info *sbi = OMFS_SB(sb);
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci 	err = -ENOMEM;
578c2ecf20Sopenharmony_ci	bh = sb_bread(sb, clus_to_blk(sbi, sbi->s_bitmap_ino) + map);
588c2ecf20Sopenharmony_ci	if (!bh)
598c2ecf20Sopenharmony_ci		goto out;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	for (i = 0; i < count; i++, bit++) {
628c2ecf20Sopenharmony_ci		if (bit >= nbits) {
638c2ecf20Sopenharmony_ci			bit = 0;
648c2ecf20Sopenharmony_ci			map++;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci			mark_buffer_dirty(bh);
678c2ecf20Sopenharmony_ci			brelse(bh);
688c2ecf20Sopenharmony_ci			bh = sb_bread(sb,
698c2ecf20Sopenharmony_ci				clus_to_blk(sbi, sbi->s_bitmap_ino) + map);
708c2ecf20Sopenharmony_ci			if (!bh)
718c2ecf20Sopenharmony_ci				goto out;
728c2ecf20Sopenharmony_ci		}
738c2ecf20Sopenharmony_ci		if (set) {
748c2ecf20Sopenharmony_ci			set_bit(bit, sbi->s_imap[map]);
758c2ecf20Sopenharmony_ci			set_bit(bit, (unsigned long *)bh->b_data);
768c2ecf20Sopenharmony_ci		} else {
778c2ecf20Sopenharmony_ci			clear_bit(bit, sbi->s_imap[map]);
788c2ecf20Sopenharmony_ci			clear_bit(bit, (unsigned long *)bh->b_data);
798c2ecf20Sopenharmony_ci		}
808c2ecf20Sopenharmony_ci	}
818c2ecf20Sopenharmony_ci	mark_buffer_dirty(bh);
828c2ecf20Sopenharmony_ci	brelse(bh);
838c2ecf20Sopenharmony_ci	err = 0;
848c2ecf20Sopenharmony_ciout:
858c2ecf20Sopenharmony_ci	return err;
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci/*
898c2ecf20Sopenharmony_ci * Tries to allocate exactly one block.  Returns true if successful.
908c2ecf20Sopenharmony_ci */
918c2ecf20Sopenharmony_ciint omfs_allocate_block(struct super_block *sb, u64 block)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	struct buffer_head *bh;
948c2ecf20Sopenharmony_ci	struct omfs_sb_info *sbi = OMFS_SB(sb);
958c2ecf20Sopenharmony_ci	int bits_per_entry = 8 * sb->s_blocksize;
968c2ecf20Sopenharmony_ci	unsigned int map, bit;
978c2ecf20Sopenharmony_ci	int ret = 0;
988c2ecf20Sopenharmony_ci	u64 tmp;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	tmp = block;
1018c2ecf20Sopenharmony_ci	bit = do_div(tmp, bits_per_entry);
1028c2ecf20Sopenharmony_ci	map = tmp;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	mutex_lock(&sbi->s_bitmap_lock);
1058c2ecf20Sopenharmony_ci	if (map >= sbi->s_imap_size || test_and_set_bit(bit, sbi->s_imap[map]))
1068c2ecf20Sopenharmony_ci		goto out;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	if (sbi->s_bitmap_ino > 0) {
1098c2ecf20Sopenharmony_ci		bh = sb_bread(sb, clus_to_blk(sbi, sbi->s_bitmap_ino) + map);
1108c2ecf20Sopenharmony_ci		if (!bh)
1118c2ecf20Sopenharmony_ci			goto out;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci		set_bit(bit, (unsigned long *)bh->b_data);
1148c2ecf20Sopenharmony_ci		mark_buffer_dirty(bh);
1158c2ecf20Sopenharmony_ci		brelse(bh);
1168c2ecf20Sopenharmony_ci	}
1178c2ecf20Sopenharmony_ci	ret = 1;
1188c2ecf20Sopenharmony_ciout:
1198c2ecf20Sopenharmony_ci	mutex_unlock(&sbi->s_bitmap_lock);
1208c2ecf20Sopenharmony_ci	return ret;
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci/*
1258c2ecf20Sopenharmony_ci *  Tries to allocate a set of blocks.	The request size depends on the
1268c2ecf20Sopenharmony_ci *  type: for inodes, we must allocate sbi->s_mirrors blocks, and for file
1278c2ecf20Sopenharmony_ci *  blocks, we try to allocate sbi->s_clustersize, but can always get away
1288c2ecf20Sopenharmony_ci *  with just one block.
1298c2ecf20Sopenharmony_ci */
1308c2ecf20Sopenharmony_ciint omfs_allocate_range(struct super_block *sb,
1318c2ecf20Sopenharmony_ci			int min_request,
1328c2ecf20Sopenharmony_ci			int max_request,
1338c2ecf20Sopenharmony_ci			u64 *return_block,
1348c2ecf20Sopenharmony_ci			int *return_size)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	struct omfs_sb_info *sbi = OMFS_SB(sb);
1378c2ecf20Sopenharmony_ci	int bits_per_entry = 8 * sb->s_blocksize;
1388c2ecf20Sopenharmony_ci	int ret = 0;
1398c2ecf20Sopenharmony_ci	int i, run, bit;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	mutex_lock(&sbi->s_bitmap_lock);
1428c2ecf20Sopenharmony_ci	for (i = 0; i < sbi->s_imap_size; i++) {
1438c2ecf20Sopenharmony_ci		bit = 0;
1448c2ecf20Sopenharmony_ci		while (bit < bits_per_entry) {
1458c2ecf20Sopenharmony_ci			bit = find_next_zero_bit(sbi->s_imap[i], bits_per_entry,
1468c2ecf20Sopenharmony_ci				bit);
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci			if (bit == bits_per_entry)
1498c2ecf20Sopenharmony_ci				break;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci			run = count_run(&sbi->s_imap[i], bits_per_entry,
1528c2ecf20Sopenharmony_ci				sbi->s_imap_size-i, bit, max_request);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci			if (run >= min_request)
1558c2ecf20Sopenharmony_ci				goto found;
1568c2ecf20Sopenharmony_ci			bit += run;
1578c2ecf20Sopenharmony_ci		}
1588c2ecf20Sopenharmony_ci	}
1598c2ecf20Sopenharmony_ci	ret = -ENOSPC;
1608c2ecf20Sopenharmony_ci	goto out;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cifound:
1638c2ecf20Sopenharmony_ci	*return_block = (u64) i * bits_per_entry + bit;
1648c2ecf20Sopenharmony_ci	*return_size = run;
1658c2ecf20Sopenharmony_ci	ret = set_run(sb, i, bits_per_entry, bit, run, 1);
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ciout:
1688c2ecf20Sopenharmony_ci	mutex_unlock(&sbi->s_bitmap_lock);
1698c2ecf20Sopenharmony_ci	return ret;
1708c2ecf20Sopenharmony_ci}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci/*
1738c2ecf20Sopenharmony_ci * Clears count bits starting at a given block.
1748c2ecf20Sopenharmony_ci */
1758c2ecf20Sopenharmony_ciint omfs_clear_range(struct super_block *sb, u64 block, int count)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	struct omfs_sb_info *sbi = OMFS_SB(sb);
1788c2ecf20Sopenharmony_ci	int bits_per_entry = 8 * sb->s_blocksize;
1798c2ecf20Sopenharmony_ci	u64 tmp;
1808c2ecf20Sopenharmony_ci	unsigned int map, bit;
1818c2ecf20Sopenharmony_ci	int ret;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	tmp = block;
1848c2ecf20Sopenharmony_ci	bit = do_div(tmp, bits_per_entry);
1858c2ecf20Sopenharmony_ci	map = tmp;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	if (map >= sbi->s_imap_size)
1888c2ecf20Sopenharmony_ci		return 0;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	mutex_lock(&sbi->s_bitmap_lock);
1918c2ecf20Sopenharmony_ci	ret = set_run(sb, map, bits_per_entry, bit, count, 0);
1928c2ecf20Sopenharmony_ci	mutex_unlock(&sbi->s_bitmap_lock);
1938c2ecf20Sopenharmony_ci	return ret;
1948c2ecf20Sopenharmony_ci}
195