[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v2] hvc/xen: lock console list traversal
On Wed, 30 Nov 2022, Roger Pau Monne wrote: > The currently lockless access to the xen console list in > vtermno_to_xencons() is incorrect, as additions and removals from the > list can happen anytime, and as such the traversal of the list to get > the private console data for a given termno needs to happen with the > lock held. Note users that modify the list already do so with the > lock taken. > > Adjust current lock takers to use the _irq{save,restore} helpers, > since the context in which vtermno_to_xencons() is called can have > interrupts disabled. Use the _irq{save,restore} set of helpers to > switch the current callers to disable interrupts in the locked region. > I haven't checked if existing users could instead use the _irq > variant, as I think it's safer to use _irq{save,restore} upfront. > > While there switch from using list_for_each_entry_safe to > list_for_each_entry: the current entry cursor won't be removed as > part of the code in the loop body, so using the _safe variant is > pointless. > > Fixes: 02e19f9c7cac ('hvc_xen: implement multiconsole support') > Signed-off-by: Roger Pau Monné <roger.pau@xxxxxxxxxx> Reviewed-by: Stefano Stabellini <sstabellini@xxxxxxxxxx> > --- > Changes since v1: > - Switch current lock users to disable interrupts in the locked > region. > --- > drivers/tty/hvc/hvc_xen.c | 46 ++++++++++++++++++++++++--------------- > 1 file changed, 29 insertions(+), 17 deletions(-) > > diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c > index e63c1761a361..d9d023275328 100644 > --- a/drivers/tty/hvc/hvc_xen.c > +++ b/drivers/tty/hvc/hvc_xen.c > @@ -53,17 +53,22 @@ static DEFINE_SPINLOCK(xencons_lock); > > static struct xencons_info *vtermno_to_xencons(int vtermno) > { > - struct xencons_info *entry, *n, *ret = NULL; > + struct xencons_info *entry, *ret = NULL; > + unsigned long flags; > > - if (list_empty(&xenconsoles)) > - return NULL; > + spin_lock_irqsave(&xencons_lock, flags); > + if (list_empty(&xenconsoles)) { > + spin_unlock_irqrestore(&xencons_lock, flags); > + return NULL; > + } > > - list_for_each_entry_safe(entry, n, &xenconsoles, list) { > + list_for_each_entry(entry, &xenconsoles, list) { > if (entry->vtermno == vtermno) { > ret = entry; > break; > } > } > + spin_unlock_irqrestore(&xencons_lock, flags); > > return ret; > } > @@ -234,7 +239,7 @@ static int xen_hvm_console_init(void) > { > int r; > uint64_t v = 0; > - unsigned long gfn; > + unsigned long gfn, flags; > struct xencons_info *info; > > if (!xen_hvm_domain()) > @@ -270,9 +275,9 @@ static int xen_hvm_console_init(void) > goto err; > info->vtermno = HVC_COOKIE; > > - spin_lock(&xencons_lock); > + spin_lock_irqsave(&xencons_lock, flags); > list_add_tail(&info->list, &xenconsoles); > - spin_unlock(&xencons_lock); > + spin_unlock_irqrestore(&xencons_lock, flags); > > return 0; > err: > @@ -296,6 +301,7 @@ static int xencons_info_pv_init(struct xencons_info > *info, int vtermno) > static int xen_pv_console_init(void) > { > struct xencons_info *info; > + unsigned long flags; > > if (!xen_pv_domain()) > return -ENODEV; > @@ -312,9 +318,9 @@ static int xen_pv_console_init(void) > /* already configured */ > return 0; > } > - spin_lock(&xencons_lock); > + spin_lock_irqsave(&xencons_lock, flags); > xencons_info_pv_init(info, HVC_COOKIE); > - spin_unlock(&xencons_lock); > + spin_unlock_irqrestore(&xencons_lock, flags); > > return 0; > } > @@ -322,6 +328,7 @@ static int xen_pv_console_init(void) > static int xen_initial_domain_console_init(void) > { > struct xencons_info *info; > + unsigned long flags; > > if (!xen_initial_domain()) > return -ENODEV; > @@ -337,9 +344,9 @@ static int xen_initial_domain_console_init(void) > info->irq = bind_virq_to_irq(VIRQ_CONSOLE, 0, false); > info->vtermno = HVC_COOKIE; > > - spin_lock(&xencons_lock); > + spin_lock_irqsave(&xencons_lock, flags); > list_add_tail(&info->list, &xenconsoles); > - spin_unlock(&xencons_lock); > + spin_unlock_irqrestore(&xencons_lock, flags); > > return 0; > } > @@ -394,10 +401,12 @@ static void xencons_free(struct xencons_info *info) > > static int xen_console_remove(struct xencons_info *info) > { > + unsigned long flags; > + > xencons_disconnect_backend(info); > - spin_lock(&xencons_lock); > + spin_lock_irqsave(&xencons_lock, flags); > list_del(&info->list); > - spin_unlock(&xencons_lock); > + spin_unlock_irqrestore(&xencons_lock, flags); > if (info->xbdev != NULL) > xencons_free(info); > else { > @@ -478,6 +487,7 @@ static int xencons_probe(struct xenbus_device *dev, > { > int ret, devid; > struct xencons_info *info; > + unsigned long flags; > > devid = dev->nodename[strlen(dev->nodename) - 1] - '0'; > if (devid == 0) > @@ -497,9 +507,9 @@ static int xencons_probe(struct xenbus_device *dev, > ret = xencons_connect_backend(dev, info); > if (ret < 0) > goto error; > - spin_lock(&xencons_lock); > + spin_lock_irqsave(&xencons_lock, flags); > list_add_tail(&info->list, &xenconsoles); > - spin_unlock(&xencons_lock); > + spin_unlock_irqrestore(&xencons_lock, flags); > > return 0; > > @@ -599,10 +609,12 @@ static int __init xen_hvc_init(void) > > info->hvc = hvc_alloc(HVC_COOKIE, info->irq, ops, 256); > if (IS_ERR(info->hvc)) { > + unsigned long flags; > + > r = PTR_ERR(info->hvc); > - spin_lock(&xencons_lock); > + spin_lock_irqsave(&xencons_lock, flags); > list_del(&info->list); > - spin_unlock(&xencons_lock); > + spin_unlock_irqrestore(&xencons_lock, flags); > if (info->irq) > unbind_from_irqhandler(info->irq, NULL); > kfree(info); > -- > 2.37.3 >
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |