aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2009-06-07 12:39:29 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2009-06-11 21:36:17 -0400
commit33c8e57c86d1bd1548c12a4f7c4bceb94b862cca (patch)
tree8e2052a81dc1036e64d78da1082ab6af01ae4bbd
parent81fc20bd0e75ba6357bce2403767d7c2585d8f28 (diff)
nilfs2: get rid of sget use for acquiring nilfs object
This will change the way to obtain nilfs object in nilfs_get_sb() function. Previously, a preliminary sget() call was performed, and the nilfs object was acquired from a super block instance found by the sget() call. This patch, instead, instroduces a new dedicated function find_or_create_nilfs(); as the name implies, the function finds an existent nilfs object from a global list or creates a new one if no object is found on the device. Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> Cc: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/nilfs2/super.c80
-rw-r--r--fs/nilfs2/the_nilfs.c57
-rw-r--r--fs/nilfs2/the_nilfs.h4
3 files changed, 76 insertions, 65 deletions
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c
index 1c505d0e031e..3c9833e3e74a 100644
--- a/fs/nilfs2/super.c
+++ b/fs/nilfs2/super.c
@@ -1061,13 +1061,6 @@ static int nilfs_set_bdev_super(struct super_block *s, void *data)
1061static int nilfs_test_bdev_super(struct super_block *s, void *data) 1061static int nilfs_test_bdev_super(struct super_block *s, void *data)
1062{ 1062{
1063 struct nilfs_super_data *sd = data; 1063 struct nilfs_super_data *sd = data;
1064
1065 return s->s_bdev == sd->bdev;
1066}
1067
1068static int nilfs_test_bdev_super2(struct super_block *s, void *data)
1069{
1070 struct nilfs_super_data *sd = data;
1071 int ret; 1064 int ret;
1072 1065
1073 if (s->s_bdev != sd->bdev) 1066 if (s->s_bdev != sd->bdev)
@@ -1096,8 +1089,8 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags,
1096 const char *dev_name, void *data, struct vfsmount *mnt) 1089 const char *dev_name, void *data, struct vfsmount *mnt)
1097{ 1090{
1098 struct nilfs_super_data sd; 1091 struct nilfs_super_data sd;
1099 struct super_block *s, *s2; 1092 struct super_block *s;
1100 struct the_nilfs *nilfs = NULL; 1093 struct the_nilfs *nilfs;
1101 int err, need_to_close = 1; 1094 int err, need_to_close = 1;
1102 1095
1103 sd.bdev = open_bdev_exclusive(dev_name, flags, fs_type); 1096 sd.bdev = open_bdev_exclusive(dev_name, flags, fs_type);
@@ -1118,11 +1111,12 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags,
1118 goto failed; 1111 goto failed;
1119 } 1112 }
1120 1113
1121 /* 1114 nilfs = find_or_create_nilfs(sd.bdev);
1122 * once the super is inserted into the list by sget, s_umount 1115 if (!nilfs) {
1123 * will protect the lockfs code from trying to start a snapshot 1116 err = -ENOMEM;
1124 * while we are mounting 1117 goto failed;
1125 */ 1118 }
1119
1126 down(&sd.bdev->bd_mount_sem); 1120 down(&sd.bdev->bd_mount_sem);
1127 if (!sd.cno && 1121 if (!sd.cno &&
1128 (err = test_exclusive_mount(fs_type, sd.bdev, flags ^ MS_RDONLY))) { 1122 (err = test_exclusive_mount(fs_type, sd.bdev, flags ^ MS_RDONLY))) {
@@ -1131,51 +1125,22 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags,
1131 } 1125 }
1132 1126
1133 /* 1127 /*
1134 * Phase-1: search any existent instance and get the_nilfs 1128 * Search specified snapshot or R/W mode super_block
1135 */ 1129 */
1136 s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, &sd); 1130 if (!sd.cno)
1137 if (IS_ERR(s)) 1131 /* trying to get the latest checkpoint. */
1138 goto error_s; 1132 sd.cno = nilfs_last_cno(nilfs);
1139
1140 if (!s->s_root) {
1141 err = -ENOMEM;
1142 nilfs = alloc_nilfs(sd.bdev);
1143 if (!nilfs)
1144 goto cancel_new;
1145 } else {
1146 struct nilfs_sb_info *sbi = NILFS_SB(s);
1147 1133
1148 /* 1134 s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, &sd);
1149 * s_umount protects super_block from unmount process; 1135 if (IS_ERR(s)) {
1150 * It covers pointers of nilfs_sb_info and the_nilfs. 1136 err = PTR_ERR(s);
1151 */ 1137 goto failed_unlock;
1152 nilfs = sbi->s_nilfs;
1153 get_nilfs(nilfs);
1154 up_write(&s->s_umount);
1155
1156 /*
1157 * Phase-2: search specified snapshot or R/W mode super_block
1158 */
1159 if (!sd.cno)
1160 /* trying to get the latest checkpoint. */
1161 sd.cno = nilfs_last_cno(nilfs);
1162
1163 s2 = sget(fs_type, nilfs_test_bdev_super2,
1164 nilfs_set_bdev_super, &sd);
1165 deactivate_super(s);
1166 /*
1167 * Although deactivate_super() invokes close_bdev_exclusive() at
1168 * kill_block_super(). Here, s is an existent mount; we need
1169 * one more close_bdev_exclusive() call.
1170 */
1171 s = s2;
1172 if (IS_ERR(s))
1173 goto error_s;
1174 } 1138 }
1175 1139
1176 if (!s->s_root) { 1140 if (!s->s_root) {
1177 char b[BDEVNAME_SIZE]; 1141 char b[BDEVNAME_SIZE];
1178 1142
1143 /* New superblock instance created */
1179 s->s_flags = flags; 1144 s->s_flags = flags;
1180 strlcpy(s->s_id, bdevname(sd.bdev, b), sizeof(s->s_id)); 1145 strlcpy(s->s_id, bdevname(sd.bdev, b), sizeof(s->s_id));
1181 sb_set_blocksize(s, block_size(sd.bdev)); 1146 sb_set_blocksize(s, block_size(sd.bdev));
@@ -1195,15 +1160,9 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags,
1195 simple_set_mnt(mnt, s); 1160 simple_set_mnt(mnt, s);
1196 return 0; 1161 return 0;
1197 1162
1198 error_s:
1199 up(&sd.bdev->bd_mount_sem);
1200 if (nilfs)
1201 put_nilfs(nilfs);
1202 close_bdev_exclusive(sd.bdev, flags);
1203 return PTR_ERR(s);
1204
1205 failed_unlock: 1163 failed_unlock:
1206 up(&sd.bdev->bd_mount_sem); 1164 up(&sd.bdev->bd_mount_sem);
1165 put_nilfs(nilfs);
1207 failed: 1166 failed:
1208 close_bdev_exclusive(sd.bdev, flags); 1167 close_bdev_exclusive(sd.bdev, flags);
1209 1168
@@ -1212,8 +1171,7 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags,
1212 cancel_new: 1171 cancel_new:
1213 /* Abandoning the newly allocated superblock */ 1172 /* Abandoning the newly allocated superblock */
1214 up(&sd.bdev->bd_mount_sem); 1173 up(&sd.bdev->bd_mount_sem);
1215 if (nilfs) 1174 put_nilfs(nilfs);
1216 put_nilfs(nilfs);
1217 up_write(&s->s_umount); 1175 up_write(&s->s_umount);
1218 deactivate_super(s); 1176 deactivate_super(s);
1219 /* 1177 /*
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c
index a91f15b8673c..45dbf6a61744 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
@@ -69,6 +73,7 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev)
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);
71 mutex_init(&nilfs->ns_writer_mutex); 75 mutex_init(&nilfs->ns_writer_mutex);
76 INIT_LIST_HEAD(&nilfs->ns_list);
72 INIT_LIST_HEAD(&nilfs->ns_supers); 77 INIT_LIST_HEAD(&nilfs->ns_supers);
73 spin_lock_init(&nilfs->ns_last_segment_lock); 78 spin_lock_init(&nilfs->ns_last_segment_lock);
74 nilfs->ns_gc_inodes_h = NULL; 79 nilfs->ns_gc_inodes_h = NULL;
@@ -78,6 +83,45 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev)
78} 83}
79 84
80/** 85/**
86 * find_or_create_nilfs - find or create nilfs object
87 * @bdev: block device to which the_nilfs is related
88 *
89 * find_nilfs() looks up an existent nilfs object created on the
90 * device and gets the reference count of the object. If no nilfs object
91 * is found on the device, a new nilfs object is allocated.
92 *
93 * Return Value: On success, pointer to the nilfs object is returned.
94 * On error, NULL is returned.
95 */
96struct the_nilfs *find_or_create_nilfs(struct block_device *bdev)
97{
98 struct the_nilfs *nilfs, *new = NULL;
99
100 retry:
101 spin_lock(&nilfs_lock);
102 list_for_each_entry(nilfs, &nilfs_objects, ns_list) {
103 if (nilfs->ns_bdev == bdev) {
104 get_nilfs(nilfs);
105 spin_unlock(&nilfs_lock);
106 if (new)
107 put_nilfs(new);
108 return nilfs; /* existing object */
109 }
110 }
111 if (new) {
112 list_add_tail(&new->ns_list, &nilfs_objects);
113 spin_unlock(&nilfs_lock);
114 return new; /* new object */
115 }
116 spin_unlock(&nilfs_lock);
117
118 new = alloc_nilfs(bdev);
119 if (new)
120 goto retry;
121 return NULL; /* insufficient memory */
122}
123
124/**
81 * put_nilfs - release a reference to the_nilfs 125 * put_nilfs - release a reference to the_nilfs
82 * @nilfs: the_nilfs structure to be released 126 * @nilfs: the_nilfs structure to be released
83 * 127 *
@@ -86,13 +130,20 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev)
86 */ 130 */
87void put_nilfs(struct the_nilfs *nilfs) 131void put_nilfs(struct the_nilfs *nilfs)
88{ 132{
89 if (!atomic_dec_and_test(&nilfs->ns_count)) 133 spin_lock(&nilfs_lock);
134 if (!atomic_dec_and_test(&nilfs->ns_count)) {
135 spin_unlock(&nilfs_lock);
90 return; 136 return;
137 }
138 list_del_init(&nilfs->ns_list);
139 spin_unlock(&nilfs_lock);
140
91 /* 141 /*
92 * Increment of ns_count never occur below because the caller 142 * Increment of ns_count never occurs below because the caller
93 * of get_nilfs() holds at least one reference to the_nilfs. 143 * of get_nilfs() holds at least one reference to the_nilfs.
94 * Thus its exclusion control is not required here. 144 * Thus its exclusion control is not required here.
95 */ 145 */
146
96 might_sleep(); 147 might_sleep();
97 if (nilfs_loaded(nilfs)) { 148 if (nilfs_loaded(nilfs)) {
98 nilfs_mdt_clear(nilfs->ns_sufile); 149 nilfs_mdt_clear(nilfs->ns_sufile);
diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h
index 30fe58778d05..116caf96e7f3 100644
--- a/fs/nilfs2/the_nilfs.h
+++ b/fs/nilfs2/the_nilfs.h
@@ -43,6 +43,7 @@ enum {
43 * struct the_nilfs - struct to supervise multiple nilfs mount points 43 * struct the_nilfs - struct to supervise multiple nilfs mount points
44 * @ns_flags: flags 44 * @ns_flags: flags
45 * @ns_count: reference count 45 * @ns_count: reference count
46 * @ns_list: list head for nilfs_list
46 * @ns_bdev: block device 47 * @ns_bdev: block device
47 * @ns_bdi: backing dev info 48 * @ns_bdi: backing dev info
48 * @ns_writer: back pointer to writable nilfs_sb_info 49 * @ns_writer: back pointer to writable nilfs_sb_info
@@ -88,6 +89,7 @@ enum {
88struct the_nilfs { 89struct the_nilfs {
89 unsigned long ns_flags; 90 unsigned long ns_flags;
90 atomic_t ns_count; 91 atomic_t ns_count;
92 struct list_head ns_list;
91 93
92 struct block_device *ns_bdev; 94 struct block_device *ns_bdev;
93 struct backing_dev_info *ns_bdi; 95 struct backing_dev_info *ns_bdi;
@@ -191,7 +193,7 @@ THE_NILFS_FNS(DISCONTINUED, discontinued)
191#define NILFS_ALTSB_FREQ 60 /* spare superblock */ 193#define NILFS_ALTSB_FREQ 60 /* spare superblock */
192 194
193void nilfs_set_last_segment(struct the_nilfs *, sector_t, u64, __u64); 195void nilfs_set_last_segment(struct the_nilfs *, sector_t, u64, __u64);
194struct the_nilfs *alloc_nilfs(struct block_device *); 196struct the_nilfs *find_or_create_nilfs(struct block_device *);
195void put_nilfs(struct the_nilfs *); 197void put_nilfs(struct the_nilfs *);
196int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *); 198int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *);
197int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *); 199int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *);