diff options
Diffstat (limited to 'fs/nilfs2/the_nilfs.c')
-rw-r--r-- | fs/nilfs2/the_nilfs.c | 195 |
1 files changed, 122 insertions, 73 deletions
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index ad391a8c3e7e..33871f7e4f01 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c | |||
@@ -146,13 +146,9 @@ void put_nilfs(struct the_nilfs *nilfs) | |||
146 | 146 | ||
147 | might_sleep(); | 147 | might_sleep(); |
148 | if (nilfs_loaded(nilfs)) { | 148 | if (nilfs_loaded(nilfs)) { |
149 | nilfs_mdt_clear(nilfs->ns_sufile); | ||
150 | nilfs_mdt_destroy(nilfs->ns_sufile); | 149 | nilfs_mdt_destroy(nilfs->ns_sufile); |
151 | nilfs_mdt_clear(nilfs->ns_cpfile); | ||
152 | nilfs_mdt_destroy(nilfs->ns_cpfile); | 150 | nilfs_mdt_destroy(nilfs->ns_cpfile); |
153 | nilfs_mdt_clear(nilfs->ns_dat); | ||
154 | nilfs_mdt_destroy(nilfs->ns_dat); | 151 | nilfs_mdt_destroy(nilfs->ns_dat); |
155 | /* XXX: how and when to clear nilfs->ns_gc_dat? */ | ||
156 | nilfs_mdt_destroy(nilfs->ns_gc_dat); | 152 | nilfs_mdt_destroy(nilfs->ns_gc_dat); |
157 | } | 153 | } |
158 | if (nilfs_init(nilfs)) { | 154 | if (nilfs_init(nilfs)) { |
@@ -166,7 +162,6 @@ void put_nilfs(struct the_nilfs *nilfs) | |||
166 | static int nilfs_load_super_root(struct the_nilfs *nilfs, | 162 | static int nilfs_load_super_root(struct the_nilfs *nilfs, |
167 | struct nilfs_sb_info *sbi, sector_t sr_block) | 163 | struct nilfs_sb_info *sbi, sector_t sr_block) |
168 | { | 164 | { |
169 | static struct lock_class_key dat_lock_key; | ||
170 | struct buffer_head *bh_sr; | 165 | struct buffer_head *bh_sr; |
171 | struct nilfs_super_root *raw_sr; | 166 | struct nilfs_super_root *raw_sr; |
172 | struct nilfs_super_block **sbp = nilfs->ns_sbp; | 167 | struct nilfs_super_block **sbp = nilfs->ns_sbp; |
@@ -187,51 +182,36 @@ static int nilfs_load_super_root(struct the_nilfs *nilfs, | |||
187 | inode_size = nilfs->ns_inode_size; | 182 | inode_size = nilfs->ns_inode_size; |
188 | 183 | ||
189 | err = -ENOMEM; | 184 | err = -ENOMEM; |
190 | nilfs->ns_dat = nilfs_mdt_new(nilfs, NULL, NILFS_DAT_INO); | 185 | nilfs->ns_dat = nilfs_dat_new(nilfs, dat_entry_size); |
191 | if (unlikely(!nilfs->ns_dat)) | 186 | if (unlikely(!nilfs->ns_dat)) |
192 | goto failed; | 187 | goto failed; |
193 | 188 | ||
194 | nilfs->ns_gc_dat = nilfs_mdt_new(nilfs, NULL, NILFS_DAT_INO); | 189 | nilfs->ns_gc_dat = nilfs_dat_new(nilfs, dat_entry_size); |
195 | if (unlikely(!nilfs->ns_gc_dat)) | 190 | if (unlikely(!nilfs->ns_gc_dat)) |
196 | goto failed_dat; | 191 | goto failed_dat; |
197 | 192 | ||
198 | nilfs->ns_cpfile = nilfs_mdt_new(nilfs, NULL, NILFS_CPFILE_INO); | 193 | nilfs->ns_cpfile = nilfs_cpfile_new(nilfs, checkpoint_size); |
199 | if (unlikely(!nilfs->ns_cpfile)) | 194 | if (unlikely(!nilfs->ns_cpfile)) |
200 | goto failed_gc_dat; | 195 | goto failed_gc_dat; |
201 | 196 | ||
202 | nilfs->ns_sufile = nilfs_mdt_new(nilfs, NULL, NILFS_SUFILE_INO); | 197 | nilfs->ns_sufile = nilfs_sufile_new(nilfs, segment_usage_size); |
203 | if (unlikely(!nilfs->ns_sufile)) | 198 | if (unlikely(!nilfs->ns_sufile)) |
204 | goto failed_cpfile; | 199 | goto failed_cpfile; |
205 | 200 | ||
206 | err = nilfs_palloc_init_blockgroup(nilfs->ns_dat, dat_entry_size); | ||
207 | if (unlikely(err)) | ||
208 | goto failed_sufile; | ||
209 | |||
210 | err = nilfs_palloc_init_blockgroup(nilfs->ns_gc_dat, dat_entry_size); | ||
211 | if (unlikely(err)) | ||
212 | goto failed_sufile; | ||
213 | |||
214 | lockdep_set_class(&NILFS_MDT(nilfs->ns_dat)->mi_sem, &dat_lock_key); | ||
215 | lockdep_set_class(&NILFS_MDT(nilfs->ns_gc_dat)->mi_sem, &dat_lock_key); | ||
216 | |||
217 | nilfs_mdt_set_shadow(nilfs->ns_dat, nilfs->ns_gc_dat); | 201 | nilfs_mdt_set_shadow(nilfs->ns_dat, nilfs->ns_gc_dat); |
218 | nilfs_mdt_set_entry_size(nilfs->ns_cpfile, checkpoint_size, | ||
219 | sizeof(struct nilfs_cpfile_header)); | ||
220 | nilfs_mdt_set_entry_size(nilfs->ns_sufile, segment_usage_size, | ||
221 | sizeof(struct nilfs_sufile_header)); | ||
222 | 202 | ||
223 | err = nilfs_mdt_read_inode_direct( | 203 | err = nilfs_dat_read(nilfs->ns_dat, (void *)bh_sr->b_data + |
224 | nilfs->ns_dat, bh_sr, NILFS_SR_DAT_OFFSET(inode_size)); | 204 | NILFS_SR_DAT_OFFSET(inode_size)); |
225 | if (unlikely(err)) | 205 | if (unlikely(err)) |
226 | goto failed_sufile; | 206 | goto failed_sufile; |
227 | 207 | ||
228 | err = nilfs_mdt_read_inode_direct( | 208 | err = nilfs_cpfile_read(nilfs->ns_cpfile, (void *)bh_sr->b_data + |
229 | nilfs->ns_cpfile, bh_sr, NILFS_SR_CPFILE_OFFSET(inode_size)); | 209 | NILFS_SR_CPFILE_OFFSET(inode_size)); |
230 | if (unlikely(err)) | 210 | if (unlikely(err)) |
231 | goto failed_sufile; | 211 | goto failed_sufile; |
232 | 212 | ||
233 | err = nilfs_mdt_read_inode_direct( | 213 | err = nilfs_sufile_read(nilfs->ns_sufile, (void *)bh_sr->b_data + |
234 | nilfs->ns_sufile, bh_sr, NILFS_SR_SUFILE_OFFSET(inode_size)); | 214 | NILFS_SR_SUFILE_OFFSET(inode_size)); |
235 | if (unlikely(err)) | 215 | if (unlikely(err)) |
236 | goto failed_sufile; | 216 | goto failed_sufile; |
237 | 217 | ||
@@ -281,29 +261,30 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) | |||
281 | struct nilfs_recovery_info ri; | 261 | struct nilfs_recovery_info ri; |
282 | unsigned int s_flags = sbi->s_super->s_flags; | 262 | unsigned int s_flags = sbi->s_super->s_flags; |
283 | int really_read_only = bdev_read_only(nilfs->ns_bdev); | 263 | int really_read_only = bdev_read_only(nilfs->ns_bdev); |
284 | unsigned valid_fs; | 264 | int valid_fs = nilfs_valid_fs(nilfs); |
285 | int err = 0; | 265 | int err; |
286 | |||
287 | nilfs_init_recovery_info(&ri); | ||
288 | 266 | ||
289 | down_write(&nilfs->ns_sem); | 267 | if (nilfs_loaded(nilfs)) { |
290 | valid_fs = (nilfs->ns_mount_state & NILFS_VALID_FS); | 268 | if (valid_fs || |
291 | up_write(&nilfs->ns_sem); | 269 | ((s_flags & MS_RDONLY) && nilfs_test_opt(sbi, NORECOVERY))) |
270 | return 0; | ||
271 | printk(KERN_ERR "NILFS: the filesystem is in an incomplete " | ||
272 | "recovery state.\n"); | ||
273 | return -EINVAL; | ||
274 | } | ||
292 | 275 | ||
293 | if (!valid_fs && (s_flags & MS_RDONLY)) { | 276 | if (!valid_fs) { |
294 | printk(KERN_INFO "NILFS: INFO: recovery " | 277 | printk(KERN_WARNING "NILFS warning: mounting unchecked fs\n"); |
295 | "required for readonly filesystem.\n"); | 278 | if (s_flags & MS_RDONLY) { |
296 | if (really_read_only) { | 279 | printk(KERN_INFO "NILFS: INFO: recovery " |
297 | printk(KERN_ERR "NILFS: write access " | 280 | "required for readonly filesystem.\n"); |
298 | "unavailable, cannot proceed.\n"); | 281 | printk(KERN_INFO "NILFS: write access will " |
299 | err = -EROFS; | 282 | "be enabled during recovery.\n"); |
300 | goto failed; | ||
301 | } | 283 | } |
302 | printk(KERN_INFO "NILFS: write access will " | ||
303 | "be enabled during recovery.\n"); | ||
304 | sbi->s_super->s_flags &= ~MS_RDONLY; | ||
305 | } | 284 | } |
306 | 285 | ||
286 | nilfs_init_recovery_info(&ri); | ||
287 | |||
307 | err = nilfs_search_super_root(nilfs, sbi, &ri); | 288 | err = nilfs_search_super_root(nilfs, sbi, &ri); |
308 | if (unlikely(err)) { | 289 | if (unlikely(err)) { |
309 | printk(KERN_ERR "NILFS: error searching super root.\n"); | 290 | printk(KERN_ERR "NILFS: error searching super root.\n"); |
@@ -316,19 +297,56 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) | |||
316 | goto failed; | 297 | goto failed; |
317 | } | 298 | } |
318 | 299 | ||
319 | if (!valid_fs) { | 300 | if (valid_fs) |
320 | err = nilfs_recover_logical_segments(nilfs, sbi, &ri); | 301 | goto skip_recovery; |
321 | if (unlikely(err)) { | 302 | |
322 | nilfs_mdt_destroy(nilfs->ns_cpfile); | 303 | if (s_flags & MS_RDONLY) { |
323 | nilfs_mdt_destroy(nilfs->ns_sufile); | 304 | if (nilfs_test_opt(sbi, NORECOVERY)) { |
324 | nilfs_mdt_destroy(nilfs->ns_dat); | 305 | printk(KERN_INFO "NILFS: norecovery option specified. " |
325 | goto failed; | 306 | "skipping roll-forward recovery\n"); |
307 | goto skip_recovery; | ||
326 | } | 308 | } |
327 | if (ri.ri_need_recovery == NILFS_RECOVERY_SR_UPDATED) | 309 | if (really_read_only) { |
328 | sbi->s_super->s_dirt = 1; | 310 | printk(KERN_ERR "NILFS: write access " |
311 | "unavailable, cannot proceed.\n"); | ||
312 | err = -EROFS; | ||
313 | goto failed_unload; | ||
314 | } | ||
315 | sbi->s_super->s_flags &= ~MS_RDONLY; | ||
316 | } else if (nilfs_test_opt(sbi, NORECOVERY)) { | ||
317 | printk(KERN_ERR "NILFS: recovery cancelled because norecovery " | ||
318 | "option was specified for a read/write mount\n"); | ||
319 | err = -EINVAL; | ||
320 | goto failed_unload; | ||
321 | } | ||
322 | |||
323 | err = nilfs_recover_logical_segments(nilfs, sbi, &ri); | ||
324 | if (err) | ||
325 | goto failed_unload; | ||
326 | |||
327 | down_write(&nilfs->ns_sem); | ||
328 | nilfs->ns_mount_state |= NILFS_VALID_FS; | ||
329 | nilfs->ns_sbp[0]->s_state = cpu_to_le16(nilfs->ns_mount_state); | ||
330 | err = nilfs_commit_super(sbi, 1); | ||
331 | up_write(&nilfs->ns_sem); | ||
332 | |||
333 | if (err) { | ||
334 | printk(KERN_ERR "NILFS: failed to update super block. " | ||
335 | "recovery unfinished.\n"); | ||
336 | goto failed_unload; | ||
329 | } | 337 | } |
338 | printk(KERN_INFO "NILFS: recovery complete.\n"); | ||
330 | 339 | ||
340 | skip_recovery: | ||
331 | set_nilfs_loaded(nilfs); | 341 | set_nilfs_loaded(nilfs); |
342 | nilfs_clear_recovery_info(&ri); | ||
343 | sbi->s_super->s_flags = s_flags; | ||
344 | return 0; | ||
345 | |||
346 | failed_unload: | ||
347 | nilfs_mdt_destroy(nilfs->ns_cpfile); | ||
348 | nilfs_mdt_destroy(nilfs->ns_sufile); | ||
349 | nilfs_mdt_destroy(nilfs->ns_dat); | ||
332 | 350 | ||
333 | failed: | 351 | failed: |
334 | nilfs_clear_recovery_info(&ri); | 352 | nilfs_clear_recovery_info(&ri); |
@@ -368,7 +386,7 @@ static int nilfs_store_disk_layout(struct the_nilfs *nilfs, | |||
368 | 386 | ||
369 | nilfs->ns_blocks_per_segment = le32_to_cpu(sbp->s_blocks_per_segment); | 387 | nilfs->ns_blocks_per_segment = le32_to_cpu(sbp->s_blocks_per_segment); |
370 | if (nilfs->ns_blocks_per_segment < NILFS_SEG_MIN_BLOCKS) { | 388 | if (nilfs->ns_blocks_per_segment < NILFS_SEG_MIN_BLOCKS) { |
371 | printk(KERN_ERR "NILFS: too short segment. \n"); | 389 | printk(KERN_ERR "NILFS: too short segment.\n"); |
372 | return -EINVAL; | 390 | return -EINVAL; |
373 | } | 391 | } |
374 | 392 | ||
@@ -628,34 +646,65 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data) | |||
628 | goto out; | 646 | goto out; |
629 | } | 647 | } |
630 | 648 | ||
649 | int nilfs_discard_segments(struct the_nilfs *nilfs, __u64 *segnump, | ||
650 | size_t nsegs) | ||
651 | { | ||
652 | sector_t seg_start, seg_end; | ||
653 | sector_t start = 0, nblocks = 0; | ||
654 | unsigned int sects_per_block; | ||
655 | __u64 *sn; | ||
656 | int ret = 0; | ||
657 | |||
658 | sects_per_block = (1 << nilfs->ns_blocksize_bits) / | ||
659 | bdev_logical_block_size(nilfs->ns_bdev); | ||
660 | for (sn = segnump; sn < segnump + nsegs; sn++) { | ||
661 | nilfs_get_segment_range(nilfs, *sn, &seg_start, &seg_end); | ||
662 | |||
663 | if (!nblocks) { | ||
664 | start = seg_start; | ||
665 | nblocks = seg_end - seg_start + 1; | ||
666 | } else if (start + nblocks == seg_start) { | ||
667 | nblocks += seg_end - seg_start + 1; | ||
668 | } else { | ||
669 | ret = blkdev_issue_discard(nilfs->ns_bdev, | ||
670 | start * sects_per_block, | ||
671 | nblocks * sects_per_block, | ||
672 | GFP_NOFS, | ||
673 | DISCARD_FL_BARRIER); | ||
674 | if (ret < 0) | ||
675 | return ret; | ||
676 | nblocks = 0; | ||
677 | } | ||
678 | } | ||
679 | if (nblocks) | ||
680 | ret = blkdev_issue_discard(nilfs->ns_bdev, | ||
681 | start * sects_per_block, | ||
682 | nblocks * sects_per_block, | ||
683 | GFP_NOFS, DISCARD_FL_BARRIER); | ||
684 | return ret; | ||
685 | } | ||
686 | |||
631 | int nilfs_count_free_blocks(struct the_nilfs *nilfs, sector_t *nblocks) | 687 | int nilfs_count_free_blocks(struct the_nilfs *nilfs, sector_t *nblocks) |
632 | { | 688 | { |
633 | struct inode *dat = nilfs_dat_inode(nilfs); | 689 | struct inode *dat = nilfs_dat_inode(nilfs); |
634 | unsigned long ncleansegs; | 690 | unsigned long ncleansegs; |
635 | int err; | ||
636 | 691 | ||
637 | down_read(&NILFS_MDT(dat)->mi_sem); /* XXX */ | 692 | down_read(&NILFS_MDT(dat)->mi_sem); /* XXX */ |
638 | err = nilfs_sufile_get_ncleansegs(nilfs->ns_sufile, &ncleansegs); | 693 | ncleansegs = nilfs_sufile_get_ncleansegs(nilfs->ns_sufile); |
639 | up_read(&NILFS_MDT(dat)->mi_sem); /* XXX */ | 694 | up_read(&NILFS_MDT(dat)->mi_sem); /* XXX */ |
640 | if (likely(!err)) | 695 | *nblocks = (sector_t)ncleansegs * nilfs->ns_blocks_per_segment; |
641 | *nblocks = (sector_t)ncleansegs * nilfs->ns_blocks_per_segment; | 696 | return 0; |
642 | return err; | ||
643 | } | 697 | } |
644 | 698 | ||
645 | int nilfs_near_disk_full(struct the_nilfs *nilfs) | 699 | int nilfs_near_disk_full(struct the_nilfs *nilfs) |
646 | { | 700 | { |
647 | struct inode *sufile = nilfs->ns_sufile; | ||
648 | unsigned long ncleansegs, nincsegs; | 701 | unsigned long ncleansegs, nincsegs; |
649 | int ret; | ||
650 | 702 | ||
651 | ret = nilfs_sufile_get_ncleansegs(sufile, &ncleansegs); | 703 | ncleansegs = nilfs_sufile_get_ncleansegs(nilfs->ns_sufile); |
652 | if (likely(!ret)) { | 704 | nincsegs = atomic_read(&nilfs->ns_ndirtyblks) / |
653 | nincsegs = atomic_read(&nilfs->ns_ndirtyblks) / | 705 | nilfs->ns_blocks_per_segment + 1; |
654 | nilfs->ns_blocks_per_segment + 1; | 706 | |
655 | if (ncleansegs <= nilfs->ns_nrsvsegs + nincsegs) | 707 | return ncleansegs <= nilfs->ns_nrsvsegs + nincsegs; |
656 | ret++; | ||
657 | } | ||
658 | return ret; | ||
659 | } | 708 | } |
660 | 709 | ||
661 | /** | 710 | /** |