📄 bitmap.c
字号:
-Hans */free_and_return: for ( ; block_list_start != free_blocknrs; block_list_start++) { reiserfs_free_block (th, *block_list_start); *block_list_start = 0; } if (for_prealloc) return NO_MORE_UNUSED_CONTIGUOUS_BLOCKS; else return NO_DISK_SPACE; } } /* i and j now contain the results of the search. i = bitmap block number containing free block, j = offset in this block. we compute the blocknr which is our result, store it in free_blocknrs, and increment the pointer so that on the next loop we will insert into the next location in the array. Also in preparation for the next loop, search_start is changed so that the next search will not rescan the same range but will start where this search finished. Note that while it is possible that schedule has occurred and blocks have been freed in that range, it is perhaps more important that the blocks returned be near each other than that they be near their other neighbors, and it also simplifies and speeds the code this way. */ /* journal: we need to make sure the block we are giving out is not ** a log block, horrible things would happen there. */ new_block = (i * (s->s_blocksize << 3)) + j; if (for_prealloc && (new_block - 1) != search_start) { /* preallocated blocks must be contiguous, bail if we didnt find one. ** this is not a bug. We want to do the check here, before the ** bitmap block is prepared, and before we set the bit and log the ** bitmap. ** ** If we do the check after this function returns, we have to ** call reiserfs_free_block for new_block, which would be pure ** overhead. ** ** for_prealloc should only be set if the caller can deal with the ** NO_MORE_UNUSED_CONTIGUOUS_BLOCKS return value. This can be ** returned before the disk is actually full */ goto free_and_return ; } search_start = new_block ; if (search_start >= reiserfs_get_journal_block(s) && search_start < (reiserfs_get_journal_block(s) + JOURNAL_BLOCK_COUNT)) { reiserfs_warning("vs-4130: reiserfs_new_blocknrs: trying to allocate log block %lu\n", search_start) ; search_start++ ; amount_needed++ ; continue ; } reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[i], 1) ; RFALSE( buffer_locked (SB_AP_BITMAP (s)[i]) || is_reusable (s, search_start, 0) == 0, "vs-4140: bitmap block is locked or bad block number found"); /* if this bit was already set, we've scheduled, and someone else ** has allocated it. loop around and try again */ if (reiserfs_test_and_set_le_bit (j, SB_AP_BITMAP (s)[i]->b_data)) { reiserfs_restore_prepared_buffer(s, SB_AP_BITMAP(s)[i]) ; amount_needed++ ; continue ; } journal_mark_dirty (th, s, SB_AP_BITMAP (s)[i]); *free_blocknrs = search_start ; free_blocknrs ++; } reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ; /* update free block count in super block */ PUT_SB_FREE_BLOCKS( s, SB_FREE_BLOCKS(s) - init_amount_needed ); journal_mark_dirty (th, s, SB_BUFFER_WITH_SB (s)); s->s_dirt = 1; return CARRY_ON;}// this is called only by get_empty_nodesint reiserfs_new_blocknrs (struct reiserfs_transaction_handle *th, unsigned long * free_blocknrs, unsigned long search_start, int amount_needed) { return do_reiserfs_new_blocknrs(th, free_blocknrs, search_start, amount_needed, 0/*priority*/, 0/*for_formatted*/, 0/*for_prealloc */) ;}// called by get_new_buffer and by reiserfs_get_block with amount_needed == 1int reiserfs_new_unf_blocknrs(struct reiserfs_transaction_handle *th, unsigned long * free_blocknrs, unsigned long search_start) { return do_reiserfs_new_blocknrs(th, free_blocknrs, search_start, 1/*amount_needed*/, 0/*priority*/, 1/*for formatted*/, 0/*for prealloc */) ;}#ifdef REISERFS_PREALLOCATE/* ** We pre-allocate 8 blocks. Pre-allocation is used for files > 16 KB only.** This lowers fragmentation on large files by grabbing a contiguous set of** blocks at once. It also limits the number of times the bitmap block is** logged by making X number of allocation changes in a single transaction.**** We are using a border to divide the disk into two parts. The first part** is used for tree blocks, which have a very high turnover rate (they** are constantly allocated then freed)**** The second part of the disk is for the unformatted nodes of larger files.** Putting them away from the tree blocks lowers fragmentation, and makes** it easier to group files together. There are a number of different** allocation schemes being tried right now, each is documented below.**** A great deal of the allocator's speed comes because reiserfs_get_block** sends us the block number of the last unformatted node in the file. Once** a given block is allocated past the border, we don't collide with the** blocks near the search_start again.** */int reiserfs_new_unf_blocknrs2 (struct reiserfs_transaction_handle *th, struct inode * p_s_inode, unsigned long * free_blocknrs, unsigned long search_start){ int ret=0, blks_gotten=0; unsigned long border = 0; unsigned long bstart = 0; unsigned long hash_in, hash_out; unsigned long saved_search_start=search_start; int allocated[PREALLOCATION_SIZE]; int blks; if (!reiserfs_no_border(th->t_super)) { /* we default to having the border at the 10% mark of the disk. This ** is an arbitrary decision and it needs tuning. It also needs a limit ** to prevent it from taking too much space on huge drives. */ bstart = (SB_BLOCK_COUNT(th->t_super) / 10); } if (!reiserfs_no_unhashed_relocation(th->t_super)) { /* this is a very simple first attempt at preventing too much grouping ** around the border value. Since k_dir_id is never larger than the ** highest allocated oid, it is far from perfect, and files will tend ** to be grouped towards the start of the border */ border = le32_to_cpu(INODE_PKEY(p_s_inode)->k_dir_id) % (SB_BLOCK_COUNT(th->t_super) - bstart - 1) ; } else if (!reiserfs_hashed_relocation(th->t_super)) { hash_in = le32_to_cpu((INODE_PKEY(p_s_inode))->k_dir_id); /* I wonder if the CPU cost of the hash will obscure the layout effect? Of course, whether that effect is good or bad we don't know.... :-) */ hash_out = keyed_hash(((char *) (&hash_in)), 4); border = hash_out % (SB_BLOCK_COUNT(th->t_super) - bstart - 1) ; } border += bstart ; allocated[0] = 0 ; /* important. Allows a check later on to see if at * least one block was allocated. This prevents false * no disk space returns */ if ( (p_s_inode->i_size < 4 * 4096) || !(S_ISREG(p_s_inode->i_mode)) ) { if ( search_start < border || ( /* allow us to test whether it is a good idea to prevent files from getting too far away from their packing locality by some unexpected means. This might be poor code for directories whose files total larger than 1/10th of the disk, and it might be good code for suffering from old insertions when the disk was almost full. */ /* changed from !reiserfs_test3(th->t_super), which doesn't ** seem like a good idea. Think about adding blocks to ** a large file. If you've allocated 10% of the disk ** in contiguous blocks, you start over at the border value ** for every new allocation. This throws away all the ** information sent in about the last block that was allocated ** in the file. Not a good general case at all. ** -chris */ reiserfs_test4(th->t_super) && (search_start > border + (SB_BLOCK_COUNT(th->t_super) / 10)) ) ) search_start=border; ret = do_reiserfs_new_blocknrs(th, free_blocknrs, search_start, 1/*amount_needed*/, 0/*use reserved blocks for root */, 1/*for_formatted*/, 0/*for prealloc */) ; return ret; } /* take a block off the prealloc list and return it -Hans */ if (p_s_inode->u.reiserfs_i.i_prealloc_count > 0) { p_s_inode->u.reiserfs_i.i_prealloc_count--; *free_blocknrs = p_s_inode->u.reiserfs_i.i_prealloc_block++; /* if no more preallocated blocks, remove inode from list */ if (! p_s_inode->u.reiserfs_i.i_prealloc_count) { list_del(&p_s_inode->u.reiserfs_i.i_prealloc_list); } return ret; } /* else get a new preallocation for the file */ reiserfs_discard_prealloc (th, p_s_inode); /* this uses the last preallocated block as the search_start. discard ** prealloc does not zero out this number. */ if (search_start <= p_s_inode->u.reiserfs_i.i_prealloc_block) { search_start = p_s_inode->u.reiserfs_i.i_prealloc_block; } /* doing the compare again forces search_start to be >= the border, ** even if the file already had prealloction done. This seems extra, ** and should probably be removed */ if ( search_start < border ) search_start=border; /* If the disk free space is already below 10% we should ** start looking for the free blocks from the beginning ** of the partition, before the border line. */ if ( SB_FREE_BLOCKS(th->t_super) <= (SB_BLOCK_COUNT(th->t_super) / 10) ) { search_start=saved_search_start; } *free_blocknrs = 0; blks = PREALLOCATION_SIZE-1; for (blks_gotten=0; blks_gotten<PREALLOCATION_SIZE; blks_gotten++) { ret = do_reiserfs_new_blocknrs(th, free_blocknrs, search_start, 1/*amount_needed*/, 0/*for root reserved*/, 1/*for_formatted*/, (blks_gotten > 0)/*must_be_contiguous*/) ; /* if we didn't find a block this time, adjust blks to reflect ** the actual number of blocks allocated */ if (ret != CARRY_ON) { blks = blks_gotten > 0 ? (blks_gotten - 1) : 0 ; break ; } allocated[blks_gotten]= *free_blocknrs;#ifdef CONFIG_REISERFS_CHECK if ( (blks_gotten>0) && (allocated[blks_gotten] - allocated[blks_gotten-1]) != 1 ) { /* this should be caught by new_blocknrs now, checking code */ reiserfs_warning("yura-1, reiserfs_new_unf_blocknrs2: pre-allocated not contiguous set of blocks!\n") ; reiserfs_free_block(th, allocated[blks_gotten]); blks = blks_gotten-1; break; }#endif if (blks_gotten==0) { p_s_inode->u.reiserfs_i.i_prealloc_block = *free_blocknrs; } search_start = *free_blocknrs; *free_blocknrs = 0; } p_s_inode->u.reiserfs_i.i_prealloc_count = blks; *free_blocknrs = p_s_inode->u.reiserfs_i.i_prealloc_block; p_s_inode->u.reiserfs_i.i_prealloc_block++; /* if inode has preallocated blocks, link him to list */ if (p_s_inode->u.reiserfs_i.i_prealloc_count) { list_add(&p_s_inode->u.reiserfs_i.i_prealloc_list, &SB_JOURNAL(th->t_super)->j_prealloc_list); } /* we did actually manage to get 1 block */ if (ret != CARRY_ON && allocated[0] > 0) { return CARRY_ON ; } /* NO_MORE_UNUSED_CONTIGUOUS_BLOCKS should only mean something to ** the preallocation code. The rest of the filesystem asks for a block ** and should either get it, or know the disk is full. The code ** above should never allow ret == NO_MORE_UNUSED_CONTIGUOUS_BLOCK, ** as it doesn't send for_prealloc = 1 to do_reiserfs_new_blocknrs ** unless it has already successfully allocated at least one block. ** Just in case, we translate into a return value the rest of the ** filesystem can understand. ** ** It is an error to change this without making the ** rest of the filesystem understand NO_MORE_UNUSED_CONTIGUOUS_BLOCKS ** If you consider it a bug to return NO_DISK_SPACE here, fix the rest ** of the fs first. */ if (ret == NO_MORE_UNUSED_CONTIGUOUS_BLOCKS) {#ifdef CONFIG_REISERFS_CHECK reiserfs_warning("reiser-2015: this shouldn't happen, may cause false out of disk space error");#endif return NO_DISK_SPACE; } return ret;}//// a portion of this function, was derived from minix or ext2's// analog. You should be able to tell which portion by looking at the// ext2 code and comparing. static void __discard_prealloc (struct reiserfs_transaction_handle * th, struct inode * inode){ unsigned long save = inode->u.reiserfs_i.i_prealloc_block ; while (inode->u.reiserfs_i.i_prealloc_count > 0) { reiserfs_free_prealloc_block(th,inode->u.reiserfs_i.i_prealloc_block); inode->u.reiserfs_i.i_prealloc_block++; inode->u.reiserfs_i.i_prealloc_count --; } inode->u.reiserfs_i.i_prealloc_block = save ; list_del (&(inode->u.reiserfs_i.i_prealloc_list));}void reiserfs_discard_prealloc (struct reiserfs_transaction_handle *th, struct inode * inode){#ifdef CONFIG_REISERFS_CHECK if (inode->u.reiserfs_i.i_prealloc_count < 0) reiserfs_warning("zam-4001:" __FUNCTION__ ": inode has negative prealloc blocks count.\n");#endif if (inode->u.reiserfs_i.i_prealloc_count > 0) { __discard_prealloc(th, inode); } }void reiserfs_discard_all_prealloc (struct reiserfs_transaction_handle *th){ struct list_head * plist = &SB_JOURNAL(th->t_super)->j_prealloc_list; struct inode * inode; while (!list_empty(plist)) { inode = list_entry(plist->next, struct inode, u.reiserfs_i.i_prealloc_list);#ifdef CONFIG_REISERFS_CHECK if (!inode->u.reiserfs_i.i_prealloc_count) { reiserfs_warning("zam-4001:" __FUNCTION__ ": inode is in prealloc list but has no preallocated blocks.\n"); }#endif __discard_prealloc(th, inode); }}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -