📄 balloc.c
字号:
/* * linux/fs/ufs/balloc.c * * Copyright (C) 1998 * Daniel Pirkl <daniel.pirkl@email.cz> * Charles University, Faculty of Mathematics and Physics */#include <linux/fs.h>#include <linux/ufs_fs.h>#include <linux/stat.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/locks.h>#include <linux/quotaops.h>#include <asm/bitops.h>#include <asm/byteorder.h>#include "swab.h"#include "util.h"#undef UFS_BALLOC_DEBUG#ifdef UFS_BALLOC_DEBUG#define UFSD(x) printk("(%s, %d), %s:", __FILE__, __LINE__, __FUNCTION__); printk x;#else#define UFSD(x)#endifunsigned ufs_add_fragments (struct inode *, unsigned, unsigned, unsigned, int *);unsigned ufs_alloc_fragments (struct inode *, unsigned, unsigned, unsigned, int *);unsigned ufs_alloccg_block (struct inode *, struct ufs_cg_private_info *, unsigned, int *);unsigned ufs_bitmap_search (struct super_block *, struct ufs_cg_private_info *, unsigned, unsigned);static unsigned char ufs_fragtable_8fpb[], ufs_fragtable_other[];void ufs_clusteracct(struct super_block *, struct ufs_cg_private_info *, unsigned, int);/* * Free 'count' fragments from fragment number 'fragment' */void ufs_free_fragments (struct inode * inode, unsigned fragment, unsigned count) { struct super_block * sb; struct ufs_sb_private_info * uspi; struct ufs_super_block_first * usb1; struct ufs_cg_private_info * ucpi; struct ufs_cylinder_group * ucg; unsigned cgno, bit, end_bit, bbase, blkmap, i, blkno, cylno; sb = inode->i_sb; uspi = sb->u.ufs_sb.s_uspi; usb1 = ubh_get_usb_first(USPI_UBH); UFSD(("ENTER, fragment %u, count %u\n", fragment, count)) if (ufs_fragnum(fragment) + count > uspi->s_fpg) ufs_error (sb, "ufs_free_fragments", "internal error"); lock_super(sb); cgno = ufs_dtog(fragment); bit = ufs_dtogd(fragment); if (cgno >= uspi->s_ncg) { ufs_panic (sb, "ufs_free_fragments", "freeing blocks are outside device"); goto failed; } ucpi = ufs_load_cylinder (sb, cgno); if (!ucpi) goto failed; ucg = ubh_get_ucg (UCPI_UBH); if (!ufs_cg_chkmagic(sb, ucg)) { ufs_panic (sb, "ufs_free_fragments", "internal error, bad magic number on cg %u", cgno); goto failed; } end_bit = bit + count; bbase = ufs_blknum (bit); blkmap = ubh_blkmap (UCPI_UBH, ucpi->c_freeoff, bbase); ufs_fragacct (sb, blkmap, ucg->cg_frsum, -1); for (i = bit; i < end_bit; i++) { if (ubh_isclr (UCPI_UBH, ucpi->c_freeoff, i)) ubh_setbit (UCPI_UBH, ucpi->c_freeoff, i); else ufs_error (sb, "ufs_free_fragments", "bit already cleared for fragment %u", i); } DQUOT_FREE_BLOCK (inode, count); fs32_add(sb, &ucg->cg_cs.cs_nffree, count); fs32_add(sb, &usb1->fs_cstotal.cs_nffree, count); fs32_add(sb, &sb->fs_cs(cgno).cs_nffree, count); blkmap = ubh_blkmap (UCPI_UBH, ucpi->c_freeoff, bbase); ufs_fragacct(sb, blkmap, ucg->cg_frsum, 1); /* * Trying to reassemble free fragments into block */ blkno = ufs_fragstoblks (bbase); if (ubh_isblockset(UCPI_UBH, ucpi->c_freeoff, blkno)) { fs32_sub(sb, &ucg->cg_cs.cs_nffree, uspi->s_fpb); fs32_sub(sb, &usb1->fs_cstotal.cs_nffree, uspi->s_fpb); fs32_sub(sb, &sb->fs_cs(cgno).cs_nffree, uspi->s_fpb); if ((sb->u.ufs_sb.s_flags & UFS_CG_MASK) == UFS_CG_44BSD) ufs_clusteracct (sb, ucpi, blkno, 1); fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1); fs32_add(sb, &usb1->fs_cstotal.cs_nbfree, 1); fs32_add(sb, &sb->fs_cs(cgno).cs_nbfree, 1); cylno = ufs_cbtocylno (bbase); fs16_add(sb, &ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(bbase)), 1); fs32_add(sb, &ubh_cg_blktot(ucpi, cylno), 1); } ubh_mark_buffer_dirty (USPI_UBH); ubh_mark_buffer_dirty (UCPI_UBH); if (sb->s_flags & MS_SYNCHRONOUS) { ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi); ubh_wait_on_buffer (UCPI_UBH); } sb->s_dirt = 1; unlock_super (sb); UFSD(("EXIT\n")) return;failed: unlock_super (sb); UFSD(("EXIT (FAILED)\n")) return;}/* * Free 'count' fragments from fragment number 'fragment' (free whole blocks) */void ufs_free_blocks (struct inode * inode, unsigned fragment, unsigned count) { struct super_block * sb; struct ufs_sb_private_info * uspi; struct ufs_super_block_first * usb1; struct ufs_cg_private_info * ucpi; struct ufs_cylinder_group * ucg; unsigned overflow, cgno, bit, end_bit, blkno, i, cylno; sb = inode->i_sb; uspi = sb->u.ufs_sb.s_uspi; usb1 = ubh_get_usb_first(USPI_UBH); UFSD(("ENTER, fragment %u, count %u\n", fragment, count)) if ((fragment & uspi->s_fpbmask) || (count & uspi->s_fpbmask)) { ufs_error (sb, "ufs_free_blocks", "internal error, " "fragment %u, count %u\n", fragment, count); goto failed; } lock_super(sb); do_more: overflow = 0; cgno = ufs_dtog (fragment); bit = ufs_dtogd (fragment); if (cgno >= uspi->s_ncg) { ufs_panic (sb, "ufs_free_blocks", "freeing blocks are outside device"); goto failed; } end_bit = bit + count; if (end_bit > uspi->s_fpg) { overflow = bit + count - uspi->s_fpg; count -= overflow; end_bit -= overflow; } ucpi = ufs_load_cylinder (sb, cgno); if (!ucpi) goto failed; ucg = ubh_get_ucg (UCPI_UBH); if (!ufs_cg_chkmagic(sb, ucg)) { ufs_panic (sb, "ufs_free_blocks", "internal error, bad magic number on cg %u", cgno); goto failed; } for (i = bit; i < end_bit; i += uspi->s_fpb) { blkno = ufs_fragstoblks(i); if (ubh_isblockset(UCPI_UBH, ucpi->c_freeoff, blkno)) { ufs_error(sb, "ufs_free_blocks", "freeing free fragment"); } ubh_setblock(UCPI_UBH, ucpi->c_freeoff, blkno); if ((sb->u.ufs_sb.s_flags & UFS_CG_MASK) == UFS_CG_44BSD) ufs_clusteracct (sb, ucpi, blkno, 1); DQUOT_FREE_BLOCK(inode, uspi->s_fpb); fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1); fs32_add(sb, &usb1->fs_cstotal.cs_nbfree, 1); fs32_add(sb, &sb->fs_cs(cgno).cs_nbfree, 1); cylno = ufs_cbtocylno(i); fs16_add(sb, &ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(i)), 1); fs32_add(sb, &ubh_cg_blktot(ucpi, cylno), 1); } ubh_mark_buffer_dirty (USPI_UBH); ubh_mark_buffer_dirty (UCPI_UBH); if (sb->s_flags & MS_SYNCHRONOUS) { ubh_ll_rw_block (WRITE, 1, (struct ufs_buffer_head **)&ucpi); ubh_wait_on_buffer (UCPI_UBH); } if (overflow) { fragment += count; count = overflow; goto do_more; } sb->s_dirt = 1; unlock_super (sb); UFSD(("EXIT\n")) return;failed: unlock_super (sb); UFSD(("EXIT (FAILED)\n")) return;}#define NULLIFY_FRAGMENTS \ for (i = oldcount; i < newcount; i++) { \ bh = sb_getblk(sb, result + i); \ memset (bh->b_data, 0, sb->s_blocksize); \ mark_buffer_uptodate(bh, 1); \ mark_buffer_dirty (bh); \ if (IS_SYNC(inode)) { \ ll_rw_block (WRITE, 1, &bh); \ wait_on_buffer (bh); \ } \ brelse (bh); \ }unsigned ufs_new_fragments (struct inode * inode, u32 * p, unsigned fragment, unsigned goal, unsigned count, int * err ){ struct super_block * sb; struct ufs_sb_private_info * uspi; struct ufs_super_block_first * usb1; struct buffer_head * bh; unsigned cgno, oldcount, newcount, tmp, request, i, result; UFSD(("ENTER, ino %lu, fragment %u, goal %u, count %u\n", inode->i_ino, fragment, goal, count)) sb = inode->i_sb; uspi = sb->u.ufs_sb.s_uspi; usb1 = ubh_get_usb_first(USPI_UBH); *err = -ENOSPC; lock_super (sb); tmp = fs32_to_cpu(sb, *p); if (count + ufs_fragnum(fragment) > uspi->s_fpb) { ufs_warning (sb, "ufs_new_fragments", "internal warning" " fragment %u, count %u", fragment, count); count = uspi->s_fpb - ufs_fragnum(fragment); } oldcount = ufs_fragnum (fragment); newcount = oldcount + count; /* * Somebody else has just allocated our fragments */ if (oldcount) { if (!tmp) { ufs_error (sb, "ufs_new_fragments", "internal error, " "fragment %u, tmp %u\n", fragment, tmp); unlock_super (sb); return (unsigned)-1; } if (fragment < inode->u.ufs_i.i_lastfrag) { UFSD(("EXIT (ALREADY ALLOCATED)\n")) unlock_super (sb); return 0; } } else { if (tmp) { UFSD(("EXIT (ALREADY ALLOCATED)\n")) unlock_super(sb); return 0; } } /* * There is not enough space for user on the device */ if (!capable(CAP_SYS_RESOURCE) && ufs_freespace(usb1, UFS_MINFREE) <= 0) { unlock_super (sb); UFSD(("EXIT (FAILED)\n")) return 0; } if (goal >= uspi->s_size) goal = 0; if (goal == 0) cgno = ufs_inotocg (inode->i_ino); else cgno = ufs_dtog (goal); /* * allocate new fragment */ if (oldcount == 0) { result = ufs_alloc_fragments (inode, cgno, goal, count, err); if (result) { *p = cpu_to_fs32(sb, result); *err = 0; inode->i_blocks += count << uspi->s_nspfshift; inode->u.ufs_i.i_lastfrag = max_t(u32, inode->u.ufs_i.i_lastfrag, fragment + count); NULLIFY_FRAGMENTS } unlock_super(sb); UFSD(("EXIT, result %u\n", result)) return result; } /* * resize block */ result = ufs_add_fragments (inode, tmp, oldcount, newcount, err); if (result) { *err = 0; inode->i_blocks += count << uspi->s_nspfshift; inode->u.ufs_i.i_lastfrag = max_t(u32, inode->u.ufs_i.i_lastfrag, fragment + count); NULLIFY_FRAGMENTS unlock_super(sb); UFSD(("EXIT, result %u\n", result)) return result; } /* * allocate new block and move data */ switch (fs32_to_cpu(sb, usb1->fs_optim)) { case UFS_OPTSPACE: request = newcount; if (uspi->s_minfree < 5 || fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree) > uspi->s_dsize * uspi->s_minfree / (2 * 100) ) break; usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME); break; default: usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME); case UFS_OPTTIME: request = uspi->s_fpb; if (fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree) < uspi->s_dsize * (uspi->s_minfree - 2) / 100) break; usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME); break; } result = ufs_alloc_fragments (inode, cgno, goal, request, err); if (result) { for (i = 0; i < oldcount; i++) { bh = sb_bread(sb, tmp + i); if(bh) { mark_buffer_clean (bh); bh->b_blocknr = result + i; mark_buffer_dirty (bh); if (IS_SYNC(inode)) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); } brelse (bh); } else { printk(KERN_ERR "ufs_new_fragments: bread fail\n"); return 0; } } *p = cpu_to_fs32(sb, result); *err = 0; inode->i_blocks += count << uspi->s_nspfshift; inode->u.ufs_i.i_lastfrag = max_t(u32, inode->u.ufs_i.i_lastfrag, fragment + count); NULLIFY_FRAGMENTS unlock_super(sb); if (newcount < request) ufs_free_fragments (inode, result + newcount, request - newcount); ufs_free_fragments (inode, tmp, oldcount); UFSD(("EXIT, result %u\n", result)) return result; } unlock_super(sb); UFSD(("EXIT (FAILED)\n")) return 0;} unsigned ufs_add_fragments (struct inode * inode, unsigned fragment, unsigned oldcount, unsigned newcount, int * err){ struct super_block * sb; struct ufs_sb_private_info * uspi; struct ufs_super_block_first * usb1; struct ufs_cg_private_info * ucpi; struct ufs_cylinder_group * ucg; unsigned cgno, fragno, fragoff, count, fragsize, i; UFSD(("ENTER, fragment %u, oldcount %u, newcount %u\n", fragment, oldcount, newcount)) sb = inode->i_sb;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -