static inline void displace_large_file(reiserfs_blocknr_hint_t *hint) { if ( TEST_OPTION(displace_based_on_dirid, hint->th->t_super)) hint->search_start = hint->beg + keyed_hash((char *)(&INODE_PKEY(hint->inode)->k_dir_id), 4) % (hint->end - hint->beg); else hint->search_start = hint->beg + keyed_hash((char *)(&INODE_PKEY(hint->inode)->k_objectid), 4) % (hint->end - hint->beg); }
static inline void hash_formatted_node(reiserfs_blocknr_hint_t *hint) { char * hash_in; if (!hint->inode) hash_in = (char*)&hint->key.k_dir_id; else if ( TEST_OPTION(displace_based_on_dirid, hint->th->t_super)) hash_in = (char *)(&INODE_PKEY(hint->inode)->k_dir_id); else hash_in = (char *)(&INODE_PKEY(hint->inode)->k_objectid); hint->search_start = hint->beg + keyed_hash(hash_in, 4) % (hint->end - hint->beg); }
/* * the packing is returned in disk byte order */ u32 reiserfs_choose_packing(struct inode *dir) { u32 packing; if (TEST_OPTION(packing_groups, dir->i_sb)) { u32 parent_dir = le32_to_cpu(INODE_PKEY(dir)->k_dir_id); /* * some versions of reiserfsck expect packing locality 1 to be * special */ if (parent_dir == 1 || block_group_used(dir->i_sb,parent_dir)) packing = INODE_PKEY(dir)->k_objectid; else packing = INODE_PKEY(dir)->k_dir_id; } else packing = INODE_PKEY(dir)->k_objectid; return packing; }
static void inline new_hashed_relocation (reiserfs_blocknr_hint_t * hint) { char * hash_in; if (hint->formatted_node) { hash_in = (char*)&hint->key.k_dir_id; } else { if (!hint->inode) { //hint->search_start = hint->beg; hash_in = (char*)&hint->key.k_dir_id; } else if ( TEST_OPTION(displace_based_on_dirid, hint->th->t_super)) hash_in = (char *)(&INODE_PKEY(hint->inode)->k_dir_id); else hash_in = (char *)(&INODE_PKEY(hint->inode)->k_objectid); } hint->search_start = hint->beg + keyed_hash(hash_in, 4) % (hint->end - hint->beg); }
/* Tries to find contiguous zero bit window (given size) in given region of * bitmap and place new blocks there. Returns number of allocated blocks. */ static int scan_bitmap (struct reiserfs_transaction_handle *th, unsigned long *start, unsigned long finish, int min, int max, int unfm, unsigned long file_block) { int nr_allocated=0; struct super_block * s = th->t_super; /* find every bm and bmap and bmap_nr in this file, and change them all to bitmap_blocknr * - Hans, it is not a block number - Zam. */ int bm, off; int end_bm, end_off; int off_max = s->s_blocksize << 3; PROC_INFO_INC( s, scan_bitmap.call ); if ( SB_FREE_BLOCKS(s) <= 0) return 0; // No point in looking for more free blocks get_bit_address (s, *start, &bm, &off); get_bit_address (s, finish, &end_bm, &end_off); // With this option set first we try to find a bitmap that is at least 10% // free, and if that fails, then we fall back to old whole bitmap scanning if ( TEST_OPTION(skip_busy, s) && SB_FREE_BLOCKS(s) > SB_BLOCK_COUNT(s)/20 ) { for (; bm < end_bm; bm++, off = 0) { if ( ( off && (!unfm || (file_block != 0))) || SB_AP_BITMAP(s)[bm].free_count > (s->s_blocksize << 3) / 10 ) nr_allocated = scan_bitmap_block(th, bm, &off, off_max, min, max, unfm); if (nr_allocated) goto ret; } get_bit_address (s, *start, &bm, &off); } for (; bm < end_bm; bm++, off = 0) { nr_allocated = scan_bitmap_block(th, bm, &off, off_max, min, max, unfm); if (nr_allocated) goto ret; } nr_allocated = scan_bitmap_block(th, bm, &off, end_off + 1, min, max, unfm); ret: *start = bm * off_max + off; return nr_allocated; }
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; }
/* Tries to find contiguous zero bit window (given size) in given region of * bitmap and place new blocks there. Returns number of allocated blocks. */ static int scan_bitmap (struct reiserfs_transaction_handle *th, b_blocknr_t *start, b_blocknr_t finish, int min, int max, int unfm, unsigned long file_block) { int nr_allocated=0; struct super_block * s = th->t_super; /* find every bm and bmap and bmap_nr in this file, and change them all to bitmap_blocknr * - Hans, it is not a block number - Zam. */ int bm, off; int end_bm, end_off; int off_max = s->s_blocksize << 3; BUG_ON (!th->t_trans_id); PROC_INFO_INC( s, scan_bitmap.call ); if ( SB_FREE_BLOCKS(s) <= 0) return 0; // No point in looking for more free blocks get_bit_address (s, *start, &bm, &off); get_bit_address (s, finish, &end_bm, &end_off); if (bm > SB_BMAP_NR(s)) return 0; if (end_bm > SB_BMAP_NR(s)) end_bm = SB_BMAP_NR(s); /* When the bitmap is more than 10% free, anyone can allocate. * When it's less than 10% free, only files that already use the * bitmap are allowed. Once we pass 80% full, this restriction * is lifted. * * We do this so that files that grow later still have space close to * their original allocation. This improves locality, and presumably * performance as a result. * * This is only an allocation policy and does not make up for getting a * bad hint. Decent hinting must be implemented for this to work well. */ if ( TEST_OPTION(skip_busy, s) && SB_FREE_BLOCKS(s) > SB_BLOCK_COUNT(s)/20 ) { for (; bm < end_bm; bm++, off = 0) { if ( ( off && (!unfm || (file_block != 0))) || SB_AP_BITMAP(s)[bm].free_count > (s->s_blocksize << 3) / 10 ) nr_allocated = scan_bitmap_block(th, bm, &off, off_max, min, max, unfm); if (nr_allocated) goto ret; } /* we know from above that start is a reasonable number */ get_bit_address (s, *start, &bm, &off); } for (; bm < end_bm; bm++, off = 0) { nr_allocated = scan_bitmap_block(th, bm, &off, off_max, min, max, unfm); if (nr_allocated) goto ret; } nr_allocated = scan_bitmap_block(th, bm, &off, end_off + 1, min, max, unfm); ret: *start = bm * off_max + off; return nr_allocated; }