diff options
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r-- | fs/btrfs/volumes.c | 33 |
1 files changed, 31 insertions, 2 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 0b4e2af7954d..ef41f285a475 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -459,12 +459,23 @@ int btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices) | |||
459 | { | 459 | { |
460 | struct btrfs_device *device, *next; | 460 | struct btrfs_device *device, *next; |
461 | 461 | ||
462 | struct block_device *latest_bdev = NULL; | ||
463 | u64 latest_devid = 0; | ||
464 | u64 latest_transid = 0; | ||
465 | |||
462 | mutex_lock(&uuid_mutex); | 466 | mutex_lock(&uuid_mutex); |
463 | again: | 467 | again: |
464 | /* This is the initialized path, it is safe to release the devices. */ | 468 | /* This is the initialized path, it is safe to release the devices. */ |
465 | list_for_each_entry_safe(device, next, &fs_devices->devices, dev_list) { | 469 | list_for_each_entry_safe(device, next, &fs_devices->devices, dev_list) { |
466 | if (device->in_fs_metadata) | 470 | if (device->in_fs_metadata) { |
471 | if (!latest_transid || | ||
472 | device->generation > latest_transid) { | ||
473 | latest_devid = device->devid; | ||
474 | latest_transid = device->generation; | ||
475 | latest_bdev = device->bdev; | ||
476 | } | ||
467 | continue; | 477 | continue; |
478 | } | ||
468 | 479 | ||
469 | if (device->bdev) { | 480 | if (device->bdev) { |
470 | blkdev_put(device->bdev, device->mode); | 481 | blkdev_put(device->bdev, device->mode); |
@@ -487,6 +498,10 @@ again: | |||
487 | goto again; | 498 | goto again; |
488 | } | 499 | } |
489 | 500 | ||
501 | fs_devices->latest_bdev = latest_bdev; | ||
502 | fs_devices->latest_devid = latest_devid; | ||
503 | fs_devices->latest_trans = latest_transid; | ||
504 | |||
490 | mutex_unlock(&uuid_mutex); | 505 | mutex_unlock(&uuid_mutex); |
491 | return 0; | 506 | return 0; |
492 | } | 507 | } |
@@ -1953,7 +1968,7 @@ static int btrfs_relocate_chunk(struct btrfs_root *root, | |||
1953 | em = lookup_extent_mapping(em_tree, chunk_offset, 1); | 1968 | em = lookup_extent_mapping(em_tree, chunk_offset, 1); |
1954 | read_unlock(&em_tree->lock); | 1969 | read_unlock(&em_tree->lock); |
1955 | 1970 | ||
1956 | BUG_ON(em->start > chunk_offset || | 1971 | BUG_ON(!em || em->start > chunk_offset || |
1957 | em->start + em->len < chunk_offset); | 1972 | em->start + em->len < chunk_offset); |
1958 | map = (struct map_lookup *)em->bdev; | 1973 | map = (struct map_lookup *)em->bdev; |
1959 | 1974 | ||
@@ -4356,6 +4371,20 @@ int btrfs_read_sys_array(struct btrfs_root *root) | |||
4356 | return -ENOMEM; | 4371 | return -ENOMEM; |
4357 | btrfs_set_buffer_uptodate(sb); | 4372 | btrfs_set_buffer_uptodate(sb); |
4358 | btrfs_set_buffer_lockdep_class(root->root_key.objectid, sb, 0); | 4373 | btrfs_set_buffer_lockdep_class(root->root_key.objectid, sb, 0); |
4374 | /* | ||
4375 | * The sb extent buffer is artifical and just used to read the system array. | ||
4376 | * btrfs_set_buffer_uptodate() call does not properly mark all it's | ||
4377 | * pages up-to-date when the page is larger: extent does not cover the | ||
4378 | * whole page and consequently check_page_uptodate does not find all | ||
4379 | * the page's extents up-to-date (the hole beyond sb), | ||
4380 | * write_extent_buffer then triggers a WARN_ON. | ||
4381 | * | ||
4382 | * Regular short extents go through mark_extent_buffer_dirty/writeback cycle, | ||
4383 | * but sb spans only this function. Add an explicit SetPageUptodate call | ||
4384 | * to silence the warning eg. on PowerPC 64. | ||
4385 | */ | ||
4386 | if (PAGE_CACHE_SIZE > BTRFS_SUPER_INFO_SIZE) | ||
4387 | SetPageUptodate(sb->first_page); | ||
4359 | 4388 | ||
4360 | write_extent_buffer(sb, super_copy, 0, BTRFS_SUPER_INFO_SIZE); | 4389 | write_extent_buffer(sb, super_copy, 0, BTRFS_SUPER_INFO_SIZE); |
4361 | array_size = btrfs_super_sys_array_size(super_copy); | 4390 | array_size = btrfs_super_sys_array_size(super_copy); |