All of lore.kernel.org
 help / color / mirror / Atom feed
From: Anton Ivanov <anton.ivanov@cambridgegreys.com>
To: Hajime Tazaki <thehajime@gmail.com>,
	linux-um@lists.infradead.org, jdike@addtoit.com, richard@nod.at
Cc: tavi.purdila@gmail.com, linux-kernel-library@freelists.org,
	linux-arch@vger.kernel.org, retrage01@gmail.com
Subject: Re: [RFC v7 21/21] um: nommu: add block device support of UML
Date: Wed, 7 Oct 2020 15:17:31 +0100	[thread overview]
Message-ID: <ac66cd8b-3bb1-5846-aa75-fc91c1149e91@cambridgegreys.com> (raw)
In-Reply-To: <a8686efcbad3c445d3e5bde054c04a58877915f1.1601960644.git.thehajime@gmail.com>


On 06/10/2020 10:44, Hajime Tazaki wrote:
> This commit adds block device support for nommu mode, and also added
> several host utilities to run a simple test program
> (tools/um/test/disk.c) successfully.
>
> Signed-off-by: Hajime Tazaki <thehajime@gmail.com>
> ---
>   arch/um/include/asm/xor.h                 |   3 +-
>   arch/um/include/shared/as-layout.h        |   1 +
>   arch/um/kernel/um_arch.c                  |   5 +
>   arch/um/nommu/include/uapi/asm/host_ops.h |   7 +
>   arch/um/nommu/include/uapi/asm/unistd.h   |   2 +
>   arch/um/nommu/um/Kconfig                  |   8 +
>   arch/um/nommu/um/setup.c                  |  12 +
>   tools/um/Targets                          |   2 +
>   tools/um/include/lkl.h                    | 206 ++++++++++
>   tools/um/include/lkl_host.h               |   1 +
>   tools/um/lib/Build                        |   1 +
>   tools/um/lib/fs.c                         | 461 ++++++++++++++++++++++
>   tools/um/lib/posix-host.c                 |   1 +
>   tools/um/lib/utils.c                      |   3 +
>   tools/um/tests/Build                      |   1 +
>   tools/um/tests/cla.c                      | 159 ++++++++
>   tools/um/tests/cla.h                      |  33 ++
>   tools/um/tests/disk.c                     | 168 ++++++++
>   tools/um/tests/disk.sh                    |  70 ++++
>   tools/um/tests/run.py                     |   2 +
>   20 files changed, 1145 insertions(+), 1 deletion(-)
>   create mode 100644 tools/um/lib/fs.c
>   create mode 100644 tools/um/tests/cla.c
>   create mode 100644 tools/um/tests/cla.h
>   create mode 100644 tools/um/tests/disk.c
>   create mode 100755 tools/um/tests/disk.sh
>
> diff --git a/arch/um/include/asm/xor.h b/arch/um/include/asm/xor.h
> index 36b33d62a35d..a5ea458a1ae9 100644
> --- a/arch/um/include/asm/xor.h
> +++ b/arch/um/include/asm/xor.h
> @@ -4,4 +4,5 @@
>   
>   /* pick an arbitrary one - measuring isn't possible with inf-cpu */
>   #define XOR_SELECT_TEMPLATE(x)	\
> -	(time_travel_mode == TT_MODE_INFCPU ? &xor_block_8regs : NULL)
> +	(time_travel_mode == TT_MODE_INFCPU || (!IS_ENABLED(CONFIG_MMU)) ? \
> +	 &xor_block_8regs : NULL)
> diff --git a/arch/um/include/shared/as-layout.h b/arch/um/include/shared/as-layout.h
> index 5f286ef2721b..4423437a5ace 100644
> --- a/arch/um/include/shared/as-layout.h
> +++ b/arch/um/include/shared/as-layout.h
> @@ -57,6 +57,7 @@ extern unsigned long host_task_size;
>   
>   extern int linux_main(int argc, char **argv);
>   extern void uml_finishsetup(void);
> +extern void uml_set_args(char *args);
>   
>   struct siginfo;
>   extern void (*sig_info[])(int, struct siginfo *si, struct uml_pt_regs *);
> diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
> index e2cb76c03b25..da6e06cf2808 100644
> --- a/arch/um/kernel/um_arch.c
> +++ b/arch/um/kernel/um_arch.c
> @@ -41,6 +41,11 @@ static void __init add_arg(char *arg)
>   	strcat(command_line, arg);
>   }
>   
> +void __init uml_set_args(char *args)
> +{
> +	strcat(command_line, args);
> +}
> +
>   /*
>    * These fields are initialized at boot time and not changed.
>    * XXX This structure is used only in the non-SMP case.  Maybe this
> diff --git a/arch/um/nommu/include/uapi/asm/host_ops.h b/arch/um/nommu/include/uapi/asm/host_ops.h
> index 0811494c080c..1b2507502969 100644
> --- a/arch/um/nommu/include/uapi/asm/host_ops.h
> +++ b/arch/um/nommu/include/uapi/asm/host_ops.h
> @@ -15,6 +15,11 @@ struct lkl_jmp_buf {
>    *
>    * These operations must be provided by a host library or by the application
>    * itself.
> + *
> + * @um_devices - string containg the list of UML devices in command line
> + * format. This string is appended to the kernel command line and
> + * is provided here for convenience to be implemented by the host library.
> + *
>    * @print - optional operation that receives console messages
>    * @panic - called during a kernel panic
>    *
> @@ -65,6 +70,8 @@ struct lkl_jmp_buf {
>    *
>    */
>   struct lkl_host_operations {
> +	const char *um_devices;
> +
>   	void (*print)(const char *str, int len);
>   	void (*panic)(void);
>   
> diff --git a/arch/um/nommu/include/uapi/asm/unistd.h b/arch/um/nommu/include/uapi/asm/unistd.h
> index 1762ebb829f5..320762099a62 100644
> --- a/arch/um/nommu/include/uapi/asm/unistd.h
> +++ b/arch/um/nommu/include/uapi/asm/unistd.h
> @@ -3,6 +3,8 @@
>   #define __UM_NOMMU_UAPI_UNISTD_H
>   
>   #define __ARCH_WANT_NEW_STAT
> +#define __ARCH_WANT_SET_GET_RLIMIT
> +
>   #include <asm/bitsperlong.h>
>   
>   #if __BITS_PER_LONG == 64
> diff --git a/arch/um/nommu/um/Kconfig b/arch/um/nommu/um/Kconfig
> index 20b3eaccb6f0..c6a3f472fe75 100644
> --- a/arch/um/nommu/um/Kconfig
> +++ b/arch/um/nommu/um/Kconfig
> @@ -4,6 +4,10 @@ config UML_NOMMU
>   	select UACCESS_MEMCPY
>   	select ARCH_THREAD_STACK_ALLOCATOR
>   	select ARCH_HAS_SYSCALL_WRAPPER
> +	select VFAT_FS
> +	select NLS_CODEPAGE_437
> +	select NLS_ISO8859_1
> +	select BTRFS_FS
>   
>   config 64BIT
>   	bool
> @@ -35,3 +39,7 @@ config STACKTRACE_SUPPORT
>   config PRINTK_TIME
>   	bool
>   	default y
> +
> +config RAID6_PQ_BENCHMARK
> +	bool
> +	default n

Why are we touching this? I thought this is already defined in lib/Kconfig?

Brgds,

A.

> diff --git a/arch/um/nommu/um/setup.c b/arch/um/nommu/um/setup.c
> index 922188690139..d71d61979ad6 100644
> --- a/arch/um/nommu/um/setup.c
> +++ b/arch/um/nommu/um/setup.c
> @@ -45,13 +45,25 @@ static void __init *lkl_run_kernel(void *arg)
>   	return NULL;
>   }
>   
> +static char _cmd_line[COMMAND_LINE_SIZE];
>   int __init lkl_start_kernel(struct lkl_host_operations *ops,
>   			    const char *fmt, ...)
>   {
> +	va_list ap;
>   	int ret;
>   
>   	lkl_ops = ops;
>   
> +	va_start(ap, fmt);
> +	ret = vsnprintf(_cmd_line, COMMAND_LINE_SIZE, fmt, ap);
> +	va_end(ap);
> +
> +	if (ops->um_devices)
> +		strscpy(_cmd_line + ret, ops->um_devices,
> +			COMMAND_LINE_SIZE - ret);
> +
> +	uml_set_args(_cmd_line);
> +
>   	init_sem = lkl_ops->sem_alloc(0);
>   	if (!init_sem)
>   		return -ENOMEM;
> diff --git a/tools/um/Targets b/tools/um/Targets
> index 2bb90381843c..f5f8ec4b9dbb 100644
> --- a/tools/um/Targets
> +++ b/tools/um/Targets
> @@ -1,10 +1,12 @@
>   ifeq ($(UMMODE),library)
>   progs-y += tests/boot
> +progs-y += tests/disk
>   else
>   progs-y += uml/linux
>   endif
>   
>   LDFLAGS_boot-y := -pie
> +LDFLAGS_disk-y := -pie
>   
>   LDLIBS := -lrt -lpthread -lutil
>   LDFLAGS_linux-y := -no-pie -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
> diff --git a/tools/um/include/lkl.h b/tools/um/include/lkl.h
> index 707e01b64a70..4a9d874bfbf0 100644
> --- a/tools/um/include/lkl.h
> +++ b/tools/um/include/lkl.h
> @@ -113,6 +113,16 @@ static inline long lkl_sys_creat(const char *file, int mode)
>   }
>   #endif
>   
> +#ifdef __lkl__NR_faccessat
> +/**
> + * lkl_sys_access - wrapper for lkl_sys_faccessat
> + */
> +static inline long lkl_sys_access(const char *file, int mode)
> +{
> +	return lkl_sys_faccessat(LKL_AT_FDCWD, file, mode);
> +}
> +#endif
> +
>   #ifdef __lkl__NR_mkdirat
>   /**
>    * lkl_sys_mkdir - wrapper for lkl_sys_mkdirat
> @@ -123,6 +133,36 @@ static inline long lkl_sys_mkdir(const char *path, mode_t mode)
>   }
>   #endif
>   
> +#ifdef __lkl__NR_unlinkat
> +/**
> + * lkl_sys_rmdir - wrapper for lkl_sys_unlinkrat
> + */
> +static inline long lkl_sys_rmdir(const char *path)
> +{
> +	return lkl_sys_unlinkat(LKL_AT_FDCWD, path, LKL_AT_REMOVEDIR);
> +}
> +#endif
> +
> +#ifdef __lkl__NR_unlinkat
> +/**
> + * lkl_sys_unlink - wrapper for lkl_sys_unlinkat
> + */
> +static inline long lkl_sys_unlink(const char *path)
> +{
> +	return lkl_sys_unlinkat(LKL_AT_FDCWD, path, 0);
> +}
> +#endif
> +
> +#ifdef __lkl__NR_mknodat
> +/**
> + * lkl_sys_mknod - wrapper for lkl_sys_mknodat
> + */
> +static inline long lkl_sys_mknod(const char *path, mode_t mode, dev_t dev)
> +{
> +	return lkl_sys_mknodat(LKL_AT_FDCWD, path, mode, dev);
> +}
> +#endif
> +
>   #ifdef __lkl__NR_epoll_create1
>   /**
>    * lkl_sys_epoll_create - wrapper for lkl_sys_epoll_create1
> @@ -144,6 +184,172 @@ static inline long lkl_sys_epoll_wait(int fd, struct lkl_epoll_event *ev,
>   }
>   #endif
>   
> +/**
> + * struct lkl_dev_blk_ops - block device host operations, defined in lkl_host.h.
> + */
> +struct lkl_dev_blk_ops;
> +
> +/**
> + * lkl_disk - host disk handle
> + *
> + * @dev - a pointer to private information for this disk backend
> + * @fd - a POSIX file descriptor that can be used by preadv/pwritev
> + * @handle - an NT file handle that can be used by ReadFile/WriteFile
> + */
> +struct lkl_disk {
> +	void *dev;
> +	union {
> +		int fd;
> +		void *handle;
> +	};
> +	struct lkl_dev_blk_ops *ops;
> +};
> +
> +/**
> + * lkl_disk_add - add a new disk
> + *
> + * @disk - the host disk handle
> + * @returns a disk id (0 is valid) or a strictly negative value in case of error
> + */
> +int lkl_disk_add(struct lkl_disk *disk);
> +
> +/**
> + * lkl_disk_remove - remove a disk
> + *
> + * This function makes a cleanup of the @disk's private information
> + * that was initialized by lkl_disk_add before.
> + *
> + * @disk - the host disk handle
> + */
> +int lkl_disk_remove(struct lkl_disk disk);
> +
> +/**
> + * lkl_encode_dev_from_sysfs_blkdev - extract device id from sysfs
> + *
> + * This function returns the device id for the given sysfs dev node.
> + * The content of the node has to be in the form 'MAJOR:MINOR'.
> + * Also, this function expects an absolute path which means that sysfs
> + * already has to be mounted at the given path
> + *
> + * @sysfs_path - absolute path to the sysfs dev node
> + * @pdevid - pointer to memory where dev id will be returned
> + * @returns - 0 on success, a negative value on error
> + */
> +int lkl_encode_dev_from_sysfs(const char *sysfs_path, uint32_t *pdevid);
> +
> +/**
> + * lkl_mount_dev - mount a disk
> + *
> + * This functions creates a device file for the given disk, creates a mount
> + * 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
> + * @mnt_str - a string that will be filled by this function with the path where
> + * the filesystem has been mounted
> + * @mnt_str_len - size of mnt_str
> + * @returns - 0 on success, a negative value on error
> + */
> +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
> + *
> + * This functions umounts the given disks and removes the device file and the
> + * 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, unsigned int part, int flags,
> +		    long timeout_ms);
> +
> +/**
> + * lkl_umount_timeout - umount filesystem with timeout
> + *
> + * @path - the path to unmount
> + * @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_timeout(char *path, int flags, long timeout_ms);
> +
> +/**
> + * lkl_opendir - open a directory
> + *
> + * @path - directory path
> + * @err - pointer to store the error in case of failure
> + * @returns - a handle to be used when calling lkl_readdir
> + */
> +struct lkl_dir *lkl_opendir(const char *path, int *err);
> +
> +/**
> + * lkl_fdopendir - open a directory
> + *
> + * @fd - file descriptor
> + * @err - pointer to store the error in case of failure
> + * @returns - a handle to be used when calling lkl_readdir
> + */
> +struct lkl_dir *lkl_fdopendir(int fd, int *err);
> +
> +/**
> + * lkl_rewinddir - reset directory stream
> + *
> + * @dir - the directory handler as returned by lkl_opendir
> + */
> +void lkl_rewinddir(struct lkl_dir *dir);
> +
> +/**
> + * lkl_closedir - close the directory
> + *
> + * @dir - the directory handler as returned by lkl_opendir
> + */
> +int lkl_closedir(struct lkl_dir *dir);
> +
> +/**
> + * lkl_readdir - get the next available entry of the directory
> + *
> + * @dir - the directory handler as returned by lkl_opendir
> + * @returns - a lkl_dirent64 entry or NULL if the end of the directory stream is
> + * reached or if an error occurred; check lkl_errdir() to distinguish between
> + * errors or end of the directory stream
> + */
> +struct lkl_linux_dirent64 *lkl_readdir(struct lkl_dir *dir);
> +
> +/**
> + * lkl_errdir - checks if an error occurred during the last lkl_readdir call
> + *
> + * @dir - the directory handler as returned by lkl_opendir
> + * @returns - 0 if no error occurred, or a negative value otherwise
> + */
> +int lkl_errdir(struct lkl_dir *dir);
> +
> +/**
> + * lkl_dirfd - gets the file descriptor associated with the directory handle
> + *
> + * @dir - the directory handle as returned by lkl_opendir
> + * @returns - a positive value,which is the LKL file descriptor associated with
> + * the directory handle, or a negative value otherwise
> + */
> +int lkl_dirfd(struct lkl_dir *dir);
> +
> +/**
> + * lkl_mount_fs - mount a file system type like proc, sys
> + * @fstype - file system type. e.g. proc, sys
> + * @returns - 0 on success. 1 if it's already mounted. negative on failure.
> + */
> +int lkl_mount_fs(char *fstype);
> +
>   #ifdef __cplusplus
>   }
>   #endif
> diff --git a/tools/um/include/lkl_host.h b/tools/um/include/lkl_host.h
> index 85e80eb4ad0d..12dd95616e43 100644
> --- a/tools/um/include/lkl_host.h
> +++ b/tools/um/include/lkl_host.h
> @@ -10,6 +10,7 @@ extern "C" {
>   #include <lkl.h>
>   
>   extern struct lkl_host_operations lkl_host_ops;
> +extern char lkl_um_devs[4096];
>   
>   /**
>    * lkl_printf - print a message via the host print operation
> diff --git a/tools/um/lib/Build b/tools/um/lib/Build
> index dddff26a3b4e..29491b40746c 100644
> --- a/tools/um/lib/Build
> +++ b/tools/um/lib/Build
> @@ -4,3 +4,4 @@ CFLAGS_posix-host.o += -D_FILE_OFFSET_BITS=64
>   liblinux-$(CONFIG_UMMODE_LIB) += utils.o
>   liblinux-$(CONFIG_UMMODE_LIB) += posix-host.o
>   liblinux-$(CONFIG_UMMODE_LIB) += jmp_buf.o
> +liblinux-$(CONFIG_UMMODE_LIB) += fs.o
> diff --git a/tools/um/lib/fs.c b/tools/um/lib/fs.c
> new file mode 100644
> index 000000000000..948aac9730c2
> --- /dev/null
> +++ b/tools/um/lib/fs.c
> @@ -0,0 +1,461 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include <stdarg.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <stdlib.h>
> +#include <lkl_host.h>
> +
> +#define MAX_FSTYPE_LEN 50
> +
> +static struct lkl_disk *lkl_disks[16];
> +static int registered_blk_dev_idx;
> +
> +static int lkl_disk_um_add(struct lkl_disk *disk, const char *blkparams)
> +{
> +	/* concat strings */
> +	snprintf(lkl_um_devs + strlen(lkl_um_devs), sizeof(lkl_um_devs),
> +		 " ubd%d=%s", registered_blk_dev_idx, blkparams);
> +
> +	return registered_blk_dev_idx++;
> +}
> +
> +int lkl_disk_add(struct lkl_disk *disk)
> +{
> +	int ret = -1;
> +
> +	ret = lkl_disk_um_add(disk, disk->dev);
> +
> +	lkl_disks[ret] = disk;
> +
> +	return ret;
> +}
> +
> +int lkl_disk_remove(struct lkl_disk disk)
> +{
> +	/* FIXME */
> +	return 0;
> +}
> +
> +int lkl_mount_fs(char *fstype)
> +{
> +	char dir[MAX_FSTYPE_LEN+2] = "/";
> +	int flags = 0, ret = 0;
> +
> +	strncat(dir, fstype, MAX_FSTYPE_LEN);
> +
> +	/* Create with regular umask */
> +	ret = lkl_sys_mkdir(dir, 0xff);
> +	if (ret && ret != -LKL_EEXIST) {
> +		lkl_perror("mount_fs mkdir", ret);
> +		return ret;
> +	}
> +
> +	/* We have no use for nonzero flags right now */
> +	ret = lkl_sys_mount("none", dir, fstype, flags, NULL);
> +	if (ret && ret != -LKL_EBUSY) {
> +		lkl_sys_rmdir(dir);
> +		return ret;
> +	}
> +
> +	if (ret == -LKL_EBUSY)
> +		return 1;
> +	return 0;
> +}
> +
> +static uint32_t new_encode_dev(unsigned int major, unsigned int minor)
> +{
> +	return (minor & 0xff) | (major << 8) | ((minor & ~0xff) << 12);
> +}
> +
> +static int startswith(const char *str, const char *pre)
> +{
> +	return strncmp(pre, str, strlen(pre)) == 0;
> +}
> +
> +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;
> +	int ret;
> +
> +	dir = lkl_opendir(path, &ret);
> +	if (!dir)
> +		return ret;
> +
> +	ret = -LKL_ENOENT;
> +
> +	while ((dirent = lkl_readdir(dir))) {
> +		if (startswith(dirent->d_name, prefix)) {
> +			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);
> +
> +	return ret;
> +}
> +
> +int lkl_encode_dev_from_sysfs(const char *sysfs_path, uint32_t *pdevid)
> +{
> +	int ret;
> +	long fd;
> +	int major, minor;
> +	char buf[16] = { 0, };
> +	char *bufptr;
> +
> +	fd = lkl_sys_open(sysfs_path, LKL_O_RDONLY, 0);
> +	if (fd < 0)
> +		return fd;
> +
> +	ret = lkl_sys_read(fd, buf, sizeof(buf));
> +	if (ret < 0)
> +		goto out_close;
> +
> +	if (ret == sizeof(buf)) {
> +		ret = -LKL_ENOBUFS;
> +		goto out_close;
> +	}
> +
> +	bufptr = strchr(buf, ':');
> +	if (bufptr == NULL) {
> +		ret = -LKL_EINVAL;
> +		goto out_close;
> +	}
> +	bufptr[0] = '\0';
> +	bufptr++;
> +
> +	major = atoi(buf);
> +	minor = atoi(bufptr);
> +
> +	*pdevid = new_encode_dev(major, minor);
> +	ret = 0;
> +
> +out_close:
> +	lkl_sys_close(fd);
> +
> +	return ret;
> +}
> +
> +#define SYSFS_DEV_UMBLK_CMDLINE_PATH \
> +	"/sysfs/devices/platform/uml-blkdev.%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 >= (int)(buf->len - (buf->ptr - buf->mem))))
> +		return -LKL_ENOMEM;
> +
> +	buf->ptr += ret;
> +
> +	return 0;
> +}
> +
> +static int __lkl_get_blkdev(int disk_id, unsigned int part, uint32_t *pdevid,
> +			    const char *sysfs_path_fmt, const char *drv_prefix,
> +			    const char *disk_prefix)
> +{
> +	char sysfs_path[LKL_PATH_MAX];
> +	char drv_name[LKL_PATH_MAX];
> +	char disk_name[LKL_PATH_MAX];
> +	struct abuf sysfs_path_buf = {
> +		.mem = sysfs_path,
> +		.len = sizeof(sysfs_path),
> +	};
> +	int ret;
> +
> +	if (disk_id < 0)
> +		return -LKL_EINVAL;
> +
> +	ret = lkl_mount_fs("sysfs");
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = snprintf_append(&sysfs_path_buf, sysfs_path_fmt, disk_id);
> +	if (ret)
> +		return ret;
> +
> +	ret = get_node_with_prefix(sysfs_path, drv_prefix, drv_name,
> +				   sizeof(drv_name));
> +	if (ret)
> +		return ret;
> +
> +	ret = snprintf_append(&sysfs_path_buf, "/%s/block", drv_name);
> +	if (ret)
> +		return ret;
> +
> +	ret = get_node_with_prefix(sysfs_path, disk_prefix, 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 lkl_encode_dev_from_sysfs(sysfs_path, pdevid);
> +}
> +
> +int lkl_get_blkdev(int disk_id, unsigned int part, uint32_t *pdevid)
> +{
> +	char *fmt;
> +
> +	fmt = SYSFS_DEV_UMBLK_CMDLINE_PATH;
> +	return __lkl_get_blkdev(disk_id, part, pdevid, fmt, "", "ubd");
> +}
> +
> +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" };
> +	unsigned int dev;
> +	int err;
> +	char _data[4096]; /* FIXME: PAGE_SIZE is not exported by LKL */
> +
> +	if (mnt_str_len < sizeof(dev_str))
> +		return -LKL_ENOMEM;
> +
> +	err = lkl_get_blkdev(disk_id, part, &dev);
> +	if (err < 0)
> +		return err;
> +
> +	snprintf(dev_str, sizeof(dev_str), "/dev/%08x", dev);
> +	snprintf(mnt_str, mnt_str_len, "/mnt/%08x", dev);
> +
> +	err = lkl_sys_access("/dev", LKL_S_IRWXO);
> +	if (err < 0) {
> +		if (err == -LKL_ENOENT)
> +			err = lkl_sys_mkdir("/dev", 0700);
> +		if (err < 0)
> +			return err;
> +	}
> +
> +	err = lkl_sys_mknod(dev_str, LKL_S_IFBLK | 0600, dev);
> +	if (err < 0)
> +		return err;
> +
> +	err = lkl_sys_access("/mnt", LKL_S_IRWXO);
> +	if (err < 0) {
> +		if (err == -LKL_ENOENT)
> +			err = lkl_sys_mkdir("/mnt", 0700);
> +		if (err < 0)
> +			return err;
> +	}
> +
> +	err = lkl_sys_mkdir(mnt_str, 0700);
> +	if (err < 0) {
> +		lkl_sys_unlink(dev_str);
> +		return err;
> +	}
> +
> +	/* kernel always copies a full page */
> +	if (data) {
> +		strncpy(_data, data, sizeof(_data));
> +		_data[sizeof(_data) - 1] = 0;
> +	} else {
> +		_data[0] = 0;
> +	}
> +
> +	err = lkl_sys_mount(dev_str, mnt_str, (char *)fs_type, flags, _data);
> +	if (err < 0) {
> +		lkl_sys_unlink(dev_str);
> +		lkl_sys_rmdir(mnt_str);
> +		return err;
> +	}
> +
> +	return 0;
> +}
> +
> +long lkl_umount_timeout(char *path, int flags, long timeout_ms)
> +{
> +	long incr = 10000000; /* 10 ms */
> +	struct lkl_timespec ts = {
> +		.tv_sec = 0,
> +		.tv_nsec = incr,
> +	};
> +	long err;
> +
> +	do {
> +		err = lkl_sys_umount(path, flags);
> +		if (err == -LKL_EBUSY) {
> +			lkl_sys_nanosleep((struct __lkl__kernel_timespec *)&ts,
> +					  NULL);
> +			timeout_ms -= incr / 1000000;
> +		}
> +	} while (err == -LKL_EBUSY && timeout_ms > 0);
> +
> +	return err;
> +}
> +
> +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_blkdev(disk_id, part, &dev);
> +	if (err < 0)
> +		return err;
> +
> +	snprintf(dev_str, sizeof(dev_str), "/dev/%08x", dev);
> +	snprintf(mnt_str, sizeof(mnt_str), "/mnt/%08x", dev);
> +
> +	err = lkl_umount_timeout(mnt_str, flags, timeout_ms);
> +	if (err)
> +		return err;
> +
> +	err = lkl_sys_unlink(dev_str);
> +	if (err)
> +		return err;
> +
> +	return lkl_sys_rmdir(mnt_str);
> +}
> +
> +struct lkl_dir {
> +	int fd;
> +	char buf[1024];
> +	char *pos;
> +	int len;
> +};
> +
> +static struct lkl_dir *lkl_dir_alloc(int *err)
> +{
> +	struct lkl_dir *dir = lkl_host_ops.mem_alloc(sizeof(struct lkl_dir));
> +
> +	if (!dir) {
> +		*err = -LKL_ENOMEM;
> +		return NULL;
> +	}
> +
> +	dir->len = 0;
> +	dir->pos = NULL;
> +
> +	return dir;
> +}
> +
> +struct lkl_dir *lkl_opendir(const char *path, int *err)
> +{
> +	struct lkl_dir *dir = lkl_dir_alloc(err);
> +
> +	if (!dir) {
> +		*err = -LKL_ENOMEM;
> +		return NULL;
> +	}
> +
> +	dir->fd = lkl_sys_open(path, LKL_O_RDONLY | LKL_O_DIRECTORY, 0);
> +	if (dir->fd < 0) {
> +		*err = dir->fd;
> +		lkl_host_ops.mem_free(dir);
> +		return NULL;
> +	}
> +
> +	*err = 0;
> +
> +	return dir;
> +}
> +
> +struct lkl_dir *lkl_fdopendir(int fd, int *err)
> +{
> +	struct lkl_dir *dir = lkl_dir_alloc(err);
> +
> +	if (!dir)
> +		return NULL;
> +
> +	dir->fd = fd;
> +
> +	return dir;
> +}
> +
> +void lkl_rewinddir(struct lkl_dir *dir)
> +{
> +	lkl_sys_lseek(dir->fd, 0, LKL_SEEK_SET);
> +	dir->len = 0;
> +	dir->pos = NULL;
> +}
> +
> +int lkl_closedir(struct lkl_dir *dir)
> +{
> +	int ret;
> +
> +	ret = lkl_sys_close(dir->fd);
> +	lkl_host_ops.mem_free(dir);
> +
> +	return ret;
> +}
> +
> +struct lkl_linux_dirent64 *lkl_readdir(struct lkl_dir *dir)
> +{
> +	struct lkl_linux_dirent64 *de;
> +
> +	if (dir->len < 0)
> +		return NULL;
> +
> +	if (!dir->pos || dir->pos - dir->buf >= dir->len)
> +		goto read_buf;
> +
> +return_de:
> +	de = (struct lkl_linux_dirent64 *)dir->pos;
> +	dir->pos += de->d_reclen;
> +
> +	return de;
> +
> +read_buf:
> +	dir->pos = NULL;
> +	de = (struct lkl_linux_dirent64 *)dir->buf;
> +	dir->len = lkl_sys_getdents64(dir->fd, de, sizeof(dir->buf));
> +	if (dir->len <= 0)
> +		return NULL;
> +
> +	dir->pos = dir->buf;
> +	goto return_de;
> +}
> +
> +int lkl_errdir(struct lkl_dir *dir)
> +{
> +	if (dir->len >= 0)
> +		return 0;
> +
> +	return dir->len;
> +}
> +
> +int lkl_dirfd(struct lkl_dir *dir)
> +{
> +	return dir->fd;
> +}
> +
> +int lkl_set_fd_limit(unsigned int fd_limit)
> +{
> +	struct lkl_rlimit rlim = {
> +		.rlim_cur = fd_limit,
> +		.rlim_max = fd_limit,
> +	};
> +	return lkl_sys_setrlimit(LKL_RLIMIT_NOFILE, &rlim);
> +}
> diff --git a/tools/um/lib/posix-host.c b/tools/um/lib/posix-host.c
> index b6b5b2902254..8fd88031bf2b 100644
> --- a/tools/um/lib/posix-host.c
> +++ b/tools/um/lib/posix-host.c
> @@ -263,6 +263,7 @@ static void *tls_get(struct lkl_tls_key *key)
>   }
>   
>   struct lkl_host_operations lkl_host_ops = {
> +	.um_devices = lkl_um_devs,
>   	.panic = panic,
>   	.print = print,
>   	.mem_alloc = (void *)malloc,
> diff --git a/tools/um/lib/utils.c b/tools/um/lib/utils.c
> index 4930479a8a35..ac65cd744a14 100644
> --- a/tools/um/lib/utils.c
> +++ b/tools/um/lib/utils.c
> @@ -4,6 +4,9 @@
>   #include <string.h>
>   #include <lkl_host.h>
>   
> +/* XXX: find a better place */
> +char lkl_um_devs[4096];
> +
>   static const char * const lkl_err_strings[] = {
>   	"Success",
>   	"Operation not permitted",
> diff --git a/tools/um/tests/Build b/tools/um/tests/Build
> index 564560486f98..1aa78f9ed7ef 100644
> --- a/tools/um/tests/Build
> +++ b/tools/um/tests/Build
> @@ -1,3 +1,4 @@
>   boot-y += boot.o test.o
> +disk-y += disk.o test.o cla.o
>   
>   CFLAGS_test.o += -Wno-implicit-fallthrough
> diff --git a/tools/um/tests/cla.c b/tools/um/tests/cla.c
> new file mode 100644
> index 000000000000..694e3a3822be
> --- /dev/null
> +++ b/tools/um/tests/cla.c
> @@ -0,0 +1,159 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include <stdio.h>
> +#include <string.h>
> +#include <errno.h>
> +#include <stdlib.h>
> +#ifdef __MINGW32__
> +#include <winsock2.h>
> +#else
> +#include <sys/socket.h>
> +#include <netinet/in.h>
> +#include <arpa/inet.h>
> +#endif
> +
> +#include "cla.h"
> +
> +static int cl_arg_parse_bool(struct cl_arg *arg, const char *value)
> +{
> +	*((int *)arg->store) = 1;
> +	return 0;
> +}
> +
> +static int cl_arg_parse_str(struct cl_arg *arg, const char *value)
> +{
> +	*((const char **)arg->store) = value;
> +	return 0;
> +}
> +
> +static int cl_arg_parse_int(struct cl_arg *arg, const char *value)
> +{
> +	errno = 0;
> +	*((int *)arg->store) = strtol(value, NULL, 0);
> +	return errno == 0;
> +}
> +
> +static int cl_arg_parse_str_set(struct cl_arg *arg, const char *value)
> +{
> +	const char **set = arg->set;
> +	int i;
> +
> +	for (i = 0; set[i] != NULL; i++) {
> +		if (strcmp(set[i], value) == 0) {
> +			*((int *)arg->store) = i;
> +			return 0;
> +		}
> +	}
> +
> +	return (-1);
> +}
> +
> +static int cl_arg_parse_ipv4(struct cl_arg *arg, const char *value)
> +{
> +	unsigned int addr;
> +
> +	if (!value)
> +		return (-1);
> +
> +	addr = inet_addr(value);
> +	if (addr == INADDR_NONE)
> +		return (-1);
> +	*((unsigned int *)arg->store) = addr;
> +	return 0;
> +}
> +
> +static cl_arg_parser_t parsers[] = {
> +	[CL_ARG_BOOL] = cl_arg_parse_bool,
> +	[CL_ARG_INT] = cl_arg_parse_int,
> +	[CL_ARG_STR] = cl_arg_parse_str,
> +	[CL_ARG_STR_SET] = cl_arg_parse_str_set,
> +	[CL_ARG_IPV4] = cl_arg_parse_ipv4,
> +};
> +
> +static struct cl_arg *find_short_arg(char name, struct cl_arg *args)
> +{
> +	struct cl_arg *arg;
> +
> +	for (arg = args; arg->short_name != 0; arg++) {
> +		if (arg->short_name == name)
> +			return arg;
> +	}
> +
> +	return NULL;
> +}
> +
> +static struct cl_arg *find_long_arg(const char *name, struct cl_arg *args)
> +{
> +	struct cl_arg *arg;
> +
> +	for (arg = args; arg->long_name; arg++) {
> +		if (strcmp(arg->long_name, name) == 0)
> +			return arg;
> +	}
> +
> +	return NULL;
> +}
> +
> +static void print_help(struct cl_arg *args)
> +{
> +	struct cl_arg *arg;
> +
> +	fprintf(stderr, "usage:\n");
> +	for (arg = args; arg->long_name; arg++) {
> +		fprintf(stderr, "-%c, --%-20s %s", arg->short_name,
> +			arg->long_name, arg->help);
> +		if (arg->type == CL_ARG_STR_SET) {
> +			const char **set = arg->set;
> +
> +			fprintf(stderr, " [ ");
> +			while (*set != NULL)
> +				fprintf(stderr, "%s ", *(set++));
> +			fprintf(stderr, "]");
> +		}
> +		fprintf(stderr, "\n");
> +	}
> +}
> +
> +int cla_parse_args(int argc, const char **argv, struct cl_arg *args)
> +{
> +	int i;
> +
> +	for (i = 1; i < argc; i++) {
> +		struct cl_arg *arg = NULL;
> +		cl_arg_parser_t parser;
> +
> +		if (argv[i][0] == '-') {
> +			if (argv[i][1] != '-')
> +				arg = find_short_arg(argv[i][1], args);
> +			else
> +				arg = find_long_arg(&argv[i][2], args);
> +		}
> +
> +		if (!arg) {
> +			fprintf(stderr, "unknown option '%s'\n", argv[i]);
> +			print_help(args);
> +			return (-1);
> +		}
> +
> +		if (arg->type == CL_ARG_USER || arg->type >= CL_ARG_END)
> +			parser = arg->parser;
> +		else
> +			parser = parsers[arg->type];
> +
> +		if (!parser) {
> +			fprintf(stderr, "can't parse --'%s'/-'%c'\n",
> +				arg->long_name, args->short_name);
> +			return (-1);
> +		}
> +
> +		if (parser(arg, argv[i + 1]) < 0) {
> +			fprintf(stderr, "can't parse '%s'\n", argv[i]);
> +			print_help(args);
> +			return (-1);
> +		}
> +
> +		if (arg->has_arg)
> +			i++;
> +	}
> +
> +	return 0;
> +}
> diff --git a/tools/um/tests/cla.h b/tools/um/tests/cla.h
> new file mode 100644
> index 000000000000..3d879233681f
> --- /dev/null
> +++ b/tools/um/tests/cla.h
> @@ -0,0 +1,33 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +#ifndef _LKL_TEST_CLA_H
> +#define _LKL_TEST_CLA_H
> +
> +enum cl_arg_type {
> +	CL_ARG_USER = 0,
> +	CL_ARG_BOOL,
> +	CL_ARG_INT,
> +	CL_ARG_STR,
> +	CL_ARG_STR_SET,
> +	CL_ARG_IPV4,
> +	CL_ARG_END,
> +};
> +
> +struct cl_arg;
> +
> +typedef int (*cl_arg_parser_t)(struct cl_arg *arg, const char *value);
> +
> +struct cl_arg {
> +	const char *long_name;
> +	char short_name;
> +	const char *help;
> +	int has_arg;
> +	enum cl_arg_type type;
> +	void *store;
> +	void *set;
> +	cl_arg_parser_t parser;
> +};
> +
> +int cla_parse_args(int argc, const char **argv, struct cl_arg *args);
> +
> +
> +#endif /* _LKL_TEST_CLA_H */
> diff --git a/tools/um/tests/disk.c b/tools/um/tests/disk.c
> new file mode 100644
> index 000000000000..325934935e6a
> --- /dev/null
> +++ b/tools/um/tests/disk.c
> @@ -0,0 +1,168 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <time.h>
> +#include <stdlib.h>
> +#include <stdint.h>
> +#include <lkl.h>
> +#include <lkl_host.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <sys/ioctl.h>
> +
> +#include "test.h"
> +#include "cla.h"
> +
> +static struct {
> +	int printk;
> +	const char *disk;
> +	const char *fstype;
> +	int partition;
> +} cla;
> +
> +struct cl_arg args[] = {
> +	{"disk", 'd', "disk file to use", 1, CL_ARG_STR, &cla.disk},
> +	{"partition", 'P', "partition to mount", 1, CL_ARG_INT, &cla.partition},
> +	{"type", 't', "filesystem type", 1, CL_ARG_STR, &cla.fstype},
> +	{0},
> +};
> +
> +
> +static struct lkl_disk disk;
> +static int disk_id = -1;
> +
> +int lkl_test_disk_add(void)
> +{
> +	disk.fd = open(cla.disk, O_RDWR);
> +	if (disk.fd < 0)
> +		goto out_unlink;
> +
> +	disk.ops = NULL;
> +	disk.dev = (char *)cla.disk;
> +
> +	disk_id = lkl_disk_add(&disk);
> +	if (disk_id < 0)
> +		goto out_close;
> +
> +	goto out;
> +
> +out_close:
> +	close(disk.fd);
> +
> +out_unlink:
> +	unlink(cla.disk);
> +
> +out:
> +	lkl_test_logf("disk fd/handle %x disk_id %d", disk.fd, disk_id);
> +
> +	if (disk_id >= 0)
> +		return TEST_SUCCESS;
> +
> +	return TEST_FAILURE;
> +}
> +
> +int lkl_test_disk_remove(void)
> +{
> +	int ret;
> +
> +	ret = lkl_disk_remove(disk);
> +
> +	close(disk.fd);
> +
> +	if (ret == 0)
> +		return TEST_SUCCESS;
> +
> +	return TEST_FAILURE;
> +}
> +
> +
> +static char mnt_point[32];
> +
> +LKL_TEST_CALL(mount_dev, lkl_mount_dev, 0, disk_id, cla.partition, cla.fstype,
> +	      0, NULL, mnt_point, sizeof(mnt_point))
> +
> +static int lkl_test_umount_dev(void)
> +{
> +	long ret, ret2;
> +
> +	ret = lkl_sys_chdir("/");
> +
> +	ret2 = lkl_umount_dev(disk_id, cla.partition, 0, 1000);
> +
> +	lkl_test_logf("%ld %ld", ret, ret2);
> +
> +	if (!ret && !ret2)
> +		return TEST_SUCCESS;
> +
> +	return TEST_FAILURE;
> +}
> +
> +struct lkl_dir *dir;
> +
> +static int lkl_test_opendir(void)
> +{
> +	int err;
> +
> +	dir = lkl_opendir(mnt_point, &err);
> +
> +	lkl_test_logf("lkl_opedir(%s) = %d %s\n", mnt_point, err,
> +		      lkl_strerror(err));
> +
> +	if (err == 0)
> +		return TEST_SUCCESS;
> +
> +	return TEST_FAILURE;
> +}
> +
> +static int lkl_test_readdir(void)
> +{
> +	struct lkl_linux_dirent64 *de = lkl_readdir(dir);
> +	int wr = 0;
> +
> +	while (de) {
> +		wr += lkl_test_logf("%s ", de->d_name);
> +		if (wr >= 70) {
> +			lkl_test_logf("\n");
> +			wr = 0;
> +			break;
> +		}
> +		de = lkl_readdir(dir);
> +	}
> +
> +	if (lkl_errdir(dir) == 0)
> +		return TEST_SUCCESS;
> +
> +	return TEST_FAILURE;
> +}
> +
> +LKL_TEST_CALL(closedir, lkl_closedir, 0, dir);
> +LKL_TEST_CALL(chdir_mnt_point, lkl_sys_chdir, 0, mnt_point);
> +LKL_TEST_CALL(start_kernel, lkl_start_kernel, 0, &lkl_host_ops,
> +	     "mem=16M loglevel=8");
> +LKL_TEST_CALL(stop_kernel, lkl_sys_halt, 0);
> +
> +struct lkl_test tests[] = {
> +	LKL_TEST(disk_add),
> +	LKL_TEST(start_kernel),
> +	LKL_TEST(mount_dev),
> +	LKL_TEST(chdir_mnt_point),
> +	LKL_TEST(opendir),
> +	LKL_TEST(readdir),
> +	LKL_TEST(closedir),
> +	LKL_TEST(umount_dev),
> +	LKL_TEST(stop_kernel),
> +	LKL_TEST(disk_remove),
> +
> +};
> +
> +int main(int argc, const char **argv)
> +{
> +	if (cla_parse_args(argc, argv, args) < 0)
> +		return (-1);
> +
> +	lkl_host_ops.print = lkl_test_log;
> +
> +	return lkl_test_run(tests, sizeof(tests)/sizeof(struct lkl_test),
> +			    "disk %s", cla.fstype);
> +}
> diff --git a/tools/um/tests/disk.sh b/tools/um/tests/disk.sh
> new file mode 100755
> index 000000000000..e2ec6cf69d4b
> --- /dev/null
> +++ b/tools/um/tests/disk.sh
> @@ -0,0 +1,70 @@
> +#!/usr/bin/env bash
> +# SPDX-License-Identifier: GPL-2.0
> +
> +script_dir=$(cd $(dirname ${BASH_SOURCE:-$0}); pwd)
> +
> +source $script_dir/test.sh
> +
> +function prepfs()
> +{
> +    set -e
> +
> +    file=`mktemp`
> +
> +    dd if=/dev/zero of=$file bs=1024 count=204800
> +
> +    yes | mkfs.$1 $file
> +
> +    if ! [ -z $ANDROID_WDIR ]; then
> +        adb shell mkdir -p $ANDROID_WDIR
> +        adb push $file $ANDROID_WDIR
> +        rm $file
> +        file=$ANDROID_WDIR/$(basename $file)
> +    fi
> +    if ! [ -z $BSD_WDIR ]; then
> +        $MYSSH mkdir -p $BSD_WDIR
> +        ssh_copy $file $BSD_WDIR
> +        rm $file
> +        file=$BSD_WDIR/$(basename $file)
> +    fi
> +
> +    export_vars file
> +}
> +
> +function cleanfs()
> +{
> +    set -e
> +
> +    if ! [ -z $ANDROID_WDIR ]; then
> +        adb shell rm $1
> +        adb shell rm $ANDROID_WDIR/disk
> +    elif ! [ -z $BSD_WDIR ]; then
> +        $MYSSH rm $1
> +        $MYSSH rm $BSD_WDIR/disk
> +    else
> +        rm $1
> +    fi
> +}
> +
> +if [ "$1" = "-t" ]; then
> +    shift
> +    fstype=$1
> +    shift
> +fi
> +
> +if [ -z "$fstype" ]; then
> +    fstype="ext4"
> +fi
> +
> +if [ -z $(which mkfs.$fstype) ]; then
> +    lkl_test_plan 0 "disk $fstype"
> +    echo "no mkfs.$fstype command"
> +    exit 0
> +fi
> +
> +lkl_test_plan 1 "disk $fstype"
> +lkl_test_run 1 prepfs $fstype
> +lkl_test_exec $script_dir/disk -d $file -t $fstype $@
> +lkl_test_plan 1 "disk $fstype"
> +lkl_test_run 1 cleanfs $file
> +
> diff --git a/tools/um/tests/run.py b/tools/um/tests/run.py
> index c96ede90b6ad..97d6dedc217c 100755
> --- a/tools/um/tests/run.py
> +++ b/tools/um/tests/run.py
> @@ -50,6 +50,8 @@ mydir=os.path.dirname(os.path.realpath(__file__))
>   
>   tests = [
>       'boot.sh',
> +    'disk.sh -t ext4',
> +    'disk.sh -t vfat',
>   ]
>   
>   parser = argparse.ArgumentParser(description='LKL test runner')

-- 
Anton R. Ivanov
Cambridgegreys Limited. Registered in England. Company Number 10273661
https://www.cambridgegreys.com/


WARNING: multiple messages have this Message-ID (diff)
From: Anton Ivanov <anton.ivanov@cambridgegreys.com>
To: Hajime Tazaki <thehajime@gmail.com>,
	linux-um@lists.infradead.org, jdike@addtoit.com, richard@nod.at
Cc: tavi.purdila@gmail.com, linux-kernel-library@freelists.org,
	retrage01@gmail.com, linux-arch@vger.kernel.org
Subject: Re: [RFC v7 21/21] um: nommu: add block device support of UML
Date: Wed, 7 Oct 2020 15:17:31 +0100	[thread overview]
Message-ID: <ac66cd8b-3bb1-5846-aa75-fc91c1149e91@cambridgegreys.com> (raw)
In-Reply-To: <a8686efcbad3c445d3e5bde054c04a58877915f1.1601960644.git.thehajime@gmail.com>


On 06/10/2020 10:44, Hajime Tazaki wrote:
> This commit adds block device support for nommu mode, and also added
> several host utilities to run a simple test program
> (tools/um/test/disk.c) successfully.
>
> Signed-off-by: Hajime Tazaki <thehajime@gmail.com>
> ---
>   arch/um/include/asm/xor.h                 |   3 +-
>   arch/um/include/shared/as-layout.h        |   1 +
>   arch/um/kernel/um_arch.c                  |   5 +
>   arch/um/nommu/include/uapi/asm/host_ops.h |   7 +
>   arch/um/nommu/include/uapi/asm/unistd.h   |   2 +
>   arch/um/nommu/um/Kconfig                  |   8 +
>   arch/um/nommu/um/setup.c                  |  12 +
>   tools/um/Targets                          |   2 +
>   tools/um/include/lkl.h                    | 206 ++++++++++
>   tools/um/include/lkl_host.h               |   1 +
>   tools/um/lib/Build                        |   1 +
>   tools/um/lib/fs.c                         | 461 ++++++++++++++++++++++
>   tools/um/lib/posix-host.c                 |   1 +
>   tools/um/lib/utils.c                      |   3 +
>   tools/um/tests/Build                      |   1 +
>   tools/um/tests/cla.c                      | 159 ++++++++
>   tools/um/tests/cla.h                      |  33 ++
>   tools/um/tests/disk.c                     | 168 ++++++++
>   tools/um/tests/disk.sh                    |  70 ++++
>   tools/um/tests/run.py                     |   2 +
>   20 files changed, 1145 insertions(+), 1 deletion(-)
>   create mode 100644 tools/um/lib/fs.c
>   create mode 100644 tools/um/tests/cla.c
>   create mode 100644 tools/um/tests/cla.h
>   create mode 100644 tools/um/tests/disk.c
>   create mode 100755 tools/um/tests/disk.sh
>
> diff --git a/arch/um/include/asm/xor.h b/arch/um/include/asm/xor.h
> index 36b33d62a35d..a5ea458a1ae9 100644
> --- a/arch/um/include/asm/xor.h
> +++ b/arch/um/include/asm/xor.h
> @@ -4,4 +4,5 @@
>   
>   /* pick an arbitrary one - measuring isn't possible with inf-cpu */
>   #define XOR_SELECT_TEMPLATE(x)	\
> -	(time_travel_mode == TT_MODE_INFCPU ? &xor_block_8regs : NULL)
> +	(time_travel_mode == TT_MODE_INFCPU || (!IS_ENABLED(CONFIG_MMU)) ? \
> +	 &xor_block_8regs : NULL)
> diff --git a/arch/um/include/shared/as-layout.h b/arch/um/include/shared/as-layout.h
> index 5f286ef2721b..4423437a5ace 100644
> --- a/arch/um/include/shared/as-layout.h
> +++ b/arch/um/include/shared/as-layout.h
> @@ -57,6 +57,7 @@ extern unsigned long host_task_size;
>   
>   extern int linux_main(int argc, char **argv);
>   extern void uml_finishsetup(void);
> +extern void uml_set_args(char *args);
>   
>   struct siginfo;
>   extern void (*sig_info[])(int, struct siginfo *si, struct uml_pt_regs *);
> diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
> index e2cb76c03b25..da6e06cf2808 100644
> --- a/arch/um/kernel/um_arch.c
> +++ b/arch/um/kernel/um_arch.c
> @@ -41,6 +41,11 @@ static void __init add_arg(char *arg)
>   	strcat(command_line, arg);
>   }
>   
> +void __init uml_set_args(char *args)
> +{
> +	strcat(command_line, args);
> +}
> +
>   /*
>    * These fields are initialized at boot time and not changed.
>    * XXX This structure is used only in the non-SMP case.  Maybe this
> diff --git a/arch/um/nommu/include/uapi/asm/host_ops.h b/arch/um/nommu/include/uapi/asm/host_ops.h
> index 0811494c080c..1b2507502969 100644
> --- a/arch/um/nommu/include/uapi/asm/host_ops.h
> +++ b/arch/um/nommu/include/uapi/asm/host_ops.h
> @@ -15,6 +15,11 @@ struct lkl_jmp_buf {
>    *
>    * These operations must be provided by a host library or by the application
>    * itself.
> + *
> + * @um_devices - string containg the list of UML devices in command line
> + * format. This string is appended to the kernel command line and
> + * is provided here for convenience to be implemented by the host library.
> + *
>    * @print - optional operation that receives console messages
>    * @panic - called during a kernel panic
>    *
> @@ -65,6 +70,8 @@ struct lkl_jmp_buf {
>    *
>    */
>   struct lkl_host_operations {
> +	const char *um_devices;
> +
>   	void (*print)(const char *str, int len);
>   	void (*panic)(void);
>   
> diff --git a/arch/um/nommu/include/uapi/asm/unistd.h b/arch/um/nommu/include/uapi/asm/unistd.h
> index 1762ebb829f5..320762099a62 100644
> --- a/arch/um/nommu/include/uapi/asm/unistd.h
> +++ b/arch/um/nommu/include/uapi/asm/unistd.h
> @@ -3,6 +3,8 @@
>   #define __UM_NOMMU_UAPI_UNISTD_H
>   
>   #define __ARCH_WANT_NEW_STAT
> +#define __ARCH_WANT_SET_GET_RLIMIT
> +
>   #include <asm/bitsperlong.h>
>   
>   #if __BITS_PER_LONG == 64
> diff --git a/arch/um/nommu/um/Kconfig b/arch/um/nommu/um/Kconfig
> index 20b3eaccb6f0..c6a3f472fe75 100644
> --- a/arch/um/nommu/um/Kconfig
> +++ b/arch/um/nommu/um/Kconfig
> @@ -4,6 +4,10 @@ config UML_NOMMU
>   	select UACCESS_MEMCPY
>   	select ARCH_THREAD_STACK_ALLOCATOR
>   	select ARCH_HAS_SYSCALL_WRAPPER
> +	select VFAT_FS
> +	select NLS_CODEPAGE_437
> +	select NLS_ISO8859_1
> +	select BTRFS_FS
>   
>   config 64BIT
>   	bool
> @@ -35,3 +39,7 @@ config STACKTRACE_SUPPORT
>   config PRINTK_TIME
>   	bool
>   	default y
> +
> +config RAID6_PQ_BENCHMARK
> +	bool
> +	default n

Why are we touching this? I thought this is already defined in lib/Kconfig?

Brgds,

A.

> diff --git a/arch/um/nommu/um/setup.c b/arch/um/nommu/um/setup.c
> index 922188690139..d71d61979ad6 100644
> --- a/arch/um/nommu/um/setup.c
> +++ b/arch/um/nommu/um/setup.c
> @@ -45,13 +45,25 @@ static void __init *lkl_run_kernel(void *arg)
>   	return NULL;
>   }
>   
> +static char _cmd_line[COMMAND_LINE_SIZE];
>   int __init lkl_start_kernel(struct lkl_host_operations *ops,
>   			    const char *fmt, ...)
>   {
> +	va_list ap;
>   	int ret;
>   
>   	lkl_ops = ops;
>   
> +	va_start(ap, fmt);
> +	ret = vsnprintf(_cmd_line, COMMAND_LINE_SIZE, fmt, ap);
> +	va_end(ap);
> +
> +	if (ops->um_devices)
> +		strscpy(_cmd_line + ret, ops->um_devices,
> +			COMMAND_LINE_SIZE - ret);
> +
> +	uml_set_args(_cmd_line);
> +
>   	init_sem = lkl_ops->sem_alloc(0);
>   	if (!init_sem)
>   		return -ENOMEM;
> diff --git a/tools/um/Targets b/tools/um/Targets
> index 2bb90381843c..f5f8ec4b9dbb 100644
> --- a/tools/um/Targets
> +++ b/tools/um/Targets
> @@ -1,10 +1,12 @@
>   ifeq ($(UMMODE),library)
>   progs-y += tests/boot
> +progs-y += tests/disk
>   else
>   progs-y += uml/linux
>   endif
>   
>   LDFLAGS_boot-y := -pie
> +LDFLAGS_disk-y := -pie
>   
>   LDLIBS := -lrt -lpthread -lutil
>   LDFLAGS_linux-y := -no-pie -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
> diff --git a/tools/um/include/lkl.h b/tools/um/include/lkl.h
> index 707e01b64a70..4a9d874bfbf0 100644
> --- a/tools/um/include/lkl.h
> +++ b/tools/um/include/lkl.h
> @@ -113,6 +113,16 @@ static inline long lkl_sys_creat(const char *file, int mode)
>   }
>   #endif
>   
> +#ifdef __lkl__NR_faccessat
> +/**
> + * lkl_sys_access - wrapper for lkl_sys_faccessat
> + */
> +static inline long lkl_sys_access(const char *file, int mode)
> +{
> +	return lkl_sys_faccessat(LKL_AT_FDCWD, file, mode);
> +}
> +#endif
> +
>   #ifdef __lkl__NR_mkdirat
>   /**
>    * lkl_sys_mkdir - wrapper for lkl_sys_mkdirat
> @@ -123,6 +133,36 @@ static inline long lkl_sys_mkdir(const char *path, mode_t mode)
>   }
>   #endif
>   
> +#ifdef __lkl__NR_unlinkat
> +/**
> + * lkl_sys_rmdir - wrapper for lkl_sys_unlinkrat
> + */
> +static inline long lkl_sys_rmdir(const char *path)
> +{
> +	return lkl_sys_unlinkat(LKL_AT_FDCWD, path, LKL_AT_REMOVEDIR);
> +}
> +#endif
> +
> +#ifdef __lkl__NR_unlinkat
> +/**
> + * lkl_sys_unlink - wrapper for lkl_sys_unlinkat
> + */
> +static inline long lkl_sys_unlink(const char *path)
> +{
> +	return lkl_sys_unlinkat(LKL_AT_FDCWD, path, 0);
> +}
> +#endif
> +
> +#ifdef __lkl__NR_mknodat
> +/**
> + * lkl_sys_mknod - wrapper for lkl_sys_mknodat
> + */
> +static inline long lkl_sys_mknod(const char *path, mode_t mode, dev_t dev)
> +{
> +	return lkl_sys_mknodat(LKL_AT_FDCWD, path, mode, dev);
> +}
> +#endif
> +
>   #ifdef __lkl__NR_epoll_create1
>   /**
>    * lkl_sys_epoll_create - wrapper for lkl_sys_epoll_create1
> @@ -144,6 +184,172 @@ static inline long lkl_sys_epoll_wait(int fd, struct lkl_epoll_event *ev,
>   }
>   #endif
>   
> +/**
> + * struct lkl_dev_blk_ops - block device host operations, defined in lkl_host.h.
> + */
> +struct lkl_dev_blk_ops;
> +
> +/**
> + * lkl_disk - host disk handle
> + *
> + * @dev - a pointer to private information for this disk backend
> + * @fd - a POSIX file descriptor that can be used by preadv/pwritev
> + * @handle - an NT file handle that can be used by ReadFile/WriteFile
> + */
> +struct lkl_disk {
> +	void *dev;
> +	union {
> +		int fd;
> +		void *handle;
> +	};
> +	struct lkl_dev_blk_ops *ops;
> +};
> +
> +/**
> + * lkl_disk_add - add a new disk
> + *
> + * @disk - the host disk handle
> + * @returns a disk id (0 is valid) or a strictly negative value in case of error
> + */
> +int lkl_disk_add(struct lkl_disk *disk);
> +
> +/**
> + * lkl_disk_remove - remove a disk
> + *
> + * This function makes a cleanup of the @disk's private information
> + * that was initialized by lkl_disk_add before.
> + *
> + * @disk - the host disk handle
> + */
> +int lkl_disk_remove(struct lkl_disk disk);
> +
> +/**
> + * lkl_encode_dev_from_sysfs_blkdev - extract device id from sysfs
> + *
> + * This function returns the device id for the given sysfs dev node.
> + * The content of the node has to be in the form 'MAJOR:MINOR'.
> + * Also, this function expects an absolute path which means that sysfs
> + * already has to be mounted at the given path
> + *
> + * @sysfs_path - absolute path to the sysfs dev node
> + * @pdevid - pointer to memory where dev id will be returned
> + * @returns - 0 on success, a negative value on error
> + */
> +int lkl_encode_dev_from_sysfs(const char *sysfs_path, uint32_t *pdevid);
> +
> +/**
> + * lkl_mount_dev - mount a disk
> + *
> + * This functions creates a device file for the given disk, creates a mount
> + * 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
> + * @mnt_str - a string that will be filled by this function with the path where
> + * the filesystem has been mounted
> + * @mnt_str_len - size of mnt_str
> + * @returns - 0 on success, a negative value on error
> + */
> +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
> + *
> + * This functions umounts the given disks and removes the device file and the
> + * 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, unsigned int part, int flags,
> +		    long timeout_ms);
> +
> +/**
> + * lkl_umount_timeout - umount filesystem with timeout
> + *
> + * @path - the path to unmount
> + * @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_timeout(char *path, int flags, long timeout_ms);
> +
> +/**
> + * lkl_opendir - open a directory
> + *
> + * @path - directory path
> + * @err - pointer to store the error in case of failure
> + * @returns - a handle to be used when calling lkl_readdir
> + */
> +struct lkl_dir *lkl_opendir(const char *path, int *err);
> +
> +/**
> + * lkl_fdopendir - open a directory
> + *
> + * @fd - file descriptor
> + * @err - pointer to store the error in case of failure
> + * @returns - a handle to be used when calling lkl_readdir
> + */
> +struct lkl_dir *lkl_fdopendir(int fd, int *err);
> +
> +/**
> + * lkl_rewinddir - reset directory stream
> + *
> + * @dir - the directory handler as returned by lkl_opendir
> + */
> +void lkl_rewinddir(struct lkl_dir *dir);
> +
> +/**
> + * lkl_closedir - close the directory
> + *
> + * @dir - the directory handler as returned by lkl_opendir
> + */
> +int lkl_closedir(struct lkl_dir *dir);
> +
> +/**
> + * lkl_readdir - get the next available entry of the directory
> + *
> + * @dir - the directory handler as returned by lkl_opendir
> + * @returns - a lkl_dirent64 entry or NULL if the end of the directory stream is
> + * reached or if an error occurred; check lkl_errdir() to distinguish between
> + * errors or end of the directory stream
> + */
> +struct lkl_linux_dirent64 *lkl_readdir(struct lkl_dir *dir);
> +
> +/**
> + * lkl_errdir - checks if an error occurred during the last lkl_readdir call
> + *
> + * @dir - the directory handler as returned by lkl_opendir
> + * @returns - 0 if no error occurred, or a negative value otherwise
> + */
> +int lkl_errdir(struct lkl_dir *dir);
> +
> +/**
> + * lkl_dirfd - gets the file descriptor associated with the directory handle
> + *
> + * @dir - the directory handle as returned by lkl_opendir
> + * @returns - a positive value,which is the LKL file descriptor associated with
> + * the directory handle, or a negative value otherwise
> + */
> +int lkl_dirfd(struct lkl_dir *dir);
> +
> +/**
> + * lkl_mount_fs - mount a file system type like proc, sys
> + * @fstype - file system type. e.g. proc, sys
> + * @returns - 0 on success. 1 if it's already mounted. negative on failure.
> + */
> +int lkl_mount_fs(char *fstype);
> +
>   #ifdef __cplusplus
>   }
>   #endif
> diff --git a/tools/um/include/lkl_host.h b/tools/um/include/lkl_host.h
> index 85e80eb4ad0d..12dd95616e43 100644
> --- a/tools/um/include/lkl_host.h
> +++ b/tools/um/include/lkl_host.h
> @@ -10,6 +10,7 @@ extern "C" {
>   #include <lkl.h>
>   
>   extern struct lkl_host_operations lkl_host_ops;
> +extern char lkl_um_devs[4096];
>   
>   /**
>    * lkl_printf - print a message via the host print operation
> diff --git a/tools/um/lib/Build b/tools/um/lib/Build
> index dddff26a3b4e..29491b40746c 100644
> --- a/tools/um/lib/Build
> +++ b/tools/um/lib/Build
> @@ -4,3 +4,4 @@ CFLAGS_posix-host.o += -D_FILE_OFFSET_BITS=64
>   liblinux-$(CONFIG_UMMODE_LIB) += utils.o
>   liblinux-$(CONFIG_UMMODE_LIB) += posix-host.o
>   liblinux-$(CONFIG_UMMODE_LIB) += jmp_buf.o
> +liblinux-$(CONFIG_UMMODE_LIB) += fs.o
> diff --git a/tools/um/lib/fs.c b/tools/um/lib/fs.c
> new file mode 100644
> index 000000000000..948aac9730c2
> --- /dev/null
> +++ b/tools/um/lib/fs.c
> @@ -0,0 +1,461 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include <stdarg.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <stdlib.h>
> +#include <lkl_host.h>
> +
> +#define MAX_FSTYPE_LEN 50
> +
> +static struct lkl_disk *lkl_disks[16];
> +static int registered_blk_dev_idx;
> +
> +static int lkl_disk_um_add(struct lkl_disk *disk, const char *blkparams)
> +{
> +	/* concat strings */
> +	snprintf(lkl_um_devs + strlen(lkl_um_devs), sizeof(lkl_um_devs),
> +		 " ubd%d=%s", registered_blk_dev_idx, blkparams);
> +
> +	return registered_blk_dev_idx++;
> +}
> +
> +int lkl_disk_add(struct lkl_disk *disk)
> +{
> +	int ret = -1;
> +
> +	ret = lkl_disk_um_add(disk, disk->dev);
> +
> +	lkl_disks[ret] = disk;
> +
> +	return ret;
> +}
> +
> +int lkl_disk_remove(struct lkl_disk disk)
> +{
> +	/* FIXME */
> +	return 0;
> +}
> +
> +int lkl_mount_fs(char *fstype)
> +{
> +	char dir[MAX_FSTYPE_LEN+2] = "/";
> +	int flags = 0, ret = 0;
> +
> +	strncat(dir, fstype, MAX_FSTYPE_LEN);
> +
> +	/* Create with regular umask */
> +	ret = lkl_sys_mkdir(dir, 0xff);
> +	if (ret && ret != -LKL_EEXIST) {
> +		lkl_perror("mount_fs mkdir", ret);
> +		return ret;
> +	}
> +
> +	/* We have no use for nonzero flags right now */
> +	ret = lkl_sys_mount("none", dir, fstype, flags, NULL);
> +	if (ret && ret != -LKL_EBUSY) {
> +		lkl_sys_rmdir(dir);
> +		return ret;
> +	}
> +
> +	if (ret == -LKL_EBUSY)
> +		return 1;
> +	return 0;
> +}
> +
> +static uint32_t new_encode_dev(unsigned int major, unsigned int minor)
> +{
> +	return (minor & 0xff) | (major << 8) | ((minor & ~0xff) << 12);
> +}
> +
> +static int startswith(const char *str, const char *pre)
> +{
> +	return strncmp(pre, str, strlen(pre)) == 0;
> +}
> +
> +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;
> +	int ret;
> +
> +	dir = lkl_opendir(path, &ret);
> +	if (!dir)
> +		return ret;
> +
> +	ret = -LKL_ENOENT;
> +
> +	while ((dirent = lkl_readdir(dir))) {
> +		if (startswith(dirent->d_name, prefix)) {
> +			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);
> +
> +	return ret;
> +}
> +
> +int lkl_encode_dev_from_sysfs(const char *sysfs_path, uint32_t *pdevid)
> +{
> +	int ret;
> +	long fd;
> +	int major, minor;
> +	char buf[16] = { 0, };
> +	char *bufptr;
> +
> +	fd = lkl_sys_open(sysfs_path, LKL_O_RDONLY, 0);
> +	if (fd < 0)
> +		return fd;
> +
> +	ret = lkl_sys_read(fd, buf, sizeof(buf));
> +	if (ret < 0)
> +		goto out_close;
> +
> +	if (ret == sizeof(buf)) {
> +		ret = -LKL_ENOBUFS;
> +		goto out_close;
> +	}
> +
> +	bufptr = strchr(buf, ':');
> +	if (bufptr == NULL) {
> +		ret = -LKL_EINVAL;
> +		goto out_close;
> +	}
> +	bufptr[0] = '\0';
> +	bufptr++;
> +
> +	major = atoi(buf);
> +	minor = atoi(bufptr);
> +
> +	*pdevid = new_encode_dev(major, minor);
> +	ret = 0;
> +
> +out_close:
> +	lkl_sys_close(fd);
> +
> +	return ret;
> +}
> +
> +#define SYSFS_DEV_UMBLK_CMDLINE_PATH \
> +	"/sysfs/devices/platform/uml-blkdev.%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 >= (int)(buf->len - (buf->ptr - buf->mem))))
> +		return -LKL_ENOMEM;
> +
> +	buf->ptr += ret;
> +
> +	return 0;
> +}
> +
> +static int __lkl_get_blkdev(int disk_id, unsigned int part, uint32_t *pdevid,
> +			    const char *sysfs_path_fmt, const char *drv_prefix,
> +			    const char *disk_prefix)
> +{
> +	char sysfs_path[LKL_PATH_MAX];
> +	char drv_name[LKL_PATH_MAX];
> +	char disk_name[LKL_PATH_MAX];
> +	struct abuf sysfs_path_buf = {
> +		.mem = sysfs_path,
> +		.len = sizeof(sysfs_path),
> +	};
> +	int ret;
> +
> +	if (disk_id < 0)
> +		return -LKL_EINVAL;
> +
> +	ret = lkl_mount_fs("sysfs");
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = snprintf_append(&sysfs_path_buf, sysfs_path_fmt, disk_id);
> +	if (ret)
> +		return ret;
> +
> +	ret = get_node_with_prefix(sysfs_path, drv_prefix, drv_name,
> +				   sizeof(drv_name));
> +	if (ret)
> +		return ret;
> +
> +	ret = snprintf_append(&sysfs_path_buf, "/%s/block", drv_name);
> +	if (ret)
> +		return ret;
> +
> +	ret = get_node_with_prefix(sysfs_path, disk_prefix, 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 lkl_encode_dev_from_sysfs(sysfs_path, pdevid);
> +}
> +
> +int lkl_get_blkdev(int disk_id, unsigned int part, uint32_t *pdevid)
> +{
> +	char *fmt;
> +
> +	fmt = SYSFS_DEV_UMBLK_CMDLINE_PATH;
> +	return __lkl_get_blkdev(disk_id, part, pdevid, fmt, "", "ubd");
> +}
> +
> +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" };
> +	unsigned int dev;
> +	int err;
> +	char _data[4096]; /* FIXME: PAGE_SIZE is not exported by LKL */
> +
> +	if (mnt_str_len < sizeof(dev_str))
> +		return -LKL_ENOMEM;
> +
> +	err = lkl_get_blkdev(disk_id, part, &dev);
> +	if (err < 0)
> +		return err;
> +
> +	snprintf(dev_str, sizeof(dev_str), "/dev/%08x", dev);
> +	snprintf(mnt_str, mnt_str_len, "/mnt/%08x", dev);
> +
> +	err = lkl_sys_access("/dev", LKL_S_IRWXO);
> +	if (err < 0) {
> +		if (err == -LKL_ENOENT)
> +			err = lkl_sys_mkdir("/dev", 0700);
> +		if (err < 0)
> +			return err;
> +	}
> +
> +	err = lkl_sys_mknod(dev_str, LKL_S_IFBLK | 0600, dev);
> +	if (err < 0)
> +		return err;
> +
> +	err = lkl_sys_access("/mnt", LKL_S_IRWXO);
> +	if (err < 0) {
> +		if (err == -LKL_ENOENT)
> +			err = lkl_sys_mkdir("/mnt", 0700);
> +		if (err < 0)
> +			return err;
> +	}
> +
> +	err = lkl_sys_mkdir(mnt_str, 0700);
> +	if (err < 0) {
> +		lkl_sys_unlink(dev_str);
> +		return err;
> +	}
> +
> +	/* kernel always copies a full page */
> +	if (data) {
> +		strncpy(_data, data, sizeof(_data));
> +		_data[sizeof(_data) - 1] = 0;
> +	} else {
> +		_data[0] = 0;
> +	}
> +
> +	err = lkl_sys_mount(dev_str, mnt_str, (char *)fs_type, flags, _data);
> +	if (err < 0) {
> +		lkl_sys_unlink(dev_str);
> +		lkl_sys_rmdir(mnt_str);
> +		return err;
> +	}
> +
> +	return 0;
> +}
> +
> +long lkl_umount_timeout(char *path, int flags, long timeout_ms)
> +{
> +	long incr = 10000000; /* 10 ms */
> +	struct lkl_timespec ts = {
> +		.tv_sec = 0,
> +		.tv_nsec = incr,
> +	};
> +	long err;
> +
> +	do {
> +		err = lkl_sys_umount(path, flags);
> +		if (err == -LKL_EBUSY) {
> +			lkl_sys_nanosleep((struct __lkl__kernel_timespec *)&ts,
> +					  NULL);
> +			timeout_ms -= incr / 1000000;
> +		}
> +	} while (err == -LKL_EBUSY && timeout_ms > 0);
> +
> +	return err;
> +}
> +
> +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_blkdev(disk_id, part, &dev);
> +	if (err < 0)
> +		return err;
> +
> +	snprintf(dev_str, sizeof(dev_str), "/dev/%08x", dev);
> +	snprintf(mnt_str, sizeof(mnt_str), "/mnt/%08x", dev);
> +
> +	err = lkl_umount_timeout(mnt_str, flags, timeout_ms);
> +	if (err)
> +		return err;
> +
> +	err = lkl_sys_unlink(dev_str);
> +	if (err)
> +		return err;
> +
> +	return lkl_sys_rmdir(mnt_str);
> +}
> +
> +struct lkl_dir {
> +	int fd;
> +	char buf[1024];
> +	char *pos;
> +	int len;
> +};
> +
> +static struct lkl_dir *lkl_dir_alloc(int *err)
> +{
> +	struct lkl_dir *dir = lkl_host_ops.mem_alloc(sizeof(struct lkl_dir));
> +
> +	if (!dir) {
> +		*err = -LKL_ENOMEM;
> +		return NULL;
> +	}
> +
> +	dir->len = 0;
> +	dir->pos = NULL;
> +
> +	return dir;
> +}
> +
> +struct lkl_dir *lkl_opendir(const char *path, int *err)
> +{
> +	struct lkl_dir *dir = lkl_dir_alloc(err);
> +
> +	if (!dir) {
> +		*err = -LKL_ENOMEM;
> +		return NULL;
> +	}
> +
> +	dir->fd = lkl_sys_open(path, LKL_O_RDONLY | LKL_O_DIRECTORY, 0);
> +	if (dir->fd < 0) {
> +		*err = dir->fd;
> +		lkl_host_ops.mem_free(dir);
> +		return NULL;
> +	}
> +
> +	*err = 0;
> +
> +	return dir;
> +}
> +
> +struct lkl_dir *lkl_fdopendir(int fd, int *err)
> +{
> +	struct lkl_dir *dir = lkl_dir_alloc(err);
> +
> +	if (!dir)
> +		return NULL;
> +
> +	dir->fd = fd;
> +
> +	return dir;
> +}
> +
> +void lkl_rewinddir(struct lkl_dir *dir)
> +{
> +	lkl_sys_lseek(dir->fd, 0, LKL_SEEK_SET);
> +	dir->len = 0;
> +	dir->pos = NULL;
> +}
> +
> +int lkl_closedir(struct lkl_dir *dir)
> +{
> +	int ret;
> +
> +	ret = lkl_sys_close(dir->fd);
> +	lkl_host_ops.mem_free(dir);
> +
> +	return ret;
> +}
> +
> +struct lkl_linux_dirent64 *lkl_readdir(struct lkl_dir *dir)
> +{
> +	struct lkl_linux_dirent64 *de;
> +
> +	if (dir->len < 0)
> +		return NULL;
> +
> +	if (!dir->pos || dir->pos - dir->buf >= dir->len)
> +		goto read_buf;
> +
> +return_de:
> +	de = (struct lkl_linux_dirent64 *)dir->pos;
> +	dir->pos += de->d_reclen;
> +
> +	return de;
> +
> +read_buf:
> +	dir->pos = NULL;
> +	de = (struct lkl_linux_dirent64 *)dir->buf;
> +	dir->len = lkl_sys_getdents64(dir->fd, de, sizeof(dir->buf));
> +	if (dir->len <= 0)
> +		return NULL;
> +
> +	dir->pos = dir->buf;
> +	goto return_de;
> +}
> +
> +int lkl_errdir(struct lkl_dir *dir)
> +{
> +	if (dir->len >= 0)
> +		return 0;
> +
> +	return dir->len;
> +}
> +
> +int lkl_dirfd(struct lkl_dir *dir)
> +{
> +	return dir->fd;
> +}
> +
> +int lkl_set_fd_limit(unsigned int fd_limit)
> +{
> +	struct lkl_rlimit rlim = {
> +		.rlim_cur = fd_limit,
> +		.rlim_max = fd_limit,
> +	};
> +	return lkl_sys_setrlimit(LKL_RLIMIT_NOFILE, &rlim);
> +}
> diff --git a/tools/um/lib/posix-host.c b/tools/um/lib/posix-host.c
> index b6b5b2902254..8fd88031bf2b 100644
> --- a/tools/um/lib/posix-host.c
> +++ b/tools/um/lib/posix-host.c
> @@ -263,6 +263,7 @@ static void *tls_get(struct lkl_tls_key *key)
>   }
>   
>   struct lkl_host_operations lkl_host_ops = {
> +	.um_devices = lkl_um_devs,
>   	.panic = panic,
>   	.print = print,
>   	.mem_alloc = (void *)malloc,
> diff --git a/tools/um/lib/utils.c b/tools/um/lib/utils.c
> index 4930479a8a35..ac65cd744a14 100644
> --- a/tools/um/lib/utils.c
> +++ b/tools/um/lib/utils.c
> @@ -4,6 +4,9 @@
>   #include <string.h>
>   #include <lkl_host.h>
>   
> +/* XXX: find a better place */
> +char lkl_um_devs[4096];
> +
>   static const char * const lkl_err_strings[] = {
>   	"Success",
>   	"Operation not permitted",
> diff --git a/tools/um/tests/Build b/tools/um/tests/Build
> index 564560486f98..1aa78f9ed7ef 100644
> --- a/tools/um/tests/Build
> +++ b/tools/um/tests/Build
> @@ -1,3 +1,4 @@
>   boot-y += boot.o test.o
> +disk-y += disk.o test.o cla.o
>   
>   CFLAGS_test.o += -Wno-implicit-fallthrough
> diff --git a/tools/um/tests/cla.c b/tools/um/tests/cla.c
> new file mode 100644
> index 000000000000..694e3a3822be
> --- /dev/null
> +++ b/tools/um/tests/cla.c
> @@ -0,0 +1,159 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include <stdio.h>
> +#include <string.h>
> +#include <errno.h>
> +#include <stdlib.h>
> +#ifdef __MINGW32__
> +#include <winsock2.h>
> +#else
> +#include <sys/socket.h>
> +#include <netinet/in.h>
> +#include <arpa/inet.h>
> +#endif
> +
> +#include "cla.h"
> +
> +static int cl_arg_parse_bool(struct cl_arg *arg, const char *value)
> +{
> +	*((int *)arg->store) = 1;
> +	return 0;
> +}
> +
> +static int cl_arg_parse_str(struct cl_arg *arg, const char *value)
> +{
> +	*((const char **)arg->store) = value;
> +	return 0;
> +}
> +
> +static int cl_arg_parse_int(struct cl_arg *arg, const char *value)
> +{
> +	errno = 0;
> +	*((int *)arg->store) = strtol(value, NULL, 0);
> +	return errno == 0;
> +}
> +
> +static int cl_arg_parse_str_set(struct cl_arg *arg, const char *value)
> +{
> +	const char **set = arg->set;
> +	int i;
> +
> +	for (i = 0; set[i] != NULL; i++) {
> +		if (strcmp(set[i], value) == 0) {
> +			*((int *)arg->store) = i;
> +			return 0;
> +		}
> +	}
> +
> +	return (-1);
> +}
> +
> +static int cl_arg_parse_ipv4(struct cl_arg *arg, const char *value)
> +{
> +	unsigned int addr;
> +
> +	if (!value)
> +		return (-1);
> +
> +	addr = inet_addr(value);
> +	if (addr == INADDR_NONE)
> +		return (-1);
> +	*((unsigned int *)arg->store) = addr;
> +	return 0;
> +}
> +
> +static cl_arg_parser_t parsers[] = {
> +	[CL_ARG_BOOL] = cl_arg_parse_bool,
> +	[CL_ARG_INT] = cl_arg_parse_int,
> +	[CL_ARG_STR] = cl_arg_parse_str,
> +	[CL_ARG_STR_SET] = cl_arg_parse_str_set,
> +	[CL_ARG_IPV4] = cl_arg_parse_ipv4,
> +};
> +
> +static struct cl_arg *find_short_arg(char name, struct cl_arg *args)
> +{
> +	struct cl_arg *arg;
> +
> +	for (arg = args; arg->short_name != 0; arg++) {
> +		if (arg->short_name == name)
> +			return arg;
> +	}
> +
> +	return NULL;
> +}
> +
> +static struct cl_arg *find_long_arg(const char *name, struct cl_arg *args)
> +{
> +	struct cl_arg *arg;
> +
> +	for (arg = args; arg->long_name; arg++) {
> +		if (strcmp(arg->long_name, name) == 0)
> +			return arg;
> +	}
> +
> +	return NULL;
> +}
> +
> +static void print_help(struct cl_arg *args)
> +{
> +	struct cl_arg *arg;
> +
> +	fprintf(stderr, "usage:\n");
> +	for (arg = args; arg->long_name; arg++) {
> +		fprintf(stderr, "-%c, --%-20s %s", arg->short_name,
> +			arg->long_name, arg->help);
> +		if (arg->type == CL_ARG_STR_SET) {
> +			const char **set = arg->set;
> +
> +			fprintf(stderr, " [ ");
> +			while (*set != NULL)
> +				fprintf(stderr, "%s ", *(set++));
> +			fprintf(stderr, "]");
> +		}
> +		fprintf(stderr, "\n");
> +	}
> +}
> +
> +int cla_parse_args(int argc, const char **argv, struct cl_arg *args)
> +{
> +	int i;
> +
> +	for (i = 1; i < argc; i++) {
> +		struct cl_arg *arg = NULL;
> +		cl_arg_parser_t parser;
> +
> +		if (argv[i][0] == '-') {
> +			if (argv[i][1] != '-')
> +				arg = find_short_arg(argv[i][1], args);
> +			else
> +				arg = find_long_arg(&argv[i][2], args);
> +		}
> +
> +		if (!arg) {
> +			fprintf(stderr, "unknown option '%s'\n", argv[i]);
> +			print_help(args);
> +			return (-1);
> +		}
> +
> +		if (arg->type == CL_ARG_USER || arg->type >= CL_ARG_END)
> +			parser = arg->parser;
> +		else
> +			parser = parsers[arg->type];
> +
> +		if (!parser) {
> +			fprintf(stderr, "can't parse --'%s'/-'%c'\n",
> +				arg->long_name, args->short_name);
> +			return (-1);
> +		}
> +
> +		if (parser(arg, argv[i + 1]) < 0) {
> +			fprintf(stderr, "can't parse '%s'\n", argv[i]);
> +			print_help(args);
> +			return (-1);
> +		}
> +
> +		if (arg->has_arg)
> +			i++;
> +	}
> +
> +	return 0;
> +}
> diff --git a/tools/um/tests/cla.h b/tools/um/tests/cla.h
> new file mode 100644
> index 000000000000..3d879233681f
> --- /dev/null
> +++ b/tools/um/tests/cla.h
> @@ -0,0 +1,33 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +#ifndef _LKL_TEST_CLA_H
> +#define _LKL_TEST_CLA_H
> +
> +enum cl_arg_type {
> +	CL_ARG_USER = 0,
> +	CL_ARG_BOOL,
> +	CL_ARG_INT,
> +	CL_ARG_STR,
> +	CL_ARG_STR_SET,
> +	CL_ARG_IPV4,
> +	CL_ARG_END,
> +};
> +
> +struct cl_arg;
> +
> +typedef int (*cl_arg_parser_t)(struct cl_arg *arg, const char *value);
> +
> +struct cl_arg {
> +	const char *long_name;
> +	char short_name;
> +	const char *help;
> +	int has_arg;
> +	enum cl_arg_type type;
> +	void *store;
> +	void *set;
> +	cl_arg_parser_t parser;
> +};
> +
> +int cla_parse_args(int argc, const char **argv, struct cl_arg *args);
> +
> +
> +#endif /* _LKL_TEST_CLA_H */
> diff --git a/tools/um/tests/disk.c b/tools/um/tests/disk.c
> new file mode 100644
> index 000000000000..325934935e6a
> --- /dev/null
> +++ b/tools/um/tests/disk.c
> @@ -0,0 +1,168 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <time.h>
> +#include <stdlib.h>
> +#include <stdint.h>
> +#include <lkl.h>
> +#include <lkl_host.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <sys/ioctl.h>
> +
> +#include "test.h"
> +#include "cla.h"
> +
> +static struct {
> +	int printk;
> +	const char *disk;
> +	const char *fstype;
> +	int partition;
> +} cla;
> +
> +struct cl_arg args[] = {
> +	{"disk", 'd', "disk file to use", 1, CL_ARG_STR, &cla.disk},
> +	{"partition", 'P', "partition to mount", 1, CL_ARG_INT, &cla.partition},
> +	{"type", 't', "filesystem type", 1, CL_ARG_STR, &cla.fstype},
> +	{0},
> +};
> +
> +
> +static struct lkl_disk disk;
> +static int disk_id = -1;
> +
> +int lkl_test_disk_add(void)
> +{
> +	disk.fd = open(cla.disk, O_RDWR);
> +	if (disk.fd < 0)
> +		goto out_unlink;
> +
> +	disk.ops = NULL;
> +	disk.dev = (char *)cla.disk;
> +
> +	disk_id = lkl_disk_add(&disk);
> +	if (disk_id < 0)
> +		goto out_close;
> +
> +	goto out;
> +
> +out_close:
> +	close(disk.fd);
> +
> +out_unlink:
> +	unlink(cla.disk);
> +
> +out:
> +	lkl_test_logf("disk fd/handle %x disk_id %d", disk.fd, disk_id);
> +
> +	if (disk_id >= 0)
> +		return TEST_SUCCESS;
> +
> +	return TEST_FAILURE;
> +}
> +
> +int lkl_test_disk_remove(void)
> +{
> +	int ret;
> +
> +	ret = lkl_disk_remove(disk);
> +
> +	close(disk.fd);
> +
> +	if (ret == 0)
> +		return TEST_SUCCESS;
> +
> +	return TEST_FAILURE;
> +}
> +
> +
> +static char mnt_point[32];
> +
> +LKL_TEST_CALL(mount_dev, lkl_mount_dev, 0, disk_id, cla.partition, cla.fstype,
> +	      0, NULL, mnt_point, sizeof(mnt_point))
> +
> +static int lkl_test_umount_dev(void)
> +{
> +	long ret, ret2;
> +
> +	ret = lkl_sys_chdir("/");
> +
> +	ret2 = lkl_umount_dev(disk_id, cla.partition, 0, 1000);
> +
> +	lkl_test_logf("%ld %ld", ret, ret2);
> +
> +	if (!ret && !ret2)
> +		return TEST_SUCCESS;
> +
> +	return TEST_FAILURE;
> +}
> +
> +struct lkl_dir *dir;
> +
> +static int lkl_test_opendir(void)
> +{
> +	int err;
> +
> +	dir = lkl_opendir(mnt_point, &err);
> +
> +	lkl_test_logf("lkl_opedir(%s) = %d %s\n", mnt_point, err,
> +		      lkl_strerror(err));
> +
> +	if (err == 0)
> +		return TEST_SUCCESS;
> +
> +	return TEST_FAILURE;
> +}
> +
> +static int lkl_test_readdir(void)
> +{
> +	struct lkl_linux_dirent64 *de = lkl_readdir(dir);
> +	int wr = 0;
> +
> +	while (de) {
> +		wr += lkl_test_logf("%s ", de->d_name);
> +		if (wr >= 70) {
> +			lkl_test_logf("\n");
> +			wr = 0;
> +			break;
> +		}
> +		de = lkl_readdir(dir);
> +	}
> +
> +	if (lkl_errdir(dir) == 0)
> +		return TEST_SUCCESS;
> +
> +	return TEST_FAILURE;
> +}
> +
> +LKL_TEST_CALL(closedir, lkl_closedir, 0, dir);
> +LKL_TEST_CALL(chdir_mnt_point, lkl_sys_chdir, 0, mnt_point);
> +LKL_TEST_CALL(start_kernel, lkl_start_kernel, 0, &lkl_host_ops,
> +	     "mem=16M loglevel=8");
> +LKL_TEST_CALL(stop_kernel, lkl_sys_halt, 0);
> +
> +struct lkl_test tests[] = {
> +	LKL_TEST(disk_add),
> +	LKL_TEST(start_kernel),
> +	LKL_TEST(mount_dev),
> +	LKL_TEST(chdir_mnt_point),
> +	LKL_TEST(opendir),
> +	LKL_TEST(readdir),
> +	LKL_TEST(closedir),
> +	LKL_TEST(umount_dev),
> +	LKL_TEST(stop_kernel),
> +	LKL_TEST(disk_remove),
> +
> +};
> +
> +int main(int argc, const char **argv)
> +{
> +	if (cla_parse_args(argc, argv, args) < 0)
> +		return (-1);
> +
> +	lkl_host_ops.print = lkl_test_log;
> +
> +	return lkl_test_run(tests, sizeof(tests)/sizeof(struct lkl_test),
> +			    "disk %s", cla.fstype);
> +}
> diff --git a/tools/um/tests/disk.sh b/tools/um/tests/disk.sh
> new file mode 100755
> index 000000000000..e2ec6cf69d4b
> --- /dev/null
> +++ b/tools/um/tests/disk.sh
> @@ -0,0 +1,70 @@
> +#!/usr/bin/env bash
> +# SPDX-License-Identifier: GPL-2.0
> +
> +script_dir=$(cd $(dirname ${BASH_SOURCE:-$0}); pwd)
> +
> +source $script_dir/test.sh
> +
> +function prepfs()
> +{
> +    set -e
> +
> +    file=`mktemp`
> +
> +    dd if=/dev/zero of=$file bs=1024 count=204800
> +
> +    yes | mkfs.$1 $file
> +
> +    if ! [ -z $ANDROID_WDIR ]; then
> +        adb shell mkdir -p $ANDROID_WDIR
> +        adb push $file $ANDROID_WDIR
> +        rm $file
> +        file=$ANDROID_WDIR/$(basename $file)
> +    fi
> +    if ! [ -z $BSD_WDIR ]; then
> +        $MYSSH mkdir -p $BSD_WDIR
> +        ssh_copy $file $BSD_WDIR
> +        rm $file
> +        file=$BSD_WDIR/$(basename $file)
> +    fi
> +
> +    export_vars file
> +}
> +
> +function cleanfs()
> +{
> +    set -e
> +
> +    if ! [ -z $ANDROID_WDIR ]; then
> +        adb shell rm $1
> +        adb shell rm $ANDROID_WDIR/disk
> +    elif ! [ -z $BSD_WDIR ]; then
> +        $MYSSH rm $1
> +        $MYSSH rm $BSD_WDIR/disk
> +    else
> +        rm $1
> +    fi
> +}
> +
> +if [ "$1" = "-t" ]; then
> +    shift
> +    fstype=$1
> +    shift
> +fi
> +
> +if [ -z "$fstype" ]; then
> +    fstype="ext4"
> +fi
> +
> +if [ -z $(which mkfs.$fstype) ]; then
> +    lkl_test_plan 0 "disk $fstype"
> +    echo "no mkfs.$fstype command"
> +    exit 0
> +fi
> +
> +lkl_test_plan 1 "disk $fstype"
> +lkl_test_run 1 prepfs $fstype
> +lkl_test_exec $script_dir/disk -d $file -t $fstype $@
> +lkl_test_plan 1 "disk $fstype"
> +lkl_test_run 1 cleanfs $file
> +
> diff --git a/tools/um/tests/run.py b/tools/um/tests/run.py
> index c96ede90b6ad..97d6dedc217c 100755
> --- a/tools/um/tests/run.py
> +++ b/tools/um/tests/run.py
> @@ -50,6 +50,8 @@ mydir=os.path.dirname(os.path.realpath(__file__))
>   
>   tests = [
>       'boot.sh',
> +    'disk.sh -t ext4',
> +    'disk.sh -t vfat',
>   ]
>   
>   parser = argparse.ArgumentParser(description='LKL test runner')

-- 
Anton R. Ivanov
Cambridgegreys Limited. Registered in England. Company Number 10273661
https://www.cambridgegreys.com/


_______________________________________________
linux-um mailing list
linux-um@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-um


  reply	other threads:[~2020-10-07 14:17 UTC|newest]

Thread overview: 476+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-02-05  7:30 [RFC v3 00/26] Unifying LKL into UML Hajime Tazaki
2020-02-05  7:30 ` [RFC v3 01/26] asm-generic: atomic64: allow using generic atomic64 on 64bit platforms Hajime Tazaki
2020-02-05  9:34   ` Peter Zijlstra
2020-02-05 12:24     ` Octavian Purdila
2020-02-05 12:24       ` Octavian Purdila
2020-02-05 12:29       ` Anton Ivanov
2020-02-05 12:29         ` Anton Ivanov
2020-02-05 12:49       ` Peter Zijlstra
2020-02-05 12:49         ` Peter Zijlstra
2020-02-05 14:00         ` Octavian Purdila
2020-02-05 14:00           ` Octavian Purdila
2020-02-05 17:13           ` Peter Zijlstra
2020-02-05 17:13             ` Peter Zijlstra
2020-02-07 12:32             ` Octavian Purdila
2020-02-07 12:32               ` Octavian Purdila
     [not found] ` <cover.1580882335.git.thehajime-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2020-02-05  7:30   ` [RFC v3 02/26] arch: add __SYSCALL_DEFINE_ARCH Hajime Tazaki
2020-02-05  7:30     ` Hajime Tazaki
2020-02-05  7:30 ` [RFC v3 03/26] um lkl: architecture skeleton for Linux kernel library Hajime Tazaki
2020-02-05  7:30   ` Hajime Tazaki
2020-02-05  7:30 ` [RFC v3 04/26] um lkl: host interface Hajime Tazaki
2020-02-05  7:30   ` Hajime Tazaki
2020-02-05  7:30 ` [RFC v3 05/26] um lkl: memory handling Hajime Tazaki
2020-02-05  7:30   ` Hajime Tazaki
2020-02-05  7:30 ` [RFC v3 06/26] um lkl: kernel threads support Hajime Tazaki
2020-02-05  7:30   ` Hajime Tazaki
2020-02-05  7:30 ` [RFC v3 07/26] um lkl: interrupt support Hajime Tazaki
2020-02-05  7:30   ` Hajime Tazaki
2020-02-05 10:47   ` Anton Ivanov
2020-02-05 10:47     ` Anton Ivanov
2020-02-05 14:46     ` Hajime Tazaki
2020-02-05 14:46       ` Hajime Tazaki
2020-02-05  7:30 ` [RFC v3 08/26] um lkl: system call interface and application API Hajime Tazaki
2020-02-05  7:30   ` Hajime Tazaki
2020-02-05  7:30 ` [RFC v3 09/26] um lkl: timers, time and delay support Hajime Tazaki
2020-02-05  7:30   ` Hajime Tazaki
2020-02-05  7:30 ` [RFC v3 10/26] um lkl: basic kernel console support Hajime Tazaki
2020-02-05  7:30   ` Hajime Tazaki
2020-02-05  7:30 ` [RFC v3 11/26] um lkl: initialization and cleanup Hajime Tazaki
2020-02-05  7:30   ` Hajime Tazaki
2020-02-05  7:30 ` [RFC v3 12/26] um lkl: plug in the build system Hajime Tazaki
2020-02-05  7:30   ` Hajime Tazaki
2020-02-05  7:30 ` [RFC v3 13/26] lkl tools: skeleton for host side library Hajime Tazaki
2020-02-05  7:30   ` Hajime Tazaki
2020-02-05  7:30 ` [RFC v3 14/26] lkl tools: host lib: add utilities functions Hajime Tazaki
2020-02-05  7:30   ` Hajime Tazaki
2020-02-05  7:30 ` [RFC v3 15/26] lkl tools: host lib: filesystem helpers Hajime Tazaki
2020-02-05  7:30   ` Hajime Tazaki
2020-02-05  7:30 ` [RFC v3 16/26] lkl tools: host lib: networking helpers Hajime Tazaki
2020-02-05  7:30 ` [RFC v3 17/26] lkl tools: host lib: posix host operations Hajime Tazaki
2020-02-05  7:30   ` Hajime Tazaki
2020-02-05  7:30 ` [RFC v3 18/26] lkl tools: add test programs Hajime Tazaki
2020-02-05  7:30 ` [RFC v3 19/26] lkl tools: cptofs that reads/writes to/from a filesystem image Hajime Tazaki
2020-02-05  7:30   ` Hajime Tazaki
2020-02-05  7:30 ` [RFC v3 20/26] lkl tools: fs2tar that converts a filesystem image to tar Hajime Tazaki
2020-02-05  7:30   ` Hajime Tazaki
2020-02-05  7:30 ` [RFC v3 21/26] lkl tools: add lklfuse Hajime Tazaki
2020-02-05  7:30 ` [RFC v3 22/26] um lkl: add documentation Hajime Tazaki
2020-02-05  7:30   ` Hajime Tazaki
2020-02-05  7:30 ` [RFC v3 23/26] um lkl: add CI scripts to conduct regression tests Hajime Tazaki
2020-02-05  7:30 ` [RFC v3 24/26] um lkl: add UML network driver for lkl Hajime Tazaki
2020-02-05  7:30 ` [RFC v3 25/26] um lkl: add UML block device driver (ubd) " Hajime Tazaki
2020-02-05  7:30 ` [RFC v3 26/26] um: fix clone flags to be familar with valgrind Hajime Tazaki
2020-03-30 14:45 ` [RFC v4 00/25] Unifying LKL into UML Hajime Tazaki
2020-03-30 14:45   ` Hajime Tazaki
2020-03-30 14:45   ` [RFC v4 01/25] arch: add __SYSCALL_DEFINE_ARCH Hajime Tazaki
2020-03-30 14:45     ` Hajime Tazaki
2020-03-30 14:45   ` [RFC v4 02/25] um lkl: architecture skeleton for Linux kernel library Hajime Tazaki
2020-03-30 14:45     ` Hajime Tazaki
2020-03-30 21:53     ` Johannes Berg
2020-03-30 21:53       ` Johannes Berg
2020-03-30 22:12       ` Richard Weinberger
2020-03-30 22:12         ` Richard Weinberger
2020-03-31  7:08         ` Hajime Tazaki
2020-03-31  7:08           ` Hajime Tazaki
2020-03-31 20:16           ` Johannes Berg
2020-03-31 20:16             ` Johannes Berg
2020-04-02  6:44             ` Hajime Tazaki
2020-04-02  6:44               ` Hajime Tazaki
2020-04-07 19:25               ` Octavian Purdila
2020-04-07 19:25                 ` Octavian Purdila
2020-04-07 19:25                 ` Octavian Purdila
2020-03-30 14:45   ` [RFC v4 03/25] um lkl: host interface Hajime Tazaki
2020-03-30 14:45     ` Hajime Tazaki
2020-03-30 14:45   ` [RFC v4 04/25] um lkl: memory handling Hajime Tazaki
2020-03-30 14:45     ` Hajime Tazaki
2020-03-30 14:45   ` [RFC v4 05/25] um lkl: kernel threads support Hajime Tazaki
2020-03-30 14:45     ` Hajime Tazaki
2020-03-30 14:45   ` [RFC v4 06/25] um lkl: interrupt support Hajime Tazaki
2020-03-30 14:45     ` Hajime Tazaki
2020-03-30 14:45   ` [RFC v4 07/25] um lkl: system call interface and application API Hajime Tazaki
2020-03-30 14:45     ` Hajime Tazaki
2020-03-30 14:45   ` [RFC v4 08/25] um lkl: timers, time and delay support Hajime Tazaki
2020-03-30 14:45     ` Hajime Tazaki
2020-03-30 14:45   ` [RFC v4 09/25] um lkl: basic kernel console support Hajime Tazaki
2020-03-30 14:45     ` Hajime Tazaki
2020-03-30 14:45   ` [RFC v4 10/25] um lkl: initialization and cleanup Hajime Tazaki
2020-03-30 14:45     ` Hajime Tazaki
2020-03-30 14:45   ` [RFC v4 11/25] um lkl: plug in the build system Hajime Tazaki
2020-03-30 14:45     ` Hajime Tazaki
2020-03-30 14:45   ` [RFC v4 12/25] lkl tools: skeleton for host side library Hajime Tazaki
2020-03-30 14:45     ` Hajime Tazaki
2020-03-30 14:45   ` [RFC v4 13/25] lkl tools: host lib: add utilities functions Hajime Tazaki
2020-03-30 14:45     ` Hajime Tazaki
2020-03-30 14:45   ` [RFC v4 14/25] lkl tools: host lib: filesystem helpers Hajime Tazaki
2020-03-30 14:45     ` Hajime Tazaki
2020-03-30 14:45   ` [RFC v4 15/25] lkl tools: host lib: networking helpers Hajime Tazaki
2020-03-30 14:45     ` Hajime Tazaki
2020-03-30 14:45   ` [RFC v4 16/25] lkl tools: host lib: posix host operations Hajime Tazaki
2020-03-30 14:45     ` Hajime Tazaki
2020-03-30 14:45   ` [RFC v4 17/25] lkl tools: add test programs Hajime Tazaki
2020-03-30 14:45     ` Hajime Tazaki
2020-03-30 14:45   ` [RFC v4 18/25] lkl tools: cptofs that reads/writes to/from a filesystem image Hajime Tazaki
2020-03-30 14:45     ` Hajime Tazaki
2020-03-30 14:45   ` [RFC v4 19/25] lkl tools: fs2tar that converts a filesystem image to tar Hajime Tazaki
2020-03-30 14:45     ` Hajime Tazaki
2020-03-30 14:45   ` [RFC v4 20/25] lkl tools: add lklfuse Hajime Tazaki
2020-03-30 14:45     ` Hajime Tazaki
2020-03-30 14:45   ` [RFC v4 21/25] um lkl: add documentation Hajime Tazaki
2020-03-30 14:45     ` Hajime Tazaki
2020-03-30 14:45   ` [RFC v4 22/25] um lkl: add CI scripts to conduct regression tests Hajime Tazaki
2020-03-30 14:45     ` Hajime Tazaki
2020-03-30 14:45   ` [RFC v4 23/25] um lkl: add UML network driver for lkl Hajime Tazaki
2020-03-30 14:45     ` Hajime Tazaki
2020-03-30 21:31     ` Johannes Berg
2020-03-30 21:31       ` Johannes Berg
2020-03-31  2:38       ` Hajime Tazaki
2020-03-31  2:38         ` Hajime Tazaki
2020-03-31 19:52         ` Johannes Berg
2020-03-31 19:52           ` Johannes Berg
2020-03-30 14:45   ` [RFC v4 24/25] um lkl: add UML block device driver (ubd) " Hajime Tazaki
2020-03-30 14:45     ` Hajime Tazaki
2020-03-30 14:45   ` [RFC v4 25/25] um: fix clone flags to be familiar with valgrind Hajime Tazaki
2020-03-30 14:45     ` Hajime Tazaki
2020-07-02 14:06   ` [RFC v5 00/21] Unifying LKL into UML Hajime Tazaki
2020-07-02 14:06     ` Hajime Tazaki
2020-07-02 14:06     ` [RFC v5 01/21] um: split build in kernel and host parts Hajime Tazaki
2020-07-02 14:06       ` Hajime Tazaki
2020-09-21 16:01       ` Anton Ivanov
2020-09-21 16:01         ` Anton Ivanov
2020-09-21 22:27         ` Hajime Tazaki
2020-09-21 22:27           ` Hajime Tazaki
2020-07-02 14:06     ` [RFC v5 02/21] um: add os init and exit calls Hajime Tazaki
2020-07-02 14:06       ` Hajime Tazaki
2020-07-02 14:06     ` [RFC v5 03/21] um: move arch/um/os-Linux dir to tools/um/uml Hajime Tazaki
2020-07-02 14:06       ` Hajime Tazaki
2020-07-02 14:06     ` [RFC v5 04/21] um: host: implement os_initcalls and os_exitcalls Hajime Tazaki
2020-07-02 14:06       ` Hajime Tazaki
2020-07-02 14:06     ` [RFC v5 05/21] um: move arch/x86/um/os-Linux to tools/um/uml/ Hajime Tazaki
2020-07-02 14:06       ` Hajime Tazaki
2020-07-02 14:07     ` [RFC v5 06/21] scritps: um: suppress warnings if SRCARCH=um Hajime Tazaki
2020-07-02 14:07       ` Hajime Tazaki
2020-07-02 14:07     ` [RFC v5 07/21] um: extend arch_switch_to for alternate SUBARCH Hajime Tazaki
2020-07-02 14:07       ` Hajime Tazaki
2020-07-02 14:07     ` [RFC v5 08/21] um: add nommu mode for UML library mode Hajime Tazaki
2020-07-02 14:07       ` Hajime Tazaki
2020-07-02 14:07     ` [RFC v5 09/21] um: nommu: host interface Hajime Tazaki
2020-07-02 14:07       ` Hajime Tazaki
2020-07-02 14:07     ` [RFC v5 10/21] um: nommu: memory handling Hajime Tazaki
2020-07-02 14:07       ` Hajime Tazaki
2020-07-02 14:07     ` [RFC v5 11/21] um: nommu: kernel thread support Hajime Tazaki
2020-07-02 14:07       ` Hajime Tazaki
2020-07-02 14:07     ` [RFC v5 12/21] um: nommu: system call interface and application API Hajime Tazaki
2020-07-02 14:07       ` Hajime Tazaki
2020-07-02 14:07     ` [RFC v5 13/21] um: nommu: basic console support Hajime Tazaki
2020-07-02 14:07       ` Hajime Tazaki
2020-07-02 14:07     ` [RFC v5 14/21] um: nommu: initialization and cleanup Hajime Tazaki
2020-07-02 14:07       ` Hajime Tazaki
2020-07-02 14:07     ` [RFC v5 15/21] um: nommu: integrate with irq infrastructure of UML Hajime Tazaki
2020-07-02 14:07       ` Hajime Tazaki
2020-07-02 14:07     ` [RFC v5 16/21] um: nommu: plug in the build system Hajime Tazaki
2020-07-02 14:07       ` Hajime Tazaki
2020-07-02 14:07     ` [RFC v5 17/21] um: host: add nommu build for ARCH=um Hajime Tazaki
2020-07-02 14:07       ` Hajime Tazaki
2020-07-02 14:07     ` [RFC v5 18/21] um: host: add utilities functions Hajime Tazaki
2020-07-02 14:07       ` Hajime Tazaki
2020-07-02 14:07     ` [RFC v5 19/21] um: host: posix host operations Hajime Tazaki
2020-07-02 14:07       ` Hajime Tazaki
2020-07-02 14:07     ` [RFC v5 20/21] um: host: add test programs Hajime Tazaki
2020-07-02 14:07       ` Hajime Tazaki
2020-07-02 14:07     ` [RFC v5 21/21] um: nommu: add block device support of UML Hajime Tazaki
2020-07-02 14:07       ` Hajime Tazaki
2020-09-24  7:12     ` [RFC v6 00/21] Unifying LKL into UML Hajime Tazaki
2020-09-24  7:12       ` Hajime Tazaki
2020-09-24  7:12       ` [RFC v6 01/21] um: split build in kernel and host parts Hajime Tazaki
2020-09-24  7:12         ` Hajime Tazaki
2020-09-24  7:33         ` Anton Ivanov
2020-09-24  7:33           ` Anton Ivanov
2020-09-24  8:26           ` Hajime Tazaki
2020-09-24  8:26             ` Hajime Tazaki
2020-09-24  8:37             ` Anton Ivanov
2020-09-24  8:37               ` Anton Ivanov
2020-09-24  7:36         ` Anton Ivanov
2020-09-24  7:36           ` Anton Ivanov
2020-09-24  8:13           ` Hajime Tazaki
2020-09-24  8:13             ` Hajime Tazaki
2020-09-24  7:12       ` [RFC v6 02/21] um: add os init and exit calls Hajime Tazaki
2020-09-24  7:12         ` Hajime Tazaki
2020-09-24  7:12       ` [RFC v6 03/21] um: move arch/um/os-Linux dir to tools/um/uml Hajime Tazaki
2020-09-24  7:12         ` Hajime Tazaki
2020-09-24  7:12       ` [RFC v6 04/21] um: host: implement os_initcalls and os_exitcalls Hajime Tazaki
2020-09-24  7:12         ` Hajime Tazaki
2020-09-24  7:12       ` [RFC v6 05/21] um: move arch/x86/um/os-Linux to tools/um/uml/ Hajime Tazaki
2020-09-24  7:12         ` Hajime Tazaki
2020-09-24  7:12       ` [RFC v6 06/21] scritps: um: suppress warnings if SRCARCH=um Hajime Tazaki
2020-09-24  7:12         ` Hajime Tazaki
2020-09-24  7:12       ` [RFC v6 07/21] um: extend arch_switch_to for alternate SUBARCH Hajime Tazaki
2020-09-24  7:12         ` Hajime Tazaki
2020-09-24  7:12       ` [RFC v6 08/21] um: add nommu mode for UML library mode Hajime Tazaki
2020-09-24  7:12         ` Hajime Tazaki
2020-09-24  7:12       ` [RFC v6 09/21] um: nommu: host interface Hajime Tazaki
2020-09-24  7:12         ` Hajime Tazaki
2020-09-24  7:12       ` [RFC v6 10/21] um: nommu: memory handling Hajime Tazaki
2020-09-24  7:12         ` Hajime Tazaki
2020-09-24  7:12       ` [RFC v6 11/21] um: nommu: kernel thread support Hajime Tazaki
2020-09-24  7:12         ` Hajime Tazaki
2020-09-24  7:12       ` [RFC v6 12/21] um: nommu: system call interface and application API Hajime Tazaki
2020-09-24  7:12         ` Hajime Tazaki
2020-09-24  7:12       ` [RFC v6 13/21] um: nommu: basic console support Hajime Tazaki
2020-09-24  7:12         ` Hajime Tazaki
2020-09-24  7:12       ` [RFC v6 14/21] um: nommu: initialization and cleanup Hajime Tazaki
2020-09-24  7:12         ` Hajime Tazaki
2020-09-24  7:12       ` [RFC v6 15/21] um: nommu: integrate with irq infrastructure of UML Hajime Tazaki
2020-09-24  7:12         ` Hajime Tazaki
2020-09-24  7:12       ` [RFC v6 16/21] um: nommu: plug in the build system Hajime Tazaki
2020-09-24  7:12         ` Hajime Tazaki
2020-09-24  7:12       ` [RFC v6 17/21] um: host: add nommu build for ARCH=um Hajime Tazaki
2020-09-24  7:12         ` Hajime Tazaki
2020-09-24  7:12       ` [RFC v6 18/21] um: host: add utilities functions Hajime Tazaki
2020-09-24  7:12         ` Hajime Tazaki
2020-09-24  7:12       ` [RFC v6 19/21] um: host: posix host operations Hajime Tazaki
2020-09-24  7:12         ` Hajime Tazaki
2020-09-24  7:13       ` [RFC v6 20/21] um: host: add test programs Hajime Tazaki
2020-09-24  7:13         ` Hajime Tazaki
2020-09-24  7:13       ` [RFC v6 21/21] um: nommu: add block device support of UML Hajime Tazaki
2020-09-24  7:13         ` Hajime Tazaki
2020-10-06  9:44       ` [RFC v7 00/21] Unifying LKL into UML Hajime Tazaki
2020-10-06  9:44         ` Hajime Tazaki
2020-10-06  9:44         ` [RFC v7 01/21] um: split build in kernel and host parts Hajime Tazaki
2020-10-06  9:44           ` Hajime Tazaki
2020-10-06  9:44         ` [RFC v7 02/21] um: add os init and exit calls Hajime Tazaki
2020-10-06  9:44           ` Hajime Tazaki
2020-10-07 15:13           ` Johannes Berg
2020-10-07 15:13             ` Johannes Berg
2020-10-08 13:18             ` Hajime Tazaki
2020-10-06  9:44         ` [RFC v7 03/21] um: move arch/um/os-Linux dir to tools/um/uml Hajime Tazaki
2020-10-06  9:44           ` Hajime Tazaki
2020-10-07 15:20           ` Johannes Berg
2020-10-07 15:20             ` Johannes Berg
2020-10-08 17:48             ` Octavian Purdila
2020-10-08 17:48               ` Octavian Purdila
2020-10-08 19:46               ` Johannes Berg
2020-10-08 19:46                 ` Johannes Berg
2020-10-08 20:53                 ` Octavian Purdila
2020-10-08 20:53                   ` Octavian Purdila
2020-10-09 15:59                   ` Johannes Berg
2020-10-09 15:59                     ` Johannes Berg
2020-10-06  9:44         ` [RFC v7 04/21] um: host: implement os_initcalls and os_exitcalls Hajime Tazaki
2020-10-06  9:44           ` Hajime Tazaki
2020-10-07 15:22           ` Johannes Berg
2020-10-07 15:22             ` Johannes Berg
2020-10-08 13:16             ` Hajime Tazaki
2020-10-06  9:44         ` [RFC v7 05/21] um: move arch/x86/um/os-Linux to tools/um/uml/ Hajime Tazaki
2020-10-06  9:44           ` Hajime Tazaki
2020-10-07 15:23           ` Johannes Berg
2020-10-07 15:23             ` Johannes Berg
2020-10-06  9:44         ` [RFC v7 06/21] scritps: um: suppress warnings if SRCARCH=um Hajime Tazaki
2020-10-06  9:44           ` Hajime Tazaki
2020-10-07 15:24           ` Johannes Berg
2020-10-07 15:24             ` Johannes Berg
2020-10-09  1:13             ` Hajime Tazaki
2020-10-09 16:00               ` Johannes Berg
2020-10-09 16:00                 ` Johannes Berg
2020-10-06  9:44         ` [RFC v7 07/21] um: extend arch_switch_to for alternate SUBARCH Hajime Tazaki
2020-10-06  9:44           ` Hajime Tazaki
2020-10-07 15:25           ` Johannes Berg
2020-10-07 15:25             ` Johannes Berg
2020-10-09  1:24             ` Hajime Tazaki
2020-10-09 16:02               ` Johannes Berg
2020-10-09 16:02                 ` Johannes Berg
2020-10-06  9:44         ` [RFC v7 08/21] um: add nommu mode for UML library mode Hajime Tazaki
2020-10-06  9:44           ` Hajime Tazaki
2020-10-07 15:44           ` Johannes Berg
2020-10-07 15:44             ` Johannes Berg
2020-10-09  3:38             ` Hajime Tazaki
2020-10-09 16:06               ` Johannes Berg
2020-10-09 16:06                 ` Johannes Berg
2020-10-20  8:44                 ` Hajime Tazaki
2020-10-06  9:44         ` [RFC v7 09/21] um: nommu: host interface Hajime Tazaki
2020-10-06  9:44           ` Hajime Tazaki
2020-10-07 15:45           ` Johannes Berg
2020-10-07 15:45             ` Johannes Berg
2020-10-08 18:10             ` Octavian Purdila
2020-10-08 18:10               ` Octavian Purdila
2020-10-06  9:44         ` [RFC v7 10/21] um: nommu: memory handling Hajime Tazaki
2020-10-06  9:44           ` Hajime Tazaki
2020-10-07 15:47           ` Johannes Berg
2020-10-07 15:47             ` Johannes Berg
2020-10-08 18:07             ` Octavian Purdila
2020-10-08 18:07               ` Octavian Purdila
2020-10-06  9:44         ` [RFC v7 11/21] um: nommu: kernel thread support Hajime Tazaki
2020-10-06  9:44           ` Hajime Tazaki
2020-10-07 18:57           ` Johannes Berg
2020-10-07 18:57             ` Johannes Berg
2020-10-08 18:54             ` Octavian Purdila
2020-10-08 18:54               ` Octavian Purdila
2020-10-08 19:39               ` Johannes Berg
2020-10-08 19:39                 ` Johannes Berg
2020-10-08 20:25                 ` Octavian Purdila
2020-10-08 20:25                   ` Octavian Purdila
2020-10-06  9:44         ` [RFC v7 12/21] um: nommu: system call interface and application API Hajime Tazaki
2020-10-06  9:44           ` Hajime Tazaki
2020-10-07 19:05           ` Johannes Berg
2020-10-07 19:05             ` Johannes Berg
2020-10-08 19:03             ` Octavian Purdila
2020-10-08 19:03               ` Octavian Purdila
2020-10-08 19:40               ` Johannes Berg
2020-10-08 19:40                 ` Johannes Berg
2020-10-06  9:44         ` [RFC v7 13/21] um: nommu: basic console support Hajime Tazaki
2020-10-06  9:44           ` Hajime Tazaki
2020-10-06  9:44         ` [RFC v7 14/21] um: nommu: initialization and cleanup Hajime Tazaki
2020-10-06  9:44           ` Hajime Tazaki
2020-10-06  9:44         ` [RFC v7 15/21] um: nommu: integrate with irq infrastructure of UML Hajime Tazaki
2020-10-06  9:44           ` Hajime Tazaki
2020-10-07 19:09           ` Johannes Berg
2020-10-07 19:09             ` Johannes Berg
2020-10-06  9:44         ` [RFC v7 16/21] um: nommu: plug in the build system Hajime Tazaki
2020-10-06  9:44           ` Hajime Tazaki
2020-10-07 19:20           ` Johannes Berg
2020-10-07 19:20             ` Johannes Berg
2020-10-09  7:40             ` Hajime TAZAKI
2020-10-09  7:40               ` Hajime TAZAKI
2020-10-06  9:44         ` [RFC v7 17/21] um: host: add nommu build for ARCH=um Hajime Tazaki
2020-10-06  9:44           ` Hajime Tazaki
2020-10-06  9:44         ` [RFC v7 18/21] um: host: add utilities functions Hajime Tazaki
2020-10-06  9:44           ` Hajime Tazaki
2020-10-07 14:53           ` Anton Ivanov
2020-10-07 14:53             ` Anton Ivanov
2020-10-07 15:02             ` Johannes Berg
2020-10-07 15:02               ` Johannes Berg
2020-10-07 15:03               ` Johannes Berg
2020-10-07 15:03                 ` Johannes Berg
2020-10-07 15:10                 ` Anton Ivanov
2020-10-07 15:10                   ` Anton Ivanov
2020-10-08 12:52                   ` Hajime Tazaki
2020-10-08 19:19                     ` Octavian Purdila
2020-10-08 19:19                       ` Octavian Purdila
2020-10-08 12:53                   ` Hajime Tazaki
2020-10-06  9:44         ` [RFC v7 19/21] um: host: posix host operations Hajime Tazaki
2020-10-06  9:44           ` Hajime Tazaki
2020-10-06  9:44         ` [RFC v7 20/21] um: host: add test programs Hajime Tazaki
2020-10-06  9:44           ` Hajime Tazaki
2020-10-07 19:23           ` Johannes Berg
2020-10-07 19:23             ` Johannes Berg
2020-10-09  6:24             ` Hajime Tazaki
2020-10-06  9:44         ` [RFC v7 21/21] um: nommu: add block device support of UML Hajime Tazaki
2020-10-06  9:44           ` Hajime Tazaki
2020-10-07 14:17           ` Anton Ivanov [this message]
2020-10-07 14:17             ` Anton Ivanov
2020-10-08 12:13             ` Hajime Tazaki
2020-10-07 13:30         ` [RFC v7 00/21] Unifying LKL into UML Anton Ivanov
2020-10-07 13:30           ` Anton Ivanov
2020-10-08 12:12           ` Hajime Tazaki
2020-10-08 12:50             ` Anton Ivanov
2020-10-08 12:50               ` Anton Ivanov
2020-10-08 17:13               ` Octavian Purdila
2020-10-08 17:13                 ` Octavian Purdila
2020-10-08 17:18                 ` Anton Ivanov
2020-10-08 17:18                   ` Anton Ivanov
2020-10-08 17:24                   ` Octavian Purdila
2020-10-08 17:24                     ` Octavian Purdila
2021-01-20  2:27         ` [RFC v8 00/20] " Hajime Tazaki
2021-01-20  2:27           ` Hajime Tazaki
2021-01-20  2:27           ` [RFC v8 01/20] um: split build in kernel and host parts Hajime Tazaki
2021-01-20  2:27             ` Hajime Tazaki
2021-01-20  2:27           ` [RFC v8 02/20] um: move arch/um/os-Linux dir to tools/um/uml Hajime Tazaki
2021-01-20  2:27             ` Hajime Tazaki
2021-01-20  2:27           ` [RFC v8 03/20] um: move arch/x86/um/os-Linux to tools/um/uml/ Hajime Tazaki
2021-01-20  2:27             ` Hajime Tazaki
2021-01-20  2:27           ` [RFC v8 04/20] um: implement os_initcalls and os_exitcalls Hajime Tazaki
2021-01-20  2:27             ` Hajime Tazaki
2021-01-20  2:27           ` [RFC v8 05/20] um: extend arch_switch_to for alternate SUBARCH Hajime Tazaki
2021-01-20  2:27             ` Hajime Tazaki
2021-01-20  2:27           ` [RFC v8 06/20] um: add UML library mode Hajime Tazaki
2021-01-20  2:27             ` Hajime Tazaki
2021-03-14 16:49             ` Johannes Berg
2021-03-14 16:49               ` Johannes Berg
2021-03-16  1:17               ` Hajime Tazaki
2021-03-16  1:17                 ` Hajime Tazaki
2021-01-20  2:27           ` [RFC v8 07/20] um: lkl: host interface Hajime Tazaki
2021-01-20  2:27             ` Hajime Tazaki
2021-03-14 16:50             ` Johannes Berg
2021-03-14 16:50               ` Johannes Berg
2021-03-16  1:17               ` Hajime Tazaki
2021-03-16  1:17                 ` Hajime Tazaki
2021-01-20  2:27           ` [RFC v8 08/20] um: lkl: memory handling Hajime Tazaki
2021-01-20  2:27             ` Hajime Tazaki
2021-03-14 16:53             ` Johannes Berg
2021-03-14 16:53               ` Johannes Berg
2021-03-16  1:18               ` Hajime Tazaki
2021-03-16  1:18                 ` Hajime Tazaki
2021-03-16 21:31                 ` Johannes Berg
2021-03-16 21:31                   ` Johannes Berg
2021-03-18  0:12                   ` Hajime Tazaki
2021-03-18  0:12                     ` Hajime Tazaki
2021-03-18  8:00                     ` Johannes Berg
2021-03-18  8:00                       ` Johannes Berg
2021-01-20  2:27           ` [RFC v8 09/20] um: lkl: kernel thread support Hajime Tazaki
2021-01-20  2:27             ` Hajime Tazaki
2021-03-14 17:01             ` Johannes Berg
2021-03-14 17:01               ` Johannes Berg
2021-03-16  1:18               ` Hajime Tazaki
2021-03-16  1:18                 ` Hajime Tazaki
2021-01-20  2:27           ` [RFC v8 10/20] um: lkl: system call interface and application API Hajime Tazaki
2021-01-20  2:27             ` Hajime Tazaki
2021-01-20  2:27           ` [RFC v8 11/20] um: lkl: basic console support Hajime Tazaki
2021-01-20  2:27             ` Hajime Tazaki
2021-03-14 20:42             ` Johannes Berg
2021-03-14 20:42               ` Johannes Berg
2021-03-16  1:19               ` Hajime Tazaki
2021-03-16  1:19                 ` Hajime Tazaki
2021-01-20  2:27           ` [RFC v8 12/20] um: lkl: initialization and cleanup Hajime Tazaki
2021-01-20  2:27             ` Hajime Tazaki
2021-03-14 20:40             ` Johannes Berg
2021-03-14 20:40               ` Johannes Berg
2021-03-16  1:19               ` Hajime Tazaki
2021-03-16  1:19                 ` Hajime Tazaki
2021-01-20  2:27           ` [RFC v8 13/20] um: lkl: integrate with irq infrastructure of UML Hajime Tazaki
2021-01-20  2:27             ` Hajime Tazaki
2021-03-14 20:45             ` Johannes Berg
2021-03-14 20:45               ` Johannes Berg
2021-03-16  1:20               ` Hajime Tazaki
2021-03-16  1:20                 ` Hajime Tazaki
2021-03-16 21:36                 ` Johannes Berg
2021-03-16 21:36                   ` Johannes Berg
2021-01-20  2:27           ` [RFC v8 14/20] um: lkl: plug in the build system Hajime Tazaki
2021-01-20  2:27             ` Hajime Tazaki
2021-01-20  2:27           ` [RFC v8 15/20] um: host: add library mode build for ARCH=um Hajime Tazaki
2021-01-20  2:27             ` Hajime Tazaki
2021-01-20  2:27           ` [RFC v8 16/20] um: host: add utilities functions Hajime Tazaki
2021-01-20  2:27             ` Hajime Tazaki
2021-01-20  2:27           ` [RFC v8 17/20] um: host: posix host operations Hajime Tazaki
2021-01-20  2:27             ` Hajime Tazaki
2021-01-20  2:27           ` [RFC v8 18/20] selftests/um: lkl: add test programs for library mode of UML Hajime Tazaki
2021-01-20  2:27             ` Hajime Tazaki
2021-01-20  2:27           ` [RFC v8 19/20] um: lkl: add block device support " Hajime Tazaki
2021-01-20  2:27             ` Hajime Tazaki
2021-03-14 20:37             ` Johannes Berg
2021-03-14 20:37               ` Johannes Berg
2021-03-16  1:19               ` Hajime Tazaki
2021-03-16  1:19                 ` Hajime Tazaki
2021-03-16 21:32                 ` Johannes Berg
2021-03-16 21:32                   ` Johannes Berg
2021-03-17 14:19                   ` Octavian Purdila
2021-03-17 14:19                     ` Octavian Purdila
2021-03-17 14:28                     ` Johannes Berg
2021-03-17 14:28                       ` Johannes Berg
2021-03-18  0:15                       ` Hajime Tazaki
2021-03-18  0:15                         ` Hajime Tazaki
2021-03-18  0:43                         ` Octavian Purdila
2021-03-18  0:43                           ` Octavian Purdila
2021-01-20  2:27           ` [RFC v8 20/20] um: lkl: add documentation Hajime Tazaki
2021-01-20  2:27             ` Hajime Tazaki
2021-03-14 21:03           ` [RFC v8 00/20] Unifying LKL into UML Johannes Berg
2021-03-14 21:03             ` Johannes Berg
2021-03-16  1:17             ` Hajime Tazaki
2021-03-16  1:17               ` Hajime Tazaki
2021-03-16 21:29               ` Johannes Berg
2021-03-16 21:29                 ` Johannes Berg
2021-03-17 14:03                 ` Octavian Purdila
2021-03-17 14:03                   ` Octavian Purdila
2021-03-17 14:24                   ` Johannes Berg
2021-03-17 14:24                     ` Johannes Berg
2021-03-18 14:17                     ` Hajime Tazaki
2021-03-18 14:17                       ` Hajime Tazaki
2021-03-18 16:28                       ` Johannes Berg
2021-03-18 16:28                         ` Johannes Berg

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ac66cd8b-3bb1-5846-aa75-fc91c1149e91@cambridgegreys.com \
    --to=anton.ivanov@cambridgegreys.com \
    --cc=jdike@addtoit.com \
    --cc=linux-arch@vger.kernel.org \
    --cc=linux-kernel-library@freelists.org \
    --cc=linux-um@lists.infradead.org \
    --cc=retrage01@gmail.com \
    --cc=richard@nod.at \
    --cc=tavi.purdila@gmail.com \
    --cc=thehajime@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.