bitmap.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,146 行 · 第 1/3 页

C
1,146
字号
    }}  static void determine_search_start(reiserfs_blocknr_hint_t *hint,					  int amount_needed){    struct super_block *s = hint->th->t_super;    int unfm_hint;    hint->beg = 0;    hint->end = SB_BLOCK_COUNT(s) - 1;    /* This is former border algorithm. Now with tunable border offset */    if (concentrating_formatted_nodes(s))	set_border_in_hint(s, hint);#ifdef DISPLACE_NEW_PACKING_LOCALITIES    /* whenever we create a new directory, we displace it.  At first we will       hash for location, later we might look for a moderately empty place for       it */    if (displacing_new_packing_localities(s)	&& hint->th->displace_new_blocks) {	displace_new_packing_locality(hint);	/* we do not continue determine_search_start,	 * if new packing locality is being displaced */	return;    }				      #endif      /* all persons should feel encouraged to add more special cases here and     * test them */    if (displacing_large_files(s) && !hint->formatted_node	&& this_blocknr_allocation_would_make_it_a_large_file(hint)) {	displace_large_file(hint);	return;    }    /* if none of our special cases is relevant, use the left neighbor in the       tree order of the new node we are allocating for */    if (hint->formatted_node && TEST_OPTION(hashed_formatted_nodes,s)) {        hash_formatted_node(hint);	return;    }    unfm_hint = get_left_neighbor(hint);    /* Mimic old block allocator behaviour, that is if VFS allowed for preallocation,       new blocks are displaced based on directory ID. Also, if suggested search_start       is less than last preallocated block, we start searching from it, assuming that       HDD dataflow is faster in forward direction */    if ( TEST_OPTION(old_way, s)) {	if (!hint->formatted_node) {	    if ( !reiserfs_hashed_relocation(s))		old_way(hint);	    else if (!reiserfs_no_unhashed_relocation(s))		old_hashed_relocation(hint);	    if ( hint->inode && hint->search_start < REISERFS_I(hint->inode)->i_prealloc_block)		hint->search_start = REISERFS_I(hint->inode)->i_prealloc_block;	}	return;    }    /* This is an approach proposed by Hans */    if ( TEST_OPTION(hundredth_slices, s) && ! (displacing_large_files(s) && !hint->formatted_node)) {	hundredth_slices(hint);	return;    }    /* old_hashed_relocation only works on unformatted */    if (!unfm_hint && !hint->formatted_node &&        TEST_OPTION(old_hashed_relocation, s))    {	old_hashed_relocation(hint);    }    /* new_hashed_relocation works with both formatted/unformatted nodes */    if ((!unfm_hint || hint->formatted_node) &&        TEST_OPTION(new_hashed_relocation, s))    {	new_hashed_relocation(hint);    }    /* dirid grouping works only on unformatted nodes */    if (!unfm_hint && !hint->formatted_node && TEST_OPTION(dirid_groups,s))    {        dirid_groups(hint);    }#ifdef DISPLACE_NEW_PACKING_LOCALITIES    if (hint->formatted_node && TEST_OPTION(dirid_groups,s))    {        dirid_groups(hint);    }#endif    /* oid grouping works only on unformatted nodes */    if (!unfm_hint && !hint->formatted_node && TEST_OPTION(oid_groups,s))    {        oid_groups(hint);    }    return;}static int determine_prealloc_size(reiserfs_blocknr_hint_t * hint){    /* make minimum size a mount option and benchmark both ways */    /* we preallocate blocks only for regular files, specific size */    /* benchmark preallocating always and see what happens */    hint->prealloc_size = 0;    if (!hint->formatted_node && hint->preallocate) {	if (S_ISREG(hint->inode->i_mode)	    && hint->inode->i_size >= REISERFS_SB(hint->th->t_super)->s_alloc_options.preallocmin * hint->inode->i_sb->s_blocksize)	    hint->prealloc_size = REISERFS_SB(hint->th->t_super)->s_alloc_options.preallocsize - 1;    }    return CARRY_ON;}/* XXX I know it could be merged with upper-level function;   but may be result function would be too complex. */static inline int allocate_without_wrapping_disk (reiserfs_blocknr_hint_t * hint,					 b_blocknr_t * new_blocknrs,					 b_blocknr_t start, b_blocknr_t finish,					 int min,					 int amount_needed, int prealloc_size){    int rest = amount_needed;    int nr_allocated;      while (rest > 0 && start <= finish) {	nr_allocated = scan_bitmap (hint->th, &start, finish, min,				    rest + prealloc_size, !hint->formatted_node,				    hint->block);	if (nr_allocated == 0)	/* no new blocks allocated, return */	    break;		/* fill free_blocknrs array first */	while (rest > 0 && nr_allocated > 0) {	    * new_blocknrs ++ = start ++;	    rest --; nr_allocated --;	}	/* do we have something to fill prealloc. array also ? */	if (nr_allocated > 0) {	    /* it means prealloc_size was greater that 0 and we do preallocation */	    list_add(&REISERFS_I(hint->inode)->i_prealloc_list,		     &SB_JOURNAL(hint->th->t_super)->j_prealloc_list);	    REISERFS_I(hint->inode)->i_prealloc_block = start;	    REISERFS_I(hint->inode)->i_prealloc_count = nr_allocated;	    break;	}    }    return (amount_needed - rest);}static inline int blocknrs_and_prealloc_arrays_from_search_start    (reiserfs_blocknr_hint_t *hint, b_blocknr_t *new_blocknrs, int amount_needed){    struct super_block *s = hint->th->t_super;    b_blocknr_t start = hint->search_start;    b_blocknr_t finish = SB_BLOCK_COUNT(s) - 1;    int passno = 0;    int nr_allocated = 0;    int bigalloc = 0;    determine_prealloc_size(hint);    if (!hint->formatted_node) {        int quota_ret;#ifdef REISERQUOTA_DEBUG	reiserfs_debug (s, "reiserquota: allocating %d blocks id=%u", amount_needed, hint->inode->i_uid);#endif	quota_ret = DQUOT_ALLOC_BLOCK_NODIRTY(hint->inode, amount_needed);	if (quota_ret)    /* Quota exceeded? */	    return QUOTA_EXCEEDED;	if (hint->preallocate && hint->prealloc_size ) {#ifdef REISERQUOTA_DEBUG	    reiserfs_debug (s, "reiserquota: allocating (prealloc) %d blocks id=%u", hint->prealloc_size, hint->inode->i_uid);#endif	    quota_ret = DQUOT_PREALLOC_BLOCK_NODIRTY(hint->inode, hint->prealloc_size);	    if (quota_ret)		hint->preallocate=hint->prealloc_size=0;	}	/* for unformatted nodes, force large allocations */	bigalloc = amount_needed;    }    do {	/* in bigalloc mode, nr_allocated should stay zero until	 * the entire allocation is filled	 */	if (unlikely(bigalloc && nr_allocated)) {	    reiserfs_warning(s, "bigalloc is %d, nr_allocated %d\n",	    bigalloc, nr_allocated);	    /* reset things to a sane value */	    bigalloc = amount_needed - nr_allocated;	}	/*	 * try pass 0 and pass 1 looking for a nice big	 * contiguous allocation.  Then reset and look	 * for anything you can find.	 */	if (passno == 2 && bigalloc) {	    passno = 0;	    bigalloc = 0;	}	switch (passno++) {        case 0: /* Search from hint->search_start to end of disk */	    start = hint->search_start;	    finish = SB_BLOCK_COUNT(s) - 1;	    break;        case 1: /* Search from hint->beg to hint->search_start */	    start = hint->beg;	    finish = hint->search_start;	    break;	case 2: /* Last chance: Search from 0 to hint->beg */	    start = 0;	    finish = hint->beg;	    break;	default: /* We've tried searching everywhere, not enough space */	    /* Free the blocks */	    if (!hint->formatted_node) {#ifdef REISERQUOTA_DEBUG		reiserfs_debug (s, "reiserquota: freeing (nospace) %d blocks id=%u", amount_needed + hint->prealloc_size - nr_allocated, hint->inode->i_uid);#endif		DQUOT_FREE_BLOCK_NODIRTY(hint->inode, amount_needed + hint->prealloc_size - nr_allocated);     /* Free not allocated blocks */	    }  	    while (nr_allocated --)		reiserfs_free_block(hint->th, hint->inode, new_blocknrs[nr_allocated], !hint->formatted_node);	    return NO_DISK_SPACE;	}    } while ((nr_allocated += allocate_without_wrapping_disk (hint,			    new_blocknrs + nr_allocated, start, finish,			    bigalloc ? bigalloc : 1,			    amount_needed - nr_allocated,			    hint->prealloc_size))			< amount_needed);    if ( !hint->formatted_node &&         amount_needed + hint->prealloc_size >	 nr_allocated + REISERFS_I(hint->inode)->i_prealloc_count) {    /* Some of preallocation blocks were not allocated */#ifdef REISERQUOTA_DEBUG	reiserfs_debug (s, "reiserquota: freeing (failed prealloc) %d blocks id=%u", amount_needed + hint->prealloc_size - nr_allocated - INODE_INFO(hint->inode)->i_prealloc_count, hint->inode->i_uid);#endif	DQUOT_FREE_BLOCK_NODIRTY(hint->inode, amount_needed +	                         hint->prealloc_size - nr_allocated -				 REISERFS_I(hint->inode)->i_prealloc_count);    }    return CARRY_ON;}/* grab new blocknrs from preallocated list *//* return amount still needed after using them */static int use_preallocated_list_if_available (reiserfs_blocknr_hint_t *hint,					       b_blocknr_t *new_blocknrs, int amount_needed){    struct inode * inode = hint->inode;    if (REISERFS_I(inode)->i_prealloc_count > 0) {	while (amount_needed) {	    *new_blocknrs ++ = REISERFS_I(inode)->i_prealloc_block ++;	    REISERFS_I(inode)->i_prealloc_count --;	    amount_needed --;	    if (REISERFS_I(inode)->i_prealloc_count <= 0) {		list_del(&REISERFS_I(inode)->i_prealloc_list);  		break;	    }	}      }    /* return amount still needed after using preallocated blocks */    return amount_needed;}int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t *hint,			       b_blocknr_t * new_blocknrs, int amount_needed,			       int reserved_by_us /* Amount of blocks we have						      already reserved */){    int initial_amount_needed = amount_needed;    int ret;    /* Check if there is enough space, taking into account reserved space */    if ( SB_FREE_BLOCKS(hint->th->t_super) - REISERFS_SB(hint->th->t_super)->reserved_blocks <	 amount_needed - reserved_by_us)        return NO_DISK_SPACE;    /* should this be if !hint->inode &&  hint->preallocate? */    /* do you mean hint->formatted_node can be removed ? - Zam */    /* hint->formatted_node cannot be removed because we try to access       inode information here, and there is often no inode assotiated with       metadata allocations - green */    if (!hint->formatted_node && hint->preallocate) {	amount_needed = use_preallocated_list_if_available	    (hint, new_blocknrs, amount_needed);	if (amount_needed == 0)	/* all blocknrs we need we got from                                   prealloc. list */	    return CARRY_ON;	new_blocknrs += (initial_amount_needed - amount_needed);    }    /* find search start and save it in hint structure */    determine_search_start(hint, amount_needed);    /* allocation itself; fill new_blocknrs and preallocation arrays */    ret = blocknrs_and_prealloc_arrays_from_search_start	(hint, new_blocknrs, amount_needed);    /* we used prealloc. list to fill (partially) new_blocknrs array. If final allocation fails we     * need to return blocks back to prealloc. list or just free them. -- Zam (I chose second     * variant) */    if (ret != CARRY_ON) {	while (amount_needed ++ < initial_amount_needed) {	    reiserfs_free_block(hint->th, hint->inode, *(--new_blocknrs), 1);	}    }    return ret;}/* These 2 functions are here to provide blocks reservation to the rest of kernel *//* Reserve @blocks amount of blocks in fs pointed by @sb. Caller must make sure   there are actually this much blocks on the FS available */void reiserfs_claim_blocks_to_be_allocated( 				      struct super_block *sb, /* super block of							        filesystem where								blocks should be								reserved */				      int blocks /* How much to reserve */					  ){    /* Fast case, if reservation is zero - exit immediately. */    if ( !blocks )	return;    spin_lock(&REISERFS_SB(sb)->bitmap_lock);    REISERFS_SB(sb)->reserved_blocks += blocks;    spin_unlock(&REISERFS_SB(sb)->bitmap_lock);}/* Unreserve @blocks amount of blocks in fs pointed by @sb */void reiserfs_release_claimed_blocks( 				struct super_block *sb, /* super block of							  filesystem where							  blocks should be							  reserved */				int blocks /* How much to unreserve */					  ){    /* Fast case, if unreservation is zero - exit immediately. */    if ( !blocks )	return;    spin_lock(&REISERFS_SB(sb)->bitmap_lock);    REISERFS_SB(sb)->reserved_blocks -= blocks;    spin_unlock(&REISERFS_SB(sb)->bitmap_lock);    RFALSE( REISERFS_SB(sb)->reserved_blocks < 0, "amount of blocks reserved became zero?");}/* This function estimates how much pages we will be able to write to FS   used for reiserfs_file_write() purposes for now. */int reiserfs_can_fit_pages ( struct super_block *sb /* superblock of filesystem						       to estimate space */ ){	int space;	spin_lock(&REISERFS_SB(sb)->bitmap_lock);	space = (SB_FREE_BLOCKS(sb) - REISERFS_SB(sb)->reserved_blocks) >> ( PAGE_CACHE_SHIFT - sb->s_blocksize_bits);	spin_unlock(&REISERFS_SB(sb)->bitmap_lock);	return space>0?space:0;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?