aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nilfs2/the_nilfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nilfs2/the_nilfs.c')
-rw-r--r--fs/nilfs2/the_nilfs.c115
1 files changed, 109 insertions, 6 deletions
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c
index 7f65b3be4aa9..e4e5c78bcc93 100644
--- a/fs/nilfs2/the_nilfs.c
+++ b/fs/nilfs2/the_nilfs.c
@@ -35,6 +35,10 @@
35#include "seglist.h" 35#include "seglist.h"
36#include "segbuf.h" 36#include "segbuf.h"
37 37
38
39static LIST_HEAD(nilfs_objects);
40static DEFINE_SPINLOCK(nilfs_lock);
41
38void nilfs_set_last_segment(struct the_nilfs *nilfs, 42void nilfs_set_last_segment(struct the_nilfs *nilfs,
39 sector_t start_blocknr, u64 seq, __u64 cno) 43 sector_t start_blocknr, u64 seq, __u64 cno)
40{ 44{
@@ -55,7 +59,7 @@ void nilfs_set_last_segment(struct the_nilfs *nilfs,
55 * Return Value: On success, pointer to the_nilfs is returned. 59 * Return Value: On success, pointer to the_nilfs is returned.
56 * On error, NULL is returned. 60 * On error, NULL is returned.
57 */ 61 */
58struct the_nilfs *alloc_nilfs(struct block_device *bdev) 62static struct the_nilfs *alloc_nilfs(struct block_device *bdev)
59{ 63{
60 struct the_nilfs *nilfs; 64 struct the_nilfs *nilfs;
61 65
@@ -68,7 +72,10 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev)
68 atomic_set(&nilfs->ns_writer_refcount, -1); 72 atomic_set(&nilfs->ns_writer_refcount, -1);
69 atomic_set(&nilfs->ns_ndirtyblks, 0); 73 atomic_set(&nilfs->ns_ndirtyblks, 0);
70 init_rwsem(&nilfs->ns_sem); 74 init_rwsem(&nilfs->ns_sem);
75 init_rwsem(&nilfs->ns_super_sem);
76 mutex_init(&nilfs->ns_mount_mutex);
71 mutex_init(&nilfs->ns_writer_mutex); 77 mutex_init(&nilfs->ns_writer_mutex);
78 INIT_LIST_HEAD(&nilfs->ns_list);
72 INIT_LIST_HEAD(&nilfs->ns_supers); 79 INIT_LIST_HEAD(&nilfs->ns_supers);
73 spin_lock_init(&nilfs->ns_last_segment_lock); 80 spin_lock_init(&nilfs->ns_last_segment_lock);
74 nilfs->ns_gc_inodes_h = NULL; 81 nilfs->ns_gc_inodes_h = NULL;
@@ -78,6 +85,45 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev)
78} 85}
79 86
80/** 87/**
88 * find_or_create_nilfs - find or create nilfs object
89 * @bdev: block device to which the_nilfs is related
90 *
91 * find_nilfs() looks up an existent nilfs object created on the
92 * device and gets the reference count of the object. If no nilfs object
93 * is found on the device, a new nilfs object is allocated.
94 *
95 * Return Value: On success, pointer to the nilfs object is returned.
96 * On error, NULL is returned.
97 */
98struct the_nilfs *find_or_create_nilfs(struct block_device *bdev)
99{
100 struct the_nilfs *nilfs, *new = NULL;
101
102 retry:
103 spin_lock(&nilfs_lock);
104 list_for_each_entry(nilfs, &nilfs_objects, ns_list) {
105 if (nilfs->ns_bdev == bdev) {
106 get_nilfs(nilfs);
107 spin_unlock(&nilfs_lock);
108 if (new)
109 put_nilfs(new);
110 return nilfs; /* existing object */
111 }
112 }
113 if (new) {
114 list_add_tail(&new->ns_list, &nilfs_objects);
115 spin_unlock(&nilfs_lock);
116 return new; /* new object */
117 }
118 spin_unlock(&nilfs_lock);
119
120 new = alloc_nilfs(bdev);
121 if (new)
122 goto retry;
123 return NULL; /* insufficient memory */
124}
125
126/**
81 * put_nilfs - release a reference to the_nilfs 127 * put_nilfs - release a reference to the_nilfs
82 * @nilfs: the_nilfs structure to be released 128 * @nilfs: the_nilfs structure to be released
83 * 129 *
@@ -86,13 +132,20 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev)
86 */ 132 */
87void put_nilfs(struct the_nilfs *nilfs) 133void put_nilfs(struct the_nilfs *nilfs)
88{ 134{
89 if (!atomic_dec_and_test(&nilfs->ns_count)) 135 spin_lock(&nilfs_lock);
136 if (!atomic_dec_and_test(&nilfs->ns_count)) {
137 spin_unlock(&nilfs_lock);
90 return; 138 return;
139 }
140 list_del_init(&nilfs->ns_list);
141 spin_unlock(&nilfs_lock);
142
91 /* 143 /*
92 * Increment of ns_count never occur below because the caller 144 * Increment of ns_count never occurs below because the caller
93 * of get_nilfs() holds at least one reference to the_nilfs. 145 * of get_nilfs() holds at least one reference to the_nilfs.
94 * Thus its exclusion control is not required here. 146 * Thus its exclusion control is not required here.
95 */ 147 */
148
96 might_sleep(); 149 might_sleep();
97 if (nilfs_loaded(nilfs)) { 150 if (nilfs_loaded(nilfs)) {
98 nilfs_mdt_clear(nilfs->ns_sufile); 151 nilfs_mdt_clear(nilfs->ns_sufile);
@@ -515,7 +568,7 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data)
515 568
516 blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size); 569 blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size);
517 if (sb->s_blocksize != blocksize) { 570 if (sb->s_blocksize != blocksize) {
518 int hw_blocksize = bdev_hardsect_size(sb->s_bdev); 571 int hw_blocksize = bdev_logical_block_size(sb->s_bdev);
519 572
520 if (blocksize < hw_blocksize) { 573 if (blocksize < hw_blocksize) {
521 printk(KERN_ERR 574 printk(KERN_ERR
@@ -613,13 +666,63 @@ int nilfs_near_disk_full(struct the_nilfs *nilfs)
613 return ret; 666 return ret;
614} 667}
615 668
669/**
670 * nilfs_find_sbinfo - find existing nilfs_sb_info structure
671 * @nilfs: nilfs object
672 * @rw_mount: mount type (non-zero value for read/write mount)
673 * @cno: checkpoint number (zero for read-only mount)
674 *
675 * nilfs_find_sbinfo() returns the nilfs_sb_info structure which
676 * @rw_mount and @cno (in case of snapshots) matched. If no instance
677 * was found, NULL is returned. Although the super block instance can
678 * be unmounted after this function returns, the nilfs_sb_info struct
679 * is kept on memory until nilfs_put_sbinfo() is called.
680 */
681struct nilfs_sb_info *nilfs_find_sbinfo(struct the_nilfs *nilfs,
682 int rw_mount, __u64 cno)
683{
684 struct nilfs_sb_info *sbi;
685
686 down_read(&nilfs->ns_super_sem);
687 /*
688 * The SNAPSHOT flag and sb->s_flags are supposed to be
689 * protected with nilfs->ns_super_sem.
690 */
691 sbi = nilfs->ns_current;
692 if (rw_mount) {
693 if (sbi && !(sbi->s_super->s_flags & MS_RDONLY))
694 goto found; /* read/write mount */
695 else
696 goto out;
697 } else if (cno == 0) {
698 if (sbi && (sbi->s_super->s_flags & MS_RDONLY))
699 goto found; /* read-only mount */
700 else
701 goto out;
702 }
703
704 list_for_each_entry(sbi, &nilfs->ns_supers, s_list) {
705 if (nilfs_test_opt(sbi, SNAPSHOT) &&
706 sbi->s_snapshot_cno == cno)
707 goto found; /* snapshot mount */
708 }
709 out:
710 up_read(&nilfs->ns_super_sem);
711 return NULL;
712
713 found:
714 atomic_inc(&sbi->s_count);
715 up_read(&nilfs->ns_super_sem);
716 return sbi;
717}
718
616int nilfs_checkpoint_is_mounted(struct the_nilfs *nilfs, __u64 cno, 719int nilfs_checkpoint_is_mounted(struct the_nilfs *nilfs, __u64 cno,
617 int snapshot_mount) 720 int snapshot_mount)
618{ 721{
619 struct nilfs_sb_info *sbi; 722 struct nilfs_sb_info *sbi;
620 int ret = 0; 723 int ret = 0;
621 724
622 down_read(&nilfs->ns_sem); 725 down_read(&nilfs->ns_super_sem);
623 if (cno == 0 || cno > nilfs->ns_cno) 726 if (cno == 0 || cno > nilfs->ns_cno)
624 goto out_unlock; 727 goto out_unlock;
625 728
@@ -636,6 +739,6 @@ int nilfs_checkpoint_is_mounted(struct the_nilfs *nilfs, __u64 cno,
636 ret++; 739 ret++;
637 740
638 out_unlock: 741 out_unlock:
639 up_read(&nilfs->ns_sem); 742 up_read(&nilfs->ns_super_sem);
640 return ret; 743 return ret;
641} 744}