Skip to content

Commit

Permalink
Merge pull request torvalds#279 from tavip/part-mount
Browse files Browse the repository at this point in the history
Add support for mounting partitions
  • Loading branch information
tavip authored Dec 18, 2016
2 parents e297704 + 63befd1 commit 4b6e5a7
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 80 deletions.
10 changes: 8 additions & 2 deletions tools/lkl/cptofs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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));
Expand All @@ -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);
Expand Down
11 changes: 8 additions & 3 deletions tools/lkl/fs2tar.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand Down
16 changes: 11 additions & 5 deletions tools/lkl/include/lkl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
177 changes: 111 additions & 66 deletions tools/lkl/lib/fs.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
Expand Down Expand Up @@ -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)
Expand All @@ -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" };
Expand All @@ -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;

Expand Down Expand Up @@ -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;

Expand Down
Loading

0 comments on commit 4b6e5a7

Please sign in to comment.