diff options
Diffstat (limited to 'fs/nilfs2/the_nilfs.c')
-rw-r--r-- | fs/nilfs2/the_nilfs.c | 115 |
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 | |||
39 | static LIST_HEAD(nilfs_objects); | ||
40 | static DEFINE_SPINLOCK(nilfs_lock); | ||
41 | |||
38 | void nilfs_set_last_segment(struct the_nilfs *nilfs, | 42 | void 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 | */ |
58 | struct the_nilfs *alloc_nilfs(struct block_device *bdev) | 62 | static 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 | */ | ||
98 | struct 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 | */ |
87 | void put_nilfs(struct the_nilfs *nilfs) | 133 | void 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 | */ | ||
681 | struct 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 | |||
616 | int nilfs_checkpoint_is_mounted(struct the_nilfs *nilfs, __u64 cno, | 719 | int 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 | } |