@@ -62,6 +62,175 @@ static inline void nova_set_entry_type(void *p, enum nova_entry_type type)
*(u8 *)p = type;
}
+/*
+ * Write log entry. Records a write to a contiguous range of PMEM pages.
+ *
+ * Documentation/filesystems/nova.txt contains descriptions of some fields.
+ */
+struct nova_file_write_entry {
+ u8 entry_type;
+ u8 reassigned; /* Data is not latest */
+ u8 padding[2];
+ __le32 num_pages;
+ __le64 block; /* offset of first block in this write */
+ __le64 pgoff; /* file offset at the beginning of this write */
+ __le32 invalid_pages; /* For GC */
+ /* For both ctime and mtime */
+ __le32 mtime;
+ __le64 size; /* Write size for non-aligned writes */
+ __le64 epoch_id;
+ __le64 trans_id;
+ __le32 csumpadding;
+ __le32 csum;
+} __attribute((__packed__));
+
+#define WENTRY(entry) ((struct nova_file_write_entry *) entry)
+
+/* List of file write entries */
+struct nova_file_write_item {
+ struct nova_file_write_entry entry;
+ struct list_head list;
+};
+
+/*
+ * Log entry for adding a file/directory to a directory.
+ *
+ * Update DIR_LOG_REC_LEN if modify this struct!
+ */
+struct nova_dentry {
+ u8 entry_type;
+ u8 name_len; /* length of the dentry name */
+ u8 reassigned; /* Currently deleted */
+ u8 invalid; /* Invalid now? */
+ __le16 de_len; /* length of this dentry */
+ __le16 links_count;
+ __le32 mtime; /* For both mtime and ctime */
+ __le32 csum; /* entry checksum */
+ __le64 ino; /* inode no pointed to by this entry */
+ __le64 padding;
+ __le64 epoch_id;
+ __le64 trans_id;
+ char name[NOVA_NAME_LEN + 1]; /* File name */
+} __attribute((__packed__));
+
+#define DENTRY(entry) ((struct nova_dentry *) entry)
+
+#define NOVA_DIR_PAD 8 /* Align to 8 bytes boundary */
+#define NOVA_DIR_ROUND (NOVA_DIR_PAD - 1)
+#define NOVA_DENTRY_HEADER_LEN 48
+#define NOVA_DIR_LOG_REC_LEN(name_len) \
+ (((name_len + 1) + NOVA_DENTRY_HEADER_LEN \
+ + NOVA_DIR_ROUND) & ~NOVA_DIR_ROUND)
+
+#define NOVA_MAX_ENTRY_LEN NOVA_DIR_LOG_REC_LEN(NOVA_NAME_LEN)
+
+/*
+ * Log entry for updating file attributes.
+ */
+struct nova_setattr_logentry {
+ u8 entry_type;
+ u8 attr; /* bitmap of which attributes to update */
+ __le16 mode;
+ __le32 uid;
+ __le32 gid;
+ __le32 atime;
+ __le32 mtime;
+ __le32 ctime;
+ __le64 size; /* File size after truncation */
+ __le64 epoch_id;
+ __le64 trans_id;
+ u8 invalid;
+ u8 paddings[3];
+ __le32 csum;
+} __attribute((__packed__));
+
+#define SENTRY(entry) ((struct nova_setattr_logentry *) entry)
+
+/* Link change log entry.
+ *
+ * TODO: Do we need this to be 32 bytes?
+ */
+struct nova_link_change_entry {
+ u8 entry_type;
+ u8 invalid;
+ __le16 links;
+ __le32 ctime;
+ __le32 flags;
+ __le32 generation; /* for NFS handles */
+ __le64 epoch_id;
+ __le64 trans_id;
+ __le32 csumpadding;
+ __le32 csum;
+} __attribute((__packed__));
+
+#define LCENTRY(entry) ((struct nova_link_change_entry *) entry)
+
+
+/*
+ * Transient DRAM structure that describes changes needed to append a log entry
+ * to an inode
+ */
+struct nova_inode_update {
+ u64 head;
+ u64 tail;
+ u64 curr_entry;
+ struct nova_dentry *create_dentry;
+ struct nova_dentry *delete_dentry;
+};
+
+
+/*
+ * Transient DRAM structure to parameterize the creation of a log entry.
+ */
+struct nova_log_entry_info {
+ enum nova_entry_type type;
+ struct iattr *attr;
+ struct nova_inode_update *update;
+ void *data; /* struct dentry */
+ u64 epoch_id;
+ u64 trans_id;
+ u64 curr_p; /* output */
+ u64 file_size; /* de_len for dentry */
+ u64 ino;
+ u32 time;
+ int link_change;
+ int inplace; /* For file write entry */
+};
+
+
+
+static inline size_t nova_get_log_entry_size(struct super_block *sb,
+ enum nova_entry_type type)
+{
+ size_t size = 0;
+
+ switch (type) {
+ case FILE_WRITE:
+ size = sizeof(struct nova_file_write_entry);
+ break;
+ case DIR_LOG:
+ size = NOVA_DENTRY_HEADER_LEN;
+ break;
+ case SET_ATTR:
+ size = sizeof(struct nova_setattr_logentry);
+ break;
+ case LINK_CHANGE:
+ size = sizeof(struct nova_link_change_entry);
+ break;
+ default:
+ break;
+ }
+
+ return size;
+}
+
+static inline void nova_persist_entry(void *entry)
+{
+ size_t entry_len = CACHELINE_SIZE;
+
+ nova_flush_buffer(entry, entry_len, 0);
+}
+
static inline u64 next_log_page(struct super_block *sb, u64 curr)
{
struct nova_inode_log_page *curr_page;
@@ -183,6 +352,17 @@ static inline bool goto_next_page(struct super_block *sb, u64 curr_p)
return false;
}
+static inline int is_dir_init_entry(struct super_block *sb,
+ struct nova_dentry *entry)
+{
+ if (entry->name_len == 1 && strncmp(entry->name, ".", 1) == 0)
+ return 1;
+ if (entry->name_len == 2 && strncmp(entry->name, "..", 2) == 0)
+ return 1;
+
+ return 0;
+}
+
int nova_allocate_inode_log_pages(struct super_block *sb,
struct nova_inode_info_header *sih, unsigned long num_pages,