aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/disk-io.c4
-rw-r--r--fs/btrfs/volumes.c70
-rw-r--r--fs/btrfs/volumes.h4
3 files changed, 63 insertions, 15 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 38b0d9ecda6a..264f297260f8 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1266,10 +1266,10 @@ struct btrfs_root *open_ctree(struct super_block *sb,
1266 1266
1267 btrfs_parse_options(options, tree_root, NULL); 1267 btrfs_parse_options(options, tree_root, NULL);
1268 1268
1269 if (btrfs_super_num_devices(disk_super) > fs_devices->num_devices) { 1269 if (btrfs_super_num_devices(disk_super) > fs_devices->open_devices) {
1270 printk("Btrfs: wanted %llu devices, but found %llu\n", 1270 printk("Btrfs: wanted %llu devices, but found %llu\n",
1271 (unsigned long long)btrfs_super_num_devices(disk_super), 1271 (unsigned long long)btrfs_super_num_devices(disk_super),
1272 (unsigned long long)fs_devices->num_devices); 1272 (unsigned long long)fs_devices->open_devices);
1273 if (btrfs_test_opt(tree_root, DEGRADED)) 1273 if (btrfs_test_opt(tree_root, DEGRADED))
1274 printk("continuing in degraded mode\n"); 1274 printk("continuing in degraded mode\n");
1275 else { 1275 else {
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 43f74d17bcea..501d23d3ebfd 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -71,6 +71,7 @@ int btrfs_cleanup_fs_uuids(void)
71 dev_list); 71 dev_list);
72 if (dev->bdev) { 72 if (dev->bdev) {
73 close_bdev_excl(dev->bdev); 73 close_bdev_excl(dev->bdev);
74 fs_devices->open_devices--;
74 } 75 }
75 list_del(&dev->dev_list); 76 list_del(&dev->dev_list);
76 kfree(dev->name); 77 kfree(dev->name);
@@ -174,9 +175,10 @@ again:
174 list_for_each(cur, head) { 175 list_for_each(cur, head) {
175 device = list_entry(cur, struct btrfs_device, dev_list); 176 device = list_entry(cur, struct btrfs_device, dev_list);
176 if (!device->in_fs_metadata) { 177 if (!device->in_fs_metadata) {
177printk("getting rid of extra dev %s\n", device->name); 178 if (device->bdev) {
178 if (device->bdev)
179 close_bdev_excl(device->bdev); 179 close_bdev_excl(device->bdev);
180 fs_devices->open_devices--;
181 }
180 list_del(&device->dev_list); 182 list_del(&device->dev_list);
181 list_del(&device->dev_alloc_list); 183 list_del(&device->dev_alloc_list);
182 fs_devices->num_devices--; 184 fs_devices->num_devices--;
@@ -188,6 +190,7 @@ printk("getting rid of extra dev %s\n", device->name);
188 mutex_unlock(&uuid_mutex); 190 mutex_unlock(&uuid_mutex);
189 return 0; 191 return 0;
190} 192}
193
191int btrfs_close_devices(struct btrfs_fs_devices *fs_devices) 194int btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
192{ 195{
193 struct list_head *head = &fs_devices->devices; 196 struct list_head *head = &fs_devices->devices;
@@ -199,10 +202,12 @@ int btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
199 device = list_entry(cur, struct btrfs_device, dev_list); 202 device = list_entry(cur, struct btrfs_device, dev_list);
200 if (device->bdev) { 203 if (device->bdev) {
201 close_bdev_excl(device->bdev); 204 close_bdev_excl(device->bdev);
205 fs_devices->open_devices--;
202 } 206 }
203 device->bdev = NULL; 207 device->bdev = NULL;
204 device->in_fs_metadata = 0; 208 device->in_fs_metadata = 0;
205 } 209 }
210 fs_devices->mounted = 0;
206 mutex_unlock(&uuid_mutex); 211 mutex_unlock(&uuid_mutex);
207 return 0; 212 return 0;
208} 213}
@@ -214,9 +219,19 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
214 struct list_head *head = &fs_devices->devices; 219 struct list_head *head = &fs_devices->devices;
215 struct list_head *cur; 220 struct list_head *cur;
216 struct btrfs_device *device; 221 struct btrfs_device *device;
217 int ret; 222 struct block_device *latest_bdev = NULL;
223 struct buffer_head *bh;
224 struct btrfs_super_block *disk_super;
225 u64 latest_devid = 0;
226 u64 latest_transid = 0;
227 u64 transid;
228 u64 devid;
229 int ret = 0;
218 230
219 mutex_lock(&uuid_mutex); 231 mutex_lock(&uuid_mutex);
232 if (fs_devices->mounted)
233 goto out;
234
220 list_for_each(cur, head) { 235 list_for_each(cur, head) {
221 device = list_entry(cur, struct btrfs_device, dev_list); 236 device = list_entry(cur, struct btrfs_device, dev_list);
222 if (device->bdev) 237 if (device->bdev)
@@ -229,21 +244,52 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
229 244
230 if (IS_ERR(bdev)) { 245 if (IS_ERR(bdev)) {
231 printk("open %s failed\n", device->name); 246 printk("open %s failed\n", device->name);
232 ret = PTR_ERR(bdev); 247 goto error;
233 goto fail;
234 } 248 }
235 set_blocksize(bdev, 4096); 249 set_blocksize(bdev, 4096);
236 if (device->devid == fs_devices->latest_devid) 250
237 fs_devices->latest_bdev = bdev; 251 bh = __bread(bdev, BTRFS_SUPER_INFO_OFFSET / 4096, 4096);
252 if (!bh)
253 goto error_close;
254
255 disk_super = (struct btrfs_super_block *)bh->b_data;
256 if (strncmp((char *)(&disk_super->magic), BTRFS_MAGIC,
257 sizeof(disk_super->magic)))
258 goto error_brelse;
259
260 devid = le64_to_cpu(disk_super->dev_item.devid);
261 if (devid != device->devid)
262 goto error_brelse;
263
264 transid = btrfs_super_generation(disk_super);
265 if (transid > latest_transid) {
266 latest_devid = devid;
267 latest_transid = transid;
268 latest_bdev = bdev;
269 }
270
238 device->bdev = bdev; 271 device->bdev = bdev;
239 device->in_fs_metadata = 0; 272 device->in_fs_metadata = 0;
273 fs_devices->open_devices++;
274 continue;
240 275
276error_brelse:
277 brelse(bh);
278error_close:
279 close_bdev_excl(bdev);
280error:
281 continue;
241 } 282 }
283 if (fs_devices->open_devices == 0) {
284 ret = -EIO;
285 goto out;
286 }
287 fs_devices->mounted = 1;
288 fs_devices->latest_bdev = latest_bdev;
289 fs_devices->latest_devid = latest_devid;
290 fs_devices->latest_trans = latest_transid;
291out:
242 mutex_unlock(&uuid_mutex); 292 mutex_unlock(&uuid_mutex);
243 return 0;
244fail:
245 mutex_unlock(&uuid_mutex);
246 btrfs_close_devices(fs_devices);
247 return ret; 293 return ret;
248} 294}
249 295
@@ -828,6 +874,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
828 if (device->bdev) { 874 if (device->bdev) {
829 /* one close for the device struct or super_block */ 875 /* one close for the device struct or super_block */
830 close_bdev_excl(device->bdev); 876 close_bdev_excl(device->bdev);
877 root->fs_info->fs_devices->open_devices--;
831 } 878 }
832 if (bdev) { 879 if (bdev) {
833 /* one close for us */ 880 /* one close for us */
@@ -914,6 +961,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
914 list_add(&device->dev_alloc_list, 961 list_add(&device->dev_alloc_list,
915 &root->fs_info->fs_devices->alloc_list); 962 &root->fs_info->fs_devices->alloc_list);
916 root->fs_info->fs_devices->num_devices++; 963 root->fs_info->fs_devices->num_devices++;
964 root->fs_info->fs_devices->open_devices++;
917out: 965out:
918 btrfs_end_transaction(trans, root); 966 btrfs_end_transaction(trans, root);
919 mutex_unlock(&root->fs_info->fs_mutex); 967 mutex_unlock(&root->fs_info->fs_mutex);
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 454fe8103329..4df6b1608f91 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -71,16 +71,16 @@ struct btrfs_fs_devices {
71 /* the device with this id has the most recent coyp of the super */ 71 /* the device with this id has the most recent coyp of the super */
72 u64 latest_devid; 72 u64 latest_devid;
73 u64 latest_trans; 73 u64 latest_trans;
74 u64 lowest_devid;
75 u64 num_devices; 74 u64 num_devices;
75 u64 open_devices;
76 struct block_device *latest_bdev; 76 struct block_device *latest_bdev;
77 struct block_device *lowest_bdev;
78 /* all of the devices in the FS */ 77 /* all of the devices in the FS */
79 struct list_head devices; 78 struct list_head devices;
80 79
81 /* devices not currently being allocated */ 80 /* devices not currently being allocated */
82 struct list_head alloc_list; 81 struct list_head alloc_list;
83 struct list_head list; 82 struct list_head list;
83 int mounted;
84}; 84};
85 85
86struct btrfs_bio_stripe { 86struct btrfs_bio_stripe {