xref: /openbmc/linux/fs/omfs/bitmap.c (revision b2441318)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
236cc410aSBob Copeland #include <linux/kernel.h>
336cc410aSBob Copeland #include <linux/fs.h>
436cc410aSBob Copeland #include <linux/buffer_head.h>
536cc410aSBob Copeland #include <asm/div64.h>
636cc410aSBob Copeland #include "omfs.h"
736cc410aSBob Copeland 
omfs_count_free(struct super_block * sb)836cc410aSBob Copeland unsigned long omfs_count_free(struct super_block *sb)
936cc410aSBob Copeland {
1036cc410aSBob Copeland 	unsigned int i;
1136cc410aSBob Copeland 	unsigned long sum = 0;
1236cc410aSBob Copeland 	struct omfs_sb_info *sbi = OMFS_SB(sb);
1336cc410aSBob Copeland 	int nbits = sb->s_blocksize * 8;
1436cc410aSBob Copeland 
1536cc410aSBob Copeland 	for (i = 0; i < sbi->s_imap_size; i++)
1636cc410aSBob Copeland 		sum += nbits - bitmap_weight(sbi->s_imap[i], nbits);
1736cc410aSBob Copeland 
1836cc410aSBob Copeland 	return sum;
1936cc410aSBob Copeland }
2036cc410aSBob Copeland 
2136cc410aSBob Copeland /*
2236cc410aSBob Copeland  *  Counts the run of zero bits starting at bit up to max.
2336cc410aSBob Copeland  *  It handles the case where a run might spill over a buffer.
2436cc410aSBob Copeland  *  Called with bitmap lock.
2536cc410aSBob Copeland  */
count_run(unsigned long ** addr,int nbits,int addrlen,int bit,int max)2636cc410aSBob Copeland static int count_run(unsigned long **addr, int nbits,
2736cc410aSBob Copeland 		int addrlen, int bit, int max)
2836cc410aSBob Copeland {
2936cc410aSBob Copeland 	int count = 0;
3036cc410aSBob Copeland 	int x;
3136cc410aSBob Copeland 
3236cc410aSBob Copeland 	for (; addrlen > 0; addrlen--, addr++) {
3336cc410aSBob Copeland 		x = find_next_bit(*addr, nbits, bit);
3436cc410aSBob Copeland 		count += x - bit;
3536cc410aSBob Copeland 
3636cc410aSBob Copeland 		if (x < nbits || count > max)
3736cc410aSBob Copeland 			return min(count, max);
3836cc410aSBob Copeland 
3936cc410aSBob Copeland 		bit = 0;
4036cc410aSBob Copeland 	}
4136cc410aSBob Copeland 	return min(count, max);
4236cc410aSBob Copeland }
4336cc410aSBob Copeland 
4436cc410aSBob Copeland /*
4536cc410aSBob Copeland  * Sets or clears the run of count bits starting with bit.
4636cc410aSBob Copeland  * Called with bitmap lock.
4736cc410aSBob Copeland  */
set_run(struct super_block * sb,int map,int nbits,int bit,int count,int set)4836cc410aSBob Copeland static int set_run(struct super_block *sb, int map,
4936cc410aSBob Copeland 		int nbits, int bit, int count, int set)
5036cc410aSBob Copeland {
5136cc410aSBob Copeland 	int i;
5236cc410aSBob Copeland 	int err;
5336cc410aSBob Copeland 	struct buffer_head *bh;
5436cc410aSBob Copeland 	struct omfs_sb_info *sbi = OMFS_SB(sb);
5536cc410aSBob Copeland 
5636cc410aSBob Copeland  	err = -ENOMEM;
5736cc410aSBob Copeland 	bh = sb_bread(sb, clus_to_blk(sbi, sbi->s_bitmap_ino) + map);
5836cc410aSBob Copeland 	if (!bh)
5936cc410aSBob Copeland 		goto out;
6036cc410aSBob Copeland 
6136cc410aSBob Copeland 	for (i = 0; i < count; i++, bit++) {
6236cc410aSBob Copeland 		if (bit >= nbits) {
6336cc410aSBob Copeland 			bit = 0;
6436cc410aSBob Copeland 			map++;
6536cc410aSBob Copeland 
6636cc410aSBob Copeland 			mark_buffer_dirty(bh);
6736cc410aSBob Copeland 			brelse(bh);
6836cc410aSBob Copeland 			bh = sb_bread(sb,
6936cc410aSBob Copeland 				clus_to_blk(sbi, sbi->s_bitmap_ino) + map);
7036cc410aSBob Copeland 			if (!bh)
7136cc410aSBob Copeland 				goto out;
7236cc410aSBob Copeland 		}
7336cc410aSBob Copeland 		if (set) {
7436cc410aSBob Copeland 			set_bit(bit, sbi->s_imap[map]);
75d406f66dSHarvey Harrison 			set_bit(bit, (unsigned long *)bh->b_data);
7636cc410aSBob Copeland 		} else {
7736cc410aSBob Copeland 			clear_bit(bit, sbi->s_imap[map]);
78d406f66dSHarvey Harrison 			clear_bit(bit, (unsigned long *)bh->b_data);
7936cc410aSBob Copeland 		}
8036cc410aSBob Copeland 	}
8136cc410aSBob Copeland 	mark_buffer_dirty(bh);
8236cc410aSBob Copeland 	brelse(bh);
8336cc410aSBob Copeland 	err = 0;
8436cc410aSBob Copeland out:
8536cc410aSBob Copeland 	return err;
8636cc410aSBob Copeland }
8736cc410aSBob Copeland 
8836cc410aSBob Copeland /*
89af901ca1SAndré Goddard Rosa  * Tries to allocate exactly one block.  Returns true if successful.
9036cc410aSBob Copeland  */
omfs_allocate_block(struct super_block * sb,u64 block)9136cc410aSBob Copeland int omfs_allocate_block(struct super_block *sb, u64 block)
9236cc410aSBob Copeland {
9336cc410aSBob Copeland 	struct buffer_head *bh;
9436cc410aSBob Copeland 	struct omfs_sb_info *sbi = OMFS_SB(sb);
9536cc410aSBob Copeland 	int bits_per_entry = 8 * sb->s_blocksize;
969419fc1cSBob Copeland 	unsigned int map, bit;
9736cc410aSBob Copeland 	int ret = 0;
9836cc410aSBob Copeland 	u64 tmp;
9936cc410aSBob Copeland 
10036cc410aSBob Copeland 	tmp = block;
10136cc410aSBob Copeland 	bit = do_div(tmp, bits_per_entry);
10236cc410aSBob Copeland 	map = tmp;
10336cc410aSBob Copeland 
10436cc410aSBob Copeland 	mutex_lock(&sbi->s_bitmap_lock);
10536cc410aSBob Copeland 	if (map >= sbi->s_imap_size || test_and_set_bit(bit, sbi->s_imap[map]))
10636cc410aSBob Copeland 		goto out;
10736cc410aSBob Copeland 
10836cc410aSBob Copeland 	if (sbi->s_bitmap_ino > 0) {
10936cc410aSBob Copeland 		bh = sb_bread(sb, clus_to_blk(sbi, sbi->s_bitmap_ino) + map);
11036cc410aSBob Copeland 		if (!bh)
11136cc410aSBob Copeland 			goto out;
11236cc410aSBob Copeland 
113d406f66dSHarvey Harrison 		set_bit(bit, (unsigned long *)bh->b_data);
11436cc410aSBob Copeland 		mark_buffer_dirty(bh);
11536cc410aSBob Copeland 		brelse(bh);
11636cc410aSBob Copeland 	}
11736cc410aSBob Copeland 	ret = 1;
11836cc410aSBob Copeland out:
11936cc410aSBob Copeland 	mutex_unlock(&sbi->s_bitmap_lock);
12036cc410aSBob Copeland 	return ret;
12136cc410aSBob Copeland }
12236cc410aSBob Copeland 
12336cc410aSBob Copeland 
12436cc410aSBob Copeland /*
12536cc410aSBob Copeland  *  Tries to allocate a set of blocks.	The request size depends on the
12636cc410aSBob Copeland  *  type: for inodes, we must allocate sbi->s_mirrors blocks, and for file
12736cc410aSBob Copeland  *  blocks, we try to allocate sbi->s_clustersize, but can always get away
12836cc410aSBob Copeland  *  with just one block.
12936cc410aSBob Copeland  */
omfs_allocate_range(struct super_block * sb,int min_request,int max_request,u64 * return_block,int * return_size)13036cc410aSBob Copeland int omfs_allocate_range(struct super_block *sb,
13136cc410aSBob Copeland 			int min_request,
13236cc410aSBob Copeland 			int max_request,
13336cc410aSBob Copeland 			u64 *return_block,
13436cc410aSBob Copeland 			int *return_size)
13536cc410aSBob Copeland {
13636cc410aSBob Copeland 	struct omfs_sb_info *sbi = OMFS_SB(sb);
13736cc410aSBob Copeland 	int bits_per_entry = 8 * sb->s_blocksize;
13836cc410aSBob Copeland 	int ret = 0;
13936cc410aSBob Copeland 	int i, run, bit;
14036cc410aSBob Copeland 
14136cc410aSBob Copeland 	mutex_lock(&sbi->s_bitmap_lock);
14236cc410aSBob Copeland 	for (i = 0; i < sbi->s_imap_size; i++) {
14336cc410aSBob Copeland 		bit = 0;
14436cc410aSBob Copeland 		while (bit < bits_per_entry) {
14536cc410aSBob Copeland 			bit = find_next_zero_bit(sbi->s_imap[i], bits_per_entry,
14636cc410aSBob Copeland 				bit);
14736cc410aSBob Copeland 
14836cc410aSBob Copeland 			if (bit == bits_per_entry)
14936cc410aSBob Copeland 				break;
15036cc410aSBob Copeland 
15136cc410aSBob Copeland 			run = count_run(&sbi->s_imap[i], bits_per_entry,
15236cc410aSBob Copeland 				sbi->s_imap_size-i, bit, max_request);
15336cc410aSBob Copeland 
15436cc410aSBob Copeland 			if (run >= min_request)
15536cc410aSBob Copeland 				goto found;
15636cc410aSBob Copeland 			bit += run;
15736cc410aSBob Copeland 		}
15836cc410aSBob Copeland 	}
15936cc410aSBob Copeland 	ret = -ENOSPC;
16036cc410aSBob Copeland 	goto out;
16136cc410aSBob Copeland 
16236cc410aSBob Copeland found:
1635a6b2b36SBob Copeland 	*return_block = (u64) i * bits_per_entry + bit;
16436cc410aSBob Copeland 	*return_size = run;
16536cc410aSBob Copeland 	ret = set_run(sb, i, bits_per_entry, bit, run, 1);
16636cc410aSBob Copeland 
16736cc410aSBob Copeland out:
16836cc410aSBob Copeland 	mutex_unlock(&sbi->s_bitmap_lock);
16936cc410aSBob Copeland 	return ret;
17036cc410aSBob Copeland }
17136cc410aSBob Copeland 
17236cc410aSBob Copeland /*
17336cc410aSBob Copeland  * Clears count bits starting at a given block.
17436cc410aSBob Copeland  */
omfs_clear_range(struct super_block * sb,u64 block,int count)17536cc410aSBob Copeland int omfs_clear_range(struct super_block *sb, u64 block, int count)
17636cc410aSBob Copeland {
17736cc410aSBob Copeland 	struct omfs_sb_info *sbi = OMFS_SB(sb);
17836cc410aSBob Copeland 	int bits_per_entry = 8 * sb->s_blocksize;
17936cc410aSBob Copeland 	u64 tmp;
1809419fc1cSBob Copeland 	unsigned int map, bit;
1819419fc1cSBob Copeland 	int ret;
18236cc410aSBob Copeland 
18336cc410aSBob Copeland 	tmp = block;
18436cc410aSBob Copeland 	bit = do_div(tmp, bits_per_entry);
18536cc410aSBob Copeland 	map = tmp;
18636cc410aSBob Copeland 
18736cc410aSBob Copeland 	if (map >= sbi->s_imap_size)
18836cc410aSBob Copeland 		return 0;
18936cc410aSBob Copeland 
19036cc410aSBob Copeland 	mutex_lock(&sbi->s_bitmap_lock);
19136cc410aSBob Copeland 	ret = set_run(sb, map, bits_per_entry, bit, count, 0);
19236cc410aSBob Copeland 	mutex_unlock(&sbi->s_bitmap_lock);
19336cc410aSBob Copeland 	return ret;
19436cc410aSBob Copeland }
195