nilfs2: add checkpoint tree to nilfs object
[firefly-linux-kernel-4.4.55.git] / fs / nilfs2 / the_nilfs.c
index ba7c10c917fcd1545a668c53f6abb2819b04f3bc..f1d599273d9e310874c0c75920a925a90c44d560 100644 (file)
@@ -87,8 +87,10 @@ static struct the_nilfs *alloc_nilfs(struct block_device *bdev)
        init_rwsem(&nilfs->ns_writer_sem);
        INIT_LIST_HEAD(&nilfs->ns_list);
        INIT_LIST_HEAD(&nilfs->ns_supers);
+       INIT_LIST_HEAD(&nilfs->ns_gc_inodes);
        spin_lock_init(&nilfs->ns_last_segment_lock);
-       nilfs->ns_gc_inodes_h = NULL;
+       nilfs->ns_cptree = RB_ROOT;
+       spin_lock_init(&nilfs->ns_cptree_lock);
        init_rwsem(&nilfs->ns_segctor_sem);
 
        return nilfs;
@@ -164,7 +166,6 @@ void put_nilfs(struct the_nilfs *nilfs)
                nilfs_mdt_destroy(nilfs->ns_gc_dat);
        }
        if (nilfs_init(nilfs)) {
-               nilfs_destroy_gccache(nilfs);
                brelse(nilfs->ns_sbh[0]);
                brelse(nilfs->ns_sbh[1]);
        }
@@ -468,8 +469,8 @@ static unsigned long long nilfs_max_size(unsigned int blkbits)
 static int nilfs_store_disk_layout(struct the_nilfs *nilfs,
                                   struct nilfs_super_block *sbp)
 {
-       if (le32_to_cpu(sbp->s_rev_level) != NILFS_CURRENT_REV) {
-               printk(KERN_ERR "NILFS: revision mismatch "
+       if (le32_to_cpu(sbp->s_rev_level) < NILFS_MIN_SUPP_REV) {
+               printk(KERN_ERR "NILFS: unsupported revision "
                       "(superblock rev.=%d.%d, current rev.=%d.%d). "
                       "Please check the version of mkfs.nilfs.\n",
                       le32_to_cpu(sbp->s_rev_level),
@@ -736,11 +737,6 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data)
        if (err)
                goto failed_sbh;
 
-       /* Initialize gcinode cache */
-       err = nilfs_init_gccache(nilfs);
-       if (err)
-               goto failed_sbh;
-
        set_nilfs_init(nilfs);
        err = 0;
  out:
@@ -815,6 +811,96 @@ int nilfs_near_disk_full(struct the_nilfs *nilfs)
        return ncleansegs <= nilfs->ns_nrsvsegs + nincsegs;
 }
 
+struct nilfs_root *nilfs_lookup_root(struct the_nilfs *nilfs, __u64 cno)
+{
+       struct rb_node *n;
+       struct nilfs_root *root;
+
+       spin_lock(&nilfs->ns_cptree_lock);
+       n = nilfs->ns_cptree.rb_node;
+       while (n) {
+               root = rb_entry(n, struct nilfs_root, rb_node);
+
+               if (cno < root->cno) {
+                       n = n->rb_left;
+               } else if (cno > root->cno) {
+                       n = n->rb_right;
+               } else {
+                       atomic_inc(&root->count);
+                       spin_unlock(&nilfs->ns_cptree_lock);
+                       return root;
+               }
+       }
+       spin_unlock(&nilfs->ns_cptree_lock);
+
+       return NULL;
+}
+
+struct nilfs_root *
+nilfs_find_or_create_root(struct the_nilfs *nilfs, __u64 cno)
+{
+       struct rb_node **p, *parent;
+       struct nilfs_root *root, *new;
+
+       root = nilfs_lookup_root(nilfs, cno);
+       if (root)
+               return root;
+
+       new = kmalloc(sizeof(*root), GFP_KERNEL);
+       if (!new)
+               return NULL;
+
+       spin_lock(&nilfs->ns_cptree_lock);
+
+       p = &nilfs->ns_cptree.rb_node;
+       parent = NULL;
+
+       while (*p) {
+               parent = *p;
+               root = rb_entry(parent, struct nilfs_root, rb_node);
+
+               if (cno < root->cno) {
+                       p = &(*p)->rb_left;
+               } else if (cno > root->cno) {
+                       p = &(*p)->rb_right;
+               } else {
+                       atomic_inc(&root->count);
+                       spin_unlock(&nilfs->ns_cptree_lock);
+                       kfree(new);
+                       return root;
+               }
+       }
+
+       new->cno = cno;
+       new->ifile = NULL;
+       new->nilfs = nilfs;
+       atomic_set(&new->count, 1);
+       atomic_set(&new->inodes_count, 0);
+       atomic_set(&new->blocks_count, 0);
+
+       rb_link_node(&new->rb_node, parent, p);
+       rb_insert_color(&new->rb_node, &nilfs->ns_cptree);
+
+       spin_unlock(&nilfs->ns_cptree_lock);
+
+       return new;
+}
+
+void nilfs_put_root(struct nilfs_root *root)
+{
+       if (atomic_dec_and_test(&root->count)) {
+               struct the_nilfs *nilfs = root->nilfs;
+
+               spin_lock(&nilfs->ns_cptree_lock);
+               rb_erase(&root->rb_node, &nilfs->ns_cptree);
+               spin_unlock(&nilfs->ns_cptree_lock);
+               if (root->ifile)
+                       nilfs_mdt_destroy(root->ifile);
+
+               kfree(root);
+       }
+}
+
 /**
  * nilfs_find_sbinfo - find existing nilfs_sb_info structure
  * @nilfs: nilfs object