162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * linux/fs/hfs/bitmap.c 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 1996-1997 Paul H. Hargrove 562306a36Sopenharmony_ci * (C) 2003 Ardis Technologies <roman@ardistech.com> 662306a36Sopenharmony_ci * This file may be distributed under the terms of the GNU General Public License. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Based on GPLed code Copyright (C) 1995 Michael Dreher 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * This file contains the code to modify the volume bitmap: 1162306a36Sopenharmony_ci * search/set/clear bits. 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "hfs_fs.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci/* 1762306a36Sopenharmony_ci * hfs_find_zero_bit() 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * Description: 2062306a36Sopenharmony_ci * Given a block of memory, its length in bits, and a starting bit number, 2162306a36Sopenharmony_ci * determine the number of the first zero bits (in left-to-right ordering) 2262306a36Sopenharmony_ci * in that range. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * Returns >= 'size' if no zero bits are found in the range. 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * Accesses memory in 32-bit aligned chunks of 32-bits and thus 2762306a36Sopenharmony_ci * may read beyond the 'size'th bit. 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_cistatic u32 hfs_find_set_zero_bits(__be32 *bitmap, u32 size, u32 offset, u32 *max) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci __be32 *curr, *end; 3262306a36Sopenharmony_ci u32 mask, start, len, n; 3362306a36Sopenharmony_ci __be32 val; 3462306a36Sopenharmony_ci int i; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci len = *max; 3762306a36Sopenharmony_ci if (!len) 3862306a36Sopenharmony_ci return size; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci curr = bitmap + (offset / 32); 4162306a36Sopenharmony_ci end = bitmap + ((size + 31) / 32); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci /* scan the first partial u32 for zero bits */ 4462306a36Sopenharmony_ci val = *curr; 4562306a36Sopenharmony_ci if (~val) { 4662306a36Sopenharmony_ci n = be32_to_cpu(val); 4762306a36Sopenharmony_ci i = offset % 32; 4862306a36Sopenharmony_ci mask = (1U << 31) >> i; 4962306a36Sopenharmony_ci for (; i < 32; mask >>= 1, i++) { 5062306a36Sopenharmony_ci if (!(n & mask)) 5162306a36Sopenharmony_ci goto found; 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci /* scan complete u32s for the first zero bit */ 5662306a36Sopenharmony_ci while (++curr < end) { 5762306a36Sopenharmony_ci val = *curr; 5862306a36Sopenharmony_ci if (~val) { 5962306a36Sopenharmony_ci n = be32_to_cpu(val); 6062306a36Sopenharmony_ci mask = 1 << 31; 6162306a36Sopenharmony_ci for (i = 0; i < 32; mask >>= 1, i++) { 6262306a36Sopenharmony_ci if (!(n & mask)) 6362306a36Sopenharmony_ci goto found; 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci return size; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cifound: 7062306a36Sopenharmony_ci start = (curr - bitmap) * 32 + i; 7162306a36Sopenharmony_ci if (start >= size) 7262306a36Sopenharmony_ci return start; 7362306a36Sopenharmony_ci /* do any partial u32 at the start */ 7462306a36Sopenharmony_ci len = min(size - start, len); 7562306a36Sopenharmony_ci while (1) { 7662306a36Sopenharmony_ci n |= mask; 7762306a36Sopenharmony_ci if (++i >= 32) 7862306a36Sopenharmony_ci break; 7962306a36Sopenharmony_ci mask >>= 1; 8062306a36Sopenharmony_ci if (!--len || n & mask) 8162306a36Sopenharmony_ci goto done; 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci if (!--len) 8462306a36Sopenharmony_ci goto done; 8562306a36Sopenharmony_ci *curr++ = cpu_to_be32(n); 8662306a36Sopenharmony_ci /* do full u32s */ 8762306a36Sopenharmony_ci while (1) { 8862306a36Sopenharmony_ci n = be32_to_cpu(*curr); 8962306a36Sopenharmony_ci if (len < 32) 9062306a36Sopenharmony_ci break; 9162306a36Sopenharmony_ci if (n) { 9262306a36Sopenharmony_ci len = 32; 9362306a36Sopenharmony_ci break; 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci *curr++ = cpu_to_be32(0xffffffff); 9662306a36Sopenharmony_ci len -= 32; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci /* do any partial u32 at end */ 9962306a36Sopenharmony_ci mask = 1U << 31; 10062306a36Sopenharmony_ci for (i = 0; i < len; i++) { 10162306a36Sopenharmony_ci if (n & mask) 10262306a36Sopenharmony_ci break; 10362306a36Sopenharmony_ci n |= mask; 10462306a36Sopenharmony_ci mask >>= 1; 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_cidone: 10762306a36Sopenharmony_ci *curr = cpu_to_be32(n); 10862306a36Sopenharmony_ci *max = (curr - bitmap) * 32 + i - start; 10962306a36Sopenharmony_ci return start; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci/* 11362306a36Sopenharmony_ci * hfs_vbm_search_free() 11462306a36Sopenharmony_ci * 11562306a36Sopenharmony_ci * Description: 11662306a36Sopenharmony_ci * Search for 'num_bits' consecutive cleared bits in the bitmap blocks of 11762306a36Sopenharmony_ci * the hfs MDB. 'mdb' had better be locked or the returned range 11862306a36Sopenharmony_ci * may be no longer free, when this functions returns! 11962306a36Sopenharmony_ci * XXX Currently the search starts from bit 0, but it should start with 12062306a36Sopenharmony_ci * the bit number stored in 's_alloc_ptr' of the MDB. 12162306a36Sopenharmony_ci * Input Variable(s): 12262306a36Sopenharmony_ci * struct hfs_mdb *mdb: Pointer to the hfs MDB 12362306a36Sopenharmony_ci * u16 *num_bits: Pointer to the number of cleared bits 12462306a36Sopenharmony_ci * to search for 12562306a36Sopenharmony_ci * Output Variable(s): 12662306a36Sopenharmony_ci * u16 *num_bits: The number of consecutive clear bits of the 12762306a36Sopenharmony_ci * returned range. If the bitmap is fragmented, this will be less than 12862306a36Sopenharmony_ci * requested and it will be zero, when the disk is full. 12962306a36Sopenharmony_ci * Returns: 13062306a36Sopenharmony_ci * The number of the first bit of the range of cleared bits which has been 13162306a36Sopenharmony_ci * found. When 'num_bits' is zero, this is invalid! 13262306a36Sopenharmony_ci * Preconditions: 13362306a36Sopenharmony_ci * 'mdb' points to a "valid" (struct hfs_mdb). 13462306a36Sopenharmony_ci * 'num_bits' points to a variable of type (u16), which contains 13562306a36Sopenharmony_ci * the number of cleared bits to find. 13662306a36Sopenharmony_ci * Postconditions: 13762306a36Sopenharmony_ci * 'num_bits' is set to the length of the found sequence. 13862306a36Sopenharmony_ci */ 13962306a36Sopenharmony_ciu32 hfs_vbm_search_free(struct super_block *sb, u32 goal, u32 *num_bits) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci void *bitmap; 14262306a36Sopenharmony_ci u32 pos; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci /* make sure we have actual work to perform */ 14562306a36Sopenharmony_ci if (!*num_bits) 14662306a36Sopenharmony_ci return 0; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci mutex_lock(&HFS_SB(sb)->bitmap_lock); 14962306a36Sopenharmony_ci bitmap = HFS_SB(sb)->bitmap; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci pos = hfs_find_set_zero_bits(bitmap, HFS_SB(sb)->fs_ablocks, goal, num_bits); 15262306a36Sopenharmony_ci if (pos >= HFS_SB(sb)->fs_ablocks) { 15362306a36Sopenharmony_ci if (goal) 15462306a36Sopenharmony_ci pos = hfs_find_set_zero_bits(bitmap, goal, 0, num_bits); 15562306a36Sopenharmony_ci if (pos >= HFS_SB(sb)->fs_ablocks) { 15662306a36Sopenharmony_ci *num_bits = pos = 0; 15762306a36Sopenharmony_ci goto out; 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci hfs_dbg(BITMAP, "alloc_bits: %u,%u\n", pos, *num_bits); 16262306a36Sopenharmony_ci HFS_SB(sb)->free_ablocks -= *num_bits; 16362306a36Sopenharmony_ci hfs_bitmap_dirty(sb); 16462306a36Sopenharmony_ciout: 16562306a36Sopenharmony_ci mutex_unlock(&HFS_SB(sb)->bitmap_lock); 16662306a36Sopenharmony_ci return pos; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci/* 17162306a36Sopenharmony_ci * hfs_clear_vbm_bits() 17262306a36Sopenharmony_ci * 17362306a36Sopenharmony_ci * Description: 17462306a36Sopenharmony_ci * Clear the requested bits in the volume bitmap of the hfs filesystem 17562306a36Sopenharmony_ci * Input Variable(s): 17662306a36Sopenharmony_ci * struct hfs_mdb *mdb: Pointer to the hfs MDB 17762306a36Sopenharmony_ci * u16 start: The offset of the first bit 17862306a36Sopenharmony_ci * u16 count: The number of bits 17962306a36Sopenharmony_ci * Output Variable(s): 18062306a36Sopenharmony_ci * None 18162306a36Sopenharmony_ci * Returns: 18262306a36Sopenharmony_ci * 0: no error 18362306a36Sopenharmony_ci * -1: One of the bits was already clear. This is a strange 18462306a36Sopenharmony_ci * error and when it happens, the filesystem must be repaired! 18562306a36Sopenharmony_ci * -2: One or more of the bits are out of range of the bitmap. 18662306a36Sopenharmony_ci * Preconditions: 18762306a36Sopenharmony_ci * 'mdb' points to a "valid" (struct hfs_mdb). 18862306a36Sopenharmony_ci * Postconditions: 18962306a36Sopenharmony_ci * Starting with bit number 'start', 'count' bits in the volume bitmap 19062306a36Sopenharmony_ci * are cleared. The affected bitmap blocks are marked "dirty", the free 19162306a36Sopenharmony_ci * block count of the MDB is updated and the MDB is marked dirty. 19262306a36Sopenharmony_ci */ 19362306a36Sopenharmony_ciint hfs_clear_vbm_bits(struct super_block *sb, u16 start, u16 count) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci __be32 *curr; 19662306a36Sopenharmony_ci u32 mask; 19762306a36Sopenharmony_ci int i, len; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci /* is there any actual work to be done? */ 20062306a36Sopenharmony_ci if (!count) 20162306a36Sopenharmony_ci return 0; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci hfs_dbg(BITMAP, "clear_bits: %u,%u\n", start, count); 20462306a36Sopenharmony_ci /* are all of the bits in range? */ 20562306a36Sopenharmony_ci if ((start + count) > HFS_SB(sb)->fs_ablocks) 20662306a36Sopenharmony_ci return -2; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci mutex_lock(&HFS_SB(sb)->bitmap_lock); 20962306a36Sopenharmony_ci /* bitmap is always on a 32-bit boundary */ 21062306a36Sopenharmony_ci curr = HFS_SB(sb)->bitmap + (start / 32); 21162306a36Sopenharmony_ci len = count; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci /* do any partial u32 at the start */ 21462306a36Sopenharmony_ci i = start % 32; 21562306a36Sopenharmony_ci if (i) { 21662306a36Sopenharmony_ci int j = 32 - i; 21762306a36Sopenharmony_ci mask = 0xffffffffU << j; 21862306a36Sopenharmony_ci if (j > count) { 21962306a36Sopenharmony_ci mask |= 0xffffffffU >> (i + count); 22062306a36Sopenharmony_ci *curr &= cpu_to_be32(mask); 22162306a36Sopenharmony_ci goto out; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci *curr++ &= cpu_to_be32(mask); 22462306a36Sopenharmony_ci count -= j; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci /* do full u32s */ 22862306a36Sopenharmony_ci while (count >= 32) { 22962306a36Sopenharmony_ci *curr++ = 0; 23062306a36Sopenharmony_ci count -= 32; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci /* do any partial u32 at end */ 23362306a36Sopenharmony_ci if (count) { 23462306a36Sopenharmony_ci mask = 0xffffffffU >> count; 23562306a36Sopenharmony_ci *curr &= cpu_to_be32(mask); 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ciout: 23862306a36Sopenharmony_ci HFS_SB(sb)->free_ablocks += len; 23962306a36Sopenharmony_ci mutex_unlock(&HFS_SB(sb)->bitmap_lock); 24062306a36Sopenharmony_ci hfs_bitmap_dirty(sb); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci return 0; 24362306a36Sopenharmony_ci} 244