diff options
author | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2010-08-13 23:59:15 -0400 |
---|---|---|
committer | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2010-10-22 20:24:34 -0400 |
commit | ba65ae4729bf81c58d9fc847f67d57eec525b042 (patch) | |
tree | 6b2a4499a1e67bf858ce55cfe2e806b24c3697e7 /fs | |
parent | 263d90cefc7d82a01c296c59532ff59d67c63509 (diff) |
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')
-rw-r--r-- | fs/nilfs2/the_nilfs.c | 92 | ||||
-rw-r--r-- | fs/nilfs2/the_nilfs.h | 42 |
2 files changed, 134 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) | |||
89 | INIT_LIST_HEAD(&nilfs->ns_supers); | 89 | INIT_LIST_HEAD(&nilfs->ns_supers); |
90 | INIT_LIST_HEAD(&nilfs->ns_gc_inodes); | 90 | INIT_LIST_HEAD(&nilfs->ns_gc_inodes); |
91 | spin_lock_init(&nilfs->ns_last_segment_lock); | 91 | spin_lock_init(&nilfs->ns_last_segment_lock); |
92 | nilfs->ns_cptree = RB_ROOT; | ||
93 | spin_lock_init(&nilfs->ns_cptree_lock); | ||
92 | init_rwsem(&nilfs->ns_segctor_sem); | 94 | init_rwsem(&nilfs->ns_segctor_sem); |
93 | 95 | ||
94 | return nilfs; | 96 | return nilfs; |
@@ -809,6 +811,96 @@ int nilfs_near_disk_full(struct the_nilfs *nilfs) | |||
809 | return ncleansegs <= nilfs->ns_nrsvsegs + nincsegs; | 811 | return ncleansegs <= nilfs->ns_nrsvsegs + nincsegs; |
810 | } | 812 | } |
811 | 813 | ||
814 | struct nilfs_root *nilfs_lookup_root(struct the_nilfs *nilfs, __u64 cno) | ||
815 | { | ||
816 | struct rb_node *n; | ||
817 | struct nilfs_root *root; | ||
818 | |||
819 | spin_lock(&nilfs->ns_cptree_lock); | ||
820 | n = nilfs->ns_cptree.rb_node; | ||
821 | while (n) { | ||
822 | root = rb_entry(n, struct nilfs_root, rb_node); | ||
823 | |||
824 | if (cno < root->cno) { | ||
825 | n = n->rb_left; | ||
826 | } else if (cno > root->cno) { | ||
827 | n = n->rb_right; | ||
828 | } else { | ||
829 | atomic_inc(&root->count); | ||
830 | spin_unlock(&nilfs->ns_cptree_lock); | ||
831 | return root; | ||
832 | } | ||
833 | } | ||
834 | spin_unlock(&nilfs->ns_cptree_lock); | ||
835 | |||
836 | return NULL; | ||
837 | } | ||
838 | |||
839 | struct nilfs_root * | ||
840 | nilfs_find_or_create_root(struct the_nilfs *nilfs, __u64 cno) | ||
841 | { | ||
842 | struct rb_node **p, *parent; | ||
843 | struct nilfs_root *root, *new; | ||
844 | |||
845 | root = nilfs_lookup_root(nilfs, cno); | ||
846 | if (root) | ||
847 | return root; | ||
848 | |||
849 | new = kmalloc(sizeof(*root), GFP_KERNEL); | ||
850 | if (!new) | ||
851 | return NULL; | ||
852 | |||
853 | spin_lock(&nilfs->ns_cptree_lock); | ||
854 | |||
855 | p = &nilfs->ns_cptree.rb_node; | ||
856 | parent = NULL; | ||
857 | |||
858 | while (*p) { | ||
859 | parent = *p; | ||
860 | root = rb_entry(parent, struct nilfs_root, rb_node); | ||
861 | |||
862 | if (cno < root->cno) { | ||
863 | p = &(*p)->rb_left; | ||
864 | } else if (cno > root->cno) { | ||
865 | p = &(*p)->rb_right; | ||
866 | } else { | ||
867 | atomic_inc(&root->count); | ||
868 | spin_unlock(&nilfs->ns_cptree_lock); | ||
869 | kfree(new); | ||
870 | return root; | ||
871 | } | ||
872 | } | ||
873 | |||
874 | new->cno = cno; | ||
875 | new->ifile = NULL; | ||
876 | new->nilfs = nilfs; | ||
877 | atomic_set(&new->count, 1); | ||
878 | atomic_set(&new->inodes_count, 0); | ||
879 | atomic_set(&new->blocks_count, 0); | ||
880 | |||
881 | rb_link_node(&new->rb_node, parent, p); | ||
882 | rb_insert_color(&new->rb_node, &nilfs->ns_cptree); | ||
883 | |||
884 | spin_unlock(&nilfs->ns_cptree_lock); | ||
885 | |||
886 | return new; | ||
887 | } | ||
888 | |||
889 | void nilfs_put_root(struct nilfs_root *root) | ||
890 | { | ||
891 | if (atomic_dec_and_test(&root->count)) { | ||
892 | struct the_nilfs *nilfs = root->nilfs; | ||
893 | |||
894 | spin_lock(&nilfs->ns_cptree_lock); | ||
895 | rb_erase(&root->rb_node, &nilfs->ns_cptree); | ||
896 | spin_unlock(&nilfs->ns_cptree_lock); | ||
897 | if (root->ifile) | ||
898 | nilfs_mdt_destroy(root->ifile); | ||
899 | |||
900 | kfree(root); | ||
901 | } | ||
902 | } | ||
903 | |||
812 | /** | 904 | /** |
813 | * nilfs_find_sbinfo - find existing nilfs_sb_info structure | 905 | * nilfs_find_sbinfo - find existing nilfs_sb_info structure |
814 | * @nilfs: nilfs object | 906 | * @nilfs: nilfs object |
diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h index c7ecd0c623a3..0afede68a9e1 100644 --- a/fs/nilfs2/the_nilfs.h +++ b/fs/nilfs2/the_nilfs.h | |||
@@ -26,6 +26,7 @@ | |||
26 | 26 | ||
27 | #include <linux/types.h> | 27 | #include <linux/types.h> |
28 | #include <linux/buffer_head.h> | 28 | #include <linux/buffer_head.h> |
29 | #include <linux/rbtree.h> | ||
29 | #include <linux/fs.h> | 30 | #include <linux/fs.h> |
30 | #include <linux/blkdev.h> | 31 | #include <linux/blkdev.h> |
31 | #include <linux/backing-dev.h> | 32 | #include <linux/backing-dev.h> |
@@ -80,6 +81,8 @@ enum { | |||
80 | * @ns_cpfile: checkpoint file inode | 81 | * @ns_cpfile: checkpoint file inode |
81 | * @ns_sufile: segusage file inode | 82 | * @ns_sufile: segusage file inode |
82 | * @ns_gc_dat: shadow inode of the DAT file inode for GC | 83 | * @ns_gc_dat: shadow inode of the DAT file inode for GC |
84 | * @ns_cptree: rb-tree of all mounted checkpoints (nilfs_root) | ||
85 | * @ns_cptree_lock: lock protecting @ns_cptree | ||
83 | * @ns_gc_inodes: dummy inodes to keep live blocks | 86 | * @ns_gc_inodes: dummy inodes to keep live blocks |
84 | * @ns_blocksize_bits: bit length of block size | 87 | * @ns_blocksize_bits: bit length of block size |
85 | * @ns_blocksize: block size | 88 | * @ns_blocksize: block size |
@@ -164,6 +167,10 @@ struct the_nilfs { | |||
164 | struct inode *ns_sufile; | 167 | struct inode *ns_sufile; |
165 | struct inode *ns_gc_dat; | 168 | struct inode *ns_gc_dat; |
166 | 169 | ||
170 | /* Checkpoint tree */ | ||
171 | struct rb_root ns_cptree; | ||
172 | spinlock_t ns_cptree_lock; | ||
173 | |||
167 | /* GC inode list */ | 174 | /* GC inode list */ |
168 | struct list_head ns_gc_inodes; | 175 | struct list_head ns_gc_inodes; |
169 | 176 | ||
@@ -200,6 +207,32 @@ THE_NILFS_FNS(DISCONTINUED, discontinued) | |||
200 | THE_NILFS_FNS(GC_RUNNING, gc_running) | 207 | THE_NILFS_FNS(GC_RUNNING, gc_running) |
201 | THE_NILFS_FNS(SB_DIRTY, sb_dirty) | 208 | THE_NILFS_FNS(SB_DIRTY, sb_dirty) |
202 | 209 | ||
210 | /** | ||
211 | * struct nilfs_root - nilfs root object | ||
212 | * @cno: checkpoint number | ||
213 | * @rb_node: red-black tree node | ||
214 | * @count: refcount of this structure | ||
215 | * @nilfs: nilfs object | ||
216 | * @ifile: inode file | ||
217 | * @root: root inode | ||
218 | * @inodes_count: number of inodes | ||
219 | * @blocks_count: number of blocks (Reserved) | ||
220 | */ | ||
221 | struct nilfs_root { | ||
222 | __u64 cno; | ||
223 | struct rb_node rb_node; | ||
224 | |||
225 | atomic_t count; | ||
226 | struct the_nilfs *nilfs; | ||
227 | struct inode *ifile; | ||
228 | |||
229 | atomic_t inodes_count; | ||
230 | atomic_t blocks_count; | ||
231 | }; | ||
232 | |||
233 | /* Special checkpoint number */ | ||
234 | #define NILFS_CPTREE_CURRENT_CNO 0 | ||
235 | |||
203 | /* Minimum interval of periodical update of superblocks (in seconds) */ | 236 | /* Minimum interval of periodical update of superblocks (in seconds) */ |
204 | #define NILFS_SB_FREQ 10 | 237 | #define NILFS_SB_FREQ 10 |
205 | 238 | ||
@@ -222,6 +255,10 @@ int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *); | |||
222 | int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *); | 255 | int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *); |
223 | int nilfs_discard_segments(struct the_nilfs *, __u64 *, size_t); | 256 | int nilfs_discard_segments(struct the_nilfs *, __u64 *, size_t); |
224 | int nilfs_count_free_blocks(struct the_nilfs *, sector_t *); | 257 | int nilfs_count_free_blocks(struct the_nilfs *, sector_t *); |
258 | struct nilfs_root *nilfs_lookup_root(struct the_nilfs *nilfs, __u64 cno); | ||
259 | struct nilfs_root *nilfs_find_or_create_root(struct the_nilfs *nilfs, | ||
260 | __u64 cno); | ||
261 | void nilfs_put_root(struct nilfs_root *root); | ||
225 | struct nilfs_sb_info *nilfs_find_sbinfo(struct the_nilfs *, int, __u64); | 262 | struct nilfs_sb_info *nilfs_find_sbinfo(struct the_nilfs *, int, __u64); |
226 | int nilfs_checkpoint_is_mounted(struct the_nilfs *, __u64, int); | 263 | int nilfs_checkpoint_is_mounted(struct the_nilfs *, __u64, int); |
227 | int nilfs_near_disk_full(struct the_nilfs *); | 264 | int nilfs_near_disk_full(struct the_nilfs *); |
@@ -235,6 +272,11 @@ static inline void get_nilfs(struct the_nilfs *nilfs) | |||
235 | atomic_inc(&nilfs->ns_count); | 272 | atomic_inc(&nilfs->ns_count); |
236 | } | 273 | } |
237 | 274 | ||
275 | static inline void nilfs_get_root(struct nilfs_root *root) | ||
276 | { | ||
277 | atomic_inc(&root->count); | ||
278 | } | ||
279 | |||
238 | static inline void | 280 | static inline void |
239 | nilfs_attach_writer(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) | 281 | nilfs_attach_writer(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) |
240 | { | 282 | { |