diff options
| -rw-r--r-- | fs/btrfs/disk-io.c | 4 | ||||
| -rw-r--r-- | fs/btrfs/volumes.c | 70 | ||||
| -rw-r--r-- | fs/btrfs/volumes.h | 4 |
3 files changed, 63 insertions, 15 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 38b0d9ecda6..264f297260f 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 43f74d17bce..501d23d3ebf 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) { |
| 177 | printk("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 | |||
| 191 | int btrfs_close_devices(struct btrfs_fs_devices *fs_devices) | 194 | int 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 | ||
| 276 | error_brelse: | ||
| 277 | brelse(bh); | ||
| 278 | error_close: | ||
| 279 | close_bdev_excl(bdev); | ||
| 280 | error: | ||
| 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; | ||
| 291 | out: | ||
| 242 | mutex_unlock(&uuid_mutex); | 292 | mutex_unlock(&uuid_mutex); |
| 243 | return 0; | ||
| 244 | fail: | ||
| 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++; | ||
| 917 | out: | 965 | out: |
| 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 454fe810332..4df6b1608f9 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 | ||
| 86 | struct btrfs_bio_stripe { | 86 | struct btrfs_bio_stripe { |
