18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README 38c2ecf20Sopenharmony_ci */ 48c2ecf20Sopenharmony_ci/* Reiserfs block (de)allocator, bitmap-based. */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/time.h> 78c2ecf20Sopenharmony_ci#include "reiserfs.h" 88c2ecf20Sopenharmony_ci#include <linux/errno.h> 98c2ecf20Sopenharmony_ci#include <linux/buffer_head.h> 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 128c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 138c2ecf20Sopenharmony_ci#include <linux/quotaops.h> 148c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define PREALLOCATION_SIZE 9 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/* different reiserfs block allocator options */ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define SB_ALLOC_OPTS(s) (REISERFS_SB(s)->s_alloc_options.bits) 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define _ALLOC_concentrating_formatted_nodes 0 238c2ecf20Sopenharmony_ci#define _ALLOC_displacing_large_files 1 248c2ecf20Sopenharmony_ci#define _ALLOC_displacing_new_packing_localities 2 258c2ecf20Sopenharmony_ci#define _ALLOC_old_hashed_relocation 3 268c2ecf20Sopenharmony_ci#define _ALLOC_new_hashed_relocation 4 278c2ecf20Sopenharmony_ci#define _ALLOC_skip_busy 5 288c2ecf20Sopenharmony_ci#define _ALLOC_displace_based_on_dirid 6 298c2ecf20Sopenharmony_ci#define _ALLOC_hashed_formatted_nodes 7 308c2ecf20Sopenharmony_ci#define _ALLOC_old_way 8 318c2ecf20Sopenharmony_ci#define _ALLOC_hundredth_slices 9 328c2ecf20Sopenharmony_ci#define _ALLOC_dirid_groups 10 338c2ecf20Sopenharmony_ci#define _ALLOC_oid_groups 11 348c2ecf20Sopenharmony_ci#define _ALLOC_packing_groups 12 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define concentrating_formatted_nodes(s) test_bit(_ALLOC_concentrating_formatted_nodes, &SB_ALLOC_OPTS(s)) 378c2ecf20Sopenharmony_ci#define displacing_large_files(s) test_bit(_ALLOC_displacing_large_files, &SB_ALLOC_OPTS(s)) 388c2ecf20Sopenharmony_ci#define displacing_new_packing_localities(s) test_bit(_ALLOC_displacing_new_packing_localities, &SB_ALLOC_OPTS(s)) 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define SET_OPTION(optname) \ 418c2ecf20Sopenharmony_ci do { \ 428c2ecf20Sopenharmony_ci reiserfs_info(s, "block allocator option \"%s\" is set", #optname); \ 438c2ecf20Sopenharmony_ci set_bit(_ALLOC_ ## optname , &SB_ALLOC_OPTS(s)); \ 448c2ecf20Sopenharmony_ci } while(0) 458c2ecf20Sopenharmony_ci#define TEST_OPTION(optname, s) \ 468c2ecf20Sopenharmony_ci test_bit(_ALLOC_ ## optname , &SB_ALLOC_OPTS(s)) 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic inline void get_bit_address(struct super_block *s, 498c2ecf20Sopenharmony_ci b_blocknr_t block, 508c2ecf20Sopenharmony_ci unsigned int *bmap_nr, 518c2ecf20Sopenharmony_ci unsigned int *offset) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci /* 548c2ecf20Sopenharmony_ci * It is in the bitmap block number equal to the block 558c2ecf20Sopenharmony_ci * number divided by the number of bits in a block. 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_ci *bmap_nr = block >> (s->s_blocksize_bits + 3); 588c2ecf20Sopenharmony_ci /* Within that bitmap block it is located at bit offset *offset. */ 598c2ecf20Sopenharmony_ci *offset = block & ((s->s_blocksize << 3) - 1); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ciint is_reusable(struct super_block *s, b_blocknr_t block, int bit_value) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci unsigned int bmap, offset; 658c2ecf20Sopenharmony_ci unsigned int bmap_count = reiserfs_bmap_count(s); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (block == 0 || block >= SB_BLOCK_COUNT(s)) { 688c2ecf20Sopenharmony_ci reiserfs_error(s, "vs-4010", 698c2ecf20Sopenharmony_ci "block number is out of range %lu (%u)", 708c2ecf20Sopenharmony_ci block, SB_BLOCK_COUNT(s)); 718c2ecf20Sopenharmony_ci return 0; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci get_bit_address(s, block, &bmap, &offset); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci /* 778c2ecf20Sopenharmony_ci * Old format filesystem? Unlikely, but the bitmaps are all 788c2ecf20Sopenharmony_ci * up front so we need to account for it. 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_ci if (unlikely(test_bit(REISERFS_OLD_FORMAT, 818c2ecf20Sopenharmony_ci &REISERFS_SB(s)->s_properties))) { 828c2ecf20Sopenharmony_ci b_blocknr_t bmap1 = REISERFS_SB(s)->s_sbh->b_blocknr + 1; 838c2ecf20Sopenharmony_ci if (block >= bmap1 && 848c2ecf20Sopenharmony_ci block <= bmap1 + bmap_count) { 858c2ecf20Sopenharmony_ci reiserfs_error(s, "vs-4019", "bitmap block %lu(%u) " 868c2ecf20Sopenharmony_ci "can't be freed or reused", 878c2ecf20Sopenharmony_ci block, bmap_count); 888c2ecf20Sopenharmony_ci return 0; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci } else { 918c2ecf20Sopenharmony_ci if (offset == 0) { 928c2ecf20Sopenharmony_ci reiserfs_error(s, "vs-4020", "bitmap block %lu(%u) " 938c2ecf20Sopenharmony_ci "can't be freed or reused", 948c2ecf20Sopenharmony_ci block, bmap_count); 958c2ecf20Sopenharmony_ci return 0; 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (bmap >= bmap_count) { 1008c2ecf20Sopenharmony_ci reiserfs_error(s, "vs-4030", "bitmap for requested block " 1018c2ecf20Sopenharmony_ci "is out of range: block=%lu, bitmap_nr=%u", 1028c2ecf20Sopenharmony_ci block, bmap); 1038c2ecf20Sopenharmony_ci return 0; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (bit_value == 0 && block == SB_ROOT_BLOCK(s)) { 1078c2ecf20Sopenharmony_ci reiserfs_error(s, "vs-4050", "this is root block (%u), " 1088c2ecf20Sopenharmony_ci "it must be busy", SB_ROOT_BLOCK(s)); 1098c2ecf20Sopenharmony_ci return 0; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci return 1; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/* 1168c2ecf20Sopenharmony_ci * Searches in journal structures for a given block number (bmap, off). 1178c2ecf20Sopenharmony_ci * If block is found in reiserfs journal it suggests next free block 1188c2ecf20Sopenharmony_ci * candidate to test. 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_cistatic inline int is_block_in_journal(struct super_block *s, unsigned int bmap, 1218c2ecf20Sopenharmony_ci int off, int *next) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci b_blocknr_t tmp; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci if (reiserfs_in_journal(s, bmap, off, 1, &tmp)) { 1268c2ecf20Sopenharmony_ci if (tmp) { /* hint supplied */ 1278c2ecf20Sopenharmony_ci *next = tmp; 1288c2ecf20Sopenharmony_ci PROC_INFO_INC(s, scan_bitmap.in_journal_hint); 1298c2ecf20Sopenharmony_ci } else { 1308c2ecf20Sopenharmony_ci (*next) = off + 1; /* inc offset to avoid looping. */ 1318c2ecf20Sopenharmony_ci PROC_INFO_INC(s, scan_bitmap.in_journal_nohint); 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci PROC_INFO_INC(s, scan_bitmap.retry); 1348c2ecf20Sopenharmony_ci return 1; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci return 0; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci/* 1408c2ecf20Sopenharmony_ci * Searches for a window of zero bits with given minimum and maximum 1418c2ecf20Sopenharmony_ci * lengths in one bitmap block 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_cistatic int scan_bitmap_block(struct reiserfs_transaction_handle *th, 1448c2ecf20Sopenharmony_ci unsigned int bmap_n, int *beg, int boundary, 1458c2ecf20Sopenharmony_ci int min, int max, int unfm) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci struct super_block *s = th->t_super; 1488c2ecf20Sopenharmony_ci struct reiserfs_bitmap_info *bi = &SB_AP_BITMAP(s)[bmap_n]; 1498c2ecf20Sopenharmony_ci struct buffer_head *bh; 1508c2ecf20Sopenharmony_ci int end, next; 1518c2ecf20Sopenharmony_ci int org = *beg; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci BUG_ON(!th->t_trans_id); 1548c2ecf20Sopenharmony_ci RFALSE(bmap_n >= reiserfs_bmap_count(s), "Bitmap %u is out of " 1558c2ecf20Sopenharmony_ci "range (0..%u)", bmap_n, reiserfs_bmap_count(s) - 1); 1568c2ecf20Sopenharmony_ci PROC_INFO_INC(s, scan_bitmap.bmap); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (!bi) { 1598c2ecf20Sopenharmony_ci reiserfs_error(s, "jdm-4055", "NULL bitmap info pointer " 1608c2ecf20Sopenharmony_ci "for bitmap %d", bmap_n); 1618c2ecf20Sopenharmony_ci return 0; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci bh = reiserfs_read_bitmap_block(s, bmap_n); 1658c2ecf20Sopenharmony_ci if (bh == NULL) 1668c2ecf20Sopenharmony_ci return 0; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci while (1) { 1698c2ecf20Sopenharmony_cicont: 1708c2ecf20Sopenharmony_ci if (bi->free_count < min) { 1718c2ecf20Sopenharmony_ci brelse(bh); 1728c2ecf20Sopenharmony_ci return 0; /* No free blocks in this bitmap */ 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci /* search for a first zero bit -- beginning of a window */ 1768c2ecf20Sopenharmony_ci *beg = reiserfs_find_next_zero_le_bit 1778c2ecf20Sopenharmony_ci ((unsigned long *)(bh->b_data), boundary, *beg); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* 1808c2ecf20Sopenharmony_ci * search for a zero bit fails or the rest of bitmap block 1818c2ecf20Sopenharmony_ci * cannot contain a zero window of minimum size 1828c2ecf20Sopenharmony_ci */ 1838c2ecf20Sopenharmony_ci if (*beg + min > boundary) { 1848c2ecf20Sopenharmony_ci brelse(bh); 1858c2ecf20Sopenharmony_ci return 0; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci if (unfm && is_block_in_journal(s, bmap_n, *beg, beg)) 1898c2ecf20Sopenharmony_ci continue; 1908c2ecf20Sopenharmony_ci /* first zero bit found; we check next bits */ 1918c2ecf20Sopenharmony_ci for (end = *beg + 1;; end++) { 1928c2ecf20Sopenharmony_ci if (end >= *beg + max || end >= boundary 1938c2ecf20Sopenharmony_ci || reiserfs_test_le_bit(end, bh->b_data)) { 1948c2ecf20Sopenharmony_ci next = end; 1958c2ecf20Sopenharmony_ci break; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci /* 1998c2ecf20Sopenharmony_ci * finding the other end of zero bit window requires 2008c2ecf20Sopenharmony_ci * looking into journal structures (in case of 2018c2ecf20Sopenharmony_ci * searching for free blocks for unformatted nodes) 2028c2ecf20Sopenharmony_ci */ 2038c2ecf20Sopenharmony_ci if (unfm && is_block_in_journal(s, bmap_n, end, &next)) 2048c2ecf20Sopenharmony_ci break; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci /* 2088c2ecf20Sopenharmony_ci * now (*beg) points to beginning of zero bits window, 2098c2ecf20Sopenharmony_ci * (end) points to one bit after the window end 2108c2ecf20Sopenharmony_ci */ 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci /* found window of proper size */ 2138c2ecf20Sopenharmony_ci if (end - *beg >= min) { 2148c2ecf20Sopenharmony_ci int i; 2158c2ecf20Sopenharmony_ci reiserfs_prepare_for_journal(s, bh, 1); 2168c2ecf20Sopenharmony_ci /* 2178c2ecf20Sopenharmony_ci * try to set all blocks used checking are 2188c2ecf20Sopenharmony_ci * they still free 2198c2ecf20Sopenharmony_ci */ 2208c2ecf20Sopenharmony_ci for (i = *beg; i < end; i++) { 2218c2ecf20Sopenharmony_ci /* Don't check in journal again. */ 2228c2ecf20Sopenharmony_ci if (reiserfs_test_and_set_le_bit 2238c2ecf20Sopenharmony_ci (i, bh->b_data)) { 2248c2ecf20Sopenharmony_ci /* 2258c2ecf20Sopenharmony_ci * bit was set by another process while 2268c2ecf20Sopenharmony_ci * we slept in prepare_for_journal() 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_ci PROC_INFO_INC(s, scan_bitmap.stolen); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci /* 2318c2ecf20Sopenharmony_ci * we can continue with smaller set 2328c2ecf20Sopenharmony_ci * of allocated blocks, if length of 2338c2ecf20Sopenharmony_ci * this set is more or equal to `min' 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_ci if (i >= *beg + min) { 2368c2ecf20Sopenharmony_ci end = i; 2378c2ecf20Sopenharmony_ci break; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci /* 2418c2ecf20Sopenharmony_ci * otherwise we clear all bit 2428c2ecf20Sopenharmony_ci * were set ... 2438c2ecf20Sopenharmony_ci */ 2448c2ecf20Sopenharmony_ci while (--i >= *beg) 2458c2ecf20Sopenharmony_ci reiserfs_clear_le_bit 2468c2ecf20Sopenharmony_ci (i, bh->b_data); 2478c2ecf20Sopenharmony_ci reiserfs_restore_prepared_buffer(s, bh); 2488c2ecf20Sopenharmony_ci *beg = org; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci /* 2518c2ecf20Sopenharmony_ci * Search again in current block 2528c2ecf20Sopenharmony_ci * from beginning 2538c2ecf20Sopenharmony_ci */ 2548c2ecf20Sopenharmony_ci goto cont; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci bi->free_count -= (end - *beg); 2588c2ecf20Sopenharmony_ci journal_mark_dirty(th, bh); 2598c2ecf20Sopenharmony_ci brelse(bh); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci /* free block count calculation */ 2628c2ecf20Sopenharmony_ci reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 2638c2ecf20Sopenharmony_ci 1); 2648c2ecf20Sopenharmony_ci PUT_SB_FREE_BLOCKS(s, SB_FREE_BLOCKS(s) - (end - *beg)); 2658c2ecf20Sopenharmony_ci journal_mark_dirty(th, SB_BUFFER_WITH_SB(s)); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci return end - (*beg); 2688c2ecf20Sopenharmony_ci } else { 2698c2ecf20Sopenharmony_ci *beg = next; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_cistatic int bmap_hash_id(struct super_block *s, u32 id) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci char *hash_in = NULL; 2778c2ecf20Sopenharmony_ci unsigned long hash; 2788c2ecf20Sopenharmony_ci unsigned bm; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if (id <= 2) { 2818c2ecf20Sopenharmony_ci bm = 1; 2828c2ecf20Sopenharmony_ci } else { 2838c2ecf20Sopenharmony_ci hash_in = (char *)(&id); 2848c2ecf20Sopenharmony_ci hash = keyed_hash(hash_in, 4); 2858c2ecf20Sopenharmony_ci bm = hash % reiserfs_bmap_count(s); 2868c2ecf20Sopenharmony_ci if (!bm) 2878c2ecf20Sopenharmony_ci bm = 1; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci /* this can only be true when SB_BMAP_NR = 1 */ 2908c2ecf20Sopenharmony_ci if (bm >= reiserfs_bmap_count(s)) 2918c2ecf20Sopenharmony_ci bm = 0; 2928c2ecf20Sopenharmony_ci return bm; 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci/* 2968c2ecf20Sopenharmony_ci * hashes the id and then returns > 0 if the block group for the 2978c2ecf20Sopenharmony_ci * corresponding hash is full 2988c2ecf20Sopenharmony_ci */ 2998c2ecf20Sopenharmony_cistatic inline int block_group_used(struct super_block *s, u32 id) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci int bm = bmap_hash_id(s, id); 3028c2ecf20Sopenharmony_ci struct reiserfs_bitmap_info *info = &SB_AP_BITMAP(s)[bm]; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci /* 3058c2ecf20Sopenharmony_ci * If we don't have cached information on this bitmap block, we're 3068c2ecf20Sopenharmony_ci * going to have to load it later anyway. Loading it here allows us 3078c2ecf20Sopenharmony_ci * to make a better decision. This favors long-term performance gain 3088c2ecf20Sopenharmony_ci * with a better on-disk layout vs. a short term gain of skipping the 3098c2ecf20Sopenharmony_ci * read and potentially having a bad placement. 3108c2ecf20Sopenharmony_ci */ 3118c2ecf20Sopenharmony_ci if (info->free_count == UINT_MAX) { 3128c2ecf20Sopenharmony_ci struct buffer_head *bh = reiserfs_read_bitmap_block(s, bm); 3138c2ecf20Sopenharmony_ci brelse(bh); 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (info->free_count > ((s->s_blocksize << 3) * 60 / 100)) { 3178c2ecf20Sopenharmony_ci return 0; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci return 1; 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci/* 3238c2ecf20Sopenharmony_ci * the packing is returned in disk byte order 3248c2ecf20Sopenharmony_ci */ 3258c2ecf20Sopenharmony_ci__le32 reiserfs_choose_packing(struct inode * dir) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci __le32 packing; 3288c2ecf20Sopenharmony_ci if (TEST_OPTION(packing_groups, dir->i_sb)) { 3298c2ecf20Sopenharmony_ci u32 parent_dir = le32_to_cpu(INODE_PKEY(dir)->k_dir_id); 3308c2ecf20Sopenharmony_ci /* 3318c2ecf20Sopenharmony_ci * some versions of reiserfsck expect packing locality 1 to be 3328c2ecf20Sopenharmony_ci * special 3338c2ecf20Sopenharmony_ci */ 3348c2ecf20Sopenharmony_ci if (parent_dir == 1 || block_group_used(dir->i_sb, parent_dir)) 3358c2ecf20Sopenharmony_ci packing = INODE_PKEY(dir)->k_objectid; 3368c2ecf20Sopenharmony_ci else 3378c2ecf20Sopenharmony_ci packing = INODE_PKEY(dir)->k_dir_id; 3388c2ecf20Sopenharmony_ci } else 3398c2ecf20Sopenharmony_ci packing = INODE_PKEY(dir)->k_objectid; 3408c2ecf20Sopenharmony_ci return packing; 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci/* 3448c2ecf20Sopenharmony_ci * Tries to find contiguous zero bit window (given size) in given region of 3458c2ecf20Sopenharmony_ci * bitmap and place new blocks there. Returns number of allocated blocks. 3468c2ecf20Sopenharmony_ci */ 3478c2ecf20Sopenharmony_cistatic int scan_bitmap(struct reiserfs_transaction_handle *th, 3488c2ecf20Sopenharmony_ci b_blocknr_t * start, b_blocknr_t finish, 3498c2ecf20Sopenharmony_ci int min, int max, int unfm, sector_t file_block) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci int nr_allocated = 0; 3528c2ecf20Sopenharmony_ci struct super_block *s = th->t_super; 3538c2ecf20Sopenharmony_ci unsigned int bm, off; 3548c2ecf20Sopenharmony_ci unsigned int end_bm, end_off; 3558c2ecf20Sopenharmony_ci unsigned int off_max = s->s_blocksize << 3; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci BUG_ON(!th->t_trans_id); 3588c2ecf20Sopenharmony_ci PROC_INFO_INC(s, scan_bitmap.call); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* No point in looking for more free blocks */ 3618c2ecf20Sopenharmony_ci if (SB_FREE_BLOCKS(s) <= 0) 3628c2ecf20Sopenharmony_ci return 0; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci get_bit_address(s, *start, &bm, &off); 3658c2ecf20Sopenharmony_ci get_bit_address(s, finish, &end_bm, &end_off); 3668c2ecf20Sopenharmony_ci if (bm > reiserfs_bmap_count(s)) 3678c2ecf20Sopenharmony_ci return 0; 3688c2ecf20Sopenharmony_ci if (end_bm > reiserfs_bmap_count(s)) 3698c2ecf20Sopenharmony_ci end_bm = reiserfs_bmap_count(s); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci /* 3728c2ecf20Sopenharmony_ci * When the bitmap is more than 10% free, anyone can allocate. 3738c2ecf20Sopenharmony_ci * When it's less than 10% free, only files that already use the 3748c2ecf20Sopenharmony_ci * bitmap are allowed. Once we pass 80% full, this restriction 3758c2ecf20Sopenharmony_ci * is lifted. 3768c2ecf20Sopenharmony_ci * 3778c2ecf20Sopenharmony_ci * We do this so that files that grow later still have space close to 3788c2ecf20Sopenharmony_ci * their original allocation. This improves locality, and presumably 3798c2ecf20Sopenharmony_ci * performance as a result. 3808c2ecf20Sopenharmony_ci * 3818c2ecf20Sopenharmony_ci * This is only an allocation policy and does not make up for getting a 3828c2ecf20Sopenharmony_ci * bad hint. Decent hinting must be implemented for this to work well. 3838c2ecf20Sopenharmony_ci */ 3848c2ecf20Sopenharmony_ci if (TEST_OPTION(skip_busy, s) 3858c2ecf20Sopenharmony_ci && SB_FREE_BLOCKS(s) > SB_BLOCK_COUNT(s) / 20) { 3868c2ecf20Sopenharmony_ci for (; bm < end_bm; bm++, off = 0) { 3878c2ecf20Sopenharmony_ci if ((off && (!unfm || (file_block != 0))) 3888c2ecf20Sopenharmony_ci || SB_AP_BITMAP(s)[bm].free_count > 3898c2ecf20Sopenharmony_ci (s->s_blocksize << 3) / 10) 3908c2ecf20Sopenharmony_ci nr_allocated = 3918c2ecf20Sopenharmony_ci scan_bitmap_block(th, bm, &off, off_max, 3928c2ecf20Sopenharmony_ci min, max, unfm); 3938c2ecf20Sopenharmony_ci if (nr_allocated) 3948c2ecf20Sopenharmony_ci goto ret; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci /* we know from above that start is a reasonable number */ 3978c2ecf20Sopenharmony_ci get_bit_address(s, *start, &bm, &off); 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci for (; bm < end_bm; bm++, off = 0) { 4018c2ecf20Sopenharmony_ci nr_allocated = 4028c2ecf20Sopenharmony_ci scan_bitmap_block(th, bm, &off, off_max, min, max, unfm); 4038c2ecf20Sopenharmony_ci if (nr_allocated) 4048c2ecf20Sopenharmony_ci goto ret; 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci nr_allocated = 4088c2ecf20Sopenharmony_ci scan_bitmap_block(th, bm, &off, end_off + 1, min, max, unfm); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ciret: 4118c2ecf20Sopenharmony_ci *start = bm * off_max + off; 4128c2ecf20Sopenharmony_ci return nr_allocated; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistatic void _reiserfs_free_block(struct reiserfs_transaction_handle *th, 4178c2ecf20Sopenharmony_ci struct inode *inode, b_blocknr_t block, 4188c2ecf20Sopenharmony_ci int for_unformatted) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci struct super_block *s = th->t_super; 4218c2ecf20Sopenharmony_ci struct reiserfs_super_block *rs; 4228c2ecf20Sopenharmony_ci struct buffer_head *sbh, *bmbh; 4238c2ecf20Sopenharmony_ci struct reiserfs_bitmap_info *apbi; 4248c2ecf20Sopenharmony_ci unsigned int nr, offset; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci BUG_ON(!th->t_trans_id); 4278c2ecf20Sopenharmony_ci PROC_INFO_INC(s, free_block); 4288c2ecf20Sopenharmony_ci rs = SB_DISK_SUPER_BLOCK(s); 4298c2ecf20Sopenharmony_ci sbh = SB_BUFFER_WITH_SB(s); 4308c2ecf20Sopenharmony_ci apbi = SB_AP_BITMAP(s); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci get_bit_address(s, block, &nr, &offset); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci if (nr >= reiserfs_bmap_count(s)) { 4358c2ecf20Sopenharmony_ci reiserfs_error(s, "vs-4075", "block %lu is out of range", 4368c2ecf20Sopenharmony_ci block); 4378c2ecf20Sopenharmony_ci return; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci bmbh = reiserfs_read_bitmap_block(s, nr); 4418c2ecf20Sopenharmony_ci if (!bmbh) 4428c2ecf20Sopenharmony_ci return; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci reiserfs_prepare_for_journal(s, bmbh, 1); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci /* clear bit for the given block in bit map */ 4478c2ecf20Sopenharmony_ci if (!reiserfs_test_and_clear_le_bit(offset, bmbh->b_data)) { 4488c2ecf20Sopenharmony_ci reiserfs_error(s, "vs-4080", 4498c2ecf20Sopenharmony_ci "block %lu: bit already cleared", block); 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci apbi[nr].free_count++; 4528c2ecf20Sopenharmony_ci journal_mark_dirty(th, bmbh); 4538c2ecf20Sopenharmony_ci brelse(bmbh); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci reiserfs_prepare_for_journal(s, sbh, 1); 4568c2ecf20Sopenharmony_ci /* update super block */ 4578c2ecf20Sopenharmony_ci set_sb_free_blocks(rs, sb_free_blocks(rs) + 1); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci journal_mark_dirty(th, sbh); 4608c2ecf20Sopenharmony_ci if (for_unformatted) { 4618c2ecf20Sopenharmony_ci int depth = reiserfs_write_unlock_nested(s); 4628c2ecf20Sopenharmony_ci dquot_free_block_nodirty(inode, 1); 4638c2ecf20Sopenharmony_ci reiserfs_write_lock_nested(s, depth); 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_civoid reiserfs_free_block(struct reiserfs_transaction_handle *th, 4688c2ecf20Sopenharmony_ci struct inode *inode, b_blocknr_t block, 4698c2ecf20Sopenharmony_ci int for_unformatted) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci struct super_block *s = th->t_super; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci BUG_ON(!th->t_trans_id); 4748c2ecf20Sopenharmony_ci RFALSE(!s, "vs-4061: trying to free block on nonexistent device"); 4758c2ecf20Sopenharmony_ci if (!is_reusable(s, block, 1)) 4768c2ecf20Sopenharmony_ci return; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci if (block > sb_block_count(REISERFS_SB(s)->s_rs)) { 4798c2ecf20Sopenharmony_ci reiserfs_error(th->t_super, "bitmap-4072", 4808c2ecf20Sopenharmony_ci "Trying to free block outside file system " 4818c2ecf20Sopenharmony_ci "boundaries (%lu > %lu)", 4828c2ecf20Sopenharmony_ci block, sb_block_count(REISERFS_SB(s)->s_rs)); 4838c2ecf20Sopenharmony_ci return; 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci /* mark it before we clear it, just in case */ 4868c2ecf20Sopenharmony_ci journal_mark_freed(th, s, block); 4878c2ecf20Sopenharmony_ci _reiserfs_free_block(th, inode, block, for_unformatted); 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci/* preallocated blocks don't need to be run through journal_mark_freed */ 4918c2ecf20Sopenharmony_cistatic void reiserfs_free_prealloc_block(struct reiserfs_transaction_handle *th, 4928c2ecf20Sopenharmony_ci struct inode *inode, b_blocknr_t block) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci BUG_ON(!th->t_trans_id); 4958c2ecf20Sopenharmony_ci RFALSE(!th->t_super, 4968c2ecf20Sopenharmony_ci "vs-4060: trying to free block on nonexistent device"); 4978c2ecf20Sopenharmony_ci if (!is_reusable(th->t_super, block, 1)) 4988c2ecf20Sopenharmony_ci return; 4998c2ecf20Sopenharmony_ci _reiserfs_free_block(th, inode, block, 1); 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cistatic void __discard_prealloc(struct reiserfs_transaction_handle *th, 5038c2ecf20Sopenharmony_ci struct reiserfs_inode_info *ei) 5048c2ecf20Sopenharmony_ci{ 5058c2ecf20Sopenharmony_ci unsigned long save = ei->i_prealloc_block; 5068c2ecf20Sopenharmony_ci int dirty = 0; 5078c2ecf20Sopenharmony_ci struct inode *inode = &ei->vfs_inode; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci BUG_ON(!th->t_trans_id); 5108c2ecf20Sopenharmony_ci#ifdef CONFIG_REISERFS_CHECK 5118c2ecf20Sopenharmony_ci if (ei->i_prealloc_count < 0) 5128c2ecf20Sopenharmony_ci reiserfs_error(th->t_super, "zam-4001", 5138c2ecf20Sopenharmony_ci "inode has negative prealloc blocks count."); 5148c2ecf20Sopenharmony_ci#endif 5158c2ecf20Sopenharmony_ci while (ei->i_prealloc_count > 0) { 5168c2ecf20Sopenharmony_ci b_blocknr_t block_to_free; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci /* 5198c2ecf20Sopenharmony_ci * reiserfs_free_prealloc_block can drop the write lock, 5208c2ecf20Sopenharmony_ci * which could allow another caller to free the same block. 5218c2ecf20Sopenharmony_ci * We can protect against it by modifying the prealloc 5228c2ecf20Sopenharmony_ci * state before calling it. 5238c2ecf20Sopenharmony_ci */ 5248c2ecf20Sopenharmony_ci block_to_free = ei->i_prealloc_block++; 5258c2ecf20Sopenharmony_ci ei->i_prealloc_count--; 5268c2ecf20Sopenharmony_ci reiserfs_free_prealloc_block(th, inode, block_to_free); 5278c2ecf20Sopenharmony_ci dirty = 1; 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci if (dirty) 5308c2ecf20Sopenharmony_ci reiserfs_update_sd(th, inode); 5318c2ecf20Sopenharmony_ci ei->i_prealloc_block = save; 5328c2ecf20Sopenharmony_ci list_del_init(&ei->i_prealloc_list); 5338c2ecf20Sopenharmony_ci} 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci/* FIXME: It should be inline function */ 5368c2ecf20Sopenharmony_civoid reiserfs_discard_prealloc(struct reiserfs_transaction_handle *th, 5378c2ecf20Sopenharmony_ci struct inode *inode) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci struct reiserfs_inode_info *ei = REISERFS_I(inode); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci BUG_ON(!th->t_trans_id); 5428c2ecf20Sopenharmony_ci if (ei->i_prealloc_count) 5438c2ecf20Sopenharmony_ci __discard_prealloc(th, ei); 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_civoid reiserfs_discard_all_prealloc(struct reiserfs_transaction_handle *th) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci struct list_head *plist = &SB_JOURNAL(th->t_super)->j_prealloc_list; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci BUG_ON(!th->t_trans_id); 5518c2ecf20Sopenharmony_ci while (!list_empty(plist)) { 5528c2ecf20Sopenharmony_ci struct reiserfs_inode_info *ei; 5538c2ecf20Sopenharmony_ci ei = list_entry(plist->next, struct reiserfs_inode_info, 5548c2ecf20Sopenharmony_ci i_prealloc_list); 5558c2ecf20Sopenharmony_ci#ifdef CONFIG_REISERFS_CHECK 5568c2ecf20Sopenharmony_ci if (!ei->i_prealloc_count) { 5578c2ecf20Sopenharmony_ci reiserfs_error(th->t_super, "zam-4001", 5588c2ecf20Sopenharmony_ci "inode is in prealloc list but has " 5598c2ecf20Sopenharmony_ci "no preallocated blocks."); 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci#endif 5628c2ecf20Sopenharmony_ci __discard_prealloc(th, ei); 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_civoid reiserfs_init_alloc_options(struct super_block *s) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci set_bit(_ALLOC_skip_busy, &SB_ALLOC_OPTS(s)); 5698c2ecf20Sopenharmony_ci set_bit(_ALLOC_dirid_groups, &SB_ALLOC_OPTS(s)); 5708c2ecf20Sopenharmony_ci set_bit(_ALLOC_packing_groups, &SB_ALLOC_OPTS(s)); 5718c2ecf20Sopenharmony_ci} 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci/* block allocator related options are parsed here */ 5748c2ecf20Sopenharmony_ciint reiserfs_parse_alloc_options(struct super_block *s, char *options) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci char *this_char, *value; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci /* clear default settings */ 5798c2ecf20Sopenharmony_ci REISERFS_SB(s)->s_alloc_options.bits = 0; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci while ((this_char = strsep(&options, ":")) != NULL) { 5828c2ecf20Sopenharmony_ci if ((value = strchr(this_char, '=')) != NULL) 5838c2ecf20Sopenharmony_ci *value++ = 0; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci if (!strcmp(this_char, "concentrating_formatted_nodes")) { 5868c2ecf20Sopenharmony_ci int temp; 5878c2ecf20Sopenharmony_ci SET_OPTION(concentrating_formatted_nodes); 5888c2ecf20Sopenharmony_ci temp = (value 5898c2ecf20Sopenharmony_ci && *value) ? simple_strtoul(value, &value, 5908c2ecf20Sopenharmony_ci 0) : 10; 5918c2ecf20Sopenharmony_ci if (temp <= 0 || temp > 100) { 5928c2ecf20Sopenharmony_ci REISERFS_SB(s)->s_alloc_options.border = 10; 5938c2ecf20Sopenharmony_ci } else { 5948c2ecf20Sopenharmony_ci REISERFS_SB(s)->s_alloc_options.border = 5958c2ecf20Sopenharmony_ci 100 / temp; 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci continue; 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci if (!strcmp(this_char, "displacing_large_files")) { 6008c2ecf20Sopenharmony_ci SET_OPTION(displacing_large_files); 6018c2ecf20Sopenharmony_ci REISERFS_SB(s)->s_alloc_options.large_file_size = 6028c2ecf20Sopenharmony_ci (value 6038c2ecf20Sopenharmony_ci && *value) ? simple_strtoul(value, &value, 0) : 16; 6048c2ecf20Sopenharmony_ci continue; 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci if (!strcmp(this_char, "displacing_new_packing_localities")) { 6078c2ecf20Sopenharmony_ci SET_OPTION(displacing_new_packing_localities); 6088c2ecf20Sopenharmony_ci continue; 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci if (!strcmp(this_char, "old_hashed_relocation")) { 6128c2ecf20Sopenharmony_ci SET_OPTION(old_hashed_relocation); 6138c2ecf20Sopenharmony_ci continue; 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci if (!strcmp(this_char, "new_hashed_relocation")) { 6178c2ecf20Sopenharmony_ci SET_OPTION(new_hashed_relocation); 6188c2ecf20Sopenharmony_ci continue; 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci if (!strcmp(this_char, "dirid_groups")) { 6228c2ecf20Sopenharmony_ci SET_OPTION(dirid_groups); 6238c2ecf20Sopenharmony_ci continue; 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci if (!strcmp(this_char, "oid_groups")) { 6268c2ecf20Sopenharmony_ci SET_OPTION(oid_groups); 6278c2ecf20Sopenharmony_ci continue; 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci if (!strcmp(this_char, "packing_groups")) { 6308c2ecf20Sopenharmony_ci SET_OPTION(packing_groups); 6318c2ecf20Sopenharmony_ci continue; 6328c2ecf20Sopenharmony_ci } 6338c2ecf20Sopenharmony_ci if (!strcmp(this_char, "hashed_formatted_nodes")) { 6348c2ecf20Sopenharmony_ci SET_OPTION(hashed_formatted_nodes); 6358c2ecf20Sopenharmony_ci continue; 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci if (!strcmp(this_char, "skip_busy")) { 6398c2ecf20Sopenharmony_ci SET_OPTION(skip_busy); 6408c2ecf20Sopenharmony_ci continue; 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci if (!strcmp(this_char, "hundredth_slices")) { 6448c2ecf20Sopenharmony_ci SET_OPTION(hundredth_slices); 6458c2ecf20Sopenharmony_ci continue; 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci if (!strcmp(this_char, "old_way")) { 6498c2ecf20Sopenharmony_ci SET_OPTION(old_way); 6508c2ecf20Sopenharmony_ci continue; 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci if (!strcmp(this_char, "displace_based_on_dirid")) { 6548c2ecf20Sopenharmony_ci SET_OPTION(displace_based_on_dirid); 6558c2ecf20Sopenharmony_ci continue; 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci if (!strcmp(this_char, "preallocmin")) { 6598c2ecf20Sopenharmony_ci REISERFS_SB(s)->s_alloc_options.preallocmin = 6608c2ecf20Sopenharmony_ci (value 6618c2ecf20Sopenharmony_ci && *value) ? simple_strtoul(value, &value, 0) : 4; 6628c2ecf20Sopenharmony_ci continue; 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci if (!strcmp(this_char, "preallocsize")) { 6668c2ecf20Sopenharmony_ci REISERFS_SB(s)->s_alloc_options.preallocsize = 6678c2ecf20Sopenharmony_ci (value 6688c2ecf20Sopenharmony_ci && *value) ? simple_strtoul(value, &value, 6698c2ecf20Sopenharmony_ci 0) : 6708c2ecf20Sopenharmony_ci PREALLOCATION_SIZE; 6718c2ecf20Sopenharmony_ci continue; 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci reiserfs_warning(s, "zam-4001", "unknown option - %s", 6758c2ecf20Sopenharmony_ci this_char); 6768c2ecf20Sopenharmony_ci return 1; 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci reiserfs_info(s, "allocator options = [%08x]\n", SB_ALLOC_OPTS(s)); 6808c2ecf20Sopenharmony_ci return 0; 6818c2ecf20Sopenharmony_ci} 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_cistatic void print_sep(struct seq_file *seq, int *first) 6848c2ecf20Sopenharmony_ci{ 6858c2ecf20Sopenharmony_ci if (!*first) 6868c2ecf20Sopenharmony_ci seq_puts(seq, ":"); 6878c2ecf20Sopenharmony_ci else 6888c2ecf20Sopenharmony_ci *first = 0; 6898c2ecf20Sopenharmony_ci} 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_civoid show_alloc_options(struct seq_file *seq, struct super_block *s) 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci int first = 1; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci if (SB_ALLOC_OPTS(s) == ((1 << _ALLOC_skip_busy) | 6968c2ecf20Sopenharmony_ci (1 << _ALLOC_dirid_groups) | (1 << _ALLOC_packing_groups))) 6978c2ecf20Sopenharmony_ci return; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci seq_puts(seq, ",alloc="); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci if (TEST_OPTION(concentrating_formatted_nodes, s)) { 7028c2ecf20Sopenharmony_ci print_sep(seq, &first); 7038c2ecf20Sopenharmony_ci if (REISERFS_SB(s)->s_alloc_options.border != 10) { 7048c2ecf20Sopenharmony_ci seq_printf(seq, "concentrating_formatted_nodes=%d", 7058c2ecf20Sopenharmony_ci 100 / REISERFS_SB(s)->s_alloc_options.border); 7068c2ecf20Sopenharmony_ci } else 7078c2ecf20Sopenharmony_ci seq_puts(seq, "concentrating_formatted_nodes"); 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci if (TEST_OPTION(displacing_large_files, s)) { 7108c2ecf20Sopenharmony_ci print_sep(seq, &first); 7118c2ecf20Sopenharmony_ci if (REISERFS_SB(s)->s_alloc_options.large_file_size != 16) { 7128c2ecf20Sopenharmony_ci seq_printf(seq, "displacing_large_files=%lu", 7138c2ecf20Sopenharmony_ci REISERFS_SB(s)->s_alloc_options.large_file_size); 7148c2ecf20Sopenharmony_ci } else 7158c2ecf20Sopenharmony_ci seq_puts(seq, "displacing_large_files"); 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci if (TEST_OPTION(displacing_new_packing_localities, s)) { 7188c2ecf20Sopenharmony_ci print_sep(seq, &first); 7198c2ecf20Sopenharmony_ci seq_puts(seq, "displacing_new_packing_localities"); 7208c2ecf20Sopenharmony_ci } 7218c2ecf20Sopenharmony_ci if (TEST_OPTION(old_hashed_relocation, s)) { 7228c2ecf20Sopenharmony_ci print_sep(seq, &first); 7238c2ecf20Sopenharmony_ci seq_puts(seq, "old_hashed_relocation"); 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci if (TEST_OPTION(new_hashed_relocation, s)) { 7268c2ecf20Sopenharmony_ci print_sep(seq, &first); 7278c2ecf20Sopenharmony_ci seq_puts(seq, "new_hashed_relocation"); 7288c2ecf20Sopenharmony_ci } 7298c2ecf20Sopenharmony_ci if (TEST_OPTION(dirid_groups, s)) { 7308c2ecf20Sopenharmony_ci print_sep(seq, &first); 7318c2ecf20Sopenharmony_ci seq_puts(seq, "dirid_groups"); 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci if (TEST_OPTION(oid_groups, s)) { 7348c2ecf20Sopenharmony_ci print_sep(seq, &first); 7358c2ecf20Sopenharmony_ci seq_puts(seq, "oid_groups"); 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci if (TEST_OPTION(packing_groups, s)) { 7388c2ecf20Sopenharmony_ci print_sep(seq, &first); 7398c2ecf20Sopenharmony_ci seq_puts(seq, "packing_groups"); 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci if (TEST_OPTION(hashed_formatted_nodes, s)) { 7428c2ecf20Sopenharmony_ci print_sep(seq, &first); 7438c2ecf20Sopenharmony_ci seq_puts(seq, "hashed_formatted_nodes"); 7448c2ecf20Sopenharmony_ci } 7458c2ecf20Sopenharmony_ci if (TEST_OPTION(skip_busy, s)) { 7468c2ecf20Sopenharmony_ci print_sep(seq, &first); 7478c2ecf20Sopenharmony_ci seq_puts(seq, "skip_busy"); 7488c2ecf20Sopenharmony_ci } 7498c2ecf20Sopenharmony_ci if (TEST_OPTION(hundredth_slices, s)) { 7508c2ecf20Sopenharmony_ci print_sep(seq, &first); 7518c2ecf20Sopenharmony_ci seq_puts(seq, "hundredth_slices"); 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci if (TEST_OPTION(old_way, s)) { 7548c2ecf20Sopenharmony_ci print_sep(seq, &first); 7558c2ecf20Sopenharmony_ci seq_puts(seq, "old_way"); 7568c2ecf20Sopenharmony_ci } 7578c2ecf20Sopenharmony_ci if (TEST_OPTION(displace_based_on_dirid, s)) { 7588c2ecf20Sopenharmony_ci print_sep(seq, &first); 7598c2ecf20Sopenharmony_ci seq_puts(seq, "displace_based_on_dirid"); 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci if (REISERFS_SB(s)->s_alloc_options.preallocmin != 0) { 7628c2ecf20Sopenharmony_ci print_sep(seq, &first); 7638c2ecf20Sopenharmony_ci seq_printf(seq, "preallocmin=%d", 7648c2ecf20Sopenharmony_ci REISERFS_SB(s)->s_alloc_options.preallocmin); 7658c2ecf20Sopenharmony_ci } 7668c2ecf20Sopenharmony_ci if (REISERFS_SB(s)->s_alloc_options.preallocsize != 17) { 7678c2ecf20Sopenharmony_ci print_sep(seq, &first); 7688c2ecf20Sopenharmony_ci seq_printf(seq, "preallocsize=%d", 7698c2ecf20Sopenharmony_ci REISERFS_SB(s)->s_alloc_options.preallocsize); 7708c2ecf20Sopenharmony_ci } 7718c2ecf20Sopenharmony_ci} 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_cistatic inline void new_hashed_relocation(reiserfs_blocknr_hint_t * hint) 7748c2ecf20Sopenharmony_ci{ 7758c2ecf20Sopenharmony_ci char *hash_in; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci if (hint->formatted_node) { 7788c2ecf20Sopenharmony_ci hash_in = (char *)&hint->key.k_dir_id; 7798c2ecf20Sopenharmony_ci } else { 7808c2ecf20Sopenharmony_ci if (!hint->inode) { 7818c2ecf20Sopenharmony_ci /*hint->search_start = hint->beg;*/ 7828c2ecf20Sopenharmony_ci hash_in = (char *)&hint->key.k_dir_id; 7838c2ecf20Sopenharmony_ci } else 7848c2ecf20Sopenharmony_ci if (TEST_OPTION(displace_based_on_dirid, hint->th->t_super)) 7858c2ecf20Sopenharmony_ci hash_in = (char *)(&INODE_PKEY(hint->inode)->k_dir_id); 7868c2ecf20Sopenharmony_ci else 7878c2ecf20Sopenharmony_ci hash_in = 7888c2ecf20Sopenharmony_ci (char *)(&INODE_PKEY(hint->inode)->k_objectid); 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci hint->search_start = 7928c2ecf20Sopenharmony_ci hint->beg + keyed_hash(hash_in, 4) % (hint->end - hint->beg); 7938c2ecf20Sopenharmony_ci} 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci/* 7968c2ecf20Sopenharmony_ci * Relocation based on dirid, hashing them into a given bitmap block 7978c2ecf20Sopenharmony_ci * files. Formatted nodes are unaffected, a separate policy covers them 7988c2ecf20Sopenharmony_ci */ 7998c2ecf20Sopenharmony_cistatic void dirid_groups(reiserfs_blocknr_hint_t * hint) 8008c2ecf20Sopenharmony_ci{ 8018c2ecf20Sopenharmony_ci unsigned long hash; 8028c2ecf20Sopenharmony_ci __u32 dirid = 0; 8038c2ecf20Sopenharmony_ci int bm = 0; 8048c2ecf20Sopenharmony_ci struct super_block *sb = hint->th->t_super; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci if (hint->inode) 8078c2ecf20Sopenharmony_ci dirid = le32_to_cpu(INODE_PKEY(hint->inode)->k_dir_id); 8088c2ecf20Sopenharmony_ci else if (hint->formatted_node) 8098c2ecf20Sopenharmony_ci dirid = hint->key.k_dir_id; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci if (dirid) { 8128c2ecf20Sopenharmony_ci bm = bmap_hash_id(sb, dirid); 8138c2ecf20Sopenharmony_ci hash = bm * (sb->s_blocksize << 3); 8148c2ecf20Sopenharmony_ci /* give a portion of the block group to metadata */ 8158c2ecf20Sopenharmony_ci if (hint->inode) 8168c2ecf20Sopenharmony_ci hash += sb->s_blocksize / 2; 8178c2ecf20Sopenharmony_ci hint->search_start = hash; 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci} 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci/* 8228c2ecf20Sopenharmony_ci * Relocation based on oid, hashing them into a given bitmap block 8238c2ecf20Sopenharmony_ci * files. Formatted nodes are unaffected, a separate policy covers them 8248c2ecf20Sopenharmony_ci */ 8258c2ecf20Sopenharmony_cistatic void oid_groups(reiserfs_blocknr_hint_t * hint) 8268c2ecf20Sopenharmony_ci{ 8278c2ecf20Sopenharmony_ci if (hint->inode) { 8288c2ecf20Sopenharmony_ci unsigned long hash; 8298c2ecf20Sopenharmony_ci __u32 oid; 8308c2ecf20Sopenharmony_ci __u32 dirid; 8318c2ecf20Sopenharmony_ci int bm; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci dirid = le32_to_cpu(INODE_PKEY(hint->inode)->k_dir_id); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci /* 8368c2ecf20Sopenharmony_ci * keep the root dir and it's first set of subdirs close to 8378c2ecf20Sopenharmony_ci * the start of the disk 8388c2ecf20Sopenharmony_ci */ 8398c2ecf20Sopenharmony_ci if (dirid <= 2) 8408c2ecf20Sopenharmony_ci hash = (hint->inode->i_sb->s_blocksize << 3); 8418c2ecf20Sopenharmony_ci else { 8428c2ecf20Sopenharmony_ci oid = le32_to_cpu(INODE_PKEY(hint->inode)->k_objectid); 8438c2ecf20Sopenharmony_ci bm = bmap_hash_id(hint->inode->i_sb, oid); 8448c2ecf20Sopenharmony_ci hash = bm * (hint->inode->i_sb->s_blocksize << 3); 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci hint->search_start = hash; 8478c2ecf20Sopenharmony_ci } 8488c2ecf20Sopenharmony_ci} 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci/* 8518c2ecf20Sopenharmony_ci * returns 1 if it finds an indirect item and gets valid hint info 8528c2ecf20Sopenharmony_ci * from it, otherwise 0 8538c2ecf20Sopenharmony_ci */ 8548c2ecf20Sopenharmony_cistatic int get_left_neighbor(reiserfs_blocknr_hint_t * hint) 8558c2ecf20Sopenharmony_ci{ 8568c2ecf20Sopenharmony_ci struct treepath *path; 8578c2ecf20Sopenharmony_ci struct buffer_head *bh; 8588c2ecf20Sopenharmony_ci struct item_head *ih; 8598c2ecf20Sopenharmony_ci int pos_in_item; 8608c2ecf20Sopenharmony_ci __le32 *item; 8618c2ecf20Sopenharmony_ci int ret = 0; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci /* 8648c2ecf20Sopenharmony_ci * reiserfs code can call this function w/o pointer to path 8658c2ecf20Sopenharmony_ci * structure supplied; then we rely on supplied search_start 8668c2ecf20Sopenharmony_ci */ 8678c2ecf20Sopenharmony_ci if (!hint->path) 8688c2ecf20Sopenharmony_ci return 0; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci path = hint->path; 8718c2ecf20Sopenharmony_ci bh = get_last_bh(path); 8728c2ecf20Sopenharmony_ci RFALSE(!bh, "green-4002: Illegal path specified to get_left_neighbor"); 8738c2ecf20Sopenharmony_ci ih = tp_item_head(path); 8748c2ecf20Sopenharmony_ci pos_in_item = path->pos_in_item; 8758c2ecf20Sopenharmony_ci item = tp_item_body(path); 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci hint->search_start = bh->b_blocknr; 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci /* 8808c2ecf20Sopenharmony_ci * for indirect item: go to left and look for the first non-hole entry 8818c2ecf20Sopenharmony_ci * in the indirect item 8828c2ecf20Sopenharmony_ci */ 8838c2ecf20Sopenharmony_ci if (!hint->formatted_node && is_indirect_le_ih(ih)) { 8848c2ecf20Sopenharmony_ci if (pos_in_item == I_UNFM_NUM(ih)) 8858c2ecf20Sopenharmony_ci pos_in_item--; 8868c2ecf20Sopenharmony_ci while (pos_in_item >= 0) { 8878c2ecf20Sopenharmony_ci int t = get_block_num(item, pos_in_item); 8888c2ecf20Sopenharmony_ci if (t) { 8898c2ecf20Sopenharmony_ci hint->search_start = t; 8908c2ecf20Sopenharmony_ci ret = 1; 8918c2ecf20Sopenharmony_ci break; 8928c2ecf20Sopenharmony_ci } 8938c2ecf20Sopenharmony_ci pos_in_item--; 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci /* does result value fit into specified region? */ 8988c2ecf20Sopenharmony_ci return ret; 8998c2ecf20Sopenharmony_ci} 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci/* 9028c2ecf20Sopenharmony_ci * should be, if formatted node, then try to put on first part of the device 9038c2ecf20Sopenharmony_ci * specified as number of percent with mount option device, else try to put 9048c2ecf20Sopenharmony_ci * on last of device. This is not to say it is good code to do so, 9058c2ecf20Sopenharmony_ci * but the effect should be measured. 9068c2ecf20Sopenharmony_ci */ 9078c2ecf20Sopenharmony_cistatic inline void set_border_in_hint(struct super_block *s, 9088c2ecf20Sopenharmony_ci reiserfs_blocknr_hint_t * hint) 9098c2ecf20Sopenharmony_ci{ 9108c2ecf20Sopenharmony_ci b_blocknr_t border = 9118c2ecf20Sopenharmony_ci SB_BLOCK_COUNT(s) / REISERFS_SB(s)->s_alloc_options.border; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci if (hint->formatted_node) 9148c2ecf20Sopenharmony_ci hint->end = border - 1; 9158c2ecf20Sopenharmony_ci else 9168c2ecf20Sopenharmony_ci hint->beg = border; 9178c2ecf20Sopenharmony_ci} 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_cistatic inline void displace_large_file(reiserfs_blocknr_hint_t * hint) 9208c2ecf20Sopenharmony_ci{ 9218c2ecf20Sopenharmony_ci if (TEST_OPTION(displace_based_on_dirid, hint->th->t_super)) 9228c2ecf20Sopenharmony_ci hint->search_start = 9238c2ecf20Sopenharmony_ci hint->beg + 9248c2ecf20Sopenharmony_ci keyed_hash((char *)(&INODE_PKEY(hint->inode)->k_dir_id), 9258c2ecf20Sopenharmony_ci 4) % (hint->end - hint->beg); 9268c2ecf20Sopenharmony_ci else 9278c2ecf20Sopenharmony_ci hint->search_start = 9288c2ecf20Sopenharmony_ci hint->beg + 9298c2ecf20Sopenharmony_ci keyed_hash((char *)(&INODE_PKEY(hint->inode)->k_objectid), 9308c2ecf20Sopenharmony_ci 4) % (hint->end - hint->beg); 9318c2ecf20Sopenharmony_ci} 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_cistatic inline void hash_formatted_node(reiserfs_blocknr_hint_t * hint) 9348c2ecf20Sopenharmony_ci{ 9358c2ecf20Sopenharmony_ci char *hash_in; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci if (!hint->inode) 9388c2ecf20Sopenharmony_ci hash_in = (char *)&hint->key.k_dir_id; 9398c2ecf20Sopenharmony_ci else if (TEST_OPTION(displace_based_on_dirid, hint->th->t_super)) 9408c2ecf20Sopenharmony_ci hash_in = (char *)(&INODE_PKEY(hint->inode)->k_dir_id); 9418c2ecf20Sopenharmony_ci else 9428c2ecf20Sopenharmony_ci hash_in = (char *)(&INODE_PKEY(hint->inode)->k_objectid); 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci hint->search_start = 9458c2ecf20Sopenharmony_ci hint->beg + keyed_hash(hash_in, 4) % (hint->end - hint->beg); 9468c2ecf20Sopenharmony_ci} 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_cistatic inline int 9498c2ecf20Sopenharmony_cithis_blocknr_allocation_would_make_it_a_large_file(reiserfs_blocknr_hint_t * 9508c2ecf20Sopenharmony_ci hint) 9518c2ecf20Sopenharmony_ci{ 9528c2ecf20Sopenharmony_ci return hint->block == 9538c2ecf20Sopenharmony_ci REISERFS_SB(hint->th->t_super)->s_alloc_options.large_file_size; 9548c2ecf20Sopenharmony_ci} 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci#ifdef DISPLACE_NEW_PACKING_LOCALITIES 9578c2ecf20Sopenharmony_cistatic inline void displace_new_packing_locality(reiserfs_blocknr_hint_t * hint) 9588c2ecf20Sopenharmony_ci{ 9598c2ecf20Sopenharmony_ci struct in_core_key *key = &hint->key; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci hint->th->displace_new_blocks = 0; 9628c2ecf20Sopenharmony_ci hint->search_start = 9638c2ecf20Sopenharmony_ci hint->beg + keyed_hash((char *)(&key->k_objectid), 9648c2ecf20Sopenharmony_ci 4) % (hint->end - hint->beg); 9658c2ecf20Sopenharmony_ci} 9668c2ecf20Sopenharmony_ci#endif 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_cistatic inline int old_hashed_relocation(reiserfs_blocknr_hint_t * hint) 9698c2ecf20Sopenharmony_ci{ 9708c2ecf20Sopenharmony_ci b_blocknr_t border; 9718c2ecf20Sopenharmony_ci u32 hash_in; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci if (hint->formatted_node || hint->inode == NULL) { 9748c2ecf20Sopenharmony_ci return 0; 9758c2ecf20Sopenharmony_ci } 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci hash_in = le32_to_cpu((INODE_PKEY(hint->inode))->k_dir_id); 9788c2ecf20Sopenharmony_ci border = 9798c2ecf20Sopenharmony_ci hint->beg + (u32) keyed_hash(((char *)(&hash_in)), 9808c2ecf20Sopenharmony_ci 4) % (hint->end - hint->beg - 1); 9818c2ecf20Sopenharmony_ci if (border > hint->search_start) 9828c2ecf20Sopenharmony_ci hint->search_start = border; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci return 1; 9858c2ecf20Sopenharmony_ci} 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_cistatic inline int old_way(reiserfs_blocknr_hint_t * hint) 9888c2ecf20Sopenharmony_ci{ 9898c2ecf20Sopenharmony_ci b_blocknr_t border; 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci if (hint->formatted_node || hint->inode == NULL) { 9928c2ecf20Sopenharmony_ci return 0; 9938c2ecf20Sopenharmony_ci } 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci border = 9968c2ecf20Sopenharmony_ci hint->beg + 9978c2ecf20Sopenharmony_ci le32_to_cpu(INODE_PKEY(hint->inode)->k_dir_id) % (hint->end - 9988c2ecf20Sopenharmony_ci hint->beg); 9998c2ecf20Sopenharmony_ci if (border > hint->search_start) 10008c2ecf20Sopenharmony_ci hint->search_start = border; 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci return 1; 10038c2ecf20Sopenharmony_ci} 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_cistatic inline void hundredth_slices(reiserfs_blocknr_hint_t * hint) 10068c2ecf20Sopenharmony_ci{ 10078c2ecf20Sopenharmony_ci struct in_core_key *key = &hint->key; 10088c2ecf20Sopenharmony_ci b_blocknr_t slice_start; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci slice_start = 10118c2ecf20Sopenharmony_ci (keyed_hash((char *)(&key->k_dir_id), 4) % 100) * (hint->end / 100); 10128c2ecf20Sopenharmony_ci if (slice_start > hint->search_start 10138c2ecf20Sopenharmony_ci || slice_start + (hint->end / 100) <= hint->search_start) { 10148c2ecf20Sopenharmony_ci hint->search_start = slice_start; 10158c2ecf20Sopenharmony_ci } 10168c2ecf20Sopenharmony_ci} 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_cistatic void determine_search_start(reiserfs_blocknr_hint_t * hint, 10198c2ecf20Sopenharmony_ci int amount_needed) 10208c2ecf20Sopenharmony_ci{ 10218c2ecf20Sopenharmony_ci struct super_block *s = hint->th->t_super; 10228c2ecf20Sopenharmony_ci int unfm_hint; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci hint->beg = 0; 10258c2ecf20Sopenharmony_ci hint->end = SB_BLOCK_COUNT(s) - 1; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci /* This is former border algorithm. Now with tunable border offset */ 10288c2ecf20Sopenharmony_ci if (concentrating_formatted_nodes(s)) 10298c2ecf20Sopenharmony_ci set_border_in_hint(s, hint); 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci#ifdef DISPLACE_NEW_PACKING_LOCALITIES 10328c2ecf20Sopenharmony_ci /* 10338c2ecf20Sopenharmony_ci * whenever we create a new directory, we displace it. At first 10348c2ecf20Sopenharmony_ci * we will hash for location, later we might look for a moderately 10358c2ecf20Sopenharmony_ci * empty place for it 10368c2ecf20Sopenharmony_ci */ 10378c2ecf20Sopenharmony_ci if (displacing_new_packing_localities(s) 10388c2ecf20Sopenharmony_ci && hint->th->displace_new_blocks) { 10398c2ecf20Sopenharmony_ci displace_new_packing_locality(hint); 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci /* 10428c2ecf20Sopenharmony_ci * we do not continue determine_search_start, 10438c2ecf20Sopenharmony_ci * if new packing locality is being displaced 10448c2ecf20Sopenharmony_ci */ 10458c2ecf20Sopenharmony_ci return; 10468c2ecf20Sopenharmony_ci } 10478c2ecf20Sopenharmony_ci#endif 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci /* 10508c2ecf20Sopenharmony_ci * all persons should feel encouraged to add more special cases 10518c2ecf20Sopenharmony_ci * here and test them 10528c2ecf20Sopenharmony_ci */ 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci if (displacing_large_files(s) && !hint->formatted_node 10558c2ecf20Sopenharmony_ci && this_blocknr_allocation_would_make_it_a_large_file(hint)) { 10568c2ecf20Sopenharmony_ci displace_large_file(hint); 10578c2ecf20Sopenharmony_ci return; 10588c2ecf20Sopenharmony_ci } 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci /* 10618c2ecf20Sopenharmony_ci * if none of our special cases is relevant, use the left 10628c2ecf20Sopenharmony_ci * neighbor in the tree order of the new node we are allocating for 10638c2ecf20Sopenharmony_ci */ 10648c2ecf20Sopenharmony_ci if (hint->formatted_node && TEST_OPTION(hashed_formatted_nodes, s)) { 10658c2ecf20Sopenharmony_ci hash_formatted_node(hint); 10668c2ecf20Sopenharmony_ci return; 10678c2ecf20Sopenharmony_ci } 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci unfm_hint = get_left_neighbor(hint); 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci /* 10728c2ecf20Sopenharmony_ci * Mimic old block allocator behaviour, that is if VFS allowed for 10738c2ecf20Sopenharmony_ci * preallocation, new blocks are displaced based on directory ID. 10748c2ecf20Sopenharmony_ci * Also, if suggested search_start is less than last preallocated 10758c2ecf20Sopenharmony_ci * block, we start searching from it, assuming that HDD dataflow 10768c2ecf20Sopenharmony_ci * is faster in forward direction 10778c2ecf20Sopenharmony_ci */ 10788c2ecf20Sopenharmony_ci if (TEST_OPTION(old_way, s)) { 10798c2ecf20Sopenharmony_ci if (!hint->formatted_node) { 10808c2ecf20Sopenharmony_ci if (!reiserfs_hashed_relocation(s)) 10818c2ecf20Sopenharmony_ci old_way(hint); 10828c2ecf20Sopenharmony_ci else if (!reiserfs_no_unhashed_relocation(s)) 10838c2ecf20Sopenharmony_ci old_hashed_relocation(hint); 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci if (hint->inode 10868c2ecf20Sopenharmony_ci && hint->search_start < 10878c2ecf20Sopenharmony_ci REISERFS_I(hint->inode)->i_prealloc_block) 10888c2ecf20Sopenharmony_ci hint->search_start = 10898c2ecf20Sopenharmony_ci REISERFS_I(hint->inode)->i_prealloc_block; 10908c2ecf20Sopenharmony_ci } 10918c2ecf20Sopenharmony_ci return; 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci /* This is an approach proposed by Hans */ 10958c2ecf20Sopenharmony_ci if (TEST_OPTION(hundredth_slices, s) 10968c2ecf20Sopenharmony_ci && !(displacing_large_files(s) && !hint->formatted_node)) { 10978c2ecf20Sopenharmony_ci hundredth_slices(hint); 10988c2ecf20Sopenharmony_ci return; 10998c2ecf20Sopenharmony_ci } 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci /* old_hashed_relocation only works on unformatted */ 11028c2ecf20Sopenharmony_ci if (!unfm_hint && !hint->formatted_node && 11038c2ecf20Sopenharmony_ci TEST_OPTION(old_hashed_relocation, s)) { 11048c2ecf20Sopenharmony_ci old_hashed_relocation(hint); 11058c2ecf20Sopenharmony_ci } 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci /* new_hashed_relocation works with both formatted/unformatted nodes */ 11088c2ecf20Sopenharmony_ci if ((!unfm_hint || hint->formatted_node) && 11098c2ecf20Sopenharmony_ci TEST_OPTION(new_hashed_relocation, s)) { 11108c2ecf20Sopenharmony_ci new_hashed_relocation(hint); 11118c2ecf20Sopenharmony_ci } 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci /* dirid grouping works only on unformatted nodes */ 11148c2ecf20Sopenharmony_ci if (!unfm_hint && !hint->formatted_node && TEST_OPTION(dirid_groups, s)) { 11158c2ecf20Sopenharmony_ci dirid_groups(hint); 11168c2ecf20Sopenharmony_ci } 11178c2ecf20Sopenharmony_ci#ifdef DISPLACE_NEW_PACKING_LOCALITIES 11188c2ecf20Sopenharmony_ci if (hint->formatted_node && TEST_OPTION(dirid_groups, s)) { 11198c2ecf20Sopenharmony_ci dirid_groups(hint); 11208c2ecf20Sopenharmony_ci } 11218c2ecf20Sopenharmony_ci#endif 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci /* oid grouping works only on unformatted nodes */ 11248c2ecf20Sopenharmony_ci if (!unfm_hint && !hint->formatted_node && TEST_OPTION(oid_groups, s)) { 11258c2ecf20Sopenharmony_ci oid_groups(hint); 11268c2ecf20Sopenharmony_ci } 11278c2ecf20Sopenharmony_ci return; 11288c2ecf20Sopenharmony_ci} 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_cistatic int determine_prealloc_size(reiserfs_blocknr_hint_t * hint) 11318c2ecf20Sopenharmony_ci{ 11328c2ecf20Sopenharmony_ci /* make minimum size a mount option and benchmark both ways */ 11338c2ecf20Sopenharmony_ci /* we preallocate blocks only for regular files, specific size */ 11348c2ecf20Sopenharmony_ci /* benchmark preallocating always and see what happens */ 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci hint->prealloc_size = 0; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci if (!hint->formatted_node && hint->preallocate) { 11398c2ecf20Sopenharmony_ci if (S_ISREG(hint->inode->i_mode) && !IS_PRIVATE(hint->inode) 11408c2ecf20Sopenharmony_ci && hint->inode->i_size >= 11418c2ecf20Sopenharmony_ci REISERFS_SB(hint->th->t_super)->s_alloc_options. 11428c2ecf20Sopenharmony_ci preallocmin * hint->inode->i_sb->s_blocksize) 11438c2ecf20Sopenharmony_ci hint->prealloc_size = 11448c2ecf20Sopenharmony_ci REISERFS_SB(hint->th->t_super)->s_alloc_options. 11458c2ecf20Sopenharmony_ci preallocsize - 1; 11468c2ecf20Sopenharmony_ci } 11478c2ecf20Sopenharmony_ci return CARRY_ON; 11488c2ecf20Sopenharmony_ci} 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_cistatic inline int allocate_without_wrapping_disk(reiserfs_blocknr_hint_t * hint, 11518c2ecf20Sopenharmony_ci b_blocknr_t * new_blocknrs, 11528c2ecf20Sopenharmony_ci b_blocknr_t start, 11538c2ecf20Sopenharmony_ci b_blocknr_t finish, int min, 11548c2ecf20Sopenharmony_ci int amount_needed, 11558c2ecf20Sopenharmony_ci int prealloc_size) 11568c2ecf20Sopenharmony_ci{ 11578c2ecf20Sopenharmony_ci int rest = amount_needed; 11588c2ecf20Sopenharmony_ci int nr_allocated; 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci while (rest > 0 && start <= finish) { 11618c2ecf20Sopenharmony_ci nr_allocated = scan_bitmap(hint->th, &start, finish, min, 11628c2ecf20Sopenharmony_ci rest + prealloc_size, 11638c2ecf20Sopenharmony_ci !hint->formatted_node, hint->block); 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci if (nr_allocated == 0) /* no new blocks allocated, return */ 11668c2ecf20Sopenharmony_ci break; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci /* fill free_blocknrs array first */ 11698c2ecf20Sopenharmony_ci while (rest > 0 && nr_allocated > 0) { 11708c2ecf20Sopenharmony_ci *new_blocknrs++ = start++; 11718c2ecf20Sopenharmony_ci rest--; 11728c2ecf20Sopenharmony_ci nr_allocated--; 11738c2ecf20Sopenharmony_ci } 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci /* do we have something to fill prealloc. array also ? */ 11768c2ecf20Sopenharmony_ci if (nr_allocated > 0) { 11778c2ecf20Sopenharmony_ci /* 11788c2ecf20Sopenharmony_ci * it means prealloc_size was greater that 0 and 11798c2ecf20Sopenharmony_ci * we do preallocation 11808c2ecf20Sopenharmony_ci */ 11818c2ecf20Sopenharmony_ci list_add(&REISERFS_I(hint->inode)->i_prealloc_list, 11828c2ecf20Sopenharmony_ci &SB_JOURNAL(hint->th->t_super)-> 11838c2ecf20Sopenharmony_ci j_prealloc_list); 11848c2ecf20Sopenharmony_ci REISERFS_I(hint->inode)->i_prealloc_block = start; 11858c2ecf20Sopenharmony_ci REISERFS_I(hint->inode)->i_prealloc_count = 11868c2ecf20Sopenharmony_ci nr_allocated; 11878c2ecf20Sopenharmony_ci break; 11888c2ecf20Sopenharmony_ci } 11898c2ecf20Sopenharmony_ci } 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci return (amount_needed - rest); 11928c2ecf20Sopenharmony_ci} 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_cistatic inline int blocknrs_and_prealloc_arrays_from_search_start 11958c2ecf20Sopenharmony_ci (reiserfs_blocknr_hint_t * hint, b_blocknr_t * new_blocknrs, 11968c2ecf20Sopenharmony_ci int amount_needed) { 11978c2ecf20Sopenharmony_ci struct super_block *s = hint->th->t_super; 11988c2ecf20Sopenharmony_ci b_blocknr_t start = hint->search_start; 11998c2ecf20Sopenharmony_ci b_blocknr_t finish = SB_BLOCK_COUNT(s) - 1; 12008c2ecf20Sopenharmony_ci int passno = 0; 12018c2ecf20Sopenharmony_ci int nr_allocated = 0; 12028c2ecf20Sopenharmony_ci int depth; 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci determine_prealloc_size(hint); 12058c2ecf20Sopenharmony_ci if (!hint->formatted_node) { 12068c2ecf20Sopenharmony_ci int quota_ret; 12078c2ecf20Sopenharmony_ci#ifdef REISERQUOTA_DEBUG 12088c2ecf20Sopenharmony_ci reiserfs_debug(s, REISERFS_DEBUG_CODE, 12098c2ecf20Sopenharmony_ci "reiserquota: allocating %d blocks id=%u", 12108c2ecf20Sopenharmony_ci amount_needed, hint->inode->i_uid); 12118c2ecf20Sopenharmony_ci#endif 12128c2ecf20Sopenharmony_ci depth = reiserfs_write_unlock_nested(s); 12138c2ecf20Sopenharmony_ci quota_ret = 12148c2ecf20Sopenharmony_ci dquot_alloc_block_nodirty(hint->inode, amount_needed); 12158c2ecf20Sopenharmony_ci if (quota_ret) { /* Quota exceeded? */ 12168c2ecf20Sopenharmony_ci reiserfs_write_lock_nested(s, depth); 12178c2ecf20Sopenharmony_ci return QUOTA_EXCEEDED; 12188c2ecf20Sopenharmony_ci } 12198c2ecf20Sopenharmony_ci if (hint->preallocate && hint->prealloc_size) { 12208c2ecf20Sopenharmony_ci#ifdef REISERQUOTA_DEBUG 12218c2ecf20Sopenharmony_ci reiserfs_debug(s, REISERFS_DEBUG_CODE, 12228c2ecf20Sopenharmony_ci "reiserquota: allocating (prealloc) %d blocks id=%u", 12238c2ecf20Sopenharmony_ci hint->prealloc_size, hint->inode->i_uid); 12248c2ecf20Sopenharmony_ci#endif 12258c2ecf20Sopenharmony_ci quota_ret = dquot_prealloc_block_nodirty(hint->inode, 12268c2ecf20Sopenharmony_ci hint->prealloc_size); 12278c2ecf20Sopenharmony_ci if (quota_ret) 12288c2ecf20Sopenharmony_ci hint->preallocate = hint->prealloc_size = 0; 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci /* for unformatted nodes, force large allocations */ 12318c2ecf20Sopenharmony_ci reiserfs_write_lock_nested(s, depth); 12328c2ecf20Sopenharmony_ci } 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci do { 12358c2ecf20Sopenharmony_ci switch (passno++) { 12368c2ecf20Sopenharmony_ci case 0: /* Search from hint->search_start to end of disk */ 12378c2ecf20Sopenharmony_ci start = hint->search_start; 12388c2ecf20Sopenharmony_ci finish = SB_BLOCK_COUNT(s) - 1; 12398c2ecf20Sopenharmony_ci break; 12408c2ecf20Sopenharmony_ci case 1: /* Search from hint->beg to hint->search_start */ 12418c2ecf20Sopenharmony_ci start = hint->beg; 12428c2ecf20Sopenharmony_ci finish = hint->search_start; 12438c2ecf20Sopenharmony_ci break; 12448c2ecf20Sopenharmony_ci case 2: /* Last chance: Search from 0 to hint->beg */ 12458c2ecf20Sopenharmony_ci start = 0; 12468c2ecf20Sopenharmony_ci finish = hint->beg; 12478c2ecf20Sopenharmony_ci break; 12488c2ecf20Sopenharmony_ci default: 12498c2ecf20Sopenharmony_ci /* We've tried searching everywhere, not enough space */ 12508c2ecf20Sopenharmony_ci /* Free the blocks */ 12518c2ecf20Sopenharmony_ci if (!hint->formatted_node) { 12528c2ecf20Sopenharmony_ci#ifdef REISERQUOTA_DEBUG 12538c2ecf20Sopenharmony_ci reiserfs_debug(s, REISERFS_DEBUG_CODE, 12548c2ecf20Sopenharmony_ci "reiserquota: freeing (nospace) %d blocks id=%u", 12558c2ecf20Sopenharmony_ci amount_needed + 12568c2ecf20Sopenharmony_ci hint->prealloc_size - 12578c2ecf20Sopenharmony_ci nr_allocated, 12588c2ecf20Sopenharmony_ci hint->inode->i_uid); 12598c2ecf20Sopenharmony_ci#endif 12608c2ecf20Sopenharmony_ci /* Free not allocated blocks */ 12618c2ecf20Sopenharmony_ci depth = reiserfs_write_unlock_nested(s); 12628c2ecf20Sopenharmony_ci dquot_free_block_nodirty(hint->inode, 12638c2ecf20Sopenharmony_ci amount_needed + hint->prealloc_size - 12648c2ecf20Sopenharmony_ci nr_allocated); 12658c2ecf20Sopenharmony_ci reiserfs_write_lock_nested(s, depth); 12668c2ecf20Sopenharmony_ci } 12678c2ecf20Sopenharmony_ci while (nr_allocated--) 12688c2ecf20Sopenharmony_ci reiserfs_free_block(hint->th, hint->inode, 12698c2ecf20Sopenharmony_ci new_blocknrs[nr_allocated], 12708c2ecf20Sopenharmony_ci !hint->formatted_node); 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci return NO_DISK_SPACE; 12738c2ecf20Sopenharmony_ci } 12748c2ecf20Sopenharmony_ci } while ((nr_allocated += allocate_without_wrapping_disk(hint, 12758c2ecf20Sopenharmony_ci new_blocknrs + 12768c2ecf20Sopenharmony_ci nr_allocated, 12778c2ecf20Sopenharmony_ci start, finish, 12788c2ecf20Sopenharmony_ci 1, 12798c2ecf20Sopenharmony_ci amount_needed - 12808c2ecf20Sopenharmony_ci nr_allocated, 12818c2ecf20Sopenharmony_ci hint-> 12828c2ecf20Sopenharmony_ci prealloc_size)) 12838c2ecf20Sopenharmony_ci < amount_needed); 12848c2ecf20Sopenharmony_ci if (!hint->formatted_node && 12858c2ecf20Sopenharmony_ci amount_needed + hint->prealloc_size > 12868c2ecf20Sopenharmony_ci nr_allocated + REISERFS_I(hint->inode)->i_prealloc_count) { 12878c2ecf20Sopenharmony_ci /* Some of preallocation blocks were not allocated */ 12888c2ecf20Sopenharmony_ci#ifdef REISERQUOTA_DEBUG 12898c2ecf20Sopenharmony_ci reiserfs_debug(s, REISERFS_DEBUG_CODE, 12908c2ecf20Sopenharmony_ci "reiserquota: freeing (failed prealloc) %d blocks id=%u", 12918c2ecf20Sopenharmony_ci amount_needed + hint->prealloc_size - 12928c2ecf20Sopenharmony_ci nr_allocated - 12938c2ecf20Sopenharmony_ci REISERFS_I(hint->inode)->i_prealloc_count, 12948c2ecf20Sopenharmony_ci hint->inode->i_uid); 12958c2ecf20Sopenharmony_ci#endif 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci depth = reiserfs_write_unlock_nested(s); 12988c2ecf20Sopenharmony_ci dquot_free_block_nodirty(hint->inode, amount_needed + 12998c2ecf20Sopenharmony_ci hint->prealloc_size - nr_allocated - 13008c2ecf20Sopenharmony_ci REISERFS_I(hint->inode)-> 13018c2ecf20Sopenharmony_ci i_prealloc_count); 13028c2ecf20Sopenharmony_ci reiserfs_write_lock_nested(s, depth); 13038c2ecf20Sopenharmony_ci } 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci return CARRY_ON; 13068c2ecf20Sopenharmony_ci} 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci/* grab new blocknrs from preallocated list */ 13098c2ecf20Sopenharmony_ci/* return amount still needed after using them */ 13108c2ecf20Sopenharmony_cistatic int use_preallocated_list_if_available(reiserfs_blocknr_hint_t * hint, 13118c2ecf20Sopenharmony_ci b_blocknr_t * new_blocknrs, 13128c2ecf20Sopenharmony_ci int amount_needed) 13138c2ecf20Sopenharmony_ci{ 13148c2ecf20Sopenharmony_ci struct inode *inode = hint->inode; 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci if (REISERFS_I(inode)->i_prealloc_count > 0) { 13178c2ecf20Sopenharmony_ci while (amount_needed) { 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci *new_blocknrs++ = REISERFS_I(inode)->i_prealloc_block++; 13208c2ecf20Sopenharmony_ci REISERFS_I(inode)->i_prealloc_count--; 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci amount_needed--; 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci if (REISERFS_I(inode)->i_prealloc_count <= 0) { 13258c2ecf20Sopenharmony_ci list_del(&REISERFS_I(inode)->i_prealloc_list); 13268c2ecf20Sopenharmony_ci break; 13278c2ecf20Sopenharmony_ci } 13288c2ecf20Sopenharmony_ci } 13298c2ecf20Sopenharmony_ci } 13308c2ecf20Sopenharmony_ci /* return amount still needed after using preallocated blocks */ 13318c2ecf20Sopenharmony_ci return amount_needed; 13328c2ecf20Sopenharmony_ci} 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ciint reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t *hint, 13358c2ecf20Sopenharmony_ci b_blocknr_t *new_blocknrs, 13368c2ecf20Sopenharmony_ci int amount_needed, 13378c2ecf20Sopenharmony_ci /* Amount of blocks we have already reserved */ 13388c2ecf20Sopenharmony_ci int reserved_by_us) 13398c2ecf20Sopenharmony_ci{ 13408c2ecf20Sopenharmony_ci int initial_amount_needed = amount_needed; 13418c2ecf20Sopenharmony_ci int ret; 13428c2ecf20Sopenharmony_ci struct super_block *s = hint->th->t_super; 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci /* Check if there is enough space, taking into account reserved space */ 13458c2ecf20Sopenharmony_ci if (SB_FREE_BLOCKS(s) - REISERFS_SB(s)->reserved_blocks < 13468c2ecf20Sopenharmony_ci amount_needed - reserved_by_us) 13478c2ecf20Sopenharmony_ci return NO_DISK_SPACE; 13488c2ecf20Sopenharmony_ci /* should this be if !hint->inode && hint->preallocate? */ 13498c2ecf20Sopenharmony_ci /* do you mean hint->formatted_node can be removed ? - Zam */ 13508c2ecf20Sopenharmony_ci /* 13518c2ecf20Sopenharmony_ci * hint->formatted_node cannot be removed because we try to access 13528c2ecf20Sopenharmony_ci * inode information here, and there is often no inode associated with 13538c2ecf20Sopenharmony_ci * metadata allocations - green 13548c2ecf20Sopenharmony_ci */ 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci if (!hint->formatted_node && hint->preallocate) { 13578c2ecf20Sopenharmony_ci amount_needed = use_preallocated_list_if_available 13588c2ecf20Sopenharmony_ci (hint, new_blocknrs, amount_needed); 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci /* 13618c2ecf20Sopenharmony_ci * We have all the block numbers we need from the 13628c2ecf20Sopenharmony_ci * prealloc list 13638c2ecf20Sopenharmony_ci */ 13648c2ecf20Sopenharmony_ci if (amount_needed == 0) 13658c2ecf20Sopenharmony_ci return CARRY_ON; 13668c2ecf20Sopenharmony_ci new_blocknrs += (initial_amount_needed - amount_needed); 13678c2ecf20Sopenharmony_ci } 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci /* find search start and save it in hint structure */ 13708c2ecf20Sopenharmony_ci determine_search_start(hint, amount_needed); 13718c2ecf20Sopenharmony_ci if (hint->search_start >= SB_BLOCK_COUNT(s)) 13728c2ecf20Sopenharmony_ci hint->search_start = SB_BLOCK_COUNT(s) - 1; 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci /* allocation itself; fill new_blocknrs and preallocation arrays */ 13758c2ecf20Sopenharmony_ci ret = blocknrs_and_prealloc_arrays_from_search_start 13768c2ecf20Sopenharmony_ci (hint, new_blocknrs, amount_needed); 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci /* 13798c2ecf20Sopenharmony_ci * We used prealloc. list to fill (partially) new_blocknrs array. 13808c2ecf20Sopenharmony_ci * If final allocation fails we need to return blocks back to 13818c2ecf20Sopenharmony_ci * prealloc. list or just free them. -- Zam (I chose second 13828c2ecf20Sopenharmony_ci * variant) 13838c2ecf20Sopenharmony_ci */ 13848c2ecf20Sopenharmony_ci if (ret != CARRY_ON) { 13858c2ecf20Sopenharmony_ci while (amount_needed++ < initial_amount_needed) { 13868c2ecf20Sopenharmony_ci reiserfs_free_block(hint->th, hint->inode, 13878c2ecf20Sopenharmony_ci *(--new_blocknrs), 1); 13888c2ecf20Sopenharmony_ci } 13898c2ecf20Sopenharmony_ci } 13908c2ecf20Sopenharmony_ci return ret; 13918c2ecf20Sopenharmony_ci} 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_civoid reiserfs_cache_bitmap_metadata(struct super_block *sb, 13948c2ecf20Sopenharmony_ci struct buffer_head *bh, 13958c2ecf20Sopenharmony_ci struct reiserfs_bitmap_info *info) 13968c2ecf20Sopenharmony_ci{ 13978c2ecf20Sopenharmony_ci unsigned long *cur = (unsigned long *)(bh->b_data + bh->b_size); 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci /* The first bit must ALWAYS be 1 */ 14008c2ecf20Sopenharmony_ci if (!reiserfs_test_le_bit(0, (unsigned long *)bh->b_data)) 14018c2ecf20Sopenharmony_ci reiserfs_error(sb, "reiserfs-2025", "bitmap block %lu is " 14028c2ecf20Sopenharmony_ci "corrupted: first bit must be 1", bh->b_blocknr); 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci info->free_count = 0; 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci while (--cur >= (unsigned long *)bh->b_data) { 14078c2ecf20Sopenharmony_ci /* 0 and ~0 are special, we can optimize for them */ 14088c2ecf20Sopenharmony_ci if (*cur == 0) 14098c2ecf20Sopenharmony_ci info->free_count += BITS_PER_LONG; 14108c2ecf20Sopenharmony_ci else if (*cur != ~0L) /* A mix, investigate */ 14118c2ecf20Sopenharmony_ci info->free_count += BITS_PER_LONG - hweight_long(*cur); 14128c2ecf20Sopenharmony_ci } 14138c2ecf20Sopenharmony_ci} 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_cistruct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb, 14168c2ecf20Sopenharmony_ci unsigned int bitmap) 14178c2ecf20Sopenharmony_ci{ 14188c2ecf20Sopenharmony_ci b_blocknr_t block = (sb->s_blocksize << 3) * bitmap; 14198c2ecf20Sopenharmony_ci struct reiserfs_bitmap_info *info = SB_AP_BITMAP(sb) + bitmap; 14208c2ecf20Sopenharmony_ci struct buffer_head *bh; 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci /* 14238c2ecf20Sopenharmony_ci * Way old format filesystems had the bitmaps packed up front. 14248c2ecf20Sopenharmony_ci * I doubt there are any of these left, but just in case... 14258c2ecf20Sopenharmony_ci */ 14268c2ecf20Sopenharmony_ci if (unlikely(test_bit(REISERFS_OLD_FORMAT, 14278c2ecf20Sopenharmony_ci &REISERFS_SB(sb)->s_properties))) 14288c2ecf20Sopenharmony_ci block = REISERFS_SB(sb)->s_sbh->b_blocknr + 1 + bitmap; 14298c2ecf20Sopenharmony_ci else if (bitmap == 0) 14308c2ecf20Sopenharmony_ci block = (REISERFS_DISK_OFFSET_IN_BYTES >> sb->s_blocksize_bits) + 1; 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci bh = sb_bread(sb, block); 14338c2ecf20Sopenharmony_ci if (bh == NULL) 14348c2ecf20Sopenharmony_ci reiserfs_warning(sb, "sh-2029: %s: bitmap block (#%u) " 14358c2ecf20Sopenharmony_ci "reading failed", __func__, block); 14368c2ecf20Sopenharmony_ci else { 14378c2ecf20Sopenharmony_ci if (buffer_locked(bh)) { 14388c2ecf20Sopenharmony_ci int depth; 14398c2ecf20Sopenharmony_ci PROC_INFO_INC(sb, scan_bitmap.wait); 14408c2ecf20Sopenharmony_ci depth = reiserfs_write_unlock_nested(sb); 14418c2ecf20Sopenharmony_ci __wait_on_buffer(bh); 14428c2ecf20Sopenharmony_ci reiserfs_write_lock_nested(sb, depth); 14438c2ecf20Sopenharmony_ci } 14448c2ecf20Sopenharmony_ci BUG_ON(!buffer_uptodate(bh)); 14458c2ecf20Sopenharmony_ci BUG_ON(atomic_read(&bh->b_count) == 0); 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci if (info->free_count == UINT_MAX) 14488c2ecf20Sopenharmony_ci reiserfs_cache_bitmap_metadata(sb, bh, info); 14498c2ecf20Sopenharmony_ci } 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci return bh; 14528c2ecf20Sopenharmony_ci} 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ciint reiserfs_init_bitmap_cache(struct super_block *sb) 14558c2ecf20Sopenharmony_ci{ 14568c2ecf20Sopenharmony_ci struct reiserfs_bitmap_info *bitmap; 14578c2ecf20Sopenharmony_ci unsigned int bmap_nr = reiserfs_bmap_count(sb); 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci bitmap = vmalloc(array_size(bmap_nr, sizeof(*bitmap))); 14608c2ecf20Sopenharmony_ci if (bitmap == NULL) 14618c2ecf20Sopenharmony_ci return -ENOMEM; 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci memset(bitmap, 0xff, sizeof(*bitmap) * bmap_nr); 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci SB_AP_BITMAP(sb) = bitmap; 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci return 0; 14688c2ecf20Sopenharmony_ci} 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_civoid reiserfs_free_bitmap_cache(struct super_block *sb) 14718c2ecf20Sopenharmony_ci{ 14728c2ecf20Sopenharmony_ci if (SB_AP_BITMAP(sb)) { 14738c2ecf20Sopenharmony_ci vfree(SB_AP_BITMAP(sb)); 14748c2ecf20Sopenharmony_ci SB_AP_BITMAP(sb) = NULL; 14758c2ecf20Sopenharmony_ci } 14768c2ecf20Sopenharmony_ci} 1477