diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-23 04:26:47 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-23 04:26:47 -0400 |
commit | ab34c02afeafd047a831e6fe2a4dd875ce86bee0 (patch) | |
tree | 833e385e8387e3d4d4531ade23c1d92fba8ed075 /fs/nilfs2/the_nilfs.c | |
parent | 7f3883962870dd28b5f2322ac44a9d03640ef448 (diff) | |
parent | 6b81e14e645016597c81e71cd27ee5c57c3a3c36 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ryusuke/nilfs2
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ryusuke/nilfs2: (36 commits)
nilfs2: eliminate sparse warning - "context imbalance"
nilfs2: eliminate sparse warnings - "symbol not declared"
nilfs2: get rid of bdi from nilfs object
nilfs2: change license of exported header file
nilfs2: add bdev freeze/thaw support
nilfs2: accept 64-bit checkpoint numbers in cp mount option
nilfs2: remove own inode allocator and destructor for metadata files
nilfs2: get rid of back pointer to writable sb instance
nilfs2: get rid of mi_nilfs back pointer to nilfs object
nilfs2: see state of root dentry for mount check of snapshots
nilfs2: use iget for all metadata files
nilfs2: get rid of GCDAT inode
nilfs2: add routines to redirect access to buffers of DAT file
nilfs2: add routines to roll back state of DAT file
nilfs2: add routines to save and restore bmap state
nilfs2: do not allocate nilfs_mdt_info structure to gc-inodes
nilfs2: allow nilfs_clear_inode to clear metadata file inodes
nilfs2: get rid of snapshot mount flag
nilfs2: simplify life cycle management of nilfs object
nilfs2: do not allocate multiple super block instances for a device
...
Diffstat (limited to 'fs/nilfs2/the_nilfs.c')
-rw-r--r-- | fs/nilfs2/the_nilfs.c | 339 |
1 files changed, 106 insertions, 233 deletions
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index d27715103376..0254be2d73c6 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c | |||
@@ -35,9 +35,6 @@ | |||
35 | #include "segbuf.h" | 35 | #include "segbuf.h" |
36 | 36 | ||
37 | 37 | ||
38 | static LIST_HEAD(nilfs_objects); | ||
39 | static DEFINE_SPINLOCK(nilfs_lock); | ||
40 | |||
41 | static int nilfs_valid_sb(struct nilfs_super_block *sbp); | 38 | static int nilfs_valid_sb(struct nilfs_super_block *sbp); |
42 | 39 | ||
43 | void nilfs_set_last_segment(struct the_nilfs *nilfs, | 40 | void nilfs_set_last_segment(struct the_nilfs *nilfs, |
@@ -61,16 +58,13 @@ void nilfs_set_last_segment(struct the_nilfs *nilfs, | |||
61 | } | 58 | } |
62 | 59 | ||
63 | /** | 60 | /** |
64 | * alloc_nilfs - allocate the_nilfs structure | 61 | * alloc_nilfs - allocate a nilfs object |
65 | * @bdev: block device to which the_nilfs is related | 62 | * @bdev: block device to which the_nilfs is related |
66 | * | 63 | * |
67 | * alloc_nilfs() allocates memory for the_nilfs and | ||
68 | * initializes its reference count and locks. | ||
69 | * | ||
70 | * Return Value: On success, pointer to the_nilfs is returned. | 64 | * Return Value: On success, pointer to the_nilfs is returned. |
71 | * On error, NULL is returned. | 65 | * On error, NULL is returned. |
72 | */ | 66 | */ |
73 | static struct the_nilfs *alloc_nilfs(struct block_device *bdev) | 67 | struct the_nilfs *alloc_nilfs(struct block_device *bdev) |
74 | { | 68 | { |
75 | struct the_nilfs *nilfs; | 69 | struct the_nilfs *nilfs; |
76 | 70 | ||
@@ -79,103 +73,38 @@ static struct the_nilfs *alloc_nilfs(struct block_device *bdev) | |||
79 | return NULL; | 73 | return NULL; |
80 | 74 | ||
81 | nilfs->ns_bdev = bdev; | 75 | nilfs->ns_bdev = bdev; |
82 | atomic_set(&nilfs->ns_count, 1); | ||
83 | atomic_set(&nilfs->ns_ndirtyblks, 0); | 76 | atomic_set(&nilfs->ns_ndirtyblks, 0); |
84 | init_rwsem(&nilfs->ns_sem); | 77 | init_rwsem(&nilfs->ns_sem); |
85 | init_rwsem(&nilfs->ns_super_sem); | 78 | INIT_LIST_HEAD(&nilfs->ns_gc_inodes); |
86 | mutex_init(&nilfs->ns_mount_mutex); | ||
87 | init_rwsem(&nilfs->ns_writer_sem); | ||
88 | INIT_LIST_HEAD(&nilfs->ns_list); | ||
89 | INIT_LIST_HEAD(&nilfs->ns_supers); | ||
90 | spin_lock_init(&nilfs->ns_last_segment_lock); | 79 | spin_lock_init(&nilfs->ns_last_segment_lock); |
91 | nilfs->ns_gc_inodes_h = NULL; | 80 | nilfs->ns_cptree = RB_ROOT; |
81 | spin_lock_init(&nilfs->ns_cptree_lock); | ||
92 | init_rwsem(&nilfs->ns_segctor_sem); | 82 | init_rwsem(&nilfs->ns_segctor_sem); |
93 | 83 | ||
94 | return nilfs; | 84 | return nilfs; |
95 | } | 85 | } |
96 | 86 | ||
97 | /** | 87 | /** |
98 | * find_or_create_nilfs - find or create nilfs object | 88 | * destroy_nilfs - destroy nilfs object |
99 | * @bdev: block device to which the_nilfs is related | 89 | * @nilfs: nilfs object to be released |
100 | * | ||
101 | * find_nilfs() looks up an existent nilfs object created on the | ||
102 | * device and gets the reference count of the object. If no nilfs object | ||
103 | * is found on the device, a new nilfs object is allocated. | ||
104 | * | ||
105 | * Return Value: On success, pointer to the nilfs object is returned. | ||
106 | * On error, NULL is returned. | ||
107 | */ | ||
108 | struct the_nilfs *find_or_create_nilfs(struct block_device *bdev) | ||
109 | { | ||
110 | struct the_nilfs *nilfs, *new = NULL; | ||
111 | |||
112 | retry: | ||
113 | spin_lock(&nilfs_lock); | ||
114 | list_for_each_entry(nilfs, &nilfs_objects, ns_list) { | ||
115 | if (nilfs->ns_bdev == bdev) { | ||
116 | get_nilfs(nilfs); | ||
117 | spin_unlock(&nilfs_lock); | ||
118 | if (new) | ||
119 | put_nilfs(new); | ||
120 | return nilfs; /* existing object */ | ||
121 | } | ||
122 | } | ||
123 | if (new) { | ||
124 | list_add_tail(&new->ns_list, &nilfs_objects); | ||
125 | spin_unlock(&nilfs_lock); | ||
126 | return new; /* new object */ | ||
127 | } | ||
128 | spin_unlock(&nilfs_lock); | ||
129 | |||
130 | new = alloc_nilfs(bdev); | ||
131 | if (new) | ||
132 | goto retry; | ||
133 | return NULL; /* insufficient memory */ | ||
134 | } | ||
135 | |||
136 | /** | ||
137 | * put_nilfs - release a reference to the_nilfs | ||
138 | * @nilfs: the_nilfs structure to be released | ||
139 | * | ||
140 | * put_nilfs() decrements a reference counter of the_nilfs. | ||
141 | * If the reference count reaches zero, the_nilfs is freed. | ||
142 | */ | 90 | */ |
143 | void put_nilfs(struct the_nilfs *nilfs) | 91 | void destroy_nilfs(struct the_nilfs *nilfs) |
144 | { | 92 | { |
145 | spin_lock(&nilfs_lock); | ||
146 | if (!atomic_dec_and_test(&nilfs->ns_count)) { | ||
147 | spin_unlock(&nilfs_lock); | ||
148 | return; | ||
149 | } | ||
150 | list_del_init(&nilfs->ns_list); | ||
151 | spin_unlock(&nilfs_lock); | ||
152 | |||
153 | /* | ||
154 | * Increment of ns_count never occurs below because the caller | ||
155 | * of get_nilfs() holds at least one reference to the_nilfs. | ||
156 | * Thus its exclusion control is not required here. | ||
157 | */ | ||
158 | |||
159 | might_sleep(); | 93 | might_sleep(); |
160 | if (nilfs_loaded(nilfs)) { | ||
161 | nilfs_mdt_destroy(nilfs->ns_sufile); | ||
162 | nilfs_mdt_destroy(nilfs->ns_cpfile); | ||
163 | nilfs_mdt_destroy(nilfs->ns_dat); | ||
164 | nilfs_mdt_destroy(nilfs->ns_gc_dat); | ||
165 | } | ||
166 | if (nilfs_init(nilfs)) { | 94 | if (nilfs_init(nilfs)) { |
167 | nilfs_destroy_gccache(nilfs); | ||
168 | brelse(nilfs->ns_sbh[0]); | 95 | brelse(nilfs->ns_sbh[0]); |
169 | brelse(nilfs->ns_sbh[1]); | 96 | brelse(nilfs->ns_sbh[1]); |
170 | } | 97 | } |
171 | kfree(nilfs); | 98 | kfree(nilfs); |
172 | } | 99 | } |
173 | 100 | ||
174 | static int nilfs_load_super_root(struct the_nilfs *nilfs, sector_t sr_block) | 101 | static int nilfs_load_super_root(struct the_nilfs *nilfs, |
102 | struct super_block *sb, sector_t sr_block) | ||
175 | { | 103 | { |
176 | struct buffer_head *bh_sr; | 104 | struct buffer_head *bh_sr; |
177 | struct nilfs_super_root *raw_sr; | 105 | struct nilfs_super_root *raw_sr; |
178 | struct nilfs_super_block **sbp = nilfs->ns_sbp; | 106 | struct nilfs_super_block **sbp = nilfs->ns_sbp; |
107 | struct nilfs_inode *rawi; | ||
179 | unsigned dat_entry_size, segment_usage_size, checkpoint_size; | 108 | unsigned dat_entry_size, segment_usage_size, checkpoint_size; |
180 | unsigned inode_size; | 109 | unsigned inode_size; |
181 | int err; | 110 | int err; |
@@ -192,40 +121,22 @@ static int nilfs_load_super_root(struct the_nilfs *nilfs, sector_t sr_block) | |||
192 | 121 | ||
193 | inode_size = nilfs->ns_inode_size; | 122 | inode_size = nilfs->ns_inode_size; |
194 | 123 | ||
195 | err = -ENOMEM; | 124 | rawi = (void *)bh_sr->b_data + NILFS_SR_DAT_OFFSET(inode_size); |
196 | nilfs->ns_dat = nilfs_dat_new(nilfs, dat_entry_size); | 125 | err = nilfs_dat_read(sb, dat_entry_size, rawi, &nilfs->ns_dat); |
197 | if (unlikely(!nilfs->ns_dat)) | 126 | if (err) |
198 | goto failed; | 127 | goto failed; |
199 | 128 | ||
200 | nilfs->ns_gc_dat = nilfs_dat_new(nilfs, dat_entry_size); | 129 | rawi = (void *)bh_sr->b_data + NILFS_SR_CPFILE_OFFSET(inode_size); |
201 | if (unlikely(!nilfs->ns_gc_dat)) | 130 | err = nilfs_cpfile_read(sb, checkpoint_size, rawi, &nilfs->ns_cpfile); |
131 | if (err) | ||
202 | goto failed_dat; | 132 | goto failed_dat; |
203 | 133 | ||
204 | nilfs->ns_cpfile = nilfs_cpfile_new(nilfs, checkpoint_size); | 134 | rawi = (void *)bh_sr->b_data + NILFS_SR_SUFILE_OFFSET(inode_size); |
205 | if (unlikely(!nilfs->ns_cpfile)) | 135 | err = nilfs_sufile_read(sb, segment_usage_size, rawi, |
206 | goto failed_gc_dat; | 136 | &nilfs->ns_sufile); |
207 | 137 | if (err) | |
208 | nilfs->ns_sufile = nilfs_sufile_new(nilfs, segment_usage_size); | ||
209 | if (unlikely(!nilfs->ns_sufile)) | ||
210 | goto failed_cpfile; | 138 | goto failed_cpfile; |
211 | 139 | ||
212 | nilfs_mdt_set_shadow(nilfs->ns_dat, nilfs->ns_gc_dat); | ||
213 | |||
214 | err = nilfs_dat_read(nilfs->ns_dat, (void *)bh_sr->b_data + | ||
215 | NILFS_SR_DAT_OFFSET(inode_size)); | ||
216 | if (unlikely(err)) | ||
217 | goto failed_sufile; | ||
218 | |||
219 | err = nilfs_cpfile_read(nilfs->ns_cpfile, (void *)bh_sr->b_data + | ||
220 | NILFS_SR_CPFILE_OFFSET(inode_size)); | ||
221 | if (unlikely(err)) | ||
222 | goto failed_sufile; | ||
223 | |||
224 | err = nilfs_sufile_read(nilfs->ns_sufile, (void *)bh_sr->b_data + | ||
225 | NILFS_SR_SUFILE_OFFSET(inode_size)); | ||
226 | if (unlikely(err)) | ||
227 | goto failed_sufile; | ||
228 | |||
229 | raw_sr = (struct nilfs_super_root *)bh_sr->b_data; | 140 | raw_sr = (struct nilfs_super_root *)bh_sr->b_data; |
230 | nilfs->ns_nongc_ctime = le64_to_cpu(raw_sr->sr_nongc_ctime); | 141 | nilfs->ns_nongc_ctime = le64_to_cpu(raw_sr->sr_nongc_ctime); |
231 | 142 | ||
@@ -233,17 +144,11 @@ static int nilfs_load_super_root(struct the_nilfs *nilfs, sector_t sr_block) | |||
233 | brelse(bh_sr); | 144 | brelse(bh_sr); |
234 | return err; | 145 | return err; |
235 | 146 | ||
236 | failed_sufile: | ||
237 | nilfs_mdt_destroy(nilfs->ns_sufile); | ||
238 | |||
239 | failed_cpfile: | 147 | failed_cpfile: |
240 | nilfs_mdt_destroy(nilfs->ns_cpfile); | 148 | iput(nilfs->ns_cpfile); |
241 | |||
242 | failed_gc_dat: | ||
243 | nilfs_mdt_destroy(nilfs->ns_gc_dat); | ||
244 | 149 | ||
245 | failed_dat: | 150 | failed_dat: |
246 | nilfs_mdt_destroy(nilfs->ns_dat); | 151 | iput(nilfs->ns_dat); |
247 | goto failed; | 152 | goto failed; |
248 | } | 153 | } |
249 | 154 | ||
@@ -306,15 +211,6 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) | |||
306 | int valid_fs = nilfs_valid_fs(nilfs); | 211 | int valid_fs = nilfs_valid_fs(nilfs); |
307 | int err; | 212 | int err; |
308 | 213 | ||
309 | if (nilfs_loaded(nilfs)) { | ||
310 | if (valid_fs || | ||
311 | ((s_flags & MS_RDONLY) && nilfs_test_opt(sbi, NORECOVERY))) | ||
312 | return 0; | ||
313 | printk(KERN_ERR "NILFS: the filesystem is in an incomplete " | ||
314 | "recovery state.\n"); | ||
315 | return -EINVAL; | ||
316 | } | ||
317 | |||
318 | if (!valid_fs) { | 214 | if (!valid_fs) { |
319 | printk(KERN_WARNING "NILFS warning: mounting unchecked fs\n"); | 215 | printk(KERN_WARNING "NILFS warning: mounting unchecked fs\n"); |
320 | if (s_flags & MS_RDONLY) { | 216 | if (s_flags & MS_RDONLY) { |
@@ -375,7 +271,7 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) | |||
375 | goto scan_error; | 271 | goto scan_error; |
376 | } | 272 | } |
377 | 273 | ||
378 | err = nilfs_load_super_root(nilfs, ri.ri_super_root); | 274 | err = nilfs_load_super_root(nilfs, sbi->s_super, ri.ri_super_root); |
379 | if (unlikely(err)) { | 275 | if (unlikely(err)) { |
380 | printk(KERN_ERR "NILFS: error loading super root.\n"); | 276 | printk(KERN_ERR "NILFS: error loading super root.\n"); |
381 | goto failed; | 277 | goto failed; |
@@ -443,10 +339,9 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) | |||
443 | goto failed; | 339 | goto failed; |
444 | 340 | ||
445 | failed_unload: | 341 | failed_unload: |
446 | nilfs_mdt_destroy(nilfs->ns_cpfile); | 342 | iput(nilfs->ns_cpfile); |
447 | nilfs_mdt_destroy(nilfs->ns_sufile); | 343 | iput(nilfs->ns_sufile); |
448 | nilfs_mdt_destroy(nilfs->ns_dat); | 344 | iput(nilfs->ns_dat); |
449 | nilfs_mdt_destroy(nilfs->ns_gc_dat); | ||
450 | 345 | ||
451 | failed: | 346 | failed: |
452 | nilfs_clear_recovery_info(&ri); | 347 | nilfs_clear_recovery_info(&ri); |
@@ -468,8 +363,8 @@ static unsigned long long nilfs_max_size(unsigned int blkbits) | |||
468 | static int nilfs_store_disk_layout(struct the_nilfs *nilfs, | 363 | static int nilfs_store_disk_layout(struct the_nilfs *nilfs, |
469 | struct nilfs_super_block *sbp) | 364 | struct nilfs_super_block *sbp) |
470 | { | 365 | { |
471 | if (le32_to_cpu(sbp->s_rev_level) != NILFS_CURRENT_REV) { | 366 | if (le32_to_cpu(sbp->s_rev_level) < NILFS_MIN_SUPP_REV) { |
472 | printk(KERN_ERR "NILFS: revision mismatch " | 367 | printk(KERN_ERR "NILFS: unsupported revision " |
473 | "(superblock rev.=%d.%d, current rev.=%d.%d). " | 368 | "(superblock rev.=%d.%d, current rev.=%d.%d). " |
474 | "Please check the version of mkfs.nilfs.\n", | 369 | "Please check the version of mkfs.nilfs.\n", |
475 | le32_to_cpu(sbp->s_rev_level), | 370 | le32_to_cpu(sbp->s_rev_level), |
@@ -631,12 +526,7 @@ static int nilfs_load_super_block(struct the_nilfs *nilfs, | |||
631 | * | 526 | * |
632 | * init_nilfs() performs common initialization per block device (e.g. | 527 | * init_nilfs() performs common initialization per block device (e.g. |
633 | * reading the super block, getting disk layout information, initializing | 528 | * reading the super block, getting disk layout information, initializing |
634 | * shared fields in the_nilfs). It takes on some portion of the jobs | 529 | * shared fields in the_nilfs). |
635 | * typically done by a fill_super() routine. This division arises from | ||
636 | * the nature that multiple NILFS instances may be simultaneously | ||
637 | * mounted on a device. | ||
638 | * For multiple mounts on the same device, only the first mount | ||
639 | * invokes these tasks. | ||
640 | * | 530 | * |
641 | * Return Value: On success, 0 is returned. On error, a negative error | 531 | * Return Value: On success, 0 is returned. On error, a negative error |
642 | * code is returned. | 532 | * code is returned. |
@@ -645,32 +535,10 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data) | |||
645 | { | 535 | { |
646 | struct super_block *sb = sbi->s_super; | 536 | struct super_block *sb = sbi->s_super; |
647 | struct nilfs_super_block *sbp; | 537 | struct nilfs_super_block *sbp; |
648 | struct backing_dev_info *bdi; | ||
649 | int blocksize; | 538 | int blocksize; |
650 | int err; | 539 | int err; |
651 | 540 | ||
652 | down_write(&nilfs->ns_sem); | 541 | down_write(&nilfs->ns_sem); |
653 | if (nilfs_init(nilfs)) { | ||
654 | /* Load values from existing the_nilfs */ | ||
655 | sbp = nilfs->ns_sbp[0]; | ||
656 | err = nilfs_store_magic_and_option(sb, sbp, data); | ||
657 | if (err) | ||
658 | goto out; | ||
659 | |||
660 | err = nilfs_check_feature_compatibility(sb, sbp); | ||
661 | if (err) | ||
662 | goto out; | ||
663 | |||
664 | blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size); | ||
665 | if (sb->s_blocksize != blocksize && | ||
666 | !sb_set_blocksize(sb, blocksize)) { | ||
667 | printk(KERN_ERR "NILFS: blocksize %d unfit to device\n", | ||
668 | blocksize); | ||
669 | err = -EINVAL; | ||
670 | } | ||
671 | sb->s_maxbytes = nilfs_max_size(sb->s_blocksize_bits); | ||
672 | goto out; | ||
673 | } | ||
674 | 542 | ||
675 | blocksize = sb_min_blocksize(sb, NILFS_MIN_BLOCK_SIZE); | 543 | blocksize = sb_min_blocksize(sb, NILFS_MIN_BLOCK_SIZE); |
676 | if (!blocksize) { | 544 | if (!blocksize) { |
@@ -729,18 +597,10 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data) | |||
729 | 597 | ||
730 | nilfs->ns_mount_state = le16_to_cpu(sbp->s_state); | 598 | nilfs->ns_mount_state = le16_to_cpu(sbp->s_state); |
731 | 599 | ||
732 | bdi = nilfs->ns_bdev->bd_inode->i_mapping->backing_dev_info; | ||
733 | nilfs->ns_bdi = bdi ? : &default_backing_dev_info; | ||
734 | |||
735 | err = nilfs_store_log_cursor(nilfs, sbp); | 600 | err = nilfs_store_log_cursor(nilfs, sbp); |
736 | if (err) | 601 | if (err) |
737 | goto failed_sbh; | 602 | goto failed_sbh; |
738 | 603 | ||
739 | /* Initialize gcinode cache */ | ||
740 | err = nilfs_init_gccache(nilfs); | ||
741 | if (err) | ||
742 | goto failed_sbh; | ||
743 | |||
744 | set_nilfs_init(nilfs); | 604 | set_nilfs_init(nilfs); |
745 | err = 0; | 605 | err = 0; |
746 | out: | 606 | out: |
@@ -812,79 +672,92 @@ int nilfs_near_disk_full(struct the_nilfs *nilfs) | |||
812 | return ncleansegs <= nilfs->ns_nrsvsegs + nincsegs; | 672 | return ncleansegs <= nilfs->ns_nrsvsegs + nincsegs; |
813 | } | 673 | } |
814 | 674 | ||
815 | /** | 675 | struct nilfs_root *nilfs_lookup_root(struct the_nilfs *nilfs, __u64 cno) |
816 | * nilfs_find_sbinfo - find existing nilfs_sb_info structure | ||
817 | * @nilfs: nilfs object | ||
818 | * @rw_mount: mount type (non-zero value for read/write mount) | ||
819 | * @cno: checkpoint number (zero for read-only mount) | ||
820 | * | ||
821 | * nilfs_find_sbinfo() returns the nilfs_sb_info structure which | ||
822 | * @rw_mount and @cno (in case of snapshots) matched. If no instance | ||
823 | * was found, NULL is returned. Although the super block instance can | ||
824 | * be unmounted after this function returns, the nilfs_sb_info struct | ||
825 | * is kept on memory until nilfs_put_sbinfo() is called. | ||
826 | */ | ||
827 | struct nilfs_sb_info *nilfs_find_sbinfo(struct the_nilfs *nilfs, | ||
828 | int rw_mount, __u64 cno) | ||
829 | { | 676 | { |
830 | struct nilfs_sb_info *sbi; | 677 | struct rb_node *n; |
831 | 678 | struct nilfs_root *root; | |
832 | down_read(&nilfs->ns_super_sem); | 679 | |
833 | /* | 680 | spin_lock(&nilfs->ns_cptree_lock); |
834 | * The SNAPSHOT flag and sb->s_flags are supposed to be | 681 | n = nilfs->ns_cptree.rb_node; |
835 | * protected with nilfs->ns_super_sem. | 682 | while (n) { |
836 | */ | 683 | root = rb_entry(n, struct nilfs_root, rb_node); |
837 | sbi = nilfs->ns_current; | 684 | |
838 | if (rw_mount) { | 685 | if (cno < root->cno) { |
839 | if (sbi && !(sbi->s_super->s_flags & MS_RDONLY)) | 686 | n = n->rb_left; |
840 | goto found; /* read/write mount */ | 687 | } else if (cno > root->cno) { |
841 | else | 688 | n = n->rb_right; |
842 | goto out; | 689 | } else { |
843 | } else if (cno == 0) { | 690 | atomic_inc(&root->count); |
844 | if (sbi && (sbi->s_super->s_flags & MS_RDONLY)) | 691 | spin_unlock(&nilfs->ns_cptree_lock); |
845 | goto found; /* read-only mount */ | 692 | return root; |
846 | else | 693 | } |
847 | goto out; | ||
848 | } | 694 | } |
695 | spin_unlock(&nilfs->ns_cptree_lock); | ||
849 | 696 | ||
850 | list_for_each_entry(sbi, &nilfs->ns_supers, s_list) { | ||
851 | if (nilfs_test_opt(sbi, SNAPSHOT) && | ||
852 | sbi->s_snapshot_cno == cno) | ||
853 | goto found; /* snapshot mount */ | ||
854 | } | ||
855 | out: | ||
856 | up_read(&nilfs->ns_super_sem); | ||
857 | return NULL; | 697 | return NULL; |
858 | |||
859 | found: | ||
860 | atomic_inc(&sbi->s_count); | ||
861 | up_read(&nilfs->ns_super_sem); | ||
862 | return sbi; | ||
863 | } | 698 | } |
864 | 699 | ||
865 | int nilfs_checkpoint_is_mounted(struct the_nilfs *nilfs, __u64 cno, | 700 | struct nilfs_root * |
866 | int snapshot_mount) | 701 | nilfs_find_or_create_root(struct the_nilfs *nilfs, __u64 cno) |
867 | { | 702 | { |
868 | struct nilfs_sb_info *sbi; | 703 | struct rb_node **p, *parent; |
869 | int ret = 0; | 704 | struct nilfs_root *root, *new; |
870 | 705 | ||
871 | down_read(&nilfs->ns_super_sem); | 706 | root = nilfs_lookup_root(nilfs, cno); |
872 | if (cno == 0 || cno > nilfs->ns_cno) | 707 | if (root) |
873 | goto out_unlock; | 708 | return root; |
874 | 709 | ||
875 | list_for_each_entry(sbi, &nilfs->ns_supers, s_list) { | 710 | new = kmalloc(sizeof(*root), GFP_KERNEL); |
876 | if (sbi->s_snapshot_cno == cno && | 711 | if (!new) |
877 | (!snapshot_mount || nilfs_test_opt(sbi, SNAPSHOT))) { | 712 | return NULL; |
878 | /* exclude read-only mounts */ | 713 | |
879 | ret++; | 714 | spin_lock(&nilfs->ns_cptree_lock); |
880 | break; | 715 | |
716 | p = &nilfs->ns_cptree.rb_node; | ||
717 | parent = NULL; | ||
718 | |||
719 | while (*p) { | ||
720 | parent = *p; | ||
721 | root = rb_entry(parent, struct nilfs_root, rb_node); | ||
722 | |||
723 | if (cno < root->cno) { | ||
724 | p = &(*p)->rb_left; | ||
725 | } else if (cno > root->cno) { | ||
726 | p = &(*p)->rb_right; | ||
727 | } else { | ||
728 | atomic_inc(&root->count); | ||
729 | spin_unlock(&nilfs->ns_cptree_lock); | ||
730 | kfree(new); | ||
731 | return root; | ||
881 | } | 732 | } |
882 | } | 733 | } |
883 | /* for protecting recent checkpoints */ | ||
884 | if (cno >= nilfs_last_cno(nilfs)) | ||
885 | ret++; | ||
886 | 734 | ||
887 | out_unlock: | 735 | new->cno = cno; |
888 | up_read(&nilfs->ns_super_sem); | 736 | new->ifile = NULL; |
889 | return ret; | 737 | new->nilfs = nilfs; |
738 | atomic_set(&new->count, 1); | ||
739 | atomic_set(&new->inodes_count, 0); | ||
740 | atomic_set(&new->blocks_count, 0); | ||
741 | |||
742 | rb_link_node(&new->rb_node, parent, p); | ||
743 | rb_insert_color(&new->rb_node, &nilfs->ns_cptree); | ||
744 | |||
745 | spin_unlock(&nilfs->ns_cptree_lock); | ||
746 | |||
747 | return new; | ||
748 | } | ||
749 | |||
750 | void nilfs_put_root(struct nilfs_root *root) | ||
751 | { | ||
752 | if (atomic_dec_and_test(&root->count)) { | ||
753 | struct the_nilfs *nilfs = root->nilfs; | ||
754 | |||
755 | spin_lock(&nilfs->ns_cptree_lock); | ||
756 | rb_erase(&root->rb_node, &nilfs->ns_cptree); | ||
757 | spin_unlock(&nilfs->ns_cptree_lock); | ||
758 | if (root->ifile) | ||
759 | iput(root->ifile); | ||
760 | |||
761 | kfree(root); | ||
762 | } | ||
890 | } | 763 | } |