diff --git a/tools/lkl/cptofs.c b/tools/lkl/cptofs.c index 37133c7f8f11ad..f4638bfdd317d2 100644 --- a/tools/lkl/cptofs.c +++ b/tools/lkl/cptofs.c @@ -23,6 +23,7 @@ static const char args_doc_cpfromfs[] = "-t fstype -i fsimage fs_path path"; static struct argp_option options[] = { {"enable-printk", 'p', 0, 0, "show Linux printks"}, + {"partition", 'P', "int", 0, "partition number"}, {"filesystem-type", 't', "string", 0, "select filesystem type - mandatory"}, {"filesystem-image", 'i', "string", 0, @@ -33,6 +34,7 @@ static struct argp_option options[] = { static struct cl_args { int printk; + int part; const char *fsimg_type; const char *fsimg_path; const char *src_path; @@ -50,6 +52,9 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) case 'p': cla->printk = 1; break; + case 'P': + cla->part = atoi(arg); + break; case 't': cla->fsimg_type = arg; break; @@ -435,7 +440,8 @@ int main(int argc, char **argv) lkl_start_kernel(&lkl_host_ops, 100 * 1024 * 1024, ""); - ret = lkl_mount_dev(disk_id, cla.fsimg_type, cptofs ? 0 : LKL_MS_RDONLY, + ret = lkl_mount_dev(disk_id, cla.part, cla.fsimg_type, + cptofs ? 0 : LKL_MS_RDONLY, NULL, mpoint, sizeof(mpoint)); if (ret) { fprintf(stderr, "can't mount disk: %s\n", lkl_strerror(ret)); @@ -457,7 +463,7 @@ int main(int argc, char **argv) ret = searchdir(src_path_dir, dst_path, src_path_base); - ret = lkl_umount_dev(disk_id, 0, 1000); + ret = lkl_umount_dev(disk_id, cla.part, 0, 1000); out_close: close(disk.fd); diff --git a/tools/lkl/fs2tar.c b/tools/lkl/fs2tar.c index 211bf0f58ad996..cc701a5c97e203 100644 --- a/tools/lkl/fs2tar.c +++ b/tools/lkl/fs2tar.c @@ -20,6 +20,7 @@ char doc[] = ""; char args_doc[] = "-t fstype fsimage_path tar_path"; static struct argp_option options[] = { {"enable-printk", 'p', 0, 0, "show Linux printks"}, + {"partition", 'P', "int", 0, "partition number"}, {"filesystem-type", 't', "string", 0, "select filesystem type - mandatory"}, {"selinux-contexts", 's', "file", 0, @@ -29,6 +30,7 @@ static struct argp_option options[] = { static struct cl_args { int printk; + int part; const char *fsimg_type; const char *fsimg_path; const char *tar_path; @@ -43,6 +45,9 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) case 'p': cla->printk = 1; break; + case 'P': + cla->part = atoi(arg); + break; case 't': cla->fsimg_type = arg; break; @@ -362,8 +367,8 @@ int main(int argc, char **argv) lkl_start_kernel(&lkl_host_ops, 10 * 1024 * 1024, ""); - ret = lkl_mount_dev(disk_id, cla.fsimg_type, LKL_MS_RDONLY, NULL, - mpoint, sizeof(mpoint)); + ret = lkl_mount_dev(disk_id, cla.part, cla.fsimg_type, LKL_MS_RDONLY, + NULL, mpoint, sizeof(mpoint)); if (ret) { fprintf(stderr, "can't mount disk: %s\n", lkl_strerror(ret)); goto out_close; @@ -388,7 +393,7 @@ int main(int argc, char **argv) fclose(cla.selinux); out_umount: - lkl_umount_dev(disk_id, 0, 1000); + lkl_umount_dev(disk_id, cla.part, 0, 1000); out_close: close(disk.fd); diff --git a/tools/lkl/include/lkl.h b/tools/lkl/include/lkl.h index 3738c561da11a7..080cea33d24874 100644 --- a/tools/lkl/include/lkl.h +++ b/tools/lkl/include/lkl.h @@ -112,15 +112,17 @@ int lkl_disk_add(struct lkl_disk *disk); int lkl_disk_remove(struct lkl_disk disk); /** - * lkl_get_virtio_blkdev - get device id of a disk + * lkl_get_virtio_blkdev - get device id of a disk (partition) * * This function returns the device id for the given disk. * * @disk_id - the disk id identifying the disk + * @part - disk partition or zero for full disk * @pdevid - pointer to memory where dev id will be returned * @returns - 0 on success, a negative value on error */ -int lkl_get_virtio_blkdev(int disk_id, uint32_t *pdevid); +int lkl_get_virtio_blkdev(int disk_id, unsigned int part, uint32_t *pdevid); + /** * lkl_mount_dev - mount a disk @@ -129,6 +131,7 @@ int lkl_get_virtio_blkdev(int disk_id, uint32_t *pdevid); * point and mounts the device over the mount point. * * @disk_id - the disk id identifying the disk to be mounted + * @part - disk partition or zero for full disk * @fs_type - filesystem type * @flags - mount flags * @opts - additional filesystem specific mount options @@ -137,8 +140,9 @@ int lkl_get_virtio_blkdev(int disk_id, uint32_t *pdevid); * @mnt_str_len - size of mnt_str * @returns - 0 on success, a negative value on error */ -long lkl_mount_dev(unsigned int disk_id, const char *fs_type, int flags, - const char *opts, char *mnt_str, unsigned int mnt_str_len); +long lkl_mount_dev(unsigned int disk_id, unsigned int part, const char *fs_type, + int flags, const char *opts, + char *mnt_str, unsigned int mnt_str_len); /** * lkl_umount_dev - umount a disk @@ -147,12 +151,14 @@ long lkl_mount_dev(unsigned int disk_id, const char *fs_type, int flags, * mount point. * * @disk_id - the disk id identifying the disk to be mounted + * @part - disk partition or zero for full disk * @flags - umount flags * @timeout_ms - timeout to wait for the kernel to flush closed files so that * umount can succeed * @returns - 0 on success, a negative value on error */ -long lkl_umount_dev(unsigned int disk_id, int flags, long timeout_ms); +long lkl_umount_dev(unsigned int disk_id, unsigned int part, int flags, + long timeout_ms); /** * lkl_umount_timeout - umount filesystem with timeout diff --git a/tools/lkl/lib/fs.c b/tools/lkl/lib/fs.c index 43fcf4fd05b163..b56a5a3d29dc4e 100644 --- a/tools/lkl/lib/fs.c +++ b/tools/lkl/lib/fs.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -42,83 +43,43 @@ static int startswith(const char *str, const char *pre) return strncmp(pre, str, strlen(pre)) == 0; } -static char *get_node_with_prefix(const char *path, const char *prefix, - int *ret) +static int get_node_with_prefix(const char *path, const char *prefix, + char *result, unsigned int result_len) { struct lkl_dir *dir = NULL; struct lkl_linux_dirent64 *dirent; - char *result = NULL; + int ret; - dir = lkl_opendir(path, ret); + dir = lkl_opendir(path, &ret); if (!dir) - return NULL; + return ret; + + ret = -LKL_ENOENT; while ((dirent = lkl_readdir(dir))) { if (startswith(dirent->d_name, prefix)) { - result = lkl_host_ops.mem_alloc(strlen(dirent->d_name) + 1); + if (strlen(dirent->d_name) + 1 > result_len) { + ret = -LKL_ENOMEM; + break; + } memcpy(result, dirent->d_name, strlen(dirent->d_name)); result[strlen(dirent->d_name)] = '\0'; + ret = 0; break; } } - lkl_closedir(dir); - if (!result) - *ret = -LKL_ENOENT; + lkl_closedir(dir); - return result; + return ret; } -int lkl_get_virtio_blkdev(int disk_id, uint32_t *pdevid) +static int encode_dev_from_sysfs(const char *sysfs_path, uint32_t *pdevid) { - char sysfs_path[LKL_PATH_MAX]; - int sysfs_path_len = 0; - char buf[16] = { 0, }; - long fd, ret = 0; + int ret; + long fd; int major, minor; - int opendir_ret; - char *virtio_name = NULL; - char *disk_name = NULL; - uint32_t device_id; - - if (disk_id < 0) - return -LKL_EINVAL; - - ret = lkl_mount_fs("sysfs"); - if (ret < 0) - return ret; - - if ((uint32_t) disk_id >= virtio_get_num_bootdevs()) - ret = snprintf(sysfs_path, sizeof(sysfs_path), "/sysfs/devices/platform/virtio-mmio.%d.auto", - disk_id - virtio_get_num_bootdevs()); - else - ret = snprintf(sysfs_path, sizeof(sysfs_path), "/sysfs/devices/virtio-mmio-cmdline/virtio-mmio.%d", - disk_id); - if (ret < 0 || (size_t) ret >= sizeof(sysfs_path)) - return -LKL_ENOMEM; - sysfs_path_len += ret; - - virtio_name = get_node_with_prefix(sysfs_path, "virtio", &opendir_ret); - if (!virtio_name) - return (long)opendir_ret; - - ret = snprintf(sysfs_path + sysfs_path_len, sizeof(sysfs_path) - sysfs_path_len, "/%s/block", - virtio_name); - lkl_host_ops.mem_free(virtio_name); - if (ret < 0 || (size_t) ret >= sizeof(sysfs_path) - sysfs_path_len) - return -LKL_ENOMEM; - sysfs_path_len += ret; - - disk_name = get_node_with_prefix(sysfs_path, "vd", &opendir_ret); - if (!disk_name) - return (long)opendir_ret; - - ret = snprintf(sysfs_path + sysfs_path_len, sizeof(sysfs_path) - sysfs_path_len, "/%s/dev", - disk_name); - lkl_host_ops.mem_free(disk_name); - if (ret < 0 || (size_t) ret >= sizeof(sysfs_path) - sysfs_path_len) - return -LKL_ENOMEM; - sysfs_path_len += ret; + char buf[16] = { 0, }; fd = lkl_sys_open(sysfs_path, LKL_O_RDONLY, 0); if (fd < 0) @@ -139,19 +100,102 @@ int lkl_get_virtio_blkdev(int disk_id, uint32_t *pdevid) goto out_close; } - device_id = new_encode_dev(major, minor); + *pdevid = new_encode_dev(major, minor); ret = 0; out_close: lkl_sys_close(fd); - if (!ret) - *pdevid = device_id; - return ret; } -long lkl_mount_dev(unsigned int disk_id, const char *fs_type, int flags, +#define SYSFS_DEV_VIRTIO_PLATFORM_PATH \ + "/sysfs/devices/platform/virtio-mmio.%d.auto" +#define SYSFS_DEV_VIRTIO_CMDLINE_PATH \ + "/sysfs/devices/virtio-mmio-cmdline/virtio-mmio.%d" + +struct abuf { + char *mem, *ptr; + unsigned int len; +}; + +static int snprintf_append(struct abuf *buf, const char *fmt, ...) +{ + int ret; + va_list args; + + if (!buf->ptr) + buf->ptr = buf->mem; + + va_start(args, fmt); + ret = vsnprintf(buf->ptr, buf->len - (buf->ptr - buf->mem), fmt, args); + va_end(args); + + if (ret < 0 || (ret >= (buf->len - (buf->ptr - buf->mem)))) + return -LKL_ENOMEM; + + buf->ptr += ret; + + return 0; +} + +int lkl_get_virtio_blkdev(int disk_id, unsigned int part, uint32_t *pdevid) +{ + char sysfs_path[LKL_PATH_MAX]; + char virtio_name[LKL_PATH_MAX]; + char disk_name[LKL_PATH_MAX]; + struct abuf sysfs_path_buf = { + .mem = sysfs_path, + .len = sizeof(sysfs_path), + }; + char *fmt; + int ret; + + if (disk_id < 0) + return -LKL_EINVAL; + + ret = lkl_mount_fs("sysfs"); + if (ret < 0) + return ret; + + if ((uint32_t) disk_id >= virtio_get_num_bootdevs()) { + fmt = SYSFS_DEV_VIRTIO_PLATFORM_PATH; + disk_id -= virtio_get_num_bootdevs(); + } else { + fmt = SYSFS_DEV_VIRTIO_CMDLINE_PATH; + } + + ret = snprintf_append(&sysfs_path_buf, fmt, disk_id); + if (ret) + return ret; + + ret = get_node_with_prefix(sysfs_path, "virtio", virtio_name, + sizeof(virtio_name)); + if (ret) + return ret; + + ret = snprintf_append(&sysfs_path_buf, "/%s/block", virtio_name); + if (ret) + return ret; + + ret = get_node_with_prefix(sysfs_path, "vd", disk_name, + sizeof(disk_name)); + if (ret) + return ret; + + if (!part) + ret = snprintf_append(&sysfs_path_buf, "/%s/dev", disk_name); + else + ret = snprintf_append(&sysfs_path_buf, "/%s/%s%d/dev", + disk_name, disk_name, part); + if (ret) + return ret; + + return encode_dev_from_sysfs(sysfs_path, pdevid); +} + +long lkl_mount_dev(unsigned int disk_id, unsigned int part, + const char *fs_type, int flags, const char *data, char *mnt_str, unsigned int mnt_str_len) { char dev_str[] = { "/dev/xxxxxxxx" }; @@ -162,7 +206,7 @@ long lkl_mount_dev(unsigned int disk_id, const char *fs_type, int flags, if (mnt_str_len < sizeof(dev_str)) return -LKL_ENOMEM; - err = lkl_get_virtio_blkdev(disk_id, &dev); + err = lkl_get_virtio_blkdev(disk_id, part, &dev); if (err < 0) return err; @@ -233,14 +277,15 @@ long lkl_umount_timeout(char *path, int flags, long timeout_ms) return err; } -long lkl_umount_dev(unsigned int disk_id, int flags, long timeout_ms) +long lkl_umount_dev(unsigned int disk_id, unsigned int part, int flags, + long timeout_ms) { char dev_str[] = { "/dev/xxxxxxxx" }; char mnt_str[] = { "/mnt/xxxxxxxx" }; unsigned int dev; int err; - err = lkl_get_virtio_blkdev(disk_id, &dev); + err = lkl_get_virtio_blkdev(disk_id, part, &dev); if (err < 0) return err; diff --git a/tools/lkl/lklfuse.c b/tools/lkl/lklfuse.c index de0e2fa267eca2..499e52bf7b6f18 100644 --- a/tools/lkl/lklfuse.c +++ b/tools/lkl/lklfuse.c @@ -23,6 +23,7 @@ struct lklfuse { const char *opts; struct lkl_disk disk; int disk_id; + int part; int ro; int mb; } lklfuse = { @@ -41,6 +42,7 @@ static struct fuse_opt lklfuse_opts[] = { LKLFUSE_OPT("type=%s", type, 0), LKLFUSE_OPT("mb=%d", mb, 0), LKLFUSE_OPT("opts=%s", opts, 0), + LKLFUSE_OPT("part=%d", part, 0), FUSE_OPT_KEY("-h", KEY_HELP), FUSE_OPT_KEY("--help", KEY_HELP), FUSE_OPT_KEY("-V", KEY_VERSION), @@ -62,6 +64,7 @@ static void usage(void) " -o log=FILE log file\n" " -o type=fstype filesystem type\n" " -o mb=memory in mb ammount of memory to allocate\n" +" -o part=parition partition to mount\n" " -o opts=options mount options (use \\ to escape , and =)\n" ); } @@ -512,7 +515,7 @@ static int start_lkl(void) goto out; } - ret = lkl_mount_dev(lklfuse.disk_id, lklfuse.type, + ret = lkl_mount_dev(lklfuse.disk_id, lklfuse.part, lklfuse.type, lklfuse.ro ? LKL_MS_RDONLY : 0, lklfuse.opts, mpoint, sizeof(mpoint)); @@ -531,7 +534,7 @@ static int start_lkl(void) return 0; out_umount: - lkl_umount_dev(lklfuse.disk_id, 0, 1000); + lkl_umount_dev(lklfuse.disk_id, lklfuse.part, 0, 1000); out_halt: lkl_sys_halt(); diff --git a/tools/lkl/tests/boot.c b/tools/lkl/tests/boot.c index 047b2f257e541e..f3b6e6332d1ee4 100644 --- a/tools/lkl/tests/boot.c +++ b/tools/lkl/tests/boot.c @@ -24,6 +24,7 @@ static struct cl_args { const char *disk_filename; const char *tap_ifname; const char *fstype; + int part; } cla; static struct cl_option { @@ -34,6 +35,7 @@ static struct cl_option { } options[] = { {"enable-printk", 'p', "show Linux printks", 0}, {"disk-file", 'd', "disk file to use", 1}, + {"partition", 'P', "partition to mount", 1}, {"net-tap", 'n', "tap interface to use", 1}, {"type", 't', "filesystem type", 1}, {0}, @@ -45,6 +47,9 @@ static int parse_opt(int key, char *arg) case 'p': cla.printk = 1; break; + case 'P': + cla.part = atoi(arg); + break; case 'd': cla.disk_filename = arg; break; @@ -542,7 +547,7 @@ static int test_mount_dev(char *str, int len) { long ret; - ret = lkl_mount_dev(disk_id, cla.fstype, 0, NULL, mnt_point, + ret = lkl_mount_dev(disk_id, cla.part, cla.fstype, 0, NULL, mnt_point, sizeof(mnt_point)); snprintf(str, len, "%ld", ret); @@ -617,7 +622,7 @@ static int test_umount_dev(char *str, int len) ret2 = lkl_sys_chdir("/"); - ret3 = lkl_umount_dev(disk_id, 0, 1000); + ret3 = lkl_umount_dev(disk_id, cla.part, 0, 1000); snprintf(str, len, "%ld %ld %ld", ret, ret2, ret3);