On 2019/4/19 16:19, Shin'ichiro Kawasaki wrote: > 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 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.kawas...@wdc.com> > --- > lib/libf2fs_zoned.c | 101 ++++++++++++++++++++++++++++++++++++++------ > 1 file changed, 88 insertions(+), 13 deletions(-) > > diff --git a/lib/libf2fs_zoned.c b/lib/libf2fs_zoned.c > index a5f3fea..e5151c0 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) - 1,
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 - 1, "%s/%s", sysfs_path, attr); ret = snprintf(buf, buflen, ...); Thanks, > + 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; > _______________________________________________ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel