/* Do not fail, do not sleep. Make it fast! */ u64 pmfs_create_lite_transaction(struct super_block *sb, struct pmfs_lite_journal_entry *dram_entry1, struct pmfs_lite_journal_entry *dram_entry2, int entries) { struct pmfs_inode *pi; struct pmfs_lite_journal_entry *entry; size_t size = sizeof(struct pmfs_lite_journal_entry); u64 new_tail, temp;; pi = pmfs_get_inode_by_ino(sb, PMFS_LITEJOURNAL_INO); if (pi->log_head == 0 || pi->log_head != pi->log_tail) BUG(); temp = pi->log_head; entry = (struct pmfs_lite_journal_entry *)pmfs_get_block(sb, temp); pmfs_print_lite_transaction(dram_entry1); memcpy_to_pmem_nocache(entry, dram_entry1, size); if (entries == 2) { temp = next_lite_journal(temp); entry = (struct pmfs_lite_journal_entry *)pmfs_get_block(sb, temp); pmfs_print_lite_transaction(dram_entry2); memcpy_to_pmem_nocache(entry, dram_entry2, size); } new_tail = next_lite_journal(temp); pmfs_update_tail(pi, new_tail); return new_tail; }
/* * Append a nova_dentry to the current nova_inode_log_page. * Note unlike append_file_write_entry(), this method returns the tail pointer * after append. */ static u64 nova_append_dir_inode_entry(struct super_block *sb, struct nova_inode *pidir, struct inode *dir, u64 ino, struct dentry *dentry, unsigned short de_len, u64 tail, int link_change, u64 *curr_tail) { struct nova_inode_info *si = NOVA_I(dir); struct nova_inode_info_header *sih = &si->header; struct nova_dentry *entry; u64 curr_p; size_t size = de_len; int extended = 0; unsigned short links_count; timing_t append_time; NOVA_START_TIMING(append_dir_entry_t, append_time); curr_p = nova_get_append_head(sb, pidir, sih, tail, size, &extended); if (curr_p == 0) BUG(); entry = (struct nova_dentry *)nova_get_block(sb, curr_p); entry->entry_type = DIR_LOG; entry->ino = cpu_to_le64(ino); entry->name_len = dentry->d_name.len; memcpy_to_pmem_nocache(entry->name, dentry->d_name.name, dentry->d_name.len); entry->name[dentry->d_name.len] = '\0'; entry->file_type = 0; entry->invalid = 0; entry->mtime = cpu_to_le32(dir->i_mtime.tv_sec); entry->size = cpu_to_le64(dir->i_size); links_count = cpu_to_le16(dir->i_nlink); if (links_count == 0 && link_change == -1) links_count = 0; else links_count += link_change; entry->links_count = cpu_to_le16(links_count); /* Update actual de_len */ entry->de_len = cpu_to_le16(de_len); nova_dbg_verbose("dir entry @ 0x%llx: ino %llu, entry len %u, " "name len %u, file type %u\n", curr_p, entry->ino, entry->de_len, entry->name_len, entry->file_type); nova_flush_buffer(entry, de_len, 0); *curr_tail = curr_p + de_len; dir->i_blocks = pidir->i_blocks; NOVA_END_TIMING(append_dir_entry_t, append_time); return curr_p; }
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; }