static int nova_insert_blocknode_map(struct super_block *sb, int cpuid, unsigned long low, unsigned long high) { struct nova_sb_info *sbi = NOVA_SB(sb); struct free_list *free_list; struct rb_root *tree; struct nova_range_node *blknode = NULL; unsigned long num_blocks = 0; int ret; num_blocks = high - low + 1; nova_dbgv("%s: cpu %d, low %lu, high %lu, num %lu\n", __func__, cpuid, low, high, num_blocks); free_list = nova_get_free_list(sb, cpuid); tree = &(free_list->block_free_tree); blknode = nova_alloc_blocknode(sb); if (blknode == NULL) return -ENOMEM; blknode->range_low = low; blknode->range_high = high; ret = nova_insert_blocktree(sbi, tree, blknode); if (ret) { nova_err(sb, "%s failed\n", __func__); nova_free_blocknode(sb, blknode); goto out; } if (!free_list->first_node) free_list->first_node = blknode; free_list->num_blocknode++; free_list->num_free_blocks += num_blocks; out: return ret; }
void nova_init_blockmap(struct super_block *sb, int recovery) { struct nova_sb_info *sbi = NOVA_SB(sb); struct rb_root *tree; unsigned long num_used_block; struct nova_range_node *blknode; struct free_list *free_list; unsigned long per_list_blocks; int i; int ret; num_used_block = sbi->reserved_blocks; /* Divide the block range among per-CPU free lists */ per_list_blocks = sbi->num_blocks / sbi->cpus; sbi->per_list_blocks = per_list_blocks; for (i = 0; i < sbi->cpus; i++) { free_list = nova_get_free_list(sb, i); tree = &(free_list->block_free_tree); free_list->block_start = per_list_blocks * i; free_list->block_end = free_list->block_start + per_list_blocks - 1; /* For recovery, update these fields later */ if (recovery == 0) { free_list->num_free_blocks = per_list_blocks; if (i == 0) { free_list->block_start += num_used_block; free_list->num_free_blocks -= num_used_block; } blknode = nova_alloc_blocknode(sb); if (blknode == NULL) NOVA_ASSERT(0); blknode->range_low = free_list->block_start; blknode->range_high = free_list->block_end; ret = nova_insert_blocktree(sbi, tree, blknode); if (ret) { nova_err(sb, "%s failed\n", __func__); nova_free_blocknode(sb, blknode); return; } free_list->first_node = blknode; free_list->num_blocknode = 1; } } free_list = nova_get_free_list(sb, (sbi->cpus - 1)); if (free_list->block_end + 1 < sbi->num_blocks) { /* Shared free list gets any remaining blocks */ sbi->shared_free_list.block_start = free_list->block_end + 1; sbi->shared_free_list.block_end = sbi->num_blocks - 1; } }
static int nova_init_blockmap_from_inode(struct super_block *sb) { struct nova_sb_info *sbi = NOVA_SB(sb); struct nova_inode *pi = nova_get_inode_by_ino(sb, NOVA_BLOCKNODE_INO); struct free_list *free_list; struct nova_range_node_lowhigh *entry; struct nova_range_node *blknode; size_t size = sizeof(struct nova_range_node_lowhigh); u64 curr_p; u64 cpuid; int ret = 0; curr_p = pi->log_head; if (curr_p == 0) { nova_dbg("%s: pi head is 0!\n", __func__); return -EINVAL; } while (curr_p != pi->log_tail) { if (is_last_entry(curr_p, size)) { curr_p = next_log_page(sb, curr_p); } if (curr_p == 0) { nova_dbg("%s: curr_p is NULL!\n", __func__); NOVA_ASSERT(0); ret = -EINVAL; break; } entry = (struct nova_range_node_lowhigh *)nova_get_block(sb, curr_p); blknode = nova_alloc_blocknode(sb); if (blknode == NULL) NOVA_ASSERT(0); blknode->range_low = le64_to_cpu(entry->range_low); blknode->range_high = le64_to_cpu(entry->range_high); cpuid = get_cpuid(sbi, blknode->range_low); /* FIXME: Assume NR_CPUS not change */ free_list = nova_get_free_list(sb, cpuid); ret = nova_insert_blocktree(sbi, &free_list->block_free_tree, blknode); if (ret) { nova_err(sb, "%s failed\n", __func__); nova_free_blocknode(sb, blknode); NOVA_ASSERT(0); nova_destroy_blocknode_trees(sb); goto out; } free_list->num_blocknode++; if (free_list->num_blocknode == 1) free_list->first_node = blknode; free_list->num_free_blocks += blknode->range_high - blknode->range_low + 1; curr_p += sizeof(struct nova_range_node_lowhigh); } out: nova_free_inode_log(sb, pi); return ret; }