aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>2019-04-22 11:04:24 +0900
committerJaegeuk Kim <jaegeuk@kernel.org>2019-08-20 11:23:51 -0700
commit19ca76f101594844afaecc65a1d2c69095433712 (patch)
tree7225b772b59bde826d8e5b36cbec9696e8804448
parent7d4480baa9ec8e695ce0e223fbc2996387bf7f6c (diff)
downloadf2fs-tools-19ca76f101594844afaecc65a1d2c69095433712.tar.gz
f2fs-tools: Fix device zoned model detection
A partition device does not have the "zoned" nor "chunk_sectors" sysfs attribute files. Only the owner block device of the partition has these files. This causes the detection of the zoned model and zone size of a partition device to fail when executing mkfs.f2fs. Fix this problem by using the owner device sysfs directory as the base directory for accessing the zoned and chunk_sectors files. This is done by using the device major:minor symbolic link under the /sys/dev/block directory, reading this link and removing the partition device name from the link path for a partition device (which is indicated by the presence of the "partition" file under the directory). Also add a check for the ENOENT error when opening the device "zoned" sysfs attribute file. The absence of this file indicates that the kernel does not support zoned block devices. Since the device file is already open, it exists, and so the device can safely be assumed as not being zoned. Changes from v2: * Addressed Chao Yu's comment on snprintf buffer length Changes from v1: * Addressed Chao Yu's comment on ENOENT and return value checks * Rewrite of sysfs file handling (simplified) * Rebased on dev-test tree Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com> Reviewed-by: Chao Yu <yuchao0@huawei.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-rw-r--r--lib/libf2fs_zoned.c101
1 files changed, 88 insertions, 13 deletions
diff --git a/lib/libf2fs_zoned.c b/lib/libf2fs_zoned.c
index a5f3fea..af00b44 100644
--- a/lib/libf2fs_zoned.c
+++ b/lib/libf2fs_zoned.c
@@ -8,6 +8,7 @@
*/
#define _LARGEFILE64_SOURCE
+#include <f2fs_fs.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -15,6 +16,12 @@
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
+#ifdef HAVE_SYS_SYSMACROS_H
+#include <sys/sysmacros.h>
+#endif
+#ifdef HAVE_LINUX_LIMITS_H
+#include <linux/limits.h>
+#endif
#ifndef ANDROID_WINDOWS_HOST
#include <sys/ioctl.h>
#endif
@@ -24,27 +31,92 @@
#ifdef HAVE_LINUX_BLKZONED_H
+int get_sysfs_path(struct device_info *dev, const char *attr,
+ char *buf, size_t buflen)
+{
+ struct stat statbuf;
+ char str[PATH_MAX];
+ char sysfs_path[PATH_MAX];
+ ssize_t len;
+ char *delim;
+ int ret;
+
+ if (stat(dev->path, &statbuf) < 0)
+ return -1;
+
+ snprintf(str, sizeof(str), "/sys/dev/block/%d:%d",
+ major(statbuf.st_rdev), minor(statbuf.st_rdev));
+ len = readlink(str, buf, buflen - 1);
+ if (len < 0)
+ return -1;
+ buf[len] = '\0';
+
+ ret = snprintf(sysfs_path, sizeof(sysfs_path),
+ "/sys/dev/block/%s", buf);
+ if (ret >= sizeof(sysfs_path))
+ return -1;
+
+ /* Test if the device is a partition */
+ ret = snprintf(str, sizeof(str), "%s/partition", sysfs_path);
+ if (ret >= sizeof(str))
+ return -1;
+ ret = stat(str, &statbuf);
+ if (ret) {
+ if (errno == ENOENT) {
+ /* Not a partition */
+ goto out;
+ }
+ return -1;
+ }
+
+ /*
+ * The device is a partition: remove the device name from the
+ * attribute file path to obtain the sysfs path of the holder device.
+ * e.g.: /sys/dev/block/.../sda/sda1 -> /sys/dev/block/.../sda
+ */
+ delim = strrchr(sysfs_path, '/');
+ if (!delim)
+ return -1;
+ *delim = '\0';
+
+out:
+ ret = snprintf(buf, buflen, "%s/%s", sysfs_path, attr);
+ if (ret >= buflen)
+ return -1;
+
+ return 0;
+}
+
int f2fs_get_zoned_model(int i)
{
struct device_info *dev = c.devices + i;
- char str[128];
+ char str[PATH_MAX];
FILE *file;
int res;
/* Check that this is a zoned block device */
- snprintf(str, sizeof(str),
- "/sys/block/%s/queue/zoned",
- basename(dev->path));
+ res = get_sysfs_path(dev, "queue/zoned", str, sizeof(str));
+ if (res != 0) {
+ MSG(0, "\tError: Failed to get device sysfs path\n");
+ return -1;
+ }
+
file = fopen(str, "r");
if (!file) {
/*
* The kernel does not support zoned block devices, but we have
- * a block device file. This means that the device is not zoned
- * or is zoned but can be randomly written (i.e. host-aware
- * zoned model). Treat the device as a regular block device.
+ * a block device file. This means that if the zoned file is
+ * not found, then the device is not zoned or is zoned but can
+ * be randomly written (i.e. host-aware zoned model).
+ * Treat the device as a regular block device. Otherwise, signal
+ * the failure to verify the disk zone model.
*/
- dev->zoned_model = F2FS_ZONED_NONE;
- return 0;
+ if (errno == ENOENT) {
+ dev->zoned_model = F2FS_ZONED_NONE;
+ return 0;
+ }
+ MSG(0, "\tError: Failed to check the device zoned model\n");
+ return -1;
}
memset(str, 0, sizeof(str));
@@ -77,16 +149,19 @@ int f2fs_get_zone_blocks(int i)
{
struct device_info *dev = c.devices + i;
uint64_t sectors;
- char str[128];
+ char str[PATH_MAX];
FILE *file;
int res;
/* Get zone size */
dev->zone_blocks = 0;
- snprintf(str, sizeof(str),
- "/sys/block/%s/queue/chunk_sectors",
- basename(dev->path));
+ res = get_sysfs_path(dev, "queue/chunk_sectors", str, sizeof(str));
+ if (res != 0) {
+ MSG(0, "\tError: Failed to get device sysfs attribute path\n");
+ return -1;
+ }
+
file = fopen(str, "r");
if (!file)
return -1;