Commit 762a9f2f authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-linus-5.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml

Pull UML updates from Richard Weinberger:

 - New mode for time travel, external via virtio

 - Fixes for ubd to make sure no requests can get lost

 - Fixes for vector networking

 - Allow CONFIG_STATIC_LINK only when possible

 - Minor cleanups and fixes

* tag 'for-linus-5.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml:
  um: Remove some unnecessary NULL checks in vector_user.c
  um: vector: Avoid NULL ptr deference if transport is unset
  um: Make CONFIG_STATIC_LINK actually static
  um: Implement cpu_relax() as ndelay(1) for time-travel
  um: Implement ndelay/udelay in time-travel mode
  um: Implement time-travel=ext
  um: virtio: Implement VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS
  um: time-travel: Rewrite as an event scheduler
  um: Move timer-internal.h to non-shared
  hostfs: Use kasprintf() instead of fixed buffer formatting
  um: falloc.h needs to be directly included for older libc
  um: ubd: Retry buffer read on any kind of error
  um: ubd: Prevent buffer overrun on command completion
  um: Fix overlapping ELF segments when statically linked
  um: Delete never executed timer
  um: Don't overwrite ethtool driver version
  um: Fix len of file in create_pid_file
  um: Don't use console_drivers directly
  um: Cleanup CONFIG_IOSCHED_CFQ
parents d5d24766 4a7c4624
...@@ -62,9 +62,12 @@ config NR_CPUS ...@@ -62,9 +62,12 @@ config NR_CPUS
source "arch/$(HEADER_ARCH)/um/Kconfig" source "arch/$(HEADER_ARCH)/um/Kconfig"
config FORBID_STATIC_LINK
bool
config STATIC_LINK config STATIC_LINK
bool "Force a static link" bool "Force a static link"
default n depends on !FORBID_STATIC_LINK
help help
This option gives you the ability to force a static link of UML. This option gives you the ability to force a static link of UML.
Normally, UML is linked as a shared binary. This is inconvenient for Normally, UML is linked as a shared binary. This is inconvenient for
...@@ -73,6 +76,9 @@ config STATIC_LINK ...@@ -73,6 +76,9 @@ config STATIC_LINK
Additionally, this option enables using higher memory spaces (up to Additionally, this option enables using higher memory spaces (up to
2.75G) for UML. 2.75G) for UML.
NOTE: This option is incompatible with some networking features which
depend on features that require being dynamically loaded (like NSS).
config LD_SCRIPT_STATIC config LD_SCRIPT_STATIC
bool bool
default y default y
...@@ -191,6 +197,7 @@ config UML_TIME_TRAVEL_SUPPORT ...@@ -191,6 +197,7 @@ config UML_TIME_TRAVEL_SUPPORT
prompt "Support time-travel mode (e.g. for test execution)" prompt "Support time-travel mode (e.g. for test execution)"
# inf-cpu mode is incompatible with the benchmarking # inf-cpu mode is incompatible with the benchmarking
depends on !RAID6_PQ_BENCHMARK depends on !RAID6_PQ_BENCHMARK
depends on !SMP
help help
Enable this option to support time travel inside the UML instance. Enable this option to support time travel inside the UML instance.
......
...@@ -26,7 +26,7 @@ CONFIG_SLAB=y ...@@ -26,7 +26,7 @@ CONFIG_SLAB=y
CONFIG_MODULES=y CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set # CONFIG_BLK_DEV_BSG is not set
CONFIG_IOSCHED_CFQ=m CONFIG_IOSCHED_BFQ=m
CONFIG_SSL=y CONFIG_SSL=y
CONFIG_NULL_CHAN=y CONFIG_NULL_CHAN=y
CONFIG_PORT_CHAN=y CONFIG_PORT_CHAN=y
......
...@@ -24,7 +24,7 @@ CONFIG_SLAB=y ...@@ -24,7 +24,7 @@ CONFIG_SLAB=y
CONFIG_MODULES=y CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set # CONFIG_BLK_DEV_BSG is not set
CONFIG_IOSCHED_CFQ=m CONFIG_IOSCHED_BFQ=m
CONFIG_SSL=y CONFIG_SSL=y
CONFIG_NULL_CHAN=y CONFIG_NULL_CHAN=y
CONFIG_PORT_CHAN=y CONFIG_PORT_CHAN=y
......
...@@ -234,6 +234,7 @@ config UML_NET_DAEMON ...@@ -234,6 +234,7 @@ config UML_NET_DAEMON
config UML_NET_VECTOR config UML_NET_VECTOR
bool "Vector I/O high performance network devices" bool "Vector I/O high performance network devices"
depends on UML_NET depends on UML_NET
select FORBID_STATIC_LINK
help help
This User-Mode Linux network driver uses multi-message send This User-Mode Linux network driver uses multi-message send
and receive functions. The host running the UML guest must have and receive functions. The host running the UML guest must have
...@@ -245,6 +246,7 @@ config UML_NET_VECTOR ...@@ -245,6 +246,7 @@ config UML_NET_VECTOR
config UML_NET_VDE config UML_NET_VDE
bool "VDE transport (obsolete)" bool "VDE transport (obsolete)"
depends on UML_NET depends on UML_NET
select FORBID_STATIC_LINK
help help
This User-Mode Linux network transport allows one or more running This User-Mode Linux network transport allows one or more running
UMLs on a single host to communicate with each other and also UMLs on a single host to communicate with each other and also
...@@ -292,6 +294,7 @@ config UML_NET_MCAST ...@@ -292,6 +294,7 @@ config UML_NET_MCAST
config UML_NET_PCAP config UML_NET_PCAP
bool "pcap transport (obsolete)" bool "pcap transport (obsolete)"
depends on UML_NET depends on UML_NET
select FORBID_STATIC_LINK
help help
The pcap transport makes a pcap packet stream on the host look The pcap transport makes a pcap packet stream on the host look
like an ethernet device inside UML. This is useful for making like an ethernet device inside UML. This is useful for making
......
...@@ -266,7 +266,6 @@ static void uml_net_get_drvinfo(struct net_device *dev, ...@@ -266,7 +266,6 @@ static void uml_net_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info) struct ethtool_drvinfo *info)
{ {
strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver)); strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver));
strlcpy(info->version, "42", sizeof(info->version));
} }
static const struct ethtool_ops uml_net_ethtool_ops = { static const struct ethtool_ops uml_net_ethtool_ops = {
...@@ -275,17 +274,6 @@ static const struct ethtool_ops uml_net_ethtool_ops = { ...@@ -275,17 +274,6 @@ static const struct ethtool_ops uml_net_ethtool_ops = {
.get_ts_info = ethtool_op_get_ts_info, .get_ts_info = ethtool_op_get_ts_info,
}; };
static void uml_net_user_timer_expire(struct timer_list *t)
{
#ifdef undef
struct uml_net_private *lp = from_timer(lp, t, tl);
struct connection *conn = &lp->user;
dprintk(KERN_INFO "uml_net_user_timer_expire [%p]\n", conn);
do_connect(conn);
#endif
}
void uml_net_setup_etheraddr(struct net_device *dev, char *str) void uml_net_setup_etheraddr(struct net_device *dev, char *str)
{ {
unsigned char *addr = dev->dev_addr; unsigned char *addr = dev->dev_addr;
...@@ -456,7 +444,6 @@ static void eth_configure(int n, void *init, char *mac, ...@@ -456,7 +444,6 @@ static void eth_configure(int n, void *init, char *mac,
.add_address = transport->user->add_address, .add_address = transport->user->add_address,
.delete_address = transport->user->delete_address }); .delete_address = transport->user->delete_address });
timer_setup(&lp->tl, uml_net_user_timer_expire, 0);
spin_lock_init(&lp->lock); spin_lock_init(&lp->lock);
memcpy(lp->mac, dev->dev_addr, sizeof(lp->mac)); memcpy(lp->mac, dev->dev_addr, sizeof(lp->mac));
......
...@@ -1592,11 +1592,11 @@ int io_thread(void *arg) ...@@ -1592,11 +1592,11 @@ int io_thread(void *arg)
&io_remainder_size, &io_remainder_size,
UBD_REQ_BUFFER_SIZE UBD_REQ_BUFFER_SIZE
); );
if (n < 0) { if (n <= 0) {
if (n == -EAGAIN) { if (n == -EAGAIN)
ubd_read_poll(-1); ubd_read_poll(-1);
continue;
} continue;
} }
for (count = 0; count < n/sizeof(struct io_thread_req *); count++) { for (count = 0; count < n/sizeof(struct io_thread_req *); count++) {
...@@ -1607,7 +1607,9 @@ int io_thread(void *arg) ...@@ -1607,7 +1607,9 @@ int io_thread(void *arg)
written = 0; written = 0;
do { do {
res = os_write_file(kernel_fd, ((char *) io_req_buffer) + written, n); res = os_write_file(kernel_fd,
((char *) io_req_buffer) + written,
n - written);
if (res >= 0) { if (res >= 0) {
written += res; written += res;
} }
......
...@@ -46,7 +46,6 @@ ...@@ -46,7 +46,6 @@
#define DRIVER_NAME "uml-vector" #define DRIVER_NAME "uml-vector"
#define DRIVER_VERSION "01"
struct vector_cmd_line_arg { struct vector_cmd_line_arg {
struct list_head list; struct list_head list;
int unit; int unit;
...@@ -198,6 +197,9 @@ static int get_transport_options(struct arglist *def) ...@@ -198,6 +197,9 @@ static int get_transport_options(struct arglist *def)
long parsed; long parsed;
int result = 0; int result = 0;
if (transport == NULL)
return -EINVAL;
if (vector != NULL) { if (vector != NULL) {
if (kstrtoul(vector, 10, &parsed) == 0) { if (kstrtoul(vector, 10, &parsed) == 0) {
if (parsed == 0) { if (parsed == 0) {
...@@ -1378,7 +1380,6 @@ static void vector_net_get_drvinfo(struct net_device *dev, ...@@ -1378,7 +1380,6 @@ static void vector_net_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info) struct ethtool_drvinfo *info)
{ {
strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver)); strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver));
strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
} }
static int vector_net_load_bpf_flash(struct net_device *dev, static int vector_net_load_bpf_flash(struct net_device *dev,
......
...@@ -221,8 +221,7 @@ static struct vector_fds *user_init_tap_fds(struct arglist *ifspec) ...@@ -221,8 +221,7 @@ static struct vector_fds *user_init_tap_fds(struct arglist *ifspec)
return result; return result;
tap_cleanup: tap_cleanup:
printk(UM_KERN_ERR "user_init_tap: init failed, error %d", fd); printk(UM_KERN_ERR "user_init_tap: init failed, error %d", fd);
if (result != NULL) kfree(result);
kfree(result);
return NULL; return NULL;
} }
...@@ -266,8 +265,7 @@ static struct vector_fds *user_init_hybrid_fds(struct arglist *ifspec) ...@@ -266,8 +265,7 @@ static struct vector_fds *user_init_hybrid_fds(struct arglist *ifspec)
return result; return result;
hybrid_cleanup: hybrid_cleanup:
printk(UM_KERN_ERR "user_init_hybrid: init failed"); printk(UM_KERN_ERR "user_init_hybrid: init failed");
if (result != NULL) kfree(result);
kfree(result);
return NULL; return NULL;
} }
...@@ -344,10 +342,8 @@ static struct vector_fds *user_init_unix_fds(struct arglist *ifspec, int id) ...@@ -344,10 +342,8 @@ static struct vector_fds *user_init_unix_fds(struct arglist *ifspec, int id)
unix_cleanup: unix_cleanup:
if (fd >= 0) if (fd >= 0)
os_close_file(fd); os_close_file(fd);
if (remote_addr != NULL) kfree(remote_addr);
kfree(remote_addr); kfree(result);
if (result != NULL)
kfree(result);
return NULL; return NULL;
} }
...@@ -382,8 +378,7 @@ static struct vector_fds *user_init_raw_fds(struct arglist *ifspec) ...@@ -382,8 +378,7 @@ static struct vector_fds *user_init_raw_fds(struct arglist *ifspec)
return result; return result;
raw_cleanup: raw_cleanup:
printk(UM_KERN_ERR "user_init_raw: init failed, error %d", err); printk(UM_KERN_ERR "user_init_raw: init failed, error %d", err);
if (result != NULL) kfree(result);
kfree(result);
return NULL; return NULL;
} }
......
...@@ -10,9 +10,10 @@ ...@@ -10,9 +10,10 @@
/* Feature bits */ /* Feature bits */
#define VHOST_USER_F_PROTOCOL_FEATURES 30 #define VHOST_USER_F_PROTOCOL_FEATURES 30
/* Protocol feature bits */ /* Protocol feature bits */
#define VHOST_USER_PROTOCOL_F_REPLY_ACK 3 #define VHOST_USER_PROTOCOL_F_REPLY_ACK 3
#define VHOST_USER_PROTOCOL_F_SLAVE_REQ 5 #define VHOST_USER_PROTOCOL_F_SLAVE_REQ 5
#define VHOST_USER_PROTOCOL_F_CONFIG 9 #define VHOST_USER_PROTOCOL_F_CONFIG 9
#define VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS 14
/* Vring state index masks */ /* Vring state index masks */
#define VHOST_USER_VRING_INDEX_MASK 0xff #define VHOST_USER_VRING_INDEX_MASK 0xff
#define VHOST_USER_VRING_POLL_MASK BIT(8) #define VHOST_USER_VRING_POLL_MASK BIT(8)
...@@ -24,7 +25,8 @@ ...@@ -24,7 +25,8 @@
/* Supported protocol features */ /* Supported protocol features */
#define VHOST_USER_SUPPORTED_PROTOCOL_F (BIT_ULL(VHOST_USER_PROTOCOL_F_REPLY_ACK) | \ #define VHOST_USER_SUPPORTED_PROTOCOL_F (BIT_ULL(VHOST_USER_PROTOCOL_F_REPLY_ACK) | \
BIT_ULL(VHOST_USER_PROTOCOL_F_SLAVE_REQ) | \ BIT_ULL(VHOST_USER_PROTOCOL_F_SLAVE_REQ) | \
BIT_ULL(VHOST_USER_PROTOCOL_F_CONFIG)) BIT_ULL(VHOST_USER_PROTOCOL_F_CONFIG) | \
BIT_ULL(VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS))
enum vhost_user_request { enum vhost_user_request {
VHOST_USER_GET_FEATURES = 1, VHOST_USER_GET_FEATURES = 1,
...@@ -52,12 +54,14 @@ enum vhost_user_request { ...@@ -52,12 +54,14 @@ enum vhost_user_request {
VHOST_USER_SET_VRING_ENDIAN = 23, VHOST_USER_SET_VRING_ENDIAN = 23,
VHOST_USER_GET_CONFIG = 24, VHOST_USER_GET_CONFIG = 24,
VHOST_USER_SET_CONFIG = 25, VHOST_USER_SET_CONFIG = 25,
VHOST_USER_VRING_KICK = 35,
}; };
enum vhost_user_slave_request { enum vhost_user_slave_request {
VHOST_USER_SLAVE_IOTLB_MSG = 1, VHOST_USER_SLAVE_IOTLB_MSG = 1,
VHOST_USER_SLAVE_CONFIG_CHANGE_MSG = 2, VHOST_USER_SLAVE_CONFIG_CHANGE_MSG = 2,
VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG = 3, VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG = 3,
VHOST_USER_SLAVE_VRING_CALL = 4,
}; };
struct vhost_user_header { struct vhost_user_header {
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/virtio.h> #include <linux/virtio.h>
#include <linux/virtio_config.h> #include <linux/virtio_config.h>
#include <linux/virtio_ring.h> #include <linux/virtio_ring.h>
#include <linux/time-internal.h>
#include <shared/as-layout.h> #include <shared/as-layout.h>
#include <irq_kern.h> #include <irq_kern.h>
#include <init.h> #include <init.h>
...@@ -53,6 +54,7 @@ struct virtio_uml_device { ...@@ -53,6 +54,7 @@ struct virtio_uml_device {
struct virtio_device vdev; struct virtio_device vdev;
struct platform_device *pdev; struct platform_device *pdev;
spinlock_t sock_lock;
int sock, req_fd; int sock, req_fd;
u64 features; u64 features;
u64 protocol_features; u64 protocol_features;
...@@ -63,6 +65,11 @@ struct virtio_uml_device { ...@@ -63,6 +65,11 @@ struct virtio_uml_device {
struct virtio_uml_vq_info { struct virtio_uml_vq_info {
int kick_fd, call_fd; int kick_fd, call_fd;
char name[32]; char name[32];
#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
struct virtqueue *vq;
vq_callback_t *callback;
struct time_travel_event defer;
#endif
}; };
extern unsigned long long physmem_size, highmem; extern unsigned long long physmem_size, highmem;
...@@ -117,10 +124,27 @@ static int vhost_user_recv_header(int fd, struct vhost_user_msg *msg) ...@@ -117,10 +124,27 @@ static int vhost_user_recv_header(int fd, struct vhost_user_msg *msg)
static int vhost_user_recv(struct virtio_uml_device *vu_dev, static int vhost_user_recv(struct virtio_uml_device *vu_dev,
int fd, struct vhost_user_msg *msg, int fd, struct vhost_user_msg *msg,
size_t max_payload_size) size_t max_payload_size, bool wait)
{ {
size_t size; size_t size;
int rc = vhost_user_recv_header(fd, msg); int rc;
/*
* In virtio time-travel mode, we're handling all the vhost-user
* FDs by polling them whenever appropriate. However, we may get
* into a situation where we're sending out an interrupt message
* to a device (e.g. a net device) and need to handle a simulation
* time message while doing so, e.g. one that tells us to update
* our idea of how long we can run without scheduling.
*
* Thus, we need to not just read() from the given fd, but need
* to also handle messages for the simulation time - this function
* does that for us while waiting for the given fd to be readable.
*/
if (wait)
time_travel_wait_readable(fd);
rc = vhost_user_recv_header(fd, msg);
if (rc == -ECONNRESET && vu_dev->registered) { if (rc == -ECONNRESET && vu_dev->registered) {
struct virtio_uml_platform_data *pdata; struct virtio_uml_platform_data *pdata;
...@@ -142,7 +166,8 @@ static int vhost_user_recv_resp(struct virtio_uml_device *vu_dev, ...@@ -142,7 +166,8 @@ static int vhost_user_recv_resp(struct virtio_uml_device *vu_dev,
struct vhost_user_msg *msg, struct vhost_user_msg *msg,
size_t max_payload_size) size_t max_payload_size)
{ {
int rc = vhost_user_recv(vu_dev, vu_dev->sock, msg, max_payload_size); int rc = vhost_user_recv(vu_dev, vu_dev->sock, msg,
max_payload_size, true);
if (rc) if (rc)
return rc; return rc;
...@@ -172,7 +197,8 @@ static int vhost_user_recv_req(struct virtio_uml_device *vu_dev, ...@@ -172,7 +197,8 @@ static int vhost_user_recv_req(struct virtio_uml_device *vu_dev,
struct vhost_user_msg *msg, struct vhost_user_msg *msg,
size_t max_payload_size) size_t max_payload_size)
{ {
int rc = vhost_user_recv(vu_dev, vu_dev->req_fd, msg, max_payload_size); int rc = vhost_user_recv(vu_dev, vu_dev->req_fd, msg,
max_payload_size, false);
if (rc) if (rc)
return rc; return rc;
...@@ -189,6 +215,7 @@ static int vhost_user_send(struct virtio_uml_device *vu_dev, ...@@ -189,6 +215,7 @@ static int vhost_user_send(struct virtio_uml_device *vu_dev,
int *fds, size_t num_fds) int *fds, size_t num_fds)
{ {
size_t size = sizeof(msg->header) + msg->header.size; size_t size = sizeof(msg->header) + msg->header.size;
unsigned long flags;
bool request_ack; bool request_ack;
int rc; int rc;
...@@ -207,24 +234,28 @@ static int vhost_user_send(struct virtio_uml_device *vu_dev, ...@@ -207,24 +234,28 @@ static int vhost_user_send(struct virtio_uml_device *vu_dev,
if (request_ack) if (request_ack)
msg->header.flags |= VHOST_USER_FLAG_NEED_REPLY; msg->header.flags |= VHOST_USER_FLAG_NEED_REPLY;
spin_lock_irqsave(&vu_dev->sock_lock, flags);
rc = full_sendmsg_fds(vu_dev->sock, msg, size, fds, num_fds); rc = full_sendmsg_fds(vu_dev->sock, msg, size, fds, num_fds);
if (rc < 0) if (rc < 0)
return rc; goto out;
if (request_ack) { if (request_ack) {
uint64_t status; uint64_t status;
rc = vhost_user_recv_u64(vu_dev, &status); rc = vhost_user_recv_u64(vu_dev, &status);
if (rc) if (rc)
return rc; goto out;
if (status) { if (status) {
vu_err(vu_dev, "slave reports error: %llu\n", status); vu_err(vu_dev, "slave reports error: %llu\n", status);
return -EIO; rc = -EIO;
goto out;
} }
} }
return 0; out:
spin_unlock_irqrestore(&vu_dev->sock_lock, flags);
return rc;
} }
static int vhost_user_send_no_payload(struct virtio_uml_device *vu_dev, static int vhost_user_send_no_payload(struct virtio_uml_device *vu_dev,
...@@ -324,6 +355,7 @@ static void vhost_user_reply(struct virtio_uml_device *vu_dev, ...@@ -324,6 +355,7 @@ static void vhost_user_reply(struct virtio_uml_device *vu_dev,
static irqreturn_t vu_req_interrupt(int irq, void *data) static irqreturn_t vu_req_interrupt(int irq, void *data)
{ {
struct virtio_uml_device *vu_dev = data; struct virtio_uml_device *vu_dev = data;
struct virtqueue *vq;
int response = 1; int response = 1;
struct { struct {
struct vhost_user_msg msg; struct vhost_user_msg msg;
...@@ -343,6 +375,15 @@ static irqreturn_t vu_req_interrupt(int irq, void *data) ...@@ -343,6 +375,15 @@ static irqreturn_t vu_req_interrupt(int irq, void *data)
virtio_config_changed(&vu_dev->vdev); virtio_config_changed(&vu_dev->vdev);
response = 0; response = 0;
break; break;
case VHOST_USER_SLAVE_VRING_CALL:
virtio_device_for_each_vq((&vu_dev->vdev), vq) {
if (vq->index == msg.msg.payload.vring_state.index) {
response = 0;
vring_interrupt(0 /* ignored */, vq);
break;
}
}
break;
case VHOST_USER_SLAVE_IOTLB_MSG: case VHOST_USER_SLAVE_IOTLB_MSG:
/* not supported - VIRTIO_F_IOMMU_PLATFORM */ /* not supported - VIRTIO_F_IOMMU_PLATFORM */
case VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG: case VHOST_USER_SLAVE_VRING_HOST_NOTIFIER_MSG:
...@@ -684,6 +725,17 @@ static bool vu_notify(struct virtqueue *vq) ...@@ -684,6 +725,17 @@ static bool vu_notify(struct virtqueue *vq)
const uint64_t n = 1; const uint64_t n = 1;
int rc; int rc;
time_travel_propagate_time();
if (info->kick_fd < 0) {
struct virtio_uml_device *vu_dev;
vu_dev = to_virtio_uml_device(vq->vdev);
return vhost_user_set_vring_state(vu_dev, VHOST_USER_VRING_KICK,
vq->index, 0) == 0;
}
do { do {
rc = os_write_file(info->kick_fd, &n, sizeof(n)); rc = os_write_file(info->kick_fd, &n, sizeof(n));
} while (rc == -EINTR); } while (rc == -EINTR);
...@@ -749,10 +801,13 @@ static void vu_del_vq(struct virtqueue *vq) ...@@ -749,10 +801,13 @@ static void vu_del_vq(struct virtqueue *vq)
{ {
struct virtio_uml_vq_info *info = vq->priv; struct virtio_uml_vq_info *info = vq->priv;
um_free_irq(VIRTIO_IRQ, vq); if (info->call_fd >= 0) {
um_free_irq(VIRTIO_IRQ, vq);
os_close_file(info->call_fd);
}
os_close_file(info->call_fd); if (info->kick_fd >= 0)
os_close_file(info->kick_fd); os_close_file(info->kick_fd);
vring_del_virtqueue(vq); vring_del_virtqueue(vq);
kfree(info); kfree(info);
...@@ -782,6 +837,15 @@ static int vu_setup_vq_call_fd(struct virtio_uml_device *vu_dev, ...@@ -782,6 +837,15 @@ static int vu_setup_vq_call_fd(struct virtio_uml_device *vu_dev,
int call_fds[2]; int call_fds[2];
int rc; int rc;
/* no call FD needed/desired in this case */
if (vu_dev->protocol_features &
BIT_ULL(VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS) &&
vu_dev->protocol_features &
BIT_ULL(VHOST_USER_PROTOCOL_F_SLAVE_REQ)) {
info->call_fd = -1;
return 0;
}
/* Use a pipe for call fd, since SIGIO is not supported for eventfd */ /* Use a pipe for call fd, since SIGIO is not supported for eventfd */
rc = os_pipe(call_fds, true, true); rc = os_pipe(call_fds, true, true);
if (rc < 0) if (rc < 0)
...@@ -810,6 +874,23 @@ static int vu_setup_vq_call_fd(struct virtio_uml_device *vu_dev, ...@@ -810,6 +874,23 @@ static int vu_setup_vq_call_fd(struct virtio_uml_device *vu_dev,
return rc; return rc;
} }
#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
static void vu_defer_irq_handle(struct time_travel_event *d)
{
struct virtio_uml_vq_info *info;
info = container_of(d, struct virtio_uml_vq_info, defer);
info->callback(info->vq);
}
static void vu_defer_irq_callback(struct virtqueue *vq)
{
struct virtio_uml_vq_info *info = vq->priv;
time_travel_add_irq_event(&info->defer);
}
#endif
static struct virtqueue *vu_setup_vq(struct virtio_device *vdev, static struct virtqueue *vu_setup_vq(struct virtio_device *vdev,
unsigned index, vq_callback_t *callback, unsigned index, vq_callback_t *callback,
const char *name, bool ctx) const char *name, bool ctx)
...@@ -829,6 +910,19 @@ static struct virtqueue *vu_setup_vq(struct virtio_device *vdev, ...@@ -829,6 +910,19 @@ static struct virtqueue *vu_setup_vq(struct virtio_device *vdev,
snprintf(info->name, sizeof(info->name), "%s.%d-%s", pdev->name, snprintf(info->name, sizeof(info->name), "%s.%d-%s", pdev->name,
pdev->id, name); pdev->id, name);
#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
/*
* When we get an interrupt, we must bounce it through the simulation
* calendar (the simtime device), except for the simtime device itself
* since that's part of the simulation control.
*/
if (time_travel_mode == TT_MODE_EXTERNAL && callback) {
info->callback = callback;
callback = vu_defer_irq_callback;
time_travel_set_event_fn(&info->defer, vu_defer_irq_handle);
}
#endif
vq = vring_create_virtqueue(index, num, PAGE_SIZE, vdev, true, true, vq = vring_create_virtqueue(index, num, PAGE_SIZE, vdev, true, true,
ctx, vu_notify, callback, info->name); ctx, vu_notify, callback, info->name);
if (!vq) { if (!vq) {
...@@ -837,11 +931,19 @@ static struct virtqueue *vu_setup_vq(struct virtio_device *vdev, ...@@ -837,11 +931,19 @@ static struct virtqueue *vu_setup_vq(struct virtio_device *vdev,
} }
vq->priv = info; vq->priv = info;
num = virtqueue_get_vring_size(vq); num = virtqueue_get_vring_size(vq);
#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
info->vq = vq;
#endif
rc = os_eventfd(0, 0); if (vu_dev->protocol_features &
if (rc < 0) BIT_ULL(VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS)) {
goto error_kick; info->kick_fd = -1;
info->kick_fd = rc; } else {
rc = os_eventfd(0, 0);
if (rc < 0)
goto error_kick;
info->kick_fd = rc;
}
rc = vu_setup_vq_call_fd(vu_dev, vq); rc = vu_setup_vq_call_fd(vu_dev, vq);
if (rc) if (rc)
...@@ -866,10 +968,13 @@ static struct virtqueue *vu_setup_vq(struct virtio_device *vdev, ...@@ -866,10 +968,13 @@ static struct virtqueue *vu_setup_vq(struct virtio_device *vdev,
return vq; return vq;
error_setup: error_setup:
um_free_irq(VIRTIO_IRQ, vq); if (info->call_fd >= 0) {
os_close_file(info->call_fd); um_free_irq(VIRTIO_IRQ, vq);
os_close_file(info->call_fd);
}
error_call: error_call:
os_close_file(info->kick_fd); if (info->kick_fd >= 0)
os_close_file(info->kick_fd);
error_kick: error_kick:
vring_del_virtqueue(vq); vring_del_virtqueue(vq);
error_create: error_create:
...@@ -908,10 +1013,12 @@ static int vu_find_vqs(struct virtio_device *vdev, unsigned nvqs, ...@@ -908,10 +1013,12 @@ static int vu_find_vqs(struct virtio_device *vdev, unsigned nvqs,
list_for_each_entry(vq, &vdev->vqs, list) { list_for_each_entry(vq, &vdev->vqs, list) {
struct virtio_uml_vq_info *info = vq->priv; struct virtio_uml_vq_info *info = vq->priv;
rc = vhost_user_set_vring_kick(vu_dev, vq->index, if (info->kick_fd >= 0) {
info->kick_fd); rc = vhost_user_set_vring_kick(vu_dev, vq->index,
if (rc) info->kick_fd);
goto error_setup; if (rc)
goto error_setup;
}
rc = vhost_user_set_vring_enable(vu_dev, vq->index, true); rc = vhost_user_set_vring_enable(vu_dev, vq->index, true);
if (rc) if (rc)
...@@ -1008,6 +1115,8 @@ static int virtio_uml_probe(struct platform_device *pdev) ...@@ -1008,6 +1115,8 @@ static int virtio_uml_probe(struct platform_device *pdev)
return rc; return rc;
vu_dev->sock = rc; vu_dev->sock = rc;
spin_lock_init(&vu_dev->sock_lock);
rc = vhost_user_init(vu_dev); rc = vhost_user_init(vu_dev);
if (rc) if (rc)
goto error_init; goto error_init;
......
...@@ -3,7 +3,6 @@ generic-y += bpf_perf_event.h ...@@ -3,7 +3,6 @@ generic-y += bpf_perf_event.h
generic-y += bug.h generic-y += bug.h
generic-y += compat.h generic-y += compat.h
generic-y += current.h generic-y += current.h
generic-y += delay.h
generic-y += device.h generic-y += device.h
generic-y += emergency-restart.h generic-y += emergency-restart.h
generic-y += exec.h generic-y += exec.h
......
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __UM_DELAY_H
#define __UM_DELAY_H
#include <asm-generic/delay.h>
#include <linux/time-internal.h>
static inline void um_ndelay(unsigned long nsecs)
{
if (time_travel_mode == TT_MODE_INFCPU ||
time_travel_mode == TT_MODE_EXTERNAL) {
time_travel_ndelay(nsecs);
return;
}
ndelay(nsecs);
}
#undef ndelay
#define ndelay um_ndelay
static inline void um_udelay(unsigned long usecs)
{
if (time_travel_mode == TT_MODE_INFCPU ||
time_travel_mode == TT_MODE_EXTERNAL) {
time_travel_ndelay(1000 * usecs);
return;
}
udelay(usecs);
}
#undef udelay
#define udelay um_udelay
#endif /* __UM_DELAY_H */
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2012 - 2014 Cisco Systems
* Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
*/
#ifndef __TIMER_INTERNAL_H__
#define __TIMER_INTERNAL_H__
#include <linux/list.h>
#define TIMER_MULTIPLIER 256
#define TIMER_MIN_DELTA 500
enum time_travel_mode {
TT_MODE_OFF,
TT_MODE_BASIC,
TT_MODE_INFCPU,
TT_MODE_EXTERNAL,
};
#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
struct time_travel_event {
unsigned long long time;
void (*fn)(struct time_travel_event *d);
struct list_head list;
bool pending, onstack;
};
extern enum time_travel_mode time_travel_mode;
void time_travel_sleep(unsigned long long duration);
static inline void
time_travel_set_event_fn(struct time_travel_event *e,
void (*fn)(struct time_travel_event *d))
{
e->fn = fn;
}
void __time_travel_propagate_time(void);
static inline void time_travel_propagate_time(void)
{
if (time_travel_mode == TT_MODE_EXTERNAL)
__time_travel_propagate_time();
}
void __time_travel_wait_readable(int fd);
static inline void time_travel_wait_readable(int fd)
{
if (time_travel_mode == TT_MODE_EXTERNAL)
__time_travel_wait_readable(fd);
}
void time_travel_add_irq_event(struct time_travel_event *e);
#else
struct time_travel_event {
};
#define time_travel_mode TT_MODE_OFF
static inline void time_travel_sleep(unsigned long long duration)
{
}
/* this is a macro so the event/function need not exist */
#define time_travel_set_event_fn(e, fn) do {} while (0)
static inline void time_travel_propagate_time(void)
{
}
static inline void time_travel_wait_readable(int fd)
{
}
#endif /* CONFIG_UML_TIME_TRAVEL_SUPPORT */
/*
* Without CONFIG_UML_TIME_TRAVEL_SUPPORT this is a linker error if used,
* which is intentional since we really shouldn't link it in that case.
*/
void time_travel_ndelay(unsigned long nsec);
#endif /* __TIMER_INTERNAL_H__ */
...@@ -181,6 +181,7 @@ extern int os_falloc_punch(int fd, unsigned long long offset, int count); ...@@ -181,6 +181,7 @@ extern int os_falloc_punch(int fd, unsigned long long offset, int count);
extern int os_eventfd(unsigned int initval, int flags); extern int os_eventfd(unsigned int initval, int flags);
extern int os_sendmsg_fds(int fd, const void *buf, unsigned int len, extern int os_sendmsg_fds(int fd, const void *buf, unsigned int len,
const int *fds, unsigned int fds_num); const int *fds, unsigned int fds_num);
int os_poll(unsigned int n, const int *fds);
/* start_up.c */ /* start_up.c */
extern void os_early_checks(void); extern void os_early_checks(void);
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2012 - 2014 Cisco Systems
* Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
*/
#ifndef __TIMER_INTERNAL_H__
#define __TIMER_INTERNAL_H__
#define TIMER_MULTIPLIER 256
#define TIMER_MIN_DELTA 500
enum time_travel_mode {
TT_MODE_OFF,
TT_MODE_BASIC,
TT_MODE_INFCPU,
};
enum time_travel_timer_mode {
TT_TMR_DISABLED,
TT_TMR_ONESHOT,
TT_TMR_PERIODIC,
};
#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
extern enum time_travel_mode time_travel_mode;
extern unsigned long long time_travel_time;
extern enum time_travel_timer_mode time_travel_timer_mode;
extern unsigned long long time_travel_timer_expiry;
extern unsigned long long time_travel_timer_interval;
static inline void time_travel_set_time(unsigned long long ns)
{
time_travel_time = ns;
}
static inline void time_travel_set_timer_mode(enum time_travel_timer_mode mode)
{
time_travel_timer_mode = mode;
}
static inline void time_travel_set_timer_expiry(unsigned long long expiry)
{
time_travel_timer_expiry = expiry;
}
static inline void time_travel_set_timer_interval(unsigned long long interval)
{
time_travel_timer_interval = interval;
}
#else
#define time_travel_mode TT_MODE_OFF
#define time_travel_time 0
#define time_travel_timer_expiry 0
#define time_travel_timer_interval 0
static inline void time_travel_set_time(unsigned long long ns)
{
}
static inline void time_travel_set_timer_mode(enum time_travel_timer_mode mode)
{
}
static inline void time_travel_set_timer_expiry(unsigned long long expiry)
{
}
static inline void time_travel_set_timer_interval(unsigned long long interval)
{
}
#define time_travel_timer_mode TT_TMR_DISABLED
#endif
#endif
...@@ -9,20 +9,19 @@ static void kmsg_dumper_stdout(struct kmsg_dumper *dumper, ...@@ -9,20 +9,19 @@ static void kmsg_dumper_stdout(struct kmsg_dumper *dumper,
enum kmsg_dump_reason reason) enum kmsg_dump_reason reason)
{ {
static char line[1024]; static char line[1024];
struct console *con;
size_t len = 0; size_t len = 0;
bool con_available = false;
/* only dump kmsg when no console is available */ /* only dump kmsg when no console is available */
if (!console_trylock()) if (!console_trylock())
return; return;
if (console_drivers != NULL) for_each_console(con)
con_available = true; break;
console_unlock(); console_unlock();
if (con_available == true) if (con)
return; return;
printf("kmsg_dump:\n"); printf("kmsg_dump:\n");
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
#include <kern_util.h> #include <kern_util.h>
#include <os.h> #include <os.h>
#include <skas.h> #include <skas.h>
#include <timer-internal.h> #include <linux/time-internal.h>
/* /*
* This is a per-cpu array. A processor only modifies its entry and it only * This is a per-cpu array. A processor only modifies its entry and it only
...@@ -203,43 +203,6 @@ void initial_thread_cb(void (*proc)(void *), void *arg) ...@@ -203,43 +203,6 @@ void initial_thread_cb(void (*proc)(void *), void *arg)
kmalloc_ok = save_kmalloc_ok; kmalloc_ok = save_kmalloc_ok;
} }
static void time_travel_sleep(unsigned long long duration)
{
unsigned long long next = time_travel_time + duration;
if (time_travel_mode != TT_MODE_INFCPU)
os_timer_disable();
while (time_travel_timer_mode == TT_TMR_PERIODIC &&
time_travel_timer_expiry < time_travel_time)
time_travel_set_timer_expiry(time_travel_timer_expiry +
time_travel_timer_interval);
if (time_travel_timer_mode != TT_TMR_DISABLED &&
time_travel_timer_expiry < next) {
if (time_travel_timer_mode == TT_TMR_ONESHOT)
time_travel_set_timer_mode(TT_TMR_DISABLED);
/*
* In basic mode, time_travel_time will be adjusted in
* the timer IRQ handler so it works even when the signal
* comes from the OS timer, see there.
*/
if (time_travel_mode != TT_MODE_BASIC)
time_travel_set_time(time_travel_timer_expiry);
deliver_alarm();
} else {
time_travel_set_time(next);
}
if (time_travel_mode != TT_MODE_INFCPU) {
if (time_travel_timer_mode == TT_TMR_PERIODIC)
os_timer_set_interval(time_travel_timer_interval);
else if (time_travel_timer_mode == TT_TMR_ONESHOT)
os_timer_one_shot(time_travel_timer_expiry - next);
}
}
static void um_idle_sleep(void) static void um_idle_sleep(void)
{ {
unsigned long long duration = UM_NSEC_PER_SEC; unsigned long long duration = UM_NSEC_PER_SEC;
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
#include <sysdep/ptrace.h> #include <sysdep/ptrace.h>
#include <sysdep/ptrace_user.h> #include <sysdep/ptrace_user.h>
#include <sysdep/syscalls.h> #include <sysdep/syscalls.h>
#include <shared/timer-internal.h> #include <linux/time-internal.h>
void handle_syscall(struct uml_pt_regs *r) void handle_syscall(struct uml_pt_regs *r)
{ {
...@@ -24,7 +24,8 @@ void handle_syscall(struct uml_pt_regs *r) ...@@ -24,7 +24,8 @@ void handle_syscall(struct uml_pt_regs *r)
* went to sleep, even if said userspace interacts with the kernel in * went to sleep, even if said userspace interacts with the kernel in
* various ways. * various ways.
*/ */
if (time_travel_mode == TT_MODE_INFCPU) if (time_travel_mode == TT_MODE_INFCPU ||
time_travel_mode == TT_MODE_EXTERNAL)
schedule(); schedule();
/* Initialize the syscall number and default return value. */ /* Initialize the syscall number and default return value. */
......
This diff is collapsed.
...@@ -19,10 +19,10 @@ SECTIONS ...@@ -19,10 +19,10 @@ SECTIONS
__binary_start = START; __binary_start = START;
. = START + SIZEOF_HEADERS; . = START + SIZEOF_HEADERS;
. = ALIGN(PAGE_SIZE);
_text = .; _text = .;
INIT_TEXT_SECTION(0) INIT_TEXT_SECTION(0)
. = ALIGN(PAGE_SIZE);
.text : .text :
{ {
......
...@@ -5,9 +5,11 @@ ...@@ -5,9 +5,11 @@
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <stdlib.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <signal.h> #include <signal.h>
#include <linux/falloc.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/mount.h> #include <sys/mount.h>
#include <sys/socket.h> #include <sys/socket.h>
...@@ -16,6 +18,7 @@ ...@@ -16,6 +18,7 @@
#include <sys/un.h> #include <sys/un.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/eventfd.h> #include <sys/eventfd.h>
#include <poll.h>
#include <os.h> #include <os.h>
static void copy_stat(struct uml_stat *dst, const struct stat64 *src) static void copy_stat(struct uml_stat *dst, const struct stat64 *src)
...@@ -664,3 +667,31 @@ int os_sendmsg_fds(int fd, const void *buf, unsigned int len, const int *fds, ...@@ -664,3 +667,31 @@ int os_sendmsg_fds(int fd, const void *buf, unsigned int len, const int *fds,
return -errno; return -errno;
return err; return err;
} }
int os_poll(unsigned int n, const int *fds)
{
/* currently need 2 FDs at most so avoid dynamic allocation */
struct pollfd pollfds[2] = {};
unsigned int i;
int ret;
if (n > ARRAY_SIZE(pollfds))
return -EINVAL;
for (i = 0; i < n; i++) {
pollfds[i].fd = fds[i];
pollfds[i].events = POLLIN;
}
ret = poll(pollfds, n, -1);
if (ret < 0)
return -errno;
/* Return the index of the available FD */
for (i = 0; i < n; i++) {
if (pollfds[i].revents)
return i;
}
return -EIO;
}
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
#include <kern_util.h> #include <kern_util.h>
#include <os.h> #include <os.h>
#include <string.h> #include <string.h>
#include <timer-internal.h>
static timer_t event_high_res_timer = 0; static timer_t event_high_res_timer = 0;
......
...@@ -220,11 +220,12 @@ static void __init create_pid_file(void) ...@@ -220,11 +220,12 @@ static void __init create_pid_file(void)
char pid[sizeof("nnnnn\0")], *file; char pid[sizeof("nnnnn\0")], *file;
int fd, n; int fd, n;
file = malloc(strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")); n = strlen(uml_dir) + UMID_LEN + sizeof("/pid\0");
file = malloc(n);
if (!file) if (!file)
return; return;
if (umid_file_name("pid", file, sizeof(file))) if (umid_file_name("pid", file, n))
goto out; goto out;
fd = open(file, O_RDWR | O_CREAT | O_EXCL, 0644); fd = open(file, O_RDWR | O_CREAT | O_EXCL, 0644);
......
/* SPDX-License-Identifier: GPL-2.0 */ /* SPDX-License-Identifier: GPL-2.0 */
#ifndef __UM_PROCESSOR_H #ifndef __UM_PROCESSOR_H
#define __UM_PROCESSOR_H #define __UM_PROCESSOR_H
#include <linux/time-internal.h>
/* include faultinfo structure */ /* include faultinfo structure */
#include <sysdep/faultinfo.h> #include <sysdep/faultinfo.h>
...@@ -21,12 +22,19 @@ ...@@ -21,12 +22,19 @@
#include <asm/user.h> #include <asm/user.h>
/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */ /* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
static inline void rep_nop(void) static __always_inline void rep_nop(void)
{ {
__asm__ __volatile__("rep;nop": : :"memory"); __asm__ __volatile__("rep;nop": : :"memory");
} }
#define cpu_relax() rep_nop() static __always_inline void cpu_relax(void)
{
if (time_travel_mode == TT_MODE_INFCPU ||
time_travel_mode == TT_MODE_EXTERNAL)
time_travel_ndelay(1);
else
rep_nop();
}
#define task_pt_regs(t) (&(t)->thread.regs) #define task_pt_regs(t) (&(t)->thread.regs)
......
...@@ -139,8 +139,8 @@ static char *inode_name(struct inode *ino) ...@@ -139,8 +139,8 @@ static char *inode_name(struct inode *ino)
static char *follow_link(char *link) static char *follow_link(char *link)
{ {
int len, n;
char *name, *resolved, *end; char *name, *resolved, *end;
int n;
name = __getname(); name = __getname();
if (!name) { if (!name) {
...@@ -164,15 +164,13 @@ static char *follow_link(char *link) ...@@ -164,15 +164,13 @@ static char *follow_link(char *link)
return name; return name;
*(end + 1) = '\0'; *(end + 1) = '\0';
len = strlen(link) + strlen(name) + 1;
resolved = kmalloc(len, GFP_KERNEL); resolved = kasprintf(GFP_KERNEL, "%s%s", link, name);
if (resolved == NULL) { if (resolved == NULL) {
n = -ENOMEM; n = -ENOMEM;
goto out_free; goto out_free;
} }
sprintf(resolved, "%s%s", link, name);
__putname(name); __putname(name);
kfree(link); kfree(link);
return resolved; return resolved;
...@@ -921,18 +919,16 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent) ...@@ -921,18 +919,16 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
sb->s_d_op = &simple_dentry_operations; sb->s_d_op = &simple_dentry_operations;
sb->s_maxbytes = MAX_LFS_FILESIZE; sb->s_maxbytes = MAX_LFS_FILESIZE;
/* NULL is printed as <NULL> by sprintf: avoid that. */ /* NULL is printed as '(null)' by printf(): avoid that. */
if (req_root == NULL) if (req_root == NULL)
req_root = ""; req_root = "";
err = -ENOMEM; err = -ENOMEM;
sb->s_fs_info = host_root_path = sb->s_fs_info = host_root_path =
kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL); kasprintf(GFP_KERNEL, "%s/%s", root_ino, req_root);
if (host_root_path == NULL) if (host_root_path == NULL)
goto out; goto out;
sprintf(host_root_path, "%s/%s", root_ino, req_root);
root_inode = new_inode(sb); root_inode = new_inode(sb);
if (!root_inode) if (!root_inode)
goto out; goto out;
......
/*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Copyright (C) 2019 Intel Corporation
*/
#ifndef _UAPI_LINUX_UM_TIMETRAVEL_H
#define _UAPI_LINUX_UM_TIMETRAVEL_H
#include <linux/types.h>
/**
* struct um_timetravel_msg - UM time travel message
*
* This is the basic message type, going in both directions.
*
* This is the message passed between the host (user-mode Linux instance)
* and the calendar (the application on the other side of the socket) in
* order to implement common scheduling.
*
* Whenever UML has an event it will request runtime for it from the
* calendar, and then wait for its turn until it can run, etc. Note
* that it will only ever request the single next runtime, i.e. multiple
* REQUEST messages override each other.
*/
struct um_timetravel_msg {
/**
* @op: operation value from &enum um_timetravel_ops
*/
__u32 op;
/**
* @seq: sequence number for the message - shall be reflected in
* the ACK response, and should be checked while processing
* the response to see if it matches
*/
__u32 seq;
/**
* @time: time in nanoseconds
*/
__u64 time;
};
/**
* enum um_timetravel_ops - Operation codes
*/
enum um_timetravel_ops {
/**
* @UM_TIMETRAVEL_ACK: response (ACK) to any previous message,
* this usually doesn't carry any data in the 'time' field
* unless otherwise specified below
*/
UM_TIMETRAVEL_ACK = 0,
/**
* @UM_TIMETRAVEL_START: initialize the connection, the time
* field contains an (arbitrary) ID to possibly be able
* to distinguish the connections.
*/
UM_TIMETRAVEL_START = 1,
/**
* @UM_TIMETRAVEL_REQUEST: request to run at the given time
* (host -> calendar)
*/
UM_TIMETRAVEL_REQUEST = 2,
/**
* @UM_TIMETRAVEL_WAIT: Indicate waiting for the previously requested
* runtime, new requests may be made while waiting (e.g. due to
* interrupts); the time field is ignored. The calendar must process
* this message and later send a %UM_TIMETRAVEL_RUN message when
* the host can run again.
* (host -> calendar)
*/
UM_TIMETRAVEL_WAIT = 3,
/**
* @UM_TIMETRAVEL_GET: return the current time from the calendar in the
* ACK message, the time in the request message is ignored
* (host -> calendar)
*/
UM_TIMETRAVEL_GET = 4,
/**
* @UM_TIMETRAVEL_UPDATE: time update to the calendar, must be sent e.g.
* before kicking an interrupt to another calendar
* (host -> calendar)
*/
UM_TIMETRAVEL_UPDATE = 5,
/**
* @UM_TIMETRAVEL_RUN: run time request granted, current time is in
* the time field
* (calendar -> host)
*/
UM_TIMETRAVEL_RUN = 6,
/**
* @UM_TIMETRAVEL_FREE_UNTIL: Enable free-running until the given time,
* this is a message from the calendar telling the host that it can
* freely do its own scheduling for anything before the indicated
* time.
* Note that if a calendar sends this message once, the host may
* assume that it will also do so in the future, if it implements
* wraparound semantics for the time field.
* (calendar -> host)
*/
UM_TIMETRAVEL_FREE_UNTIL = 7,
/**
* @UM_TIMETRAVEL_GET_TOD: Return time of day, typically used once at
* boot by the virtual machines to get a synchronized time from
* the simulation.
*/
UM_TIMETRAVEL_GET_TOD = 8,
};
#endif /* _UAPI_LINUX_UM_TIMETRAVEL_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment