All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] btrfs-progs: check: add the ability to reset btrfs_dev_item::bytes_used
@ 2021-06-09  6:27 Qu Wenruo
  2021-06-09  6:27 ` [PATCH 2/2] btrfs-progs: tests/fsck: add test case to make sure btrfs check can " Qu Wenruo
  2021-06-11 14:14 ` [PATCH 1/2] btrfs-progs: check: add the ability to " David Sterba
  0 siblings, 2 replies; 3+ messages in thread
From: Qu Wenruo @ 2021-06-09  6:27 UTC (permalink / raw)
  To: linux-btrfs

There is a report from the mail list that one user got its filesystem
with device item bytes_used mismatch.

This problem leaves the device item with some ghost bytes_used, meaning
even if we delete all device extents of that device, the bytes_used
still won't be 0.

This itself is not a big deal, but when the user used up all its
unallocated space, write time tree-checker can be triggered and make the
fs RO, as the new device::bytes_used can be larger than
device::total_bytes.

Thus we need to fix the problem in btrfs-check to avoid above write-time
tree check warning.

This patch will add the ability to reset a device's bytes_used to both
original mode and lowmem mode.

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 check/main.c        |  8 ++++++-
 check/mode-common.c | 57 +++++++++++++++++++++++++++++++++++++++++++++
 check/mode-common.h |  2 ++
 check/mode-lowmem.c | 14 +++++++++--
 4 files changed, 78 insertions(+), 3 deletions(-)

diff --git a/check/main.c b/check/main.c
index ee6cf793251c..6cf96b1a9b3b 100644
--- a/check/main.c
+++ b/check/main.c
@@ -8397,11 +8397,17 @@ static int check_device_used(struct device_record *dev_rec,
 	}
 
 	if (total_byte != dev_rec->byte_used) {
+		int ret = -1;
+
 		fprintf(stderr,
 			"Dev extent's total-byte(%llu) is not equal to byte-used(%llu) in dev[%llu, %u, %llu]\n",
 			total_byte, dev_rec->byte_used,	dev_rec->objectid,
 			dev_rec->type, dev_rec->offset);
-		return -1;
+		if (repair) {
+			ret = repair_dev_item_bytes_used(gfs_info,
+					dev_rec->devid, total_byte);
+		}
+		return ret;
 	} else {
 		return 0;
 	}
diff --git a/check/mode-common.c b/check/mode-common.c
index cb22f3233c00..5764bf6ee54c 100644
--- a/check/mode-common.c
+++ b/check/mode-common.c
@@ -21,6 +21,7 @@
 #include "kernel-shared/transaction.h"
 #include "common/utils.h"
 #include "kernel-shared/disk-io.h"
+#include "kernel-shared/volumes.h"
 #include "common/repair.h"
 #include "check/mode-common.h"
 
@@ -1243,3 +1244,59 @@ out:
 	btrfs_release_path(&path);
 	return ret;
 }
+
+int repair_dev_item_bytes_used(struct btrfs_fs_info *fs_info,
+			       u64 devid, u64 bytes_used_expected)
+{
+	struct btrfs_trans_handle *trans;
+	struct btrfs_device *device;
+	int ret;
+
+	device = btrfs_find_device_by_devid(fs_info->fs_devices, devid, 0);
+	if (!device) {
+		error("failed to find device with devid %llu", devid);
+		return -ENOENT;
+	}
+
+	/* Bytes_used matches, not what we can repair */
+	if (device->bytes_used == bytes_used_expected)
+		return -ENOTSUP;
+
+	/*
+	 * We have to set the device bytes used right now, before
+	 * starting a new transaction, as it may allocate new chunk and
+	 * modify device->bytes_used.
+	 */
+	device->bytes_used = bytes_used_expected;
+	trans = btrfs_start_transaction(fs_info->chunk_root, 1);
+	if (IS_ERR(trans)) {
+		ret = PTR_ERR(trans);
+		errno = -ret;
+		error("failed to start transaction: %d (\"%m\")", ret);
+		return ret;
+	}
+
+	/* Manually update the device item in chunk tree */
+	ret = btrfs_update_device(trans, device);
+	if (ret < 0) {
+		error(
+		"failed to update device item for devid %llu: %d (\"%m\")",
+		      devid, ret);
+		goto error;
+	}
+
+	/*
+	 * Commit transaction not only to save above change but also update
+	 * the device item in super block.
+	 */
+	ret = btrfs_commit_transaction(trans, fs_info->chunk_root);
+	if (ret < 0)
+		error("failed to commit transaction: %d (\"%m\")", ret);
+	else
+		printf("reset devid %llu bytes_used to %llu\n", devid,
+		       device->bytes_used);
+	return ret;
+error:
+	btrfs_abort_transaction(trans, ret);
+	return ret;
+}
diff --git a/check/mode-common.h b/check/mode-common.h
index 3ba29ecab6cd..711eced3acf0 100644
--- a/check/mode-common.h
+++ b/check/mode-common.h
@@ -192,4 +192,6 @@ static inline void btrfs_check_subpage_eb_alignment(u64 start, u32 len)
 			start, start + len);
 }
 
+int repair_dev_item_bytes_used(struct btrfs_fs_info *fs_info,
+			       u64 devid, u64 bytes_used_expected);
 #endif
diff --git a/check/mode-lowmem.c b/check/mode-lowmem.c
index 2f736712bc7f..64f09e68516c 100644
--- a/check/mode-lowmem.c
+++ b/check/mode-lowmem.c
@@ -4454,7 +4454,8 @@ out:
 /*
  * Check if the used space is correct with the dev item
  */
-static int check_dev_item(struct extent_buffer *eb, int slot)
+static int check_dev_item(struct extent_buffer *eb, int slot,
+			  u64 *bytes_used_expected)
 {
 	struct btrfs_root *dev_root = gfs_info->dev_root;
 	struct btrfs_dev_item *dev_item;
@@ -4543,6 +4544,7 @@ next:
 	}
 	btrfs_release_path(&path);
 
+	*bytes_used_expected = total;
 	if (used != total) {
 		btrfs_item_key_to_cpu(eb, &key, slot);
 		error(
@@ -4744,6 +4746,7 @@ static int repair_chunk_item(struct btrfs_root *chunk_root,
 static int check_leaf_items(struct btrfs_root *root, struct btrfs_path *path,
 			    struct node_refs *nrefs, int account_bytes)
 {
+	u64 bytes_used_expected = (u64)-1;
 	struct btrfs_key key;
 	struct extent_buffer *eb;
 	int slot;
@@ -4782,7 +4785,14 @@ again:
 		err |= ret;
 		break;
 	case BTRFS_DEV_ITEM_KEY:
-		ret = check_dev_item(eb, slot);
+		ret = check_dev_item(eb, slot, &bytes_used_expected);
+		if (repair && ret & ACCOUNTING_MISMATCH &&
+		    bytes_used_expected != (u64)-1) {
+			ret = repair_dev_item_bytes_used(root->fs_info,
+					key.offset, bytes_used_expected);
+			if (ret < 0)
+				ret = ACCOUNTING_MISMATCH;
+		}
 		err |= ret;
 		break;
 	case BTRFS_CHUNK_ITEM_KEY:
-- 
2.32.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH 2/2] btrfs-progs: tests/fsck: add test case to make sure btrfs check can reset btrfs_dev_item::bytes_used
  2021-06-09  6:27 [PATCH 1/2] btrfs-progs: check: add the ability to reset btrfs_dev_item::bytes_used Qu Wenruo
@ 2021-06-09  6:27 ` Qu Wenruo
  2021-06-11 14:14 ` [PATCH 1/2] btrfs-progs: check: add the ability to " David Sterba
  1 sibling, 0 replies; 3+ messages in thread
From: Qu Wenruo @ 2021-06-09  6:27 UTC (permalink / raw)
  To: linux-btrfs

The test image is manually crafted with 1MiB offset in the device item
of devid 1.

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 .../047-dev-bytes-used/.lowmem_repairable        |   0
 .../047-dev-bytes-used/default_case.img.xz       | Bin 0 -> 1896 bytes
 2 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 tests/fsck-tests/047-dev-bytes-used/.lowmem_repairable
 create mode 100644 tests/fsck-tests/047-dev-bytes-used/default_case.img.xz

diff --git a/tests/fsck-tests/047-dev-bytes-used/.lowmem_repairable b/tests/fsck-tests/047-dev-bytes-used/.lowmem_repairable
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/fsck-tests/047-dev-bytes-used/default_case.img.xz b/tests/fsck-tests/047-dev-bytes-used/default_case.img.xz
new file mode 100644
index 0000000000000000000000000000000000000000..28100c185cb6f6f3ec342434e9605b6faea135af
GIT binary patch
literal 1896
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

literal 0
HcmV?d00001

-- 
2.32.0


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH 1/2] btrfs-progs: check: add the ability to reset btrfs_dev_item::bytes_used
  2021-06-09  6:27 [PATCH 1/2] btrfs-progs: check: add the ability to reset btrfs_dev_item::bytes_used Qu Wenruo
  2021-06-09  6:27 ` [PATCH 2/2] btrfs-progs: tests/fsck: add test case to make sure btrfs check can " Qu Wenruo
@ 2021-06-11 14:14 ` David Sterba
  1 sibling, 0 replies; 3+ messages in thread
From: David Sterba @ 2021-06-11 14:14 UTC (permalink / raw)
  To: Qu Wenruo; +Cc: linux-btrfs

On Wed, Jun 09, 2021 at 02:27:42PM +0800, Qu Wenruo wrote:
> There is a report from the mail list that one user got its filesystem
> with device item bytes_used mismatch.
> 
> This problem leaves the device item with some ghost bytes_used, meaning
> even if we delete all device extents of that device, the bytes_used
> still won't be 0.
> 
> This itself is not a big deal, but when the user used up all its
> unallocated space, write time tree-checker can be triggered and make the
> fs RO, as the new device::bytes_used can be larger than
> device::total_bytes.
> 
> Thus we need to fix the problem in btrfs-check to avoid above write-time
> tree check warning.
> 
> This patch will add the ability to reset a device's bytes_used to both
> original mode and lowmem mode.
> 
> Signed-off-by: Qu Wenruo <wqu@suse.com>

Added to devel, with some fixups, thanks.

> ---
>  check/main.c        |  8 ++++++-
>  check/mode-common.c | 57 +++++++++++++++++++++++++++++++++++++++++++++
>  check/mode-common.h |  2 ++
>  check/mode-lowmem.c | 14 +++++++++--
>  4 files changed, 78 insertions(+), 3 deletions(-)
> 
> diff --git a/check/main.c b/check/main.c
> index ee6cf793251c..6cf96b1a9b3b 100644
> --- a/check/main.c
> +++ b/check/main.c
> @@ -8397,11 +8397,17 @@ static int check_device_used(struct device_record *dev_rec,
>  	}
>  
>  	if (total_byte != dev_rec->byte_used) {
> +		int ret = -1;
> +
>  		fprintf(stderr,
>  			"Dev extent's total-byte(%llu) is not equal to byte-used(%llu) in dev[%llu, %u, %llu]\n",
>  			total_byte, dev_rec->byte_used,	dev_rec->objectid,
>  			dev_rec->type, dev_rec->offset);
> -		return -1;
> +		if (repair) {
> +			ret = repair_dev_item_bytes_used(gfs_info,
> +					dev_rec->devid, total_byte);
> +		}
> +		return ret;
>  	} else {
>  		return 0;
>  	}
> diff --git a/check/mode-common.c b/check/mode-common.c
> index cb22f3233c00..5764bf6ee54c 100644
> --- a/check/mode-common.c
> +++ b/check/mode-common.c
> @@ -21,6 +21,7 @@
>  #include "kernel-shared/transaction.h"
>  #include "common/utils.h"
>  #include "kernel-shared/disk-io.h"
> +#include "kernel-shared/volumes.h"
>  #include "common/repair.h"
>  #include "check/mode-common.h"
>  
> @@ -1243,3 +1244,59 @@ out:
>  	btrfs_release_path(&path);
>  	return ret;
>  }
> +
> +int repair_dev_item_bytes_used(struct btrfs_fs_info *fs_info,
> +			       u64 devid, u64 bytes_used_expected)
> +{
> +	struct btrfs_trans_handle *trans;
> +	struct btrfs_device *device;
> +	int ret;
> +
> +	device = btrfs_find_device_by_devid(fs_info->fs_devices, devid, 0);
> +	if (!device) {
> +		error("failed to find device with devid %llu", devid);
> +		return -ENOENT;
> +	}
> +
> +	/* Bytes_used matches, not what we can repair */
> +	if (device->bytes_used == bytes_used_expected)
> +		return -ENOTSUP;
> +
> +	/*
> +	 * We have to set the device bytes used right now, before
> +	 * starting a new transaction, as it may allocate new chunk and
> +	 * modify device->bytes_used.
> +	 */
> +	device->bytes_used = bytes_used_expected;
> +	trans = btrfs_start_transaction(fs_info->chunk_root, 1);
> +	if (IS_ERR(trans)) {
> +		ret = PTR_ERR(trans);
> +		errno = -ret;
> +		error("failed to start transaction: %d (\"%m\")", ret);

It's enough to print just %m.

> +		return ret;
> +	}
> +
> +	/* Manually update the device item in chunk tree */
> +	ret = btrfs_update_device(trans, device);
> +	if (ret < 0) {
> +		error(
> +		"failed to update device item for devid %llu: %d (\"%m\")",
> +		      devid, ret);
> +		goto error;
> +	}
> +
> +	/*
> +	 * Commit transaction not only to save above change but also update
> +	 * the device item in super block.
> +	 */
> +	ret = btrfs_commit_transaction(trans, fs_info->chunk_root);
> +	if (ret < 0)
> +		error("failed to commit transaction: %d (\"%m\")", ret);

But when %m is used, errno must be set li

		errno = -ret;
		error("... %m");

> +	else
> +		printf("reset devid %llu bytes_used to %llu\n", devid,
> +		       device->bytes_used);
> +	return ret;
> +error:
> +	btrfs_abort_transaction(trans, ret);
> +	return ret;
> +}
> diff --git a/check/mode-common.h b/check/mode-common.h
> index 3ba29ecab6cd..711eced3acf0 100644
> --- a/check/mode-common.h
> +++ b/check/mode-common.h
> @@ -192,4 +192,6 @@ static inline void btrfs_check_subpage_eb_alignment(u64 start, u32 len)
>  			start, start + len);
>  }
>  
> +int repair_dev_item_bytes_used(struct btrfs_fs_info *fs_info,
> +			       u64 devid, u64 bytes_used_expected);
>  #endif
> diff --git a/check/mode-lowmem.c b/check/mode-lowmem.c
> index 2f736712bc7f..64f09e68516c 100644
> --- a/check/mode-lowmem.c
> +++ b/check/mode-lowmem.c
> @@ -4454,7 +4454,8 @@ out:
>  /*
>   * Check if the used space is correct with the dev item
>   */
> -static int check_dev_item(struct extent_buffer *eb, int slot)
> +static int check_dev_item(struct extent_buffer *eb, int slot,
> +			  u64 *bytes_used_expected)
>  {
>  	struct btrfs_root *dev_root = gfs_info->dev_root;
>  	struct btrfs_dev_item *dev_item;
> @@ -4543,6 +4544,7 @@ next:
>  	}
>  	btrfs_release_path(&path);
>  
> +	*bytes_used_expected = total;
>  	if (used != total) {
>  		btrfs_item_key_to_cpu(eb, &key, slot);
>  		error(
> @@ -4744,6 +4746,7 @@ static int repair_chunk_item(struct btrfs_root *chunk_root,
>  static int check_leaf_items(struct btrfs_root *root, struct btrfs_path *path,
>  			    struct node_refs *nrefs, int account_bytes)
>  {
> +	u64 bytes_used_expected = (u64)-1;
>  	struct btrfs_key key;
>  	struct extent_buffer *eb;
>  	int slot;
> @@ -4782,7 +4785,14 @@ again:
>  		err |= ret;
>  		break;
>  	case BTRFS_DEV_ITEM_KEY:
> -		ret = check_dev_item(eb, slot);
> +		ret = check_dev_item(eb, slot, &bytes_used_expected);
> +		if (repair && ret & ACCOUNTING_MISMATCH &&
> +		    bytes_used_expected != (u64)-1) {
> +			ret = repair_dev_item_bytes_used(root->fs_info,
> +					key.offset, bytes_used_expected);
> +			if (ret < 0)
> +				ret = ACCOUNTING_MISMATCH;
> +		}
>  		err |= ret;
>  		break;
>  	case BTRFS_CHUNK_ITEM_KEY:
> -- 
> 2.32.0

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2021-06-11 14:17 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-09  6:27 [PATCH 1/2] btrfs-progs: check: add the ability to reset btrfs_dev_item::bytes_used Qu Wenruo
2021-06-09  6:27 ` [PATCH 2/2] btrfs-progs: tests/fsck: add test case to make sure btrfs check can " Qu Wenruo
2021-06-11 14:14 ` [PATCH 1/2] btrfs-progs: check: add the ability to " David Sterba

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.