int pmfs_lite_journal_soft_init(struct super_block *sb) { struct pmfs_sb_info *sbi = PMFS_SB(sb); struct pmfs_inode *pi; u64 temp; mutex_init(&sbi->lite_journal_mutex); pi = pmfs_get_inode_by_ino(sb, PMFS_LITEJOURNAL_INO); if (pi->log_head == pi->log_tail) return 0; /* We only allow up to two uncommited entries */ temp = next_lite_journal(pi->log_head); if (pi->log_tail == temp) { pmfs_recover_lite_journal(sb, pi, 1); return 0; } temp = next_lite_journal(temp); if (pi->log_tail == temp) { pmfs_recover_lite_journal(sb, pi, 2); return 0; } /* We are in trouble */ pmfs_dbg("%s: lite journal head 0x%llx, tail 0x%llx\n", __func__, pi->log_head, pi->log_tail); return -EINVAL; }
static void pmfs_lite_transaction_for_time_and_link(struct super_block *sb, struct pmfs_inode *pi, struct pmfs_inode *pidir, u64 pi_tail, u64 pidir_tail, int invalidate) { struct pmfs_sb_info *sbi = PMFS_SB(sb); struct pmfs_lite_journal_entry entry; u64 journal_tail; /* Commit a lite transaction */ memset(&entry, 0, sizeof(struct pmfs_lite_journal_entry)); entry.addrs[0] = (u64)pmfs_get_addr_off(sbi, &pi->log_tail); entry.addrs[0] |= (u64)8 << 56; entry.values[0] = pi->log_tail; entry.addrs[1] = (u64)pmfs_get_addr_off(sbi, &pidir->log_tail); entry.addrs[1] |= (u64)8 << 56; entry.values[1] = pidir->log_tail; if (invalidate) { entry.addrs[2] = (u64)pmfs_get_addr_off(sbi, &pi->valid); entry.addrs[2] |= (u64)1 << 56; entry.values[2] = pi->valid; } mutex_lock(&sbi->lite_journal_mutex); journal_tail = pmfs_create_lite_transaction(sb, &entry, NULL, 1); pmfs_update_tail(pi, pi_tail); pmfs_update_tail(pidir, pidir_tail); if (invalidate) pi->valid = 0; pmfs_commit_lite_transaction(sb, journal_tail); mutex_unlock(&sbi->lite_journal_mutex); }
void pmfs_init_blockmap(struct super_block *sb, unsigned long init_used_size) { struct pmfs_sb_info *sbi = PMFS_SB(sb); unsigned long num_used_block; struct pmfs_blocknode *blknode; num_used_block = (init_used_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits; blknode = pmfs_alloc_blocknode(sb); if (blknode == NULL) PMFS_ASSERT(0); blknode->block_low = sbi->block_start; blknode->block_high = sbi->block_start + num_used_block - 1; sbi->num_free_blocks -= num_used_block; list_add(&blknode->link, &sbi->block_inuse_head); }
/* Stores PMFS memory image into a storage file. Uses the allocation blocknode * linked list to determine which memory ranges to save */ static int pmfs_storefs(struct file *flp, struct super_block *sb) { loff_t woff = 0; struct pmfs_sb_info *sbi = PMFS_SB(sb); u64 num_blocknodes = sbi->num_blocknode_allocated, size; struct list_head *head = &(sbi->block_inuse_head); struct pmfs_blocknode *i; struct pmfs_blocknode_lowhigh p; char *ptr; pmfs_info("storing pmfs to %s with 0x%llx blknodes\n", sbi->pmfs_backing_file, num_blocknodes); /* first save the number of blocknodes */ if (pmfs_write_backing_store(flp, (char *)&num_blocknodes, sizeof(u64), &woff) != sizeof(u64)) goto out; /* Then save the blocks containing blocknodes. */ list_for_each_entry(i, head, link) { p.block_low = cpu_to_le64(i->block_low); p.block_high = cpu_to_le64(i->block_high); if (pmfs_write_backing_store(flp, (char *)&p, sizeof(p), &woff) != sizeof(p)) goto out; }
static int pmfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { struct inode *old_inode = old_dentry->d_inode; struct inode *new_inode = new_dentry->d_inode; struct super_block *sb = old_inode->i_sb; struct pmfs_sb_info *sbi = PMFS_SB(sb); struct pmfs_inode *old_pi = NULL, *new_pi = NULL; struct pmfs_inode *new_old_pi = NULL; struct pmfs_inode *new_pidir = NULL, *old_pidir = NULL; struct pmfs_lite_journal_entry entry, entry1; struct pmfs_inode_info *si = PMFS_I(old_inode); struct pmfs_inode_info_header *sih = si->header; u64 old_tail = 0, new_tail = 0, tail, new_pi_tail = 0, old_pi_tail = 0; u64 pi_newaddr = 0; int need_new_pi = 0; int err = -ENOENT; int inc_link = 0, dec_link = 0; int entries = 0; u64 journal_tail; timing_t rename_time; pmfs_dbgv("%s: rename %s to %s, old dir %lu, new dir %lu\n", __func__, old_dentry->d_name.name, new_dentry->d_name.name, old_dir->i_ino, new_dir->i_ino); PMFS_START_TIMING(rename_t, rename_time); if (new_inode) { err = -ENOTEMPTY; if (S_ISDIR(old_inode->i_mode) && !pmfs_empty_dir(new_inode)) goto out; } else { if (S_ISDIR(old_inode->i_mode)) { err = -EMLINK; if (new_dir->i_nlink >= PMFS_LINK_MAX) goto out; } if (S_ISDIR(old_inode->i_mode)) { inc_link = 1; dec_link = -1; } } new_pidir = pmfs_get_inode(sb, new_dir); old_pidir = pmfs_get_inode(sb, old_dir); old_pi = pmfs_get_inode(sb, old_inode); old_inode->i_ctime = CURRENT_TIME; err = pmfs_append_link_change_entry(sb, old_pi, old_inode, 0, &old_pi_tail); if (err) goto out; if (new_inode) { /* First remove the old entry in the new directory */ err = pmfs_remove_entry(new_dentry, 0, 0, &new_tail); if (err) goto out; } /* If old dir is different from new dir, copy the inode to new dir */ if (new_pidir != old_pidir) need_new_pi = 1; /* link into the new directory. */ err = pmfs_add_entry(new_dentry, &pi_newaddr, old_inode->i_ino, inc_link, need_new_pi, new_tail, &new_tail); if (err) goto out; /* and unlink the inode from the old directory ... */ if (need_new_pi) { tail = 0; new_old_pi = (struct pmfs_inode *)pmfs_get_block(sb, pi_newaddr); memcpy_to_pmem_nocache(new_old_pi, old_pi, PMFS_INODE_SIZE); /* new_old_pi is part of the log so in-place update is fine */ pmfs_update_tail(new_old_pi, old_pi_tail); } else { tail = new_tail; } err = pmfs_remove_entry(old_dentry, dec_link, tail, &old_tail); if (err) goto out; if (new_inode) { new_pi = pmfs_get_inode(sb, new_inode); new_inode->i_ctime = CURRENT_TIME; if (S_ISDIR(old_inode->i_mode)) { if (new_inode->i_nlink) drop_nlink(new_inode); } if (new_inode->i_nlink) drop_nlink(new_inode); err = pmfs_append_link_change_entry(sb, new_pi, new_inode, 0, &new_pi_tail); if (err) goto out; } if (inc_link) inc_nlink(new_dir); if (dec_link < 0) drop_nlink(old_dir); entries = 1; memset(&entry, 0, sizeof(struct pmfs_lite_journal_entry)); entry.addrs[0] = (u64)pmfs_get_addr_off(sbi, &old_pi->log_tail); entry.addrs[0] |= (u64)8 << 56; entry.values[0] = old_pi->log_tail; entry.addrs[1] = (u64)pmfs_get_addr_off(sbi, &old_pidir->log_tail); entry.addrs[1] |= (u64)8 << 56; entry.values[1] = old_pidir->log_tail; if (old_pidir != new_pidir) { entry.addrs[2] = (u64)pmfs_get_addr_off(sbi, &old_pi->valid); entry.addrs[2] |= (u64)1 << 56; entry.values[2] = old_pi->valid; entry.addrs[3] = (u64)pmfs_get_addr_off(sbi, &new_pidir->log_tail); entry.addrs[3] |= (u64)8 << 56; entry.values[3] = new_pidir->log_tail; } if (new_inode) { entries++; memset(&entry1, 0, sizeof(struct pmfs_lite_journal_entry)); entry1.addrs[0] = (u64)pmfs_get_addr_off(sbi, &new_pi->log_tail); entry1.addrs[0] |= (u64)8 << 56; entry1.values[0] = new_pi->log_tail; if (!new_inode->i_nlink) { entry1.addrs[1] = (u64)pmfs_get_addr_off(sbi, &new_pi->valid); entry1.addrs[1] |= (u64)1 << 56; entry1.values[1] = new_pi->valid; } } mutex_lock(&sbi->lite_journal_mutex); journal_tail = pmfs_create_lite_transaction(sb, &entry, &entry1, entries); pmfs_update_tail(old_pi, old_pi_tail); pmfs_update_tail(old_pidir, old_tail); if (old_pidir != new_pidir) { pmfs_update_tail(new_pidir, new_tail); old_pi->valid = 0; } if (new_inode) { pmfs_update_tail(new_pi, new_pi_tail); if (!new_inode->i_nlink) new_pi->valid = 0; } pmfs_commit_lite_transaction(sb, journal_tail); mutex_unlock(&sbi->lite_journal_mutex); if (need_new_pi && pi_newaddr) sih->pi_addr = pi_newaddr; PMFS_END_TIMING(rename_t, rename_time); return 0; out: pmfs_err(sb, "%s return %d\n", __func__, err); PMFS_END_TIMING(rename_t, rename_time); return err; }
void pmfs_free_block(struct super_block *sb, unsigned long blocknr, unsigned short btype) { struct pmfs_sb_info *sbi = PMFS_SB(sb); struct list_head *head = &(sbi->block_inuse_head); unsigned long new_block_low; unsigned long new_block_high; unsigned long num_blocks = 0; struct pmfs_blocknode *i; struct pmfs_blocknode *free_blocknode= NULL; struct pmfs_blocknode *curr_node; num_blocks = pmfs_get_numblocks(btype); new_block_low = blocknr; new_block_high = blocknr + num_blocks - 1; lock_super(sb); /* Traverese each blocknode entry */ list_for_each_entry(i, head, link) { if (new_block_low > i->block_high) { /* skip to next blocknode */ continue; } if ((new_block_low == i->block_low) && (new_block_high == i->block_high)) { /* fits entire datablock */ list_del(&i->link); free_blocknode = i; sbi->num_blocknode_allocated--; sbi->num_free_blocks += num_blocks; break; } if ((new_block_low == i->block_low) && (new_block_high < i->block_high)) { /* Aligns left */ i->block_low = new_block_high + 1; sbi->num_free_blocks += num_blocks; break; } if ((new_block_low > i->block_low) && (new_block_high == i->block_high)) { /* Aligns right */ i->block_high = new_block_low - 1; sbi->num_free_blocks += num_blocks; break; } if ((new_block_low > i->block_low) && (new_block_high < i->block_high)) { /* Aligns somewhere in the middle */ curr_node = pmfs_alloc_blocknode(sb); PMFS_ASSERT(curr_node); if (curr_node == NULL) { /* returning without freeing the block*/ break; } curr_node->block_low = new_block_high + 1; curr_node->block_high = i->block_high; i->block_high = new_block_low - 1; list_add(&curr_node->link, &i->link); sbi->num_free_blocks += num_blocks; break; } } unlock_super(sb); if (free_blocknode) __pmfs_free_blocknode(free_blocknode); return; }
unsigned long pmfs_count_free_blocks(struct super_block *sb) { struct pmfs_sb_info *sbi = PMFS_SB(sb); return sbi->num_free_blocks; }
int pmfs_new_block(struct super_block *sb, unsigned long *blocknr, unsigned short btype, int zero) { struct pmfs_sb_info *sbi = PMFS_SB(sb); struct list_head *head = &(sbi->block_inuse_head); struct pmfs_blocknode *i, *next_i; struct pmfs_blocknode *free_blocknode= NULL; void *bp; unsigned long num_blocks = 0; struct pmfs_blocknode *curr_node; int errval = 0; bool found = 0; unsigned long next_block_low; unsigned long new_block_low; unsigned long new_block_high; num_blocks = pmfs_get_numblocks(btype); lock_super(sb); /* Traverese each blocknode entry */ list_for_each_entry(i, head, link) { if (i->link.next == head) { next_i = NULL; next_block_low = sbi->block_end; } else { next_i = list_entry(i->link.next, typeof(*i), link); next_block_low = next_i->block_low; } new_block_low = (i->block_high + num_blocks) & ~(num_blocks - 1); new_block_high = new_block_low + num_blocks - 1; if (new_block_high >= next_block_low) { /* Does not fit - skip to next blocknode */ continue; } if ((new_block_low == (i->block_high + 1)) && (new_block_high == (next_block_low - 1))) { /* Fill the gap completly */ if (next_i) { i->block_high = next_i->block_high; list_del(&next_i->link); free_blocknode = next_i; sbi->num_blocknode_allocated--; } else { i->block_high = new_block_high; } found = 1; break; } if ((new_block_low == (i->block_high + 1)) && (new_block_high < (next_block_low - 1))) { /* Aligns to left */ i->block_high = new_block_high; found = 1; break; } if ((new_block_low > (i->block_high + 1)) && (new_block_high == (next_block_low - 1))) { /* Aligns to right */ if (next_i) { /* right node exist */ next_i->block_low = new_block_low; } else { /* right node does NOT exist */ curr_node = pmfs_alloc_blocknode(sb); PMFS_ASSERT(curr_node); if (curr_node == NULL) { errval = -ENOSPC; break; } curr_node->block_low = new_block_low; curr_node->block_high = new_block_high; list_add(&curr_node->link, &i->link); } found = 1; break; } if ((new_block_low > (i->block_high + 1)) && (new_block_high < (next_block_low - 1))) { /* Aligns somewhere in the middle */ curr_node = pmfs_alloc_blocknode(sb); PMFS_ASSERT(curr_node); if (curr_node == NULL) { errval = -ENOSPC; break; } curr_node->block_low = new_block_low; curr_node->block_high = new_block_high; list_add(&curr_node->link, &i->link); found = 1; break; } } if (found == 1) { sbi->num_free_blocks -= num_blocks; } unlock_super(sb); if (free_blocknode) __pmfs_free_blocknode(free_blocknode); if (found == 0) { return -ENOSPC; } if (zero) { size_t size; bp = pmfs_get_block(sb, pmfs_get_block_off(sb, new_block_low, btype)); pmfs_memunlock_block(sb, bp); //TBDTBD: Need to fix this if (btype == PMFS_BLOCK_TYPE_4K) size = 0x1 << 12; else if (btype == PMFS_BLOCK_TYPE_2M) size = 0x1 << 21; else size = 0x1 << 30; memset_nt(bp, 0, size); pmfs_memlock_block(sb, bp); } *blocknr = new_block_low; return errval; }