Skip to content

Commit 6d0eabe

Browse files
committed
btrfs-progs: add error handling for device_get_partition_size()
The function device_get_partition_size() has all kinds of error paths, but it has no way to return error other than returning 0. This is not helpful for end users to know what's going wrong. Change that function to return int for error code, and a dedicated u64 pointer to return the device size in bytes. All existing call sites will exit early using that error code. The only exception is load_device_info() which will only give a warning and continue. Signed-off-by: Qu Wenruo <[email protected]>
1 parent f8872b3 commit 6d0eabe

File tree

4 files changed

+40
-26
lines changed

4 files changed

+40
-26
lines changed

cmds/filesystem-usage.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -820,8 +820,14 @@ static int load_device_info(int fd, struct array *devinfos)
820820
strcpy(info->path, "missing");
821821
} else {
822822
strcpy(info->path, (char *)dev_info.path);
823-
info->device_size =
824-
device_get_partition_size((const char *)dev_info.path);
823+
ret = device_get_partition_size((const char *)dev_info.path,
824+
&info->device_size);
825+
if (ret < 0) {
826+
errno = -ret;
827+
warning("failed to get device size for %s: %m",
828+
dev_info.path);
829+
info->device_size = 0;
830+
}
825831
}
826832
info->size = dev_info.total_bytes;
827833
ndevs++;

cmds/replace.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,12 @@ static int cmd_replace_start(const struct cmd_struct *cmd,
269269
strncpy_null((char *)start_args.start.srcdev_name, srcdev,
270270
BTRFS_DEVICE_PATH_NAME_MAX + 1);
271271
start_args.start.srcdevid = 0;
272-
srcdev_size = device_get_partition_size(srcdev);
272+
ret = device_get_partition_size(srcdev, &srcdev_size);
273+
if (ret < 0) {
274+
errno = -ret;
275+
error("failed to get device size for %s: %m", srcdev);
276+
goto leave_with_error;
277+
}
273278
} else {
274279
error("source device must be a block device or a devid");
275280
goto leave_with_error;
@@ -279,7 +284,12 @@ static int cmd_replace_start(const struct cmd_struct *cmd,
279284
if (ret)
280285
goto leave_with_error;
281286

282-
dstdev_size = device_get_partition_size(dstdev);
287+
ret = device_get_partition_size(dstdev, &dstdev_size);
288+
if (ret < 0) {
289+
errno = -ret;
290+
error("failed to get device size for %s: %m", dstdev);
291+
goto leave_with_error;
292+
}
283293
if (srcdev_size > dstdev_size) {
284294
error("target device smaller than source device (required %llu bytes)",
285295
srcdev_size);

common/device-utils.c

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ u64 device_get_partition_size_fd_stat(int fd, const struct stat *st)
323323
return 0;
324324
}
325325

326-
static u64 device_get_partition_size_sysfs(const char *dev)
326+
static int device_get_partition_size_sysfs(const char *dev, u64 *size_ret)
327327
{
328328
int ret;
329329
char path[PATH_MAX] = {};
@@ -335,47 +335,45 @@ static u64 device_get_partition_size_sysfs(const char *dev)
335335

336336
name = realpath(dev, path);
337337
if (!name)
338-
return 0;
338+
return -errno;
339339
name = path_basename(path);
340340

341341
ret = path_cat3_out(sysfs, "/sys/class/block", name, "size");
342342
if (ret < 0)
343-
return 0;
343+
return ret;
344344
sysfd = open(sysfs, O_RDONLY);
345345
if (sysfd < 0)
346-
return 0;
346+
return -errno;
347347
ret = sysfs_read_file(sysfd, sizebuf, sizeof(sizebuf));
348-
if (ret < 0) {
349-
close(sysfd);
350-
return 0;
351-
}
348+
close(sysfd);
349+
if (ret < 0)
350+
return ret;
352351
errno = 0;
353352
size = strtoull(sizebuf, NULL, 10);
354-
if (size == ULLONG_MAX && errno == ERANGE) {
355-
close(sysfd);
356-
return 0;
357-
}
358-
close(sysfd);
359-
360-
/* <device>/size value is in sector (512B) unit. */
361-
return size << SECTOR_SHIFT;
353+
if (size == ULLONG_MAX && errno == ERANGE)
354+
return -ERANGE;
355+
/* Extra overflow check. */
356+
if (size > ULLONG_MAX >> SECTOR_SHIFT)
357+
return -ERANGE;
358+
*size_ret = size << SECTOR_SHIFT;
359+
return 0;
362360
}
363361

364-
u64 device_get_partition_size(const char *dev)
362+
int device_get_partition_size(const char *dev, u64 *size_ret)
365363
{
366364
u64 result;
367365
int fd = open(dev, O_RDONLY);
368366

369367
if (fd < 0)
370-
return device_get_partition_size_sysfs(dev);
368+
return device_get_partition_size_sysfs(dev, size_ret);
371369

372370
if (ioctl(fd, BLKGETSIZE64, &result) < 0) {
373371
close(fd);
374-
return 0;
372+
return -errno;
375373
}
376374
close(fd);
377-
378-
return result;
375+
*size_ret = result;
376+
return 0;
379377
}
380378

381379
/*

common/device-utils.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ enum {
4242
*/
4343
int device_discard_blocks(int fd, u64 start, u64 len);
4444
int device_zero_blocks(int fd, off_t start, size_t len, const bool direct);
45-
u64 device_get_partition_size(const char *dev);
45+
int device_get_partition_size(const char *dev, u64 *size_ret);
4646
u64 device_get_partition_size_fd_stat(int fd, const struct stat *st);
4747
int device_get_queue_param(const char *file, const char *param, char *buf, size_t len);
4848
u64 device_get_zone_unusable(int fd, u64 flags);

0 commit comments

Comments
 (0)