Btrfs: fix wrong device bytes_used in the super block
authorMiao Xie <miaox@cn.fujitsu.com>
Wed, 3 Sep 2014 13:35:34 +0000 (21:35 +0800)
committerChris Mason <clm@fb.com>
Wed, 17 Sep 2014 20:38:34 +0000 (13:38 -0700)
device->bytes_used will be changed when allocating a new chunk, and
disk_total_size will be changed if resizing is successful.
Meanwhile, the on-disk super blocks of the previous transaction
might not be updated. Considering the consistency of the metadata
in the previous transaction, We should use the size in the previous
transaction to check if the super block is beyond the boundary
of the device.

Though it is not big problem because we don't use it now, but anyway
it is better that we make it be consistent with the common metadata,
maybe we will use it in the future.

Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
Signed-off-by: Chris Mason <clm@fb.com>
fs/btrfs/dev-replace.c
fs/btrfs/disk-io.c
fs/btrfs/transaction.c
fs/btrfs/volumes.c
fs/btrfs/volumes.h

index 7877b0fc6a8d52cb94acb2ce80ba7adec632852b..1be03d85d2672e9f533b1a8bae42f5029d3c3d59 100644 (file)
@@ -172,6 +172,8 @@ no_valid_dev_replace_entry_found:
                                        dev_replace->srcdev->commit_total_bytes;
                                dev_replace->tgtdev->bytes_used =
                                        dev_replace->srcdev->bytes_used;
+                               dev_replace->tgtdev->commit_bytes_used =
+                                       dev_replace->srcdev->commit_bytes_used;
                        }
                        dev_replace->tgtdev->is_tgtdev_for_dev_replace = 1;
                        btrfs_init_dev_replace_tgtdev_for_resume(fs_info,
@@ -558,6 +560,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
        ASSERT(list_empty(&src_device->resized_list));
        tgt_device->commit_total_bytes = src_device->commit_total_bytes;
        tgt_device->bytes_used = src_device->bytes_used;
+       tgt_device->commit_bytes_used = src_device->bytes_used;
        if (fs_info->sb->s_bdev == src_device->bdev)
                fs_info->sb->s_bdev = tgt_device->bdev;
        if (fs_info->fs_devices->latest_bdev == src_device->bdev)
index 0cd18b7255540a6d163c1dd621f85e2de032f4e5..a224fb9b34a331b9a87fb896710f2ee66474ba81 100644 (file)
@@ -3446,7 +3446,8 @@ static int write_all_supers(struct btrfs_root *root, int max_mirrors)
                btrfs_set_stack_device_id(dev_item, dev->devid);
                btrfs_set_stack_device_total_bytes(dev_item,
                                                   dev->commit_total_bytes);
-               btrfs_set_stack_device_bytes_used(dev_item, dev->bytes_used);
+               btrfs_set_stack_device_bytes_used(dev_item,
+                                                 dev->commit_bytes_used);
                btrfs_set_stack_device_io_align(dev_item, dev->io_align);
                btrfs_set_stack_device_io_width(dev_item, dev->io_width);
                btrfs_set_stack_device_sector_size(dev_item, dev->sector_size);
index 2f7c0bef404379d99be9030aa3ba0820e37f71ff..16d0c1b62b3ef2eec7e225451327cafe89994e10 100644 (file)
@@ -1869,6 +1869,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
               sizeof(*root->fs_info->super_copy));
 
        btrfs_update_commit_device_size(root->fs_info);
+       btrfs_update_commit_device_bytes_used(root, cur_trans);
 
        spin_lock(&root->fs_info->trans_lock);
        cur_trans->state = TRANS_STATE_UNBLOCKED;
index 7b5c04259a6e89d069e01aa0bc7b30d96696baef..f8273bb53b3faaabbaab978003dab81f46513399 100644 (file)
@@ -2370,6 +2370,7 @@ int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path,
        ASSERT(list_empty(&srcdev->resized_list));
        device->commit_total_bytes = srcdev->commit_total_bytes;
        device->bytes_used = srcdev->bytes_used;
+       device->commit_bytes_used = device->bytes_used;
        device->dev_root = fs_info->dev_root;
        device->bdev = bdev;
        device->in_fs_metadata = 1;
@@ -6009,6 +6010,7 @@ static void fill_device_from_item(struct extent_buffer *leaf,
        device->total_bytes = device->disk_total_bytes;
        device->commit_total_bytes = device->disk_total_bytes;
        device->bytes_used = btrfs_device_bytes_used(leaf, dev_item);
+       device->commit_bytes_used = device->bytes_used;
        device->type = btrfs_device_type(leaf, dev_item);
        device->io_align = btrfs_device_io_align(leaf, dev_item);
        device->io_width = btrfs_device_io_width(leaf, dev_item);
@@ -6558,3 +6560,28 @@ void btrfs_update_commit_device_size(struct btrfs_fs_info *fs_info)
        unlock_chunks(fs_info->dev_root);
        mutex_unlock(&fs_devices->device_list_mutex);
 }
+
+/* Must be invoked during the transaction commit */
+void btrfs_update_commit_device_bytes_used(struct btrfs_root *root,
+                                       struct btrfs_transaction *transaction)
+{
+       struct extent_map *em;
+       struct map_lookup *map;
+       struct btrfs_device *dev;
+       int i;
+
+       if (list_empty(&transaction->pending_chunks))
+               return;
+
+       /* In order to kick the device replace finish process */
+       lock_chunks(root);
+       list_for_each_entry(em, &transaction->pending_chunks, list) {
+               map = (struct map_lookup *)em->bdev;
+
+               for (i = 0; i < map->num_stripes; i++) {
+                       dev = map->stripes[i].dev;
+                       dev->commit_bytes_used = dev->bytes_used;
+               }
+       }
+       unlock_chunks(root);
+}
index b30d018fa3594c28ba2ff4dbbf8ac47b4e050f77..f79d532fedb059801a8f96043bb96b1a300cd7e6 100644 (file)
@@ -95,6 +95,8 @@ struct btrfs_device {
         */
        u64 commit_total_bytes;
 
+       /* bytes used on the current transaction */
+       u64 commit_bytes_used;
        /*
         * used to manage the device which is resized
         *
@@ -420,4 +422,6 @@ static inline void btrfs_dev_stat_reset(struct btrfs_device *dev,
 }
 
 void btrfs_update_commit_device_size(struct btrfs_fs_info *fs_info);
+void btrfs_update_commit_device_bytes_used(struct btrfs_root *root,
+                                       struct btrfs_transaction *transaction);
 #endif