@@ -29,6 +29,61 @@
unsigned int blk_type_to_shift[NOVA_BLOCK_TYPE_MAX] = {12, 21, 30};
uint32_t blk_type_to_size[NOVA_BLOCK_TYPE_MAX] = {0x1000, 0x200000, 0x40000000};
+static int nova_alloc_inode_table(struct super_block *sb,
+ struct nova_inode_info_header *sih)
+{
+ struct nova_sb_info *sbi = NOVA_SB(sb);
+ struct inode_table *inode_table;
+ unsigned long blocknr;
+ u64 block;
+ int allocated;
+ int i;
+
+ for (i = 0; i < sbi->cpus; i++) {
+ inode_table = nova_get_inode_table(sb, i);
+ if (!inode_table)
+ return -EINVAL;
+
+ allocated = nova_new_log_blocks(sb, sih, &blocknr, 1,
+ ALLOC_INIT_ZERO, i, ALLOC_FROM_HEAD);
+
+ nova_dbgv("%s: allocate log @ 0x%lx\n", __func__,
+ blocknr);
+ if (allocated != 1 || blocknr == 0)
+ return -ENOSPC;
+
+ block = nova_get_block_off(sb, blocknr, NOVA_BLOCK_TYPE_2M);
+ inode_table->log_head = block;
+ nova_flush_buffer(inode_table, CACHELINE_SIZE, 0);
+ }
+
+ return 0;
+}
+
+int nova_init_inode_table(struct super_block *sb)
+{
+ struct nova_inode *pi = nova_get_inode_by_ino(sb, NOVA_INODETABLE_INO);
+ struct nova_inode_info_header sih;
+ int ret = 0;
+
+ pi->i_mode = 0;
+ pi->i_uid = 0;
+ pi->i_gid = 0;
+ pi->i_links_count = cpu_to_le16(1);
+ pi->i_flags = 0;
+ pi->nova_ino = NOVA_INODETABLE_INO;
+
+ pi->i_blk_type = NOVA_BLOCK_TYPE_2M;
+
+ sih.ino = NOVA_INODETABLE_INO;
+ sih.i_blk_type = NOVA_BLOCK_TYPE_2M;
+
+ ret = nova_alloc_inode_table(sb, &sih);
+
+ PERSISTENT_BARRIER();
+ return ret;
+}
+
void nova_set_inode_flags(struct inode *inode, struct nova_inode *pi,
unsigned int flags)
{
@@ -60,6 +60,13 @@ struct nova_inode {
} __attribute((__packed__));
/*
+ * Inode table. It's a linked list of pages.
+ */
+struct inode_table {
+ __le64 log_head;
+};
+
+/*
* NOVA-specific inode state kept in DRAM
*/
struct nova_inode_info_header {
@@ -136,6 +143,22 @@ static inline void nova_update_tail(struct nova_inode *pi, u64 new_tail)
NOVA_END_TIMING(update_tail_t, update_time);
}
+static inline
+struct inode_table *nova_get_inode_table(struct super_block *sb, int cpu)
+{
+ struct nova_sb_info *sbi = NOVA_SB(sb);
+ int table_start;
+
+ if (cpu >= sbi->cpus)
+ return NULL;
+
+ table_start = INODE_TABLE_START;
+
+ return (struct inode_table *)((char *)nova_get_block(sb,
+ NOVA_DEF_BLOCK_SIZE_4K * table_start) +
+ cpu * CACHELINE_SIZE);
+}
+
static inline unsigned int
nova_inode_blk_shift(struct nova_inode_info_header *sih)
{
@@ -197,7 +220,10 @@ static inline int nova_persist_inode(struct nova_inode *pi)
return 0;
}
+
+int nova_init_inode_table(struct super_block *sb);
int nova_get_inode_address(struct super_block *sb, u64 ino,
u64 *pi_addr, int extendable);
struct inode *nova_iget(struct super_block *sb, unsigned long ino);
+
#endif
@@ -378,6 +378,9 @@ static struct nova_inode *nova_init(struct super_block *sb,
nova_init_blockmap(sb, 0);
+ if (nova_init_inode_table(sb) < 0)
+ return ERR_PTR(-EINVAL);
+
sbi->nova_sb->s_size = cpu_to_le64(size);
sbi->nova_sb->s_blocksize = cpu_to_le32(blocksize);
sbi->nova_sb->s_magic = cpu_to_le32(NOVA_SUPER_MAGIC);