/* This function is called by both msync() and fsync(). * TODO: Check if we can avoid calling pmfs_flush_buffer() for fsync. We use * movnti to write data to files, so we may want to avoid doing unnecessary * pmfs_flush_buffer() on fsync() */ int pmfs_fsync(struct file *file, loff_t start, loff_t end, int datasync) { /* Sync from start to end[inclusive] */ struct address_space *mapping = file->f_mapping; struct inode *inode = mapping->host; loff_t isize; int error; /* if the file is not mmap'ed, there is no need to do clflushes */ if (mapping_mapped(mapping) == 0) goto persist; end += 1; /* end is inclusive. We like our indices normal please ! */ isize = i_size_read(inode); if ((unsigned long)end > (unsigned long)isize) end = isize; if (!isize || (start >= end)) { pmfs_dbg_verbose("[%s:%d] : (ERR) isize(%llx), start(%llx)," " end(%llx)\n", __func__, __LINE__, isize, start, end); return -ENODATA; } /* Align start and end to cacheline boundaries */ start = start & CACHELINE_MASK; end = CACHELINE_ALIGN(end); do { void *xip_mem; pgoff_t pgoff; loff_t offset; unsigned long xip_pfn, nr_flush_bytes; pgoff = start >> PAGE_CACHE_SHIFT; offset = start & ~PAGE_CACHE_MASK; nr_flush_bytes = PAGE_CACHE_SIZE - offset; if (nr_flush_bytes > (end - start)) nr_flush_bytes = end - start; error = mapping->a_ops->get_xip_mem(mapping, pgoff, 0, &xip_mem, &xip_pfn); if (unlikely(error)) { /* sparse files could have such holes */ pmfs_dbg_verbose("[%s:%d] : start(%llx), end(%llx)," " pgoff(%lx)\n", __func__, __LINE__, start, end, pgoff); } else { /* flush the range */ pmfs_flush_buffer(xip_mem+offset, nr_flush_bytes, 0); } start += nr_flush_bytes; } while (start < end); persist: PERSISTENT_MARK(); PERSISTENT_BARRIER(); return 0; }
/* Returns new tail after append */ int pmfs_append_link_change_entry(struct super_block *sb, struct pmfs_inode *pi, struct inode *inode, u64 tail, u64 *new_tail) { struct pmfs_inode_info *si = PMFS_I(inode); struct pmfs_inode_info_header *sih = si->header; struct pmfs_link_change_entry *entry; u64 curr_p; size_t size = sizeof(struct pmfs_link_change_entry); timing_t append_time; PMFS_START_TIMING(append_entry_t, append_time); pmfs_dbg_verbose("%s: inode %lu attr change\n", __func__, inode->i_ino); curr_p = pmfs_get_append_head(sb, pi, sih, tail, size, 0, 1); if (curr_p == 0) return -ENOMEM; entry = (struct pmfs_link_change_entry *)pmfs_get_block(sb, curr_p); entry->entry_type = LINK_CHANGE; entry->links = cpu_to_le16(inode->i_nlink); entry->ctime = cpu_to_le32(inode->i_ctime.tv_sec); entry->flags = cpu_to_le32(inode->i_flags); entry->generation = cpu_to_le32(inode->i_generation); pmfs_flush_buffer(entry, size, 0); *new_tail = curr_p + size; PMFS_END_TIMING(append_entry_t, append_time); return 0; }
/* Caller needs to hold lite_journal_mutex until this returns. */ void pmfs_commit_lite_transaction(struct super_block *sb, u64 tail) { struct pmfs_inode *pi; pi = pmfs_get_inode_by_ino(sb, PMFS_LITEJOURNAL_INO); if (pi->log_tail != tail) BUG(); pi->log_head = tail; pmfs_flush_buffer(&pi->log_head, CACHELINE_SIZE, 1); }
int pmfs_lite_journal_hard_init(struct super_block *sb) { struct pmfs_inode *pi; unsigned long blocknr = 0; unsigned long pmfs_ino; int allocated; u64 block; pi = pmfs_get_inode_by_ino(sb, PMFS_LITEJOURNAL_INO); pmfs_ino = PMFS_LITEJOURNAL_INO; allocated = pmfs_new_log_blocks(sb, pmfs_ino, &blocknr, 1, PMFS_BLOCK_TYPE_4K, 1); pmfs_dbg_verbose("%s: allocate log @ 0x%lx\n", __func__, blocknr); if (allocated != 1 || blocknr == 0) return -ENOSPC; pi->i_blocks = 1; block = pmfs_get_block_off(sb, blocknr, PMFS_BLOCK_TYPE_4K); pi->log_head = pi->log_tail = block; pmfs_flush_buffer(&pi->log_head, CACHELINE_SIZE, 1); return pmfs_lite_journal_soft_init(sb); }
static void pmfs_recover_lite_journal_entry(struct super_block *sb, u64 addr, u64 value, u8 type) { switch (type) { case 1: *(u8 *)pmfs_get_block(sb, addr) = (u8)value; break; case 2: *(u16 *)pmfs_get_block(sb, addr) = (u16)value; break; case 4: *(u32 *)pmfs_get_block(sb, addr) = (u32)value; break; case 8: *(u64 *)pmfs_get_block(sb, addr) = (u64)value; break; default: pmfs_dbg("%s: unknown data type %u\n", __func__, type); break; } pmfs_flush_buffer((void *)pmfs_get_block(sb, addr), CACHELINE_SIZE, 0); }