[RFC v2 21/83] Add log structure.

2018-03-10 Thread Andiry Xu
From: Andiry Xu 

NOVA log is a singly linked list of 4KB pmem pages.
Each log page consists of two parts: 4064 bytes for log entries,
and 32 bytes for page tail structure. Page tail contains metadata
about the log page and the address of the next log page in the
linked list.

Signed-off-by: Andiry Xu 
---
 fs/nova/log.h  | 187 +
 fs/nova/nova.h |   1 +
 2 files changed, 188 insertions(+)
 create mode 100644 fs/nova/log.h

diff --git a/fs/nova/log.h b/fs/nova/log.h
new file mode 100644
index 000..61586a3
--- /dev/null
+++ b/fs/nova/log.h
@@ -0,0 +1,187 @@
+#ifndef __LOG_H
+#define __LOG_H
+
+#include "balloc.h"
+#include "inode.h"
+
+/* === Log entry = */
+/* Inode entry in the log */
+
+#defineMAIN_LOG0
+#defineALTER_LOG   1
+
+#definePAGE_OFFSET_MASK4095
+#defineBLOCK_OFF(p)((p) & ~PAGE_OFFSET_MASK)
+
+#defineENTRY_LOC(p)((p) & PAGE_OFFSET_MASK)
+
+#defineLOG_BLOCK_TAIL  4064
+#definePAGE_TAIL(p)(BLOCK_OFF(p) + LOG_BLOCK_TAIL)
+
+/*
+ * Log page state and pointers to next page and the replica page
+ */
+struct nova_inode_page_tail {
+   __le32  invalid_entries;
+   __le32  num_entries;
+   __le64  epoch_id;   /* For snapshot list page */
+   __le64  padding;
+   __le64  next_page;
+} __attribute((__packed__));
+
+/* Fit in PAGE_SIZE */
+struct nova_inode_log_page {
+   char padding[LOG_BLOCK_TAIL];
+   struct nova_inode_page_tail page_tail;
+} __attribute((__packed__));
+
+
+enum nova_entry_type {
+   FILE_WRITE = 1,
+   DIR_LOG,
+   SET_ATTR,
+   LINK_CHANGE,
+   NEXT_PAGE,
+};
+
+static inline u8 nova_get_entry_type(void *p)
+{
+   u8 type;
+   int rc;
+
+   rc = memcpy_mcsafe(, p, sizeof(u8));
+   if (rc)
+   return rc;
+
+   return type;
+}
+
+static inline void nova_set_entry_type(void *p, enum nova_entry_type type)
+{
+   *(u8 *)p = type;
+}
+
+static inline u64 next_log_page(struct super_block *sb, u64 curr)
+{
+   struct nova_inode_log_page *curr_page;
+   u64 next = 0;
+   int rc;
+
+   curr = BLOCK_OFF(curr);
+   curr_page = (struct nova_inode_log_page *)nova_get_block(sb, curr);
+   rc = memcpy_mcsafe(, _page->page_tail.next_page,
+   sizeof(u64));
+   if (rc)
+   return rc;
+
+   return next;
+}
+
+static inline void nova_set_next_page_flag(struct super_block *sb, u64 curr_p)
+{
+   void *p;
+
+   if (ENTRY_LOC(curr_p) >= LOG_BLOCK_TAIL)
+   return;
+
+   p = nova_get_block(sb, curr_p);
+   nova_set_entry_type(p, NEXT_PAGE);
+   nova_flush_buffer(p, CACHELINE_SIZE, 1);
+}
+
+static inline void nova_set_next_page_address(struct super_block *sb,
+   struct nova_inode_log_page *curr_page, u64 next_page, int fence)
+{
+   curr_page->page_tail.next_page = next_page;
+   nova_flush_buffer(_page->page_tail,
+   sizeof(struct nova_inode_page_tail), 0);
+   if (fence)
+   PERSISTENT_BARRIER();
+}
+
+static inline void nova_set_page_num_entries(struct super_block *sb,
+   struct nova_inode_log_page *curr_page, int num, int flush)
+{
+   curr_page->page_tail.num_entries = num;
+   if (flush)
+   nova_flush_buffer(_page->page_tail,
+   sizeof(struct nova_inode_page_tail), 0);
+}
+
+static inline void nova_set_page_invalid_entries(struct super_block *sb,
+   struct nova_inode_log_page *curr_page, int num, int flush)
+{
+   curr_page->page_tail.invalid_entries = num;
+   if (flush)
+   nova_flush_buffer(_page->page_tail,
+   sizeof(struct nova_inode_page_tail), 0);
+}
+
+static inline void nova_inc_page_num_entries(struct super_block *sb,
+   u64 curr)
+{
+   struct nova_inode_log_page *curr_page;
+
+   curr = BLOCK_OFF(curr);
+   curr_page = (struct nova_inode_log_page *)nova_get_block(sb, curr);
+
+   curr_page->page_tail.num_entries++;
+   nova_flush_buffer(_page->page_tail,
+   sizeof(struct nova_inode_page_tail), 0);
+}
+
+static inline void nova_inc_page_invalid_entries(struct super_block *sb,
+   u64 curr)
+{
+   struct nova_inode_log_page *curr_page;
+
+   curr = BLOCK_OFF(curr);
+   curr_page = (struct nova_inode_log_page *)nova_get_block(sb, curr);
+
+   curr_page->page_tail.invalid_entries++;
+   if (curr_page->page_tail.invalid_entries >
+   curr_page->page_tail.num_entries) {
+   nova_dbg("Page 0x%llx has %u entries, %u invalid\n",
+   curr,
+   curr_page->page_tail.num_entries,
+   curr_page->page_tail.invalid_entries);
+   }

[RFC v2 21/83] Add log structure.

2018-03-10 Thread Andiry Xu
From: Andiry Xu 

NOVA log is a singly linked list of 4KB pmem pages.
Each log page consists of two parts: 4064 bytes for log entries,
and 32 bytes for page tail structure. Page tail contains metadata
about the log page and the address of the next log page in the
linked list.

Signed-off-by: Andiry Xu 
---
 fs/nova/log.h  | 187 +
 fs/nova/nova.h |   1 +
 2 files changed, 188 insertions(+)
 create mode 100644 fs/nova/log.h

diff --git a/fs/nova/log.h b/fs/nova/log.h
new file mode 100644
index 000..61586a3
--- /dev/null
+++ b/fs/nova/log.h
@@ -0,0 +1,187 @@
+#ifndef __LOG_H
+#define __LOG_H
+
+#include "balloc.h"
+#include "inode.h"
+
+/* === Log entry = */
+/* Inode entry in the log */
+
+#defineMAIN_LOG0
+#defineALTER_LOG   1
+
+#definePAGE_OFFSET_MASK4095
+#defineBLOCK_OFF(p)((p) & ~PAGE_OFFSET_MASK)
+
+#defineENTRY_LOC(p)((p) & PAGE_OFFSET_MASK)
+
+#defineLOG_BLOCK_TAIL  4064
+#definePAGE_TAIL(p)(BLOCK_OFF(p) + LOG_BLOCK_TAIL)
+
+/*
+ * Log page state and pointers to next page and the replica page
+ */
+struct nova_inode_page_tail {
+   __le32  invalid_entries;
+   __le32  num_entries;
+   __le64  epoch_id;   /* For snapshot list page */
+   __le64  padding;
+   __le64  next_page;
+} __attribute((__packed__));
+
+/* Fit in PAGE_SIZE */
+struct nova_inode_log_page {
+   char padding[LOG_BLOCK_TAIL];
+   struct nova_inode_page_tail page_tail;
+} __attribute((__packed__));
+
+
+enum nova_entry_type {
+   FILE_WRITE = 1,
+   DIR_LOG,
+   SET_ATTR,
+   LINK_CHANGE,
+   NEXT_PAGE,
+};
+
+static inline u8 nova_get_entry_type(void *p)
+{
+   u8 type;
+   int rc;
+
+   rc = memcpy_mcsafe(, p, sizeof(u8));
+   if (rc)
+   return rc;
+
+   return type;
+}
+
+static inline void nova_set_entry_type(void *p, enum nova_entry_type type)
+{
+   *(u8 *)p = type;
+}
+
+static inline u64 next_log_page(struct super_block *sb, u64 curr)
+{
+   struct nova_inode_log_page *curr_page;
+   u64 next = 0;
+   int rc;
+
+   curr = BLOCK_OFF(curr);
+   curr_page = (struct nova_inode_log_page *)nova_get_block(sb, curr);
+   rc = memcpy_mcsafe(, _page->page_tail.next_page,
+   sizeof(u64));
+   if (rc)
+   return rc;
+
+   return next;
+}
+
+static inline void nova_set_next_page_flag(struct super_block *sb, u64 curr_p)
+{
+   void *p;
+
+   if (ENTRY_LOC(curr_p) >= LOG_BLOCK_TAIL)
+   return;
+
+   p = nova_get_block(sb, curr_p);
+   nova_set_entry_type(p, NEXT_PAGE);
+   nova_flush_buffer(p, CACHELINE_SIZE, 1);
+}
+
+static inline void nova_set_next_page_address(struct super_block *sb,
+   struct nova_inode_log_page *curr_page, u64 next_page, int fence)
+{
+   curr_page->page_tail.next_page = next_page;
+   nova_flush_buffer(_page->page_tail,
+   sizeof(struct nova_inode_page_tail), 0);
+   if (fence)
+   PERSISTENT_BARRIER();
+}
+
+static inline void nova_set_page_num_entries(struct super_block *sb,
+   struct nova_inode_log_page *curr_page, int num, int flush)
+{
+   curr_page->page_tail.num_entries = num;
+   if (flush)
+   nova_flush_buffer(_page->page_tail,
+   sizeof(struct nova_inode_page_tail), 0);
+}
+
+static inline void nova_set_page_invalid_entries(struct super_block *sb,
+   struct nova_inode_log_page *curr_page, int num, int flush)
+{
+   curr_page->page_tail.invalid_entries = num;
+   if (flush)
+   nova_flush_buffer(_page->page_tail,
+   sizeof(struct nova_inode_page_tail), 0);
+}
+
+static inline void nova_inc_page_num_entries(struct super_block *sb,
+   u64 curr)
+{
+   struct nova_inode_log_page *curr_page;
+
+   curr = BLOCK_OFF(curr);
+   curr_page = (struct nova_inode_log_page *)nova_get_block(sb, curr);
+
+   curr_page->page_tail.num_entries++;
+   nova_flush_buffer(_page->page_tail,
+   sizeof(struct nova_inode_page_tail), 0);
+}
+
+static inline void nova_inc_page_invalid_entries(struct super_block *sb,
+   u64 curr)
+{
+   struct nova_inode_log_page *curr_page;
+
+   curr = BLOCK_OFF(curr);
+   curr_page = (struct nova_inode_log_page *)nova_get_block(sb, curr);
+
+   curr_page->page_tail.invalid_entries++;
+   if (curr_page->page_tail.invalid_entries >
+   curr_page->page_tail.num_entries) {
+   nova_dbg("Page 0x%llx has %u entries, %u invalid\n",
+   curr,
+   curr_page->page_tail.num_entries,
+   curr_page->page_tail.invalid_entries);
+   }
+
+