static u64 nova_append_range_node_entry(struct super_block *sb, struct nova_range_node *curr, u64 tail, unsigned long cpuid) { u64 curr_p; size_t size = sizeof(struct nova_range_node_lowhigh); struct nova_range_node_lowhigh *entry; curr_p = tail; if (curr_p == 0 || (is_last_entry(curr_p, size) && next_log_page(sb, curr_p) == 0)) { nova_dbg("%s: inode log reaches end?\n", __func__); goto out; } if (is_last_entry(curr_p, size)) curr_p = next_log_page(sb, curr_p); entry = (struct nova_range_node_lowhigh *)nova_get_block(sb, curr_p); entry->range_low = cpu_to_le64(curr->range_low); if (cpuid) entry->range_low |= cpu_to_le64(cpuid << 56); entry->range_high = cpu_to_le64(curr->range_high); nova_dbgv("append entry block low 0x%lx, high 0x%lx\n", curr->range_low, curr->range_high); nova_flush_buffer(entry, sizeof(struct nova_range_node_lowhigh), 0); out: return curr_p; }
void nova_save_inode_list_to_log(struct super_block *sb) { struct nova_inode *pi = nova_get_inode_by_ino(sb, NOVA_INODELIST1_INO); struct nova_sb_info *sbi = NOVA_SB(sb); unsigned long num_blocks; unsigned long num_nodes = 0; struct inode_map *inode_map; unsigned long i; u64 temp_tail; u64 new_block; int allocated; for (i = 0; i < sbi->cpus; i++) { inode_map = &sbi->inode_maps[i]; num_nodes += inode_map->num_range_node_inode; } num_blocks = num_nodes / RANGENODE_PER_PAGE; if (num_nodes % RANGENODE_PER_PAGE) num_blocks++; allocated = nova_allocate_inode_log_pages(sb, pi, num_blocks, &new_block); if (allocated != num_blocks) { nova_dbg("Error saving inode list: %d\n", allocated); return; } pi->log_head = new_block; nova_flush_buffer(&pi->log_head, CACHELINE_SIZE, 0); temp_tail = new_block; for (i = 0; i < sbi->cpus; i++) { inode_map = &sbi->inode_maps[i]; temp_tail = nova_save_range_nodes_to_log(sb, &inode_map->inode_inuse_tree, temp_tail, i); } nova_update_tail(pi, temp_tail); nova_dbg("%s: %lu inode nodes, pi head 0x%llx, tail 0x%llx\n", __func__, num_nodes, pi->log_head, pi->log_tail); }
inline int nova_insert_blocktree(struct nova_sb_info *sbi, struct rb_root *tree, struct nova_range_node *new_node) { int ret; ret = nova_insert_range_node(sbi, tree, new_node); if (ret) nova_dbg("ERROR: %s failed %d\n", __func__, ret); return ret; }
/* Append . and .. entries */ int nova_append_dir_init_entries(struct super_block *sb, struct nova_inode *pi, u64 self_ino, u64 parent_ino) { int allocated; u64 new_block; u64 curr_p; struct nova_dentry *de_entry; if (pi->log_head) { nova_dbg("%s: log head exists @ 0x%llx!\n", __func__, pi->log_head); return - EINVAL; } allocated = nova_allocate_inode_log_pages(sb, pi, 1, &new_block); if (allocated != 1) { nova_err(sb, "ERROR: no inode log page available\n"); return - ENOMEM; } pi->log_tail = pi->log_head = new_block; pi->i_blocks = 1; nova_flush_buffer(&pi->log_head, CACHELINE_SIZE, 0); de_entry = (struct nova_dentry *)nova_get_block(sb, new_block); de_entry->entry_type = DIR_LOG; de_entry->ino = cpu_to_le64(self_ino); de_entry->name_len = 1; de_entry->de_len = cpu_to_le16(NOVA_DIR_LOG_REC_LEN(1)); de_entry->mtime = CURRENT_TIME_SEC.tv_sec; de_entry->size = sb->s_blocksize; de_entry->links_count = 1; strncpy(de_entry->name, ".\0", 2); nova_flush_buffer(de_entry, NOVA_DIR_LOG_REC_LEN(1), 0); curr_p = new_block + NOVA_DIR_LOG_REC_LEN(1); de_entry = (struct nova_dentry *)((char *)de_entry + le16_to_cpu(de_entry->de_len)); de_entry->entry_type = DIR_LOG; de_entry->ino = cpu_to_le64(parent_ino); de_entry->name_len = 2; de_entry->de_len = cpu_to_le16(NOVA_DIR_LOG_REC_LEN(2)); de_entry->mtime = CURRENT_TIME_SEC.tv_sec; de_entry->size = sb->s_blocksize; de_entry->links_count = 2; strncpy(de_entry->name, "..\0", 3); nova_flush_buffer(de_entry, NOVA_DIR_LOG_REC_LEN(2), 0); curr_p += NOVA_DIR_LOG_REC_LEN(2); nova_update_tail(pi, curr_p); return 0; }
inline int nova_insert_inodetree(struct nova_sb_info *sbi, struct nova_range_node *new_node, int cpu) { struct rb_root *tree; int ret; tree = &sbi->inode_maps[cpu].inode_inuse_tree; ret = nova_insert_range_node(sbi, tree, new_node); if (ret) nova_dbg("ERROR: %s failed %d\n", __func__, ret); return ret; }
static int __nova_build_blocknode_map(struct super_block *sb, unsigned long *bitmap, unsigned long bsize, unsigned long scale) { struct nova_sb_info *sbi = NOVA_SB(sb); struct free_list *free_list; unsigned long next = 0; unsigned long low = 0; unsigned long start, end; int cpuid = 0; free_list = nova_get_free_list(sb, cpuid); start = free_list->block_start; end = free_list->block_end + 1; while (1) { next = find_next_zero_bit(bitmap, end, start); if (next == bsize) break; if (next == end) { if (cpuid == sbi->cpus - 1) cpuid = SHARED_CPU; else cpuid++; free_list = nova_get_free_list(sb, cpuid); start = free_list->block_start; end = free_list->block_end + 1; continue; } low = next; next = find_next_bit(bitmap, end, next); if (nova_insert_blocknode_map(sb, cpuid, low << scale , (next << scale) - 1)) { nova_dbg("Error: could not insert %lu - %lu\n", low << scale, ((next << scale) - 1)); } start = next; if (next == bsize) break; if (next == end) { if (cpuid == sbi->cpus - 1) cpuid = SHARED_CPU; else cpuid++; free_list = nova_get_free_list(sb, cpuid); start = free_list->block_start; end = free_list->block_end + 1; } } return 0; }
static int nova_remove_dir_radix_tree(struct super_block *sb, struct nova_inode_info_header *sih, const char *name, int namelen, int replay) { struct nova_dentry *entry; unsigned long hash; hash = BKDRHash(name, namelen); entry = radix_tree_delete(&sih->tree, hash); if (replay == 0) { if (!entry) { nova_dbg("%s ERROR: %s, length %d, hash %lu\n", __func__, name, namelen, hash); return -EINVAL; } if (entry->ino == 0 || entry->invalid || nova_check_dentry_match(sb, entry, name, namelen)) { nova_dbg("%s dentry not match: %s, length %d, " "hash %lu\n", __func__, name, namelen, hash); nova_dbg("dentry: type %d, inode %llu, name %s, " "namelen %u, rec len %u\n", entry->entry_type, le64_to_cpu(entry->ino), entry->name, entry->name_len, le16_to_cpu(entry->de_len)); return -EINVAL; } /* No need to flush */ entry->invalid = 1; } return 0; }
static int nova_insert_dir_radix_tree(struct super_block *sb, struct nova_inode_info_header *sih, const char *name, int namelen, struct nova_dentry *direntry) { unsigned long hash; int ret; hash = BKDRHash(name, namelen); nova_dbgv("%s: insert %s hash %lu\n", __func__, name, hash); /* FIXME: hash collision ignored here */ ret = radix_tree_insert(&sih->tree, hash, direntry); if (ret) nova_dbg("%s ERROR %d: %s\n", __func__, ret, name); return ret; }
static int nova_get_block_info(struct super_block *sb, struct nova_sb_info *sbi) { void *virt_addr = NULL; #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0) pfn_t __pfn_t; #else unsigned long pfn; #endif long size; if (!sb->s_bdev->bd_disk->fops->direct_access) { nova_err(sb, "device does not support DAX\n"); return -EINVAL; } sbi->s_bdev = sb->s_bdev; #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0) size = sb->s_bdev->bd_disk->fops->direct_access(sb->s_bdev, 0, &virt_addr, &__pfn_t); #else size = sb->s_bdev->bd_disk->fops->direct_access(sb->s_bdev, 0, &virt_addr, &pfn); #endif if (size <= 0) { nova_err(sb, "direct_access failed\n"); return -EINVAL; } sbi->virt_addr = virt_addr; #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0) sbi->phys_addr = pfn_t_to_pfn(__pfn_t) << PAGE_SHIFT; #else sbi->phys_addr = pfn << PAGE_SHIFT; #endif sbi->initsize = size; nova_dbg("%s: dev %s, phys_addr 0x%llx, virt_addr %p, size %ld\n", __func__, sbi->s_bdev->bd_disk->disk_name, sbi->phys_addr, sbi->virt_addr, sbi->initsize); return 0; }
void nova_delete_dir_tree(struct super_block *sb, struct nova_inode_info_header *sih) { struct nova_dentry *direntry; unsigned long pos = 0; struct nova_dentry *entries[FREE_BATCH]; timing_t delete_time; int nr_entries; int i; void *ret; NOVA_START_TIMING(delete_dir_tree_t, delete_time); do { nr_entries = radix_tree_gang_lookup(&sih->tree, (void **)entries, pos, FREE_BATCH); for (i = 0; i < nr_entries; i++) { direntry = entries[i]; BUG_ON(!direntry); pos = BKDRHash(direntry->name, direntry->name_len); ret = radix_tree_delete(&sih->tree, pos); if (!ret || ret != direntry) { nova_err(sb, "dentry: type %d, inode %llu, " "name %s, namelen %u, rec len %u\n", direntry->entry_type, le64_to_cpu(direntry->ino), direntry->name, direntry->name_len, le16_to_cpu(direntry->de_len)); if (!ret) nova_dbg("ret is NULL\n"); } } pos++; } while (nr_entries == FREE_BATCH); NOVA_END_TIMING(delete_dir_tree_t, delete_time); return; }
/* Used for both block free tree and inode inuse tree */ int nova_find_free_slot(struct nova_sb_info *sbi, struct rb_root *tree, unsigned long range_low, unsigned long range_high, struct nova_range_node **prev, struct nova_range_node **next) { struct nova_range_node *ret_node = NULL; struct rb_node *temp; int ret; ret = nova_find_range_node(sbi, tree, range_low, &ret_node); if (ret) { nova_dbg("%s ERROR: %lu - %lu already in free list\n", __func__, range_low, range_high); return -EINVAL; } if (!ret_node) { *prev = *next = NULL; } else if (ret_node->range_high < range_low) { *prev = ret_node; temp = rb_next(&ret_node->node); if (temp) *next = container_of(temp, struct nova_range_node, node); else
static int nova_insert_range_node(struct nova_sb_info *sbi, struct rb_root *tree, struct nova_range_node *new_node) { struct nova_range_node *curr; struct rb_node **temp, *parent; int compVal; temp = &(tree->rb_node); parent = NULL; while (*temp) { curr = container_of(*temp, struct nova_range_node, node); compVal = nova_rbtree_compare_rangenode(curr, new_node->range_low); parent = *temp; if (compVal == -1) { temp = &((*temp)->rb_left); } else if (compVal == 1) { temp = &((*temp)->rb_right); } else { nova_dbg("%s: entry %lu - %lu already exists: " "%lu - %lu\n", __func__, new_node->range_low, new_node->range_high, curr->range_low, curr->range_high); return -EINVAL; } } rb_link_node(&new_node->node, parent, temp); rb_insert_color(&new_node->node, tree); return 0; }
static int nova_failure_insert_inodetree(struct super_block *sb, unsigned long ino_low, unsigned long ino_high) { struct nova_sb_info *sbi = NOVA_SB(sb); struct inode_map *inode_map; struct nova_range_node *prev = NULL, *next = NULL; struct nova_range_node *new_node; unsigned long internal_low, internal_high; int cpu; struct rb_root *tree; int ret; if (ino_low > ino_high) { nova_err(sb, "%s: ino low %lu, ino high %lu\n", __func__, ino_low, ino_high); BUG(); } cpu = ino_low % sbi->cpus; if (ino_high % sbi->cpus != cpu) { nova_err(sb, "%s: ino low %lu, ino high %lu\n", __func__, ino_low, ino_high); BUG(); } internal_low = ino_low / sbi->cpus; internal_high = ino_high / sbi->cpus; inode_map = &sbi->inode_maps[cpu]; tree = &inode_map->inode_inuse_tree; mutex_lock(&inode_map->inode_table_mutex); ret = nova_find_free_slot(sbi, tree, internal_low, internal_high, &prev, &next); if (ret) { nova_dbg("%s: ino %lu - %lu already exists!: %d\n", __func__, ino_low, ino_high, ret); mutex_unlock(&inode_map->inode_table_mutex); return ret; } if (prev && next && (internal_low == prev->range_high + 1) && (internal_high + 1 == next->range_low)) { /* fits the hole */ rb_erase(&next->node, tree); inode_map->num_range_node_inode--; prev->range_high = next->range_high; nova_free_inode_node(sb, next); goto finish; } if (prev && (internal_low == prev->range_high + 1)) { /* Aligns left */ prev->range_high += internal_high - internal_low + 1; goto finish; } if (next && (internal_high + 1 == next->range_low)) { /* Aligns right */ next->range_low -= internal_high - internal_low + 1; goto finish; } /* Aligns somewhere in the middle */ new_node = nova_alloc_inode_node(sb); NOVA_ASSERT(new_node); new_node->range_low = internal_low; new_node->range_high = internal_high; ret = nova_insert_inodetree(sbi, new_node, cpu); if (ret) { nova_err(sb, "%s failed\n", __func__); nova_free_inode_node(sb, new_node); goto finish; } inode_map->num_range_node_inode++; finish: mutex_unlock(&inode_map->inode_table_mutex); return ret; }
int nova_rebuild_dir_inode_tree(struct super_block *sb, struct nova_inode *pi, u64 pi_addr, struct nova_inode_info_header *sih) { struct nova_dentry *entry = NULL; struct nova_setattr_logentry *attr_entry = NULL; struct nova_link_change_entry *link_change_entry = NULL; struct nova_inode_log_page *curr_page; u64 ino = pi->nova_ino; unsigned short de_len; timing_t rebuild_time; void *addr; u64 curr_p; u64 next; u8 type; int ret; NOVA_START_TIMING(rebuild_dir_t, rebuild_time); nova_dbg_verbose("Rebuild dir %llu tree\n", ino); sih->pi_addr = pi_addr; curr_p = pi->log_head; if (curr_p == 0) { nova_err(sb, "Dir %llu log is NULL!\n", ino); BUG(); } nova_dbg_verbose("Log head 0x%llx, tail 0x%llx\n", curr_p, pi->log_tail); sih->log_pages = 1; while (curr_p != pi->log_tail) { if (goto_next_page(sb, curr_p)) { sih->log_pages++; curr_p = next_log_page(sb, curr_p); } if (curr_p == 0) { nova_err(sb, "Dir %llu log is NULL!\n", ino); BUG(); } addr = (void *)nova_get_block(sb, curr_p); type = nova_get_entry_type(addr); switch (type) { case SET_ATTR: attr_entry = (struct nova_setattr_logentry *)addr; nova_apply_setattr_entry(sb, pi, sih, attr_entry); sih->last_setattr = curr_p; curr_p += sizeof(struct nova_setattr_logentry); continue; case LINK_CHANGE: link_change_entry = (struct nova_link_change_entry *)addr; nova_apply_link_change_entry(pi, link_change_entry); sih->last_link_change = curr_p; curr_p += sizeof(struct nova_link_change_entry); continue; case DIR_LOG: break; default: nova_dbg("%s: unknown type %d, 0x%llx\n", __func__, type, curr_p); NOVA_ASSERT(0); } entry = (struct nova_dentry *)nova_get_block(sb, curr_p); nova_dbgv("curr_p: 0x%llx, type %d, ino %llu, " "name %s, namelen %u, rec len %u\n", curr_p, entry->entry_type, le64_to_cpu(entry->ino), entry->name, entry->name_len, le16_to_cpu(entry->de_len)); if (entry->ino > 0) { if (entry->invalid == 0) { /* A valid entry to add */ ret = nova_replay_add_dentry(sb, sih, entry); } } else { /* Delete the entry */ ret = nova_replay_remove_dentry(sb, sih, entry); } if (ret) { nova_err(sb, "%s ERROR %d\n", __func__, ret); break; } nova_rebuild_dir_time_and_size(sb, pi, entry); de_len = le16_to_cpu(entry->de_len); curr_p += de_len; } sih->i_size = le64_to_cpu(pi->i_size); sih->i_mode = le64_to_cpu(pi->i_mode); nova_flush_buffer(pi, sizeof(struct nova_inode), 0); /* Keep traversing until log ends */ curr_p &= PAGE_MASK; curr_page = (struct nova_inode_log_page *)nova_get_block(sb, curr_p); while ((next = curr_page->page_tail.next_page) != 0) { sih->log_pages++; curr_p = next; curr_page = (struct nova_inode_log_page *) nova_get_block(sb, curr_p); } pi->i_blocks = sih->log_pages; // nova_print_dir_tree(sb, sih, ino); NOVA_END_TIMING(rebuild_dir_t, rebuild_time); return 0; }
void nova_save_blocknode_mappings_to_log(struct super_block *sb) { struct nova_inode *pi = nova_get_inode_by_ino(sb, NOVA_BLOCKNODE_INO); struct nova_sb_info *sbi = NOVA_SB(sb); struct nova_super_block *super; struct free_list *free_list; unsigned long num_blocknode = 0; unsigned long num_pages; int allocated; u64 new_block = 0; u64 temp_tail; int i; /* Allocate log pages before save blocknode mappings */ for (i = 0; i < sbi->cpus; i++) { free_list = nova_get_free_list(sb, i); num_blocknode += free_list->num_blocknode; nova_dbgv("%s: free list %d: %lu nodes\n", __func__, i, free_list->num_blocknode); } free_list = nova_get_free_list(sb, SHARED_CPU); num_blocknode += free_list->num_blocknode; nova_dbgv("%s: shared list: %lu nodes\n", __func__, free_list->num_blocknode); num_pages = num_blocknode / RANGENODE_PER_PAGE; if (num_blocknode % RANGENODE_PER_PAGE) num_pages++; allocated = nova_allocate_inode_log_pages(sb, pi, num_pages, &new_block); if (allocated != num_pages) { nova_dbg("Error saving blocknode mappings: %d\n", allocated); return; } /* * save the total allocated blocknode mappings * in super block * No transaction is needed as we will recover the fields * via failure recovery */ super = nova_get_super(sb); nova_memunlock_range(sb, &super->s_wtime, NOVA_FAST_MOUNT_FIELD_SIZE); super->s_wtime = cpu_to_le32(get_seconds()); nova_memlock_range(sb, &super->s_wtime, NOVA_FAST_MOUNT_FIELD_SIZE); nova_flush_buffer(super, NOVA_SB_SIZE, 0); /* Finally update log head and tail */ pi->log_head = new_block; nova_flush_buffer(&pi->log_head, CACHELINE_SIZE, 0); temp_tail = new_block; for (i = 0; i < sbi->cpus; i++) { temp_tail = nova_save_free_list_blocknodes(sb, i, temp_tail); } temp_tail = nova_save_free_list_blocknodes(sb, SHARED_CPU, temp_tail); nova_update_tail(pi, temp_tail); nova_dbg("%s: %lu blocknodes, %lu log pages, pi head 0x%llx, " "tail 0x%llx\n", __func__, num_blocknode, num_pages, pi->log_head, pi->log_tail); }
static int nova_readdir(struct file *file, struct dir_context *ctx) { struct inode *inode = file_inode(file); struct super_block *sb = inode->i_sb; struct nova_inode *pidir; struct nova_inode_info *si = NOVA_I(inode); struct nova_inode_info_header *sih = &si->header; struct nova_inode *child_pi; struct nova_dentry *entry; struct nova_dentry *entries[FREE_BATCH]; int nr_entries; u64 pi_addr; unsigned long pos = 0; ino_t ino; int i; int ret; timing_t readdir_time; NOVA_START_TIMING(readdir_t, readdir_time); pidir = nova_get_inode(sb, inode); nova_dbgv("%s: ino %llu, size %llu, pos %llu\n", __func__, (u64)inode->i_ino, pidir->i_size, ctx->pos); if (!sih) { nova_dbg("%s: inode %lu sih does not exist!\n", __func__, inode->i_ino); ctx->pos = READDIR_END; return 0; } pos = ctx->pos; if (pos == READDIR_END) goto out; do { nr_entries = radix_tree_gang_lookup(&sih->tree, (void **)entries, pos, FREE_BATCH); for (i = 0; i < nr_entries; i++) { entry = entries[i]; pos = BKDRHash(entry->name, entry->name_len); ino = __le64_to_cpu(entry->ino); if (ino == 0) continue; ret = nova_get_inode_address(sb, ino, &pi_addr, 0); if (ret) { nova_dbg("%s: get child inode %lu address " "failed %d\n", __func__, ino, ret); ctx->pos = READDIR_END; return ret; } child_pi = nova_get_block(sb, pi_addr); nova_dbgv("ctx: ino %llu, name %s, " "name_len %u, de_len %u\n", (u64)ino, entry->name, entry->name_len, entry->de_len); if (!dir_emit(ctx, entry->name, entry->name_len, ino, IF2DT(le16_to_cpu(child_pi->i_mode)))) { nova_dbgv("Here: pos %llu\n", ctx->pos); return 0; } ctx->pos = pos + 1; } pos++; } while (nr_entries == FREE_BATCH); out: NOVA_END_TIMING(readdir_t, readdir_time); return 0; }
static int nova_readdir(struct file *file, struct dir_context *ctx) { struct inode *inode = file_inode(file); struct super_block *sb = inode->i_sb; struct nova_inode *pidir; struct nova_inode_info *si = NOVA_I(inode); struct nova_inode_info_header *sih = &si->header; struct nova_inode *child_pi; struct nova_inode *prev_child_pi = NULL; struct nova_dentry *entry = NULL; struct nova_dentry *prev_entry = NULL; unsigned short de_len; u64 pi_addr; unsigned long pos = 0; ino_t ino; void *addr; u64 curr_p; u8 type; int ret; timing_t readdir_time; NOVA_START_TIMING(readdir_t, readdir_time); pidir = nova_get_inode(sb, inode); nova_dbgv("%s: ino %llu, size %llu, pos 0x%llx\n", __func__, (u64)inode->i_ino, pidir->i_size, ctx->pos); if (pidir->log_head == 0) { nova_err(sb, "Dir %lu log is NULL!\n", inode->i_ino); BUG(); return -EINVAL; } pos = ctx->pos; if (pos == 0) { curr_p = pidir->log_head; } else if (pos == READDIR_END) { goto out; } else { curr_p = nova_find_next_dentry_addr(sb, sih, pos); if (curr_p == 0) goto out; } while (curr_p != pidir->log_tail) { if (goto_next_page(sb, curr_p)) { curr_p = next_log_page(sb, curr_p); } if (curr_p == 0) { nova_err(sb, "Dir %lu log is NULL!\n", inode->i_ino); BUG(); return -EINVAL; } addr = (void *)nova_get_block(sb, curr_p); type = nova_get_entry_type(addr); switch (type) { case SET_ATTR: curr_p += sizeof(struct nova_setattr_logentry); continue; case LINK_CHANGE: curr_p += sizeof(struct nova_link_change_entry); continue; case DIR_LOG: break; default: nova_dbg("%s: unknown type %d, 0x%llx\n", __func__, type, curr_p); BUG(); return -EINVAL; } entry = (struct nova_dentry *)nova_get_block(sb, curr_p); nova_dbgv("curr_p: 0x%llx, type %d, ino %llu, " "name %s, namelen %u, rec len %u\n", curr_p, entry->entry_type, le64_to_cpu(entry->ino), entry->name, entry->name_len, le16_to_cpu(entry->de_len)); de_len = le16_to_cpu(entry->de_len); if (entry->ino > 0 && entry->invalid == 0) { ino = __le64_to_cpu(entry->ino); pos = BKDRHash(entry->name, entry->name_len); ret = nova_get_inode_address(sb, ino, &pi_addr, 0); if (ret) { nova_dbg("%s: get child inode %lu address " "failed %d\n", __func__, ino, ret); ctx->pos = READDIR_END; return ret; } child_pi = nova_get_block(sb, pi_addr); nova_dbgv("ctx: ino %llu, name %s, " "name_len %u, de_len %u\n", (u64)ino, entry->name, entry->name_len, entry->de_len); if (prev_entry && !dir_emit(ctx, prev_entry->name, prev_entry->name_len, ino, IF2DT(le16_to_cpu(prev_child_pi->i_mode)))) { nova_dbgv("Here: pos %llu\n", ctx->pos); return 0; } prev_entry = entry; prev_child_pi = child_pi; } ctx->pos = pos; curr_p += de_len; } if (prev_entry && !dir_emit(ctx, prev_entry->name, prev_entry->name_len, ino, IF2DT(le16_to_cpu(prev_child_pi->i_mode)))) return 0; ctx->pos = READDIR_END; out: NOVA_END_TIMING(readdir_t, readdir_time); nova_dbgv("%s return\n", __func__); return 0; }
static int nova_init_inode_list_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_INODELIST1_INO); struct nova_range_node_lowhigh *entry; struct nova_range_node *range_node; struct inode_map *inode_map; size_t size = sizeof(struct nova_range_node_lowhigh); unsigned long num_inode_node = 0; u64 curr_p; unsigned long cpuid; int ret; sbi->s_inodes_used_count = 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); } entry = (struct nova_range_node_lowhigh *)nova_get_block(sb, curr_p); range_node = nova_alloc_inode_node(sb); if (range_node == NULL) NOVA_ASSERT(0); cpuid = (entry->range_low & CPUID_MASK) >> 56; if (cpuid >= sbi->cpus) { nova_err(sb, "Invalid cpuid %lu\n", cpuid); nova_free_inode_node(sb, range_node); NOVA_ASSERT(0); nova_destroy_inode_trees(sb); goto out; } range_node->range_low = entry->range_low & ~CPUID_MASK; range_node->range_high = entry->range_high; ret = nova_insert_inodetree(sbi, range_node, cpuid); if (ret) { nova_err(sb, "%s failed, %d\n", __func__, cpuid); nova_free_inode_node(sb, range_node); NOVA_ASSERT(0); nova_destroy_inode_trees(sb); goto out; } sbi->s_inodes_used_count += range_node->range_high - range_node->range_low + 1; num_inode_node++; inode_map = &sbi->inode_maps[cpuid]; inode_map->num_range_node_inode++; if (!inode_map->first_inode_range) inode_map->first_inode_range = range_node; curr_p += sizeof(struct nova_range_node_lowhigh); } nova_dbg("%s: %lu inode nodes\n", __func__, num_inode_node); out: nova_free_inode_log(sb, pi); return ret; }
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; }