Skip to content

Commit e39ed66

Browse files
raczzoliadam900710
authored andcommitted
btrfs-progs: Fixing invalid device size output when "btrfs device usage /" called as normal user
When "btrfs device usage /" is being called as a normal user, the function device_get_partition_size in device-utils.c calls device_get_partition_size_sysfs() as a fallback, which reads the size of the partition from "/sys/class/block/[partition]/size". The problem here is that the size read is not actually the size of the partition but rather a number of how many 512B (or whatever the devices sector size is) sectors the partition contains. Ex: if read value is 104857600 the size is not 100MB but 104857600 * 512B = 50GB This patch adds a function named get_partition_sector_size_sysfs which based on the partition name returns the sector size of the device, and replaces "return size" with "return size * sector_size" in device_get_partition_size_sysfs. Issue: #979 Reviewed-by: Qu Wenruo <[email protected]>
1 parent b299793 commit e39ed66

File tree

1 file changed

+53
-1
lines changed

1 file changed

+53
-1
lines changed

common/device-utils.c

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <fcntl.h>
3131
#include <dirent.h>
3232
#include <errno.h>
33+
#include <libgen.h>
3334
#include <blkid/blkid.h>
3435
#include "kernel-lib/sizes.h"
3536
#include "kernel-shared/disk-io.h"
@@ -342,6 +343,50 @@ u64 device_get_partition_size_fd(int fd)
342343
return result;
343344
}
344345

346+
static ssize_t get_partition_sector_size_sysfs(const char *name)
347+
{
348+
int ret = 0;
349+
char real_path[PATH_MAX] = {};
350+
char link_path[PATH_MAX] = {};
351+
char *dev_name = NULL;
352+
int sysfd;
353+
char sysfs[PATH_MAX] = {};
354+
char sizebuf[128];
355+
356+
snprintf(link_path, PATH_MAX, "/sys/class/block/%s/..", name);
357+
358+
if (!realpath(link_path, real_path)) {
359+
error("Failed to resolve realpath of %s: %s\n", link_path, strerror(errno));
360+
return -1;
361+
}
362+
363+
dev_name = basename(real_path);
364+
365+
if (!dev_name) {
366+
error("Failed to determine basename for path %s\n", real_path);
367+
return -1;
368+
}
369+
370+
snprintf(sysfs, PATH_MAX, "/sys/class/block/%s/queue/hw_sector_size", dev_name);
371+
372+
sysfd = open(sysfs, O_RDONLY);
373+
if (sysfd < 0) {
374+
error("Error opening %s to determine dev sector size: %s\n", real_path, strerror(errno));
375+
return -1;
376+
}
377+
378+
ret = sysfs_read_file(sysfd, sizebuf, sizeof(sizebuf));
379+
close(sysfd);
380+
381+
if (ret < 0) {
382+
error("Error reading hw_sector_size from sysfs for device %s!\n", dev_name);
383+
return -1;
384+
}
385+
386+
return atoi(sizebuf);
387+
}
388+
389+
345390
static u64 device_get_partition_size_sysfs(const char *dev)
346391
{
347392
int ret;
@@ -351,6 +396,7 @@ static u64 device_get_partition_size_sysfs(const char *dev)
351396
const char *name = NULL;
352397
int sysfd;
353398
unsigned long long size = 0;
399+
ssize_t sector_size = 0;
354400

355401
name = realpath(dev, path);
356402
if (!name)
@@ -375,7 +421,13 @@ static u64 device_get_partition_size_sysfs(const char *dev)
375421
return 0;
376422
}
377423
close(sysfd);
378-
return size;
424+
425+
sector_size = get_partition_sector_size_sysfs(name);
426+
427+
if (sector_size < 0)
428+
return 0;
429+
430+
return size * sector_size;
379431
}
380432

381433
u64 device_get_partition_size(const char *dev)

0 commit comments

Comments
 (0)