📄 balloc.c
字号:
/* * balloc.c * * PURPOSE * Block allocation handling routines for the OSTA-UDF(tm) filesystem. * * COPYRIGHT * This file is distributed under the terms of the GNU General Public * License (GPL). Copies of the GPL can be obtained from: * ftp://prep.ai.mit.edu/pub/gnu/GPL * Each contributing author retains all rights to their own work. * * (C) 1999-2001 Ben Fennema * (C) 1999 Stelias Computing Inc * * HISTORY * * 02/24/99 blf Created. * */#include "udfdecl.h"#include <linux/quotaops.h>#include <linux/buffer_head.h>#include <linux/bitops.h>#include "udf_i.h"#include "udf_sb.h"#define udf_clear_bit(nr,addr) ext2_clear_bit(nr,addr)#define udf_set_bit(nr,addr) ext2_set_bit(nr,addr)#define udf_test_bit(nr, addr) ext2_test_bit(nr, addr)#define udf_find_first_one_bit(addr, size) find_first_one_bit(addr, size)#define udf_find_next_one_bit(addr, size, offset) find_next_one_bit(addr, size, offset)#define leBPL_to_cpup(x) leNUM_to_cpup(BITS_PER_LONG, x)#define leNUM_to_cpup(x,y) xleNUM_to_cpup(x,y)#define xleNUM_to_cpup(x,y) (le ## x ## _to_cpup(y))#define uintBPL_t uint(BITS_PER_LONG)#define uint(x) xuint(x)#define xuint(x) __le ## xstatic inline int find_next_one_bit(void *addr, int size, int offset){ uintBPL_t *p = ((uintBPL_t *) addr) + (offset / BITS_PER_LONG); int result = offset & ~(BITS_PER_LONG - 1); unsigned long tmp; if (offset >= size) return size; size -= result; offset &= (BITS_PER_LONG - 1); if (offset) { tmp = leBPL_to_cpup(p++); tmp &= ~0UL << offset; if (size < BITS_PER_LONG) goto found_first; if (tmp) goto found_middle; size -= BITS_PER_LONG; result += BITS_PER_LONG; } while (size & ~(BITS_PER_LONG - 1)) { if ((tmp = leBPL_to_cpup(p++))) goto found_middle; result += BITS_PER_LONG; size -= BITS_PER_LONG; } if (!size) return result; tmp = leBPL_to_cpup(p);found_first: tmp &= ~0UL >> (BITS_PER_LONG - size);found_middle: return result + ffz(~tmp);}#define find_first_one_bit(addr, size)\ find_next_one_bit((addr), (size), 0)static int read_block_bitmap(struct super_block *sb, struct udf_bitmap *bitmap, unsigned int block, unsigned long bitmap_nr){ struct buffer_head *bh = NULL; int retval = 0; kernel_lb_addr loc; loc.logicalBlockNum = bitmap->s_extPosition; loc.partitionReferenceNum = UDF_SB_PARTITION(sb); bh = udf_tread(sb, udf_get_lb_pblock(sb, loc, block)); if (!bh) { retval = -EIO; } bitmap->s_block_bitmap[bitmap_nr] = bh; return retval;}static int __load_block_bitmap(struct super_block *sb, struct udf_bitmap *bitmap, unsigned int block_group){ int retval = 0; int nr_groups = bitmap->s_nr_groups; if (block_group >= nr_groups) { udf_debug("block_group (%d) > nr_groups (%d)\n", block_group, nr_groups); } if (bitmap->s_block_bitmap[block_group]) { return block_group; } else { retval = read_block_bitmap(sb, bitmap, block_group, block_group); if (retval < 0) return retval; return block_group; }}static inline int load_block_bitmap(struct super_block *sb, struct udf_bitmap *bitmap, unsigned int block_group){ int slot; slot = __load_block_bitmap(sb, bitmap, block_group); if (slot < 0) return slot; if (!bitmap->s_block_bitmap[slot]) return -EIO; return slot;}static void udf_bitmap_free_blocks(struct super_block *sb, struct inode *inode, struct udf_bitmap *bitmap, kernel_lb_addr bloc, uint32_t offset, uint32_t count){ struct udf_sb_info *sbi = UDF_SB(sb); struct buffer_head *bh = NULL; unsigned long block; unsigned long block_group; unsigned long bit; unsigned long i; int bitmap_nr; unsigned long overflow; mutex_lock(&sbi->s_alloc_mutex); if (bloc.logicalBlockNum < 0 || (bloc.logicalBlockNum + count) > UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum)) { udf_debug("%d < %d || %d + %d > %d\n", bloc.logicalBlockNum, 0, bloc.logicalBlockNum, count, UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum)); goto error_return; } block = bloc.logicalBlockNum + offset + (sizeof(struct spaceBitmapDesc) << 3);do_more: overflow = 0; block_group = block >> (sb->s_blocksize_bits + 3); bit = block % (sb->s_blocksize << 3); /* * Check to see if we are freeing blocks across a group boundary. */ if (bit + count > (sb->s_blocksize << 3)) { overflow = bit + count - (sb->s_blocksize << 3); count -= overflow; } bitmap_nr = load_block_bitmap(sb, bitmap, block_group); if (bitmap_nr < 0) goto error_return; bh = bitmap->s_block_bitmap[bitmap_nr]; for (i = 0; i < count; i++) { if (udf_set_bit(bit + i, bh->b_data)) { udf_debug("bit %ld already set\n", bit + i); udf_debug("byte=%2x\n", ((char *)bh->b_data)[(bit + i) >> 3]); } else { if (inode) DQUOT_FREE_BLOCK(inode, 1); if (UDF_SB_LVIDBH(sb)) { UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)] = cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)]) + 1); } } } mark_buffer_dirty(bh); if (overflow) { block += count; count = overflow; goto do_more; }error_return: sb->s_dirt = 1; if (UDF_SB_LVIDBH(sb)) mark_buffer_dirty(UDF_SB_LVIDBH(sb)); mutex_unlock(&sbi->s_alloc_mutex); return;}static int udf_bitmap_prealloc_blocks(struct super_block *sb, struct inode *inode, struct udf_bitmap *bitmap, uint16_t partition, uint32_t first_block, uint32_t block_count){ struct udf_sb_info *sbi = UDF_SB(sb); int alloc_count = 0; int bit, block, block_group, group_start; int nr_groups, bitmap_nr; struct buffer_head *bh; mutex_lock(&sbi->s_alloc_mutex); if (first_block < 0 || first_block >= UDF_SB_PARTLEN(sb, partition)) goto out; if (first_block + block_count > UDF_SB_PARTLEN(sb, partition)) block_count = UDF_SB_PARTLEN(sb, partition) - first_block;repeat: nr_groups = (UDF_SB_PARTLEN(sb, partition) + (sizeof(struct spaceBitmapDesc) << 3) + (sb->s_blocksize * 8) - 1) / (sb->s_blocksize * 8); block = first_block + (sizeof(struct spaceBitmapDesc) << 3); block_group = block >> (sb->s_blocksize_bits + 3); group_start = block_group ? 0 : sizeof(struct spaceBitmapDesc); bitmap_nr = load_block_bitmap(sb, bitmap, block_group); if (bitmap_nr < 0) goto out; bh = bitmap->s_block_bitmap[bitmap_nr]; bit = block % (sb->s_blocksize << 3); while (bit < (sb->s_blocksize << 3) && block_count > 0) { if (!udf_test_bit(bit, bh->b_data)) { goto out; } else if (DQUOT_PREALLOC_BLOCK(inode, 1)) { goto out; } else if (!udf_clear_bit(bit, bh->b_data)) { udf_debug("bit already cleared for block %d\n", bit); DQUOT_FREE_BLOCK(inode, 1); goto out; } block_count--; alloc_count++; bit++; block++; } mark_buffer_dirty(bh); if (block_count > 0) goto repeat;out: if (UDF_SB_LVIDBH(sb)) { UDF_SB_LVID(sb)->freeSpaceTable[partition] = cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition]) - alloc_count); mark_buffer_dirty(UDF_SB_LVIDBH(sb)); } sb->s_dirt = 1; mutex_unlock(&sbi->s_alloc_mutex); return alloc_count;}static int udf_bitmap_new_block(struct super_block *sb, struct inode *inode, struct udf_bitmap *bitmap, uint16_t partition, uint32_t goal, int *err){ struct udf_sb_info *sbi = UDF_SB(sb); int newbit, bit = 0, block, block_group, group_start; int end_goal, nr_groups, bitmap_nr, i; struct buffer_head *bh = NULL; char *ptr; int newblock = 0; *err = -ENOSPC; mutex_lock(&sbi->s_alloc_mutex);repeat: if (goal < 0 || goal >= UDF_SB_PARTLEN(sb, partition)) goal = 0; nr_groups = bitmap->s_nr_groups; block = goal + (sizeof(struct spaceBitmapDesc) << 3); block_group = block >> (sb->s_blocksize_bits + 3); group_start = block_group ? 0 : sizeof(struct spaceBitmapDesc); bitmap_nr = load_block_bitmap(sb, bitmap, block_group); if (bitmap_nr < 0) goto error_return; bh = bitmap->s_block_bitmap[bitmap_nr]; ptr = memscan((char *)bh->b_data + group_start, 0xFF, sb->s_blocksize - group_start); if ((ptr - ((char *)bh->b_data)) < sb->s_blocksize) { bit = block % (sb->s_blocksize << 3); if (udf_test_bit(bit, bh->b_data)) goto got_block; end_goal = (bit + 63) & ~63; bit = udf_find_next_one_bit(bh->b_data, end_goal, bit); if (bit < end_goal) goto got_block; ptr = memscan((char *)bh->b_data + (bit >> 3), 0xFF, sb->s_blocksize - ((bit + 7) >> 3)); newbit = (ptr - ((char *)bh->b_data)) << 3; if (newbit < sb->s_blocksize << 3) { bit = newbit; goto search_back; } newbit = udf_find_next_one_bit(bh->b_data, sb->s_blocksize << 3, bit); if (newbit < sb->s_blocksize << 3) { bit = newbit; goto got_block; } } for (i = 0; i < (nr_groups * 2); i++) { block_group++; if (block_group >= nr_groups) block_group = 0; group_start = block_group ? 0 : sizeof(struct spaceBitmapDesc); bitmap_nr = load_block_bitmap(sb, bitmap, block_group); if (bitmap_nr < 0) goto error_return; bh = bitmap->s_block_bitmap[bitmap_nr]; if (i < nr_groups) { ptr = memscan((char *)bh->b_data + group_start, 0xFF, sb->s_blocksize - group_start); if ((ptr - ((char *)bh->b_data)) < sb->s_blocksize) { bit = (ptr - ((char *)bh->b_data)) << 3; break; } } else { bit = udf_find_next_one_bit((char *)bh->b_data, sb->s_blocksize << 3, group_start << 3); if (bit < sb->s_blocksize << 3) break; } } if (i >= (nr_groups * 2)) { mutex_unlock(&sbi->s_alloc_mutex); return newblock; } if (bit < sb->s_blocksize << 3) goto search_back; else bit = udf_find_next_one_bit(bh->b_data, sb->s_blocksize << 3, group_start << 3); if (bit >= sb->s_blocksize << 3) { mutex_unlock(&sbi->s_alloc_mutex); return 0; }search_back: for (i = 0; i < 7 && bit > (group_start << 3) && udf_test_bit(bit - 1, bh->b_data); i++, bit--) ; /* empty loop */got_block: /* * Check quota for allocation of this block. */ if (inode && DQUOT_ALLOC_BLOCK(inode, 1)) { mutex_unlock(&sbi->s_alloc_mutex); *err = -EDQUOT; return 0; } newblock = bit + (block_group << (sb->s_blocksize_bits + 3)) - (sizeof(struct spaceBitmapDesc) << 3); if (!udf_clear_bit(bit, bh->b_data)) { udf_debug("bit already cleared for block %d\n", bit); goto repeat; } mark_buffer_dirty(bh); if (UDF_SB_LVIDBH(sb)) { UDF_SB_LVID(sb)->freeSpaceTable[partition] = cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition]) - 1); mark_buffer_dirty(UDF_SB_LVIDBH(sb)); } sb->s_dirt = 1; mutex_unlock(&sbi->s_alloc_mutex); *err = 0; return newblock;error_return: *err = -EIO; mutex_unlock(&sbi->s_alloc_mutex); return 0;}static void udf_table_free_blocks(struct super_block *sb, struct inode *inode, struct inode *table, kernel_lb_addr bloc, uint32_t offset, uint32_t count){ struct udf_sb_info *sbi = UDF_SB(sb); uint32_t start, end; uint32_t elen; kernel_lb_addr eloc; struct extent_position oepos, epos; int8_t etype; int i; mutex_lock(&sbi->s_alloc_mutex); if (bloc.logicalBlockNum < 0 || (bloc.logicalBlockNum + count) > UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum)) { udf_debug("%d < %d || %d + %d > %d\n", bloc.logicalBlockNum, 0, bloc.logicalBlockNum, count, UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum)); goto error_return; } /* We do this up front - There are some error conditions that could occure, but.. oh well */ if (inode) DQUOT_FREE_BLOCK(inode, count);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -