summaryrefslogtreecommitdiff
path: root/fs/nilfs2/the_nilfs.c
diff options
context:
space:
mode:
authorRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2010-08-14 07:59:15 +0400
committerRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2010-10-23 04:24:34 +0400
commitba65ae4729bf81c58d9fc847f67d57eec525b042 (patch)
tree6b2a4499a1e67bf858ce55cfe2e806b24c3697e7 /fs/nilfs2/the_nilfs.c
parent263d90cefc7d82a01c296c59532ff59d67c63509 (diff)
downloadlinux-ba65ae4729bf81c58d9fc847f67d57eec525b042.tar.xz
nilfs2: add checkpoint tree to nilfs object
To hold multiple versions of a filesystem in one sb instance, a new on-memory structure is necessary to handle one or more checkpoints. This adds a red-black tree of checkpoints to nilfs object, and adds lookup and create functions for them. Each checkpoint is represented by "nilfs_root" structure, and this structure has rb_node to configure the rb-tree. The nilfs_root object is identified with a checkpoint number. For each snapshot, a nilfs_root object is allocated and the checkpoint number of snapshot is assigned to it. For a regular mount (i.e. current mode mount), NILFS_CPTREE_CURRENT_CNO constant is assigned to the corresponding nilfs_root object. Each nilfs_root object has an ifile inode and some counters. These items will displace those of nilfs_sb_info structure in successive patches. Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Diffstat (limited to 'fs/nilfs2/the_nilfs.c')
-rw-r--r--fs/nilfs2/the_nilfs.c92
1 files changed, 92 insertions, 0 deletions
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c
index 6a012b9e1b31..f1d599273d9e 100644
--- a/fs/nilfs2/the_nilfs.c
+++ b/fs/nilfs2/the_nilfs.c
@@ -89,6 +89,8 @@ static struct the_nilfs *alloc_nilfs(struct block_device *bdev)
INIT_LIST_HEAD(&nilfs->ns_supers);
INIT_LIST_HEAD(&nilfs->ns_gc_inodes);
spin_lock_init(&nilfs->ns_last_segment_lock);
+ nilfs->ns_cptree = RB_ROOT;
+ spin_lock_init(&nilfs->ns_cptree_lock);
init_rwsem(&nilfs->ns_segctor_sem);
return nilfs;
@@ -809,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