Skip to content

Commit 6f29461

Browse files
committed
btrfs-progs: detect discard ability more correctly for btrfs_prepare_device()
Instead of relying on sysfs interface which had some regression reporting the discard support, let btrfs_prepare_device() to use the discard_range() result to determine if we need to output the "Performing full device TRIM" message. This is done by checking if the first discard succeeded or not. If the first discard call succeeded, then we know the device support discard and should output the message. And to reduce the initial delay before outputting the message (old/lower end disks may take a long time even discarding 1 GiB), reduce the initial discard range to 1MiB. By this it's more reliable to detect discard support for btrfs_prepare_device() and we can get rid of discard_supported(), and the timing of the meessage should still be pretty much the same as the original one, just with a small unobservable delay. Reviewed-by: Anand Jain <[email protected]> Reported-by: Anand Jain <[email protected]> Signed-off-by: Qu Wenruo <[email protected]>
1 parent a452b1e commit 6f29461

File tree

1 file changed

+24
-30
lines changed

1 file changed

+24
-30
lines changed

common/device-utils.c

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -60,25 +60,6 @@ static int discard_range(int fd, u64 start, u64 len)
6060
return 0;
6161
}
6262

63-
static int discard_supported(const char *device)
64-
{
65-
int ret;
66-
char buf[128] = {};
67-
68-
ret = device_get_queue_param(device, "discard_granularity", buf, sizeof(buf));
69-
if (ret == 0) {
70-
pr_verbose(3, "cannot read discard_granularity for %s\n", device);
71-
return 0;
72-
} else {
73-
if (atoi(buf) == 0) {
74-
pr_verbose(3, "%s: discard_granularity %s", device, buf);
75-
return 0;
76-
}
77-
}
78-
79-
return 1;
80-
}
81-
8263
/*
8364
* Discard blocks in the given range in 1G chunks, the process is interruptible
8465
*/
@@ -99,6 +80,29 @@ int device_discard_blocks(int fd, u64 start, u64 len)
9980
return 0;
10081
}
10182

83+
static void prepare_discard_device(const char *filename, int fd, u64 byte_count, unsigned opflags)
84+
{
85+
u64 cur = 0;
86+
87+
while (cur < byte_count) {
88+
/* 1G granularity */
89+
u64 chunk_size = (cur == 0) ? SZ_1M : min_t(u64, byte_count - cur, SZ_1G);
90+
int ret;
91+
92+
ret = discard_range(fd, cur, chunk_size);
93+
if (ret)
94+
return;
95+
/*
96+
* The first range discarded successfully, meaning the device supports
97+
* discard.
98+
*/
99+
if (opflags & PREP_DEVICE_VERBOSE && cur == 0)
100+
printf("Performing full device TRIM %s (%s) ...\n",
101+
filename, pretty_size(byte_count));
102+
cur += chunk_size;
103+
}
104+
}
105+
102106
/*
103107
* Write zeros to the given range [start, start + len)
104108
*/
@@ -273,17 +277,7 @@ int btrfs_prepare_device(int fd, const char *file, u64 *byte_count_ret,
273277
}
274278
}
275279
} else if (opflags & PREP_DEVICE_DISCARD) {
276-
/*
277-
* We intentionally ignore errors from the discard ioctl. It
278-
* is not necessary for the mkfs functionality but just an
279-
* optimization.
280-
*/
281-
if (discard_supported(file)) {
282-
if (opflags & PREP_DEVICE_VERBOSE)
283-
printf("Performing full device TRIM %s (%s) ...\n",
284-
file, pretty_size(byte_count));
285-
device_discard_blocks(fd, 0, byte_count);
286-
}
280+
prepare_discard_device(file, fd, byte_count, opflags);
287281
}
288282

289283
ret = zero_dev_clamped(fd, zinfo, 0, ZERO_DEV_BYTES, byte_count);

0 commit comments

Comments
 (0)