Skip to content

Commit

Permalink
Merge tag 'for-linus-5.18-rc1' of git://git.kernel.org/pub/scm/linux/…
Browse files Browse the repository at this point in the history
…kernel/git/rw/uml

Pull UML updates from Richard Weinberger:

 - Devicetree support (for testing)

 - Various cleanups and fixes: UBD, port_user, uml_mconsole

 - Maintainer update

* tag 'for-linus-5.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml:
  um: run_helper: Write error message to kernel log on exec failure on host
  um: port_user: Improve error handling when port-helper is not found
  um: port_user: Allow setting path to port-helper using UML_PORT_HELPER envvar
  um: port_user: Search for in.telnetd in PATH
  um: clang: Strip out -mno-global-merge from USER_CFLAGS
  docs: UML: Mention telnetd for port channel
  um: Remove unused timeval_to_ns() function
  um: Fix uml_mconsole stop/go
  um: Cleanup syscall_handler_t definition/cast, fix warning
  uml: net: vector: fix const issue
  um: Fix WRITE_ZEROES in the UBD Driver
  um: Migrate vector drivers to NAPI
  um: Fix order of dtb unflatten/early init
  um: fix and optimize xor select template for CONFIG64 and timetravel mode
  um: Document dtb command line option
  lib/logic_iomem: correct fallback config references
  um: Remove duplicated include in syscalls_64.c
  MAINTAINERS: Update UserModeLinux entry
  • Loading branch information
Linus Torvalds committed Mar 31, 2022
2 parents a87a08e + 8201745 commit e8b767f
Show file tree
Hide file tree
Showing 19 changed files with 131 additions and 80 deletions.
20 changes: 20 additions & 0 deletions Documentation/virt/uml/user_mode_linux_howto_v2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1193,6 +1193,26 @@ E.g. ``os_close_file()`` is just a wrapper around ``close()``
which ensures that the userspace function close does not clash
with similarly named function(s) in the kernel part.

Using UML as a Test Platform
============================

UML is an excellent test platform for device driver development. As
with most things UML, "some user assembly may be required". It is
up to the user to build their emulation environment. UML at present
provides only the kernel infrastructure.

Part of this infrastructure is the ability to load and parse fdt
device tree blobs as used in Arm or Open Firmware platforms. These
are supplied as an optional extra argument to the kernel command
line::

dtb=filename

The device tree is loaded and parsed at boottime and is accessible by
drivers which query it. At this moment in time this facility is
intended solely for development purposes. UML's own devices do not
query the device tree.

Security Considerations
-----------------------

Expand Down
5 changes: 3 additions & 2 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -20539,14 +20539,15 @@ F: Documentation/admin-guide/media/zr364xx*
F: drivers/media/usb/zr364xx/

USER-MODE LINUX (UML)
M: Jeff Dike <jdike@addtoit.com>
M: Richard Weinberger <richard@nod.at>
M: Anton Ivanov <anton.ivanov@cambridgegreys.com>
M: Johannes Berg <johannes@sipsolutions.net>
L: linux-um@lists.infradead.org
S: Maintained
W: http://user-mode-linux.sourceforge.net
Q: https://patchwork.ozlabs.org/project/linux-um/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/uml/linux.git next
T: git git://git.kernel.org/pub/scm/linux/kernel/git/uml/linux.git fixes
F: Documentation/virt/uml/
F: arch/um/
F: arch/x86/um/
Expand Down
4 changes: 4 additions & 0 deletions arch/um/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ USER_CFLAGS = $(patsubst $(KERNEL_DEFINES),,$(patsubst -I%,,$(KBUILD_CFLAGS))) \
-D_FILE_OFFSET_BITS=64 -idirafter $(srctree)/include \
-idirafter $(objtree)/include -D__KERNEL__ -D__UM_HOST__

ifdef CONFIG_CC_IS_CLANG
USER_CFLAGS := $(patsubst -mno-global-merge,,$(USER_CFLAGS))
endif

#This will adjust *FLAGS accordingly to the platform.
include $(srctree)/$(ARCH_DIR)/Makefile-os-$(OS)

Expand Down
3 changes: 2 additions & 1 deletion arch/um/drivers/mconsole_kern.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ void mconsole_go(struct mc_request *req)

void mconsole_stop(struct mc_request *req)
{
deactivate_fd(req->originating_fd, MCONSOLE_IRQ);
block_signals();
os_set_fd_block(req->originating_fd, 1);
mconsole_reply(req, "stopped", 0, 0);
for (;;) {
Expand All @@ -247,6 +247,7 @@ void mconsole_stop(struct mc_request *req)
}
os_set_fd_block(req->originating_fd, 0);
mconsole_reply(req, "", 0, 0);
unblock_signals();
}

static DEFINE_SPINLOCK(mc_devices_lock);
Expand Down
18 changes: 17 additions & 1 deletion arch/um/drivers/port_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
Expand Down Expand Up @@ -167,14 +168,29 @@ static void port_pre_exec(void *arg)
int port_connection(int fd, int *socket, int *pid_out)
{
int new, err;
char *argv[] = { "/usr/sbin/in.telnetd", "-L",
char *env;
char *argv[] = { "in.telnetd", "-L",
OS_LIB_PATH "/uml/port-helper", NULL };
struct port_pre_exec_data data;

if ((env = getenv("UML_PORT_HELPER")))
argv[2] = env;

new = accept(fd, NULL, 0);
if (new < 0)
return -errno;

err = os_access(argv[2], X_OK);
if (err < 0) {
printk(UM_KERN_ERR "port_connection : error accessing port-helper "
"executable at %s: %s\n", argv[2], strerror(-err));
if (env == NULL)
printk(UM_KERN_ERR "Set UML_PORT_HELPER environment "
"variable to path to uml-utilities port-helper "
"binary\n");
goto out_close;
}

err = os_pipe(socket, 0, 0);
if (err < 0)
goto out_close;
Expand Down
8 changes: 7 additions & 1 deletion arch/um/drivers/ubd_kern.c
Original file line number Diff line number Diff line change
Expand Up @@ -1526,13 +1526,19 @@ static void do_io(struct io_thread_req *req, struct io_desc *desc)
}
break;
case REQ_OP_DISCARD:
case REQ_OP_WRITE_ZEROES:
n = os_falloc_punch(req->fds[bit], off, len);
if (n) {
req->error = map_error(-n);
return;
}
break;
case REQ_OP_WRITE_ZEROES:
n = os_falloc_zeroes(req->fds[bit], off, len);
if (n) {
req->error = map_error(-n);
return;
}
break;
default:
WARN_ON_ONCE(1);
req->error = BLK_STS_NOTSUPP;
Expand Down
105 changes: 49 additions & 56 deletions arch/um/drivers/vector_kern.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ static LIST_HEAD(vector_devices);
static int driver_registered;

static void vector_eth_configure(int n, struct arglist *def);
static int vector_mmsg_rx(struct vector_private *vp, int budget);

/* Argument accessors to set variables (and/or set default values)
* mtu, buffer sizing, default headroom, etc
Expand All @@ -77,7 +78,6 @@ static void vector_eth_configure(int n, struct arglist *def);
#define DEFAULT_VECTOR_SIZE 64
#define TX_SMALL_PACKET 128
#define MAX_IOV_SIZE (MAX_SKB_FRAGS + 1)
#define MAX_ITERATIONS 64

static const struct {
const char string[ETH_GSTRING_LEN];
Expand Down Expand Up @@ -458,7 +458,6 @@ static int vector_send(struct vector_queue *qi)
vp->estats.tx_queue_running_average =
(vp->estats.tx_queue_running_average + result) >> 1;
}
netif_trans_update(qi->dev);
netif_wake_queue(qi->dev);
/* if TX is busy, break out of the send loop,
* poll write IRQ will reschedule xmit for us
Expand All @@ -470,8 +469,6 @@ static int vector_send(struct vector_queue *qi)
}
}
spin_unlock(&qi->head_lock);
} else {
tasklet_schedule(&vp->tx_poll);
}
return queue_depth;
}
Expand Down Expand Up @@ -608,7 +605,7 @@ static struct vector_queue *create_queue(

/*
* We do not use the RX queue as a proper wraparound queue for now
* This is not necessary because the consumption via netif_rx()
* This is not necessary because the consumption via napi_gro_receive()
* happens in-line. While we can try using the return code of
* netif_rx() for flow control there are no drivers doing this today.
* For this RX specific use we ignore the tail/head locks and
Expand Down Expand Up @@ -896,7 +893,7 @@ static int vector_legacy_rx(struct vector_private *vp)
skb->protocol = eth_type_trans(skb, skb->dev);
vp->dev->stats.rx_bytes += skb->len;
vp->dev->stats.rx_packets++;
netif_rx(skb);
napi_gro_receive(&vp->napi, skb);
} else {
dev_kfree_skb_irq(skb);
}
Expand Down Expand Up @@ -955,7 +952,7 @@ static int writev_tx(struct vector_private *vp, struct sk_buff *skb)
* mmsg vector matched to an skb vector which we prepared earlier.
*/

static int vector_mmsg_rx(struct vector_private *vp)
static int vector_mmsg_rx(struct vector_private *vp, int budget)
{
int packet_count, i;
struct vector_queue *qi = vp->rx_queue;
Expand All @@ -972,6 +969,9 @@ static int vector_mmsg_rx(struct vector_private *vp)

/* Fire the Lazy Gun - get as many packets as we can in one go. */

if (budget > qi->max_depth)
budget = qi->max_depth;

packet_count = uml_vector_recvmmsg(
vp->fds->rx_fd, qi->mmsg_vector, qi->max_depth, 0);

Expand Down Expand Up @@ -1021,7 +1021,7 @@ static int vector_mmsg_rx(struct vector_private *vp)
*/
vp->dev->stats.rx_bytes += skb->len;
vp->dev->stats.rx_packets++;
netif_rx(skb);
napi_gro_receive(&vp->napi, skb);
} else {
/* Overlay header too short to do anything - discard.
* We can actually keep this skb and reuse it,
Expand All @@ -1044,23 +1044,6 @@ static int vector_mmsg_rx(struct vector_private *vp)
return packet_count;
}

static void vector_rx(struct vector_private *vp)
{
int err;
int iter = 0;

if ((vp->options & VECTOR_RX) > 0)
while (((err = vector_mmsg_rx(vp)) > 0) && (iter < MAX_ITERATIONS))
iter++;
else
while (((err = vector_legacy_rx(vp)) > 0) && (iter < MAX_ITERATIONS))
iter++;
if ((err != 0) && net_ratelimit())
netdev_err(vp->dev, "vector_rx: error(%d)\n", err);
if (iter == MAX_ITERATIONS)
netdev_err(vp->dev, "vector_rx: device stuck, remote end may have closed the connection\n");
}

static int vector_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct vector_private *vp = netdev_priv(dev);
Expand All @@ -1085,25 +1068,15 @@ static int vector_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
netdev_sent_queue(vp->dev, skb->len);
queue_depth = vector_enqueue(vp->tx_queue, skb);

/* if the device queue is full, stop the upper layers and
* flush it.
*/

if (queue_depth >= vp->tx_queue->max_depth - 1) {
vp->estats.tx_kicks++;
netif_stop_queue(dev);
vector_send(vp->tx_queue);
return NETDEV_TX_OK;
}
if (netdev_xmit_more()) {
if (queue_depth < vp->tx_queue->max_depth && netdev_xmit_more()) {
mod_timer(&vp->tl, vp->coalesce);
return NETDEV_TX_OK;
} else {
queue_depth = vector_send(vp->tx_queue);
if (queue_depth > 0)
napi_schedule(&vp->napi);
}
if (skb->len < TX_SMALL_PACKET) {
vp->estats.tx_kicks++;
vector_send(vp->tx_queue);
} else
tasklet_schedule(&vp->tx_poll);

return NETDEV_TX_OK;
}

Expand All @@ -1114,7 +1087,7 @@ static irqreturn_t vector_rx_interrupt(int irq, void *dev_id)

if (!netif_running(dev))
return IRQ_NONE;
vector_rx(vp);
napi_schedule(&vp->napi);
return IRQ_HANDLED;

}
Expand All @@ -1133,8 +1106,7 @@ static irqreturn_t vector_tx_interrupt(int irq, void *dev_id)
* tweaking the IRQ mask less costly
*/

if (vp->in_write_poll)
tasklet_schedule(&vp->tx_poll);
napi_schedule(&vp->napi);
return IRQ_HANDLED;

}
Expand All @@ -1161,7 +1133,8 @@ static int vector_net_close(struct net_device *dev)
um_free_irq(vp->tx_irq, dev);
vp->tx_irq = 0;
}
tasklet_kill(&vp->tx_poll);
napi_disable(&vp->napi);
netif_napi_del(&vp->napi);
if (vp->fds->rx_fd > 0) {
if (vp->bpf)
uml_vector_detach_bpf(vp->fds->rx_fd, vp->bpf);
Expand Down Expand Up @@ -1193,15 +1166,32 @@ static int vector_net_close(struct net_device *dev)
return 0;
}

/* TX tasklet */

static void vector_tx_poll(struct tasklet_struct *t)
static int vector_poll(struct napi_struct *napi, int budget)
{
struct vector_private *vp = from_tasklet(vp, t, tx_poll);
struct vector_private *vp = container_of(napi, struct vector_private, napi);
int work_done = 0;
int err;
bool tx_enqueued = false;

vp->estats.tx_kicks++;
vector_send(vp->tx_queue);
if ((vp->options & VECTOR_TX) != 0)
tx_enqueued = (vector_send(vp->tx_queue) > 0);
if ((vp->options & VECTOR_RX) > 0)
err = vector_mmsg_rx(vp, budget);
else {
err = vector_legacy_rx(vp);
if (err > 0)
err = 1;
}
if (err > 0)
work_done += err;

if (tx_enqueued || err > 0)
napi_schedule(napi);
if (work_done < budget)
napi_complete_done(napi, work_done);
return work_done;
}

static void vector_reset_tx(struct work_struct *work)
{
struct vector_private *vp =
Expand Down Expand Up @@ -1265,6 +1255,9 @@ static int vector_net_open(struct net_device *dev)
goto out_close;
}

netif_napi_add(vp->dev, &vp->napi, vector_poll, get_depth(vp->parsed));
napi_enable(&vp->napi);

/* READ IRQ */
err = um_request_irq(
irq_rr + VECTOR_BASE_IRQ, vp->fds->rx_fd,
Expand Down Expand Up @@ -1306,15 +1299,15 @@ static int vector_net_open(struct net_device *dev)
uml_vector_attach_bpf(vp->fds->rx_fd, vp->bpf);

netif_start_queue(dev);
vector_reset_stats(vp);

/* clear buffer - it can happen that the host side of the interface
* is full when we get here. In this case, new data is never queued,
* SIGIOs never arrive, and the net never works.
*/

vector_rx(vp);
napi_schedule(&vp->napi);

vector_reset_stats(vp);
vdevice = find_device(vp->unit);
vdevice->opened = 1;

Expand Down Expand Up @@ -1543,15 +1536,16 @@ static const struct net_device_ops vector_netdev_ops = {
#endif
};


static void vector_timer_expire(struct timer_list *t)
{
struct vector_private *vp = from_timer(vp, t, tl);

vp->estats.tx_kicks++;
vector_send(vp->tx_queue);
napi_schedule(&vp->napi);
}



static void vector_eth_configure(
int n,
struct arglist *def
Expand Down Expand Up @@ -1634,7 +1628,6 @@ static void vector_eth_configure(
});

dev->features = dev->hw_features = (NETIF_F_SG | NETIF_F_FRAGLIST);
tasklet_setup(&vp->tx_poll, vector_tx_poll);
INIT_WORK(&vp->reset_tx, vector_reset_tx);

timer_setup(&vp->tl, vector_timer_expire, 0);
Expand Down
Loading

0 comments on commit e8b767f

Please sign in to comment.