Something went wrong. Try again.
(I'm so sorry!) Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195// SPDX-License-Identifier: GPL-2.0#include <linux/kernel.h>#include <linux/fs.h>#include <linux/buffer_head.h>#include <asm/div64.h>#include "omfs.h"
unsigned long omfs_count_free(struct super_block *sb){ unsigned int i; unsigned long sum = 0; struct omfs_sb_info *sbi = OMFS_SB(sb); int nbits = sb->s_blocksize * 8;
for (i = 0; i < sbi->s_imap_size; i++) sum += nbits - bitmap_weight(sbi->s_imap[i], nbits);
return sum;}
/* * Counts the run of zero bits starting at bit up to max. * It handles the case where a run might spill over a buffer. * Called with bitmap lock. */static int count_run(unsigned long **addr, int nbits, int addrlen, int bit, int max){ int count = 0; int x;
for (; addrlen > 0; addrlen--, addr++) { x = find_next_bit(*addr, nbits, bit); count += x - bit;
if (x < nbits || count > max) return min(count, max);
bit = 0; } return min(count, max);}
/* * Sets or clears the run of count bits starting with bit. * Called with bitmap lock. */static int set_run(struct super_block *sb, int map, int nbits, int bit, int count, int set){ int i; int err; struct buffer_head *bh; struct omfs_sb_info *sbi = OMFS_SB(sb);
err = -ENOMEM; bh = sb_bread(sb, clus_to_blk(sbi, sbi->s_bitmap_ino) + map); if (!bh) goto out;
for (i = 0; i < count; i++, bit++) { if (bit >= nbits) { bit = 0; map++;
mark_buffer_dirty(bh); brelse(bh); bh = sb_bread(sb, clus_to_blk(sbi, sbi->s_bitmap_ino) + map); if (!bh) goto out; } if (set) { set_bit(bit, sbi->s_imap[map]); set_bit(bit, (unsigned long *)bh->b_data); } else { clear_bit(bit, sbi->s_imap[map]); clear_bit(bit, (unsigned long *)bh->b_data); } } mark_buffer_dirty(bh); brelse(bh); err = 0;out: return err;}
/* * Tries to allocate exactly one block. Returns true if successful. */int omfs_allocate_block(struct super_block *sb, u64 block){ struct buffer_head *bh; struct omfs_sb_info *sbi = OMFS_SB(sb); int bits_per_entry = 8 * sb->s_blocksize; unsigned int map, bit; int ret = 0; u64 tmp;
tmp = block; bit = do_div(tmp, bits_per_entry); map = tmp;
mutex_lock(&sbi->s_bitmap_lock); if (map >= sbi->s_imap_size || test_and_set_bit(bit, sbi->s_imap[map])) goto out;
if (sbi->s_bitmap_ino > 0) { bh = sb_bread(sb, clus_to_blk(sbi, sbi->s_bitmap_ino) + map); if (!bh) goto out;
set_bit(bit, (unsigned long *)bh->b_data); mark_buffer_dirty(bh); brelse(bh); } ret = 1;out: mutex_unlock(&sbi->s_bitmap_lock); return ret;}
/* * Tries to allocate a set of blocks. The request size depends on the * type: for inodes, we must allocate sbi->s_mirrors blocks, and for file * blocks, we try to allocate sbi->s_clustersize, but can always get away * with just one block. */int omfs_allocate_range(struct super_block *sb, int min_request, int max_request, u64 *return_block, int *return_size){ struct omfs_sb_info *sbi = OMFS_SB(sb); int bits_per_entry = 8 * sb->s_blocksize; int ret = 0; int i, run, bit;
mutex_lock(&sbi->s_bitmap_lock); for (i = 0; i < sbi->s_imap_size; i++) { bit = 0; while (bit < bits_per_entry) { bit = find_next_zero_bit(sbi->s_imap[i], bits_per_entry, bit);
if (bit == bits_per_entry) break;
run = count_run(&sbi->s_imap[i], bits_per_entry, sbi->s_imap_size-i, bit, max_request);
if (run >= min_request) goto found; bit += run; } } ret = -ENOSPC; goto out;
found: *return_block = (u64) i * bits_per_entry + bit; *return_size = run; ret = set_run(sb, i, bits_per_entry, bit, run, 1);
out: mutex_unlock(&sbi->s_bitmap_lock); return ret;}
/* * Clears count bits starting at a given block. */int omfs_clear_range(struct super_block *sb, u64 block, int count){ struct omfs_sb_info *sbi = OMFS_SB(sb); int bits_per_entry = 8 * sb->s_blocksize; u64 tmp; unsigned int map, bit; int ret;
tmp = block; bit = do_div(tmp, bits_per_entry); map = tmp;
if (map >= sbi->s_imap_size) return 0;
mutex_lock(&sbi->s_bitmap_lock); ret = set_run(sb, map, bits_per_entry, bit, count, 0); mutex_unlock(&sbi->s_bitmap_lock); return ret;}