Skip to content

Commit 81eef89

Browse files
committed
Merge tag 'for-linus-6.5a-rc4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip
Pull xen fixes from Juergen Gross: - A fix for a performance problem in QubesOS, adding a way to drain the queue of grants experiencing delayed unmaps faster - A patch enabling the use of static event channels from user mode, which was omitted when introducing supporting static event channels - A fix for a problem where Xen related code didn't check properly for running in a Xen environment, resulting in a WARN splat * tag 'for-linus-6.5a-rc4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip: xen: speed up grant-table reclaim xen/evtchn: Introduce new IOCTL to bind static evtchn xenbus: check xen_domain in xenbus_probe_initcall
2 parents e62e26d + c04e989 commit 81eef89

File tree

7 files changed

+93
-32
lines changed

7 files changed

+93
-32
lines changed

Documentation/ABI/testing/sysfs-module

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,14 @@ Description: Module taint flags:
6060
C staging driver module
6161
E unsigned module
6262
== =====================
63+
64+
What: /sys/module/grant_table/parameters/free_per_iteration
65+
Date: July 2023
66+
KernelVersion: 6.5 but backported to all supported stable branches
67+
Contact: Xen developer discussion <[email protected]>
68+
Description: Read and write number of grant entries to attempt to free per iteration.
69+
70+
Note: Future versions of Xen and Linux may provide a better
71+
interface for controlling the rate of deferred grant reclaim
72+
or may not need it at all.
73+
Users: Qubes OS (https://www.qubes-os.org)

drivers/xen/events/events_base.c

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ struct irq_info {
112112
unsigned int irq_epoch; /* If eoi_cpu valid: irq_epoch of event */
113113
u64 eoi_time; /* Time in jiffies when to EOI. */
114114
raw_spinlock_t lock;
115+
bool is_static; /* Is event channel static */
115116

116117
union {
117118
unsigned short virq;
@@ -815,15 +816,6 @@ static void xen_free_irq(unsigned irq)
815816
irq_free_desc(irq);
816817
}
817818

818-
static void xen_evtchn_close(evtchn_port_t port)
819-
{
820-
struct evtchn_close close;
821-
822-
close.port = port;
823-
if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0)
824-
BUG();
825-
}
826-
827819
/* Not called for lateeoi events. */
828820
static void event_handler_exit(struct irq_info *info)
829821
{
@@ -982,7 +974,8 @@ static void __unbind_from_irq(unsigned int irq)
982974
unsigned int cpu = cpu_from_irq(irq);
983975
struct xenbus_device *dev;
984976

985-
xen_evtchn_close(evtchn);
977+
if (!info->is_static)
978+
xen_evtchn_close(evtchn);
986979

987980
switch (type_from_irq(irq)) {
988981
case IRQT_VIRQ:
@@ -1574,7 +1567,7 @@ int xen_set_irq_priority(unsigned irq, unsigned priority)
15741567
}
15751568
EXPORT_SYMBOL_GPL(xen_set_irq_priority);
15761569

1577-
int evtchn_make_refcounted(evtchn_port_t evtchn)
1570+
int evtchn_make_refcounted(evtchn_port_t evtchn, bool is_static)
15781571
{
15791572
int irq = get_evtchn_to_irq(evtchn);
15801573
struct irq_info *info;
@@ -1590,6 +1583,7 @@ int evtchn_make_refcounted(evtchn_port_t evtchn)
15901583
WARN_ON(info->refcnt != -1);
15911584

15921585
info->refcnt = 1;
1586+
info->is_static = is_static;
15931587

15941588
return 0;
15951589
}

drivers/xen/evtchn.c

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -366,10 +366,10 @@ static int evtchn_resize_ring(struct per_user_data *u)
366366
return 0;
367367
}
368368

369-
static int evtchn_bind_to_user(struct per_user_data *u, evtchn_port_t port)
369+
static int evtchn_bind_to_user(struct per_user_data *u, evtchn_port_t port,
370+
bool is_static)
370371
{
371372
struct user_evtchn *evtchn;
372-
struct evtchn_close close;
373373
int rc = 0;
374374

375375
/*
@@ -402,14 +402,14 @@ static int evtchn_bind_to_user(struct per_user_data *u, evtchn_port_t port)
402402
if (rc < 0)
403403
goto err;
404404

405-
rc = evtchn_make_refcounted(port);
405+
rc = evtchn_make_refcounted(port, is_static);
406406
return rc;
407407

408408
err:
409409
/* bind failed, should close the port now */
410-
close.port = port;
411-
if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0)
412-
BUG();
410+
if (!is_static)
411+
xen_evtchn_close(port);
412+
413413
del_evtchn(u, evtchn);
414414
return rc;
415415
}
@@ -456,7 +456,7 @@ static long evtchn_ioctl(struct file *file,
456456
if (rc != 0)
457457
break;
458458

459-
rc = evtchn_bind_to_user(u, bind_virq.port);
459+
rc = evtchn_bind_to_user(u, bind_virq.port, false);
460460
if (rc == 0)
461461
rc = bind_virq.port;
462462
break;
@@ -482,7 +482,7 @@ static long evtchn_ioctl(struct file *file,
482482
if (rc != 0)
483483
break;
484484

485-
rc = evtchn_bind_to_user(u, bind_interdomain.local_port);
485+
rc = evtchn_bind_to_user(u, bind_interdomain.local_port, false);
486486
if (rc == 0)
487487
rc = bind_interdomain.local_port;
488488
break;
@@ -507,7 +507,7 @@ static long evtchn_ioctl(struct file *file,
507507
if (rc != 0)
508508
break;
509509

510-
rc = evtchn_bind_to_user(u, alloc_unbound.port);
510+
rc = evtchn_bind_to_user(u, alloc_unbound.port, false);
511511
if (rc == 0)
512512
rc = alloc_unbound.port;
513513
break;
@@ -536,6 +536,23 @@ static long evtchn_ioctl(struct file *file,
536536
break;
537537
}
538538

539+
case IOCTL_EVTCHN_BIND_STATIC: {
540+
struct ioctl_evtchn_bind bind;
541+
struct user_evtchn *evtchn;
542+
543+
rc = -EFAULT;
544+
if (copy_from_user(&bind, uarg, sizeof(bind)))
545+
break;
546+
547+
rc = -EISCONN;
548+
evtchn = find_evtchn(u, bind.port);
549+
if (evtchn)
550+
break;
551+
552+
rc = evtchn_bind_to_user(u, bind.port, true);
553+
break;
554+
}
555+
539556
case IOCTL_EVTCHN_NOTIFY: {
540557
struct ioctl_evtchn_notify notify;
541558
struct user_evtchn *evtchn;

drivers/xen/grant-table.c

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -498,14 +498,21 @@ static LIST_HEAD(deferred_list);
498498
static void gnttab_handle_deferred(struct timer_list *);
499499
static DEFINE_TIMER(deferred_timer, gnttab_handle_deferred);
500500

501+
static atomic64_t deferred_count;
502+
static atomic64_t leaked_count;
503+
static unsigned int free_per_iteration = 10;
504+
module_param(free_per_iteration, uint, 0600);
505+
501506
static void gnttab_handle_deferred(struct timer_list *unused)
502507
{
503-
unsigned int nr = 10;
508+
unsigned int nr = READ_ONCE(free_per_iteration);
509+
const bool ignore_limit = nr == 0;
504510
struct deferred_entry *first = NULL;
505511
unsigned long flags;
512+
size_t freed = 0;
506513

507514
spin_lock_irqsave(&gnttab_list_lock, flags);
508-
while (nr--) {
515+
while ((ignore_limit || nr--) && !list_empty(&deferred_list)) {
509516
struct deferred_entry *entry
510517
= list_first_entry(&deferred_list,
511518
struct deferred_entry, list);
@@ -515,10 +522,14 @@ static void gnttab_handle_deferred(struct timer_list *unused)
515522
list_del(&entry->list);
516523
spin_unlock_irqrestore(&gnttab_list_lock, flags);
517524
if (_gnttab_end_foreign_access_ref(entry->ref)) {
525+
uint64_t ret = atomic64_dec_return(&deferred_count);
526+
518527
put_free_entry(entry->ref);
519-
pr_debug("freeing g.e. %#x (pfn %#lx)\n",
520-
entry->ref, page_to_pfn(entry->page));
528+
pr_debug("freeing g.e. %#x (pfn %#lx), %llu remaining\n",
529+
entry->ref, page_to_pfn(entry->page),
530+
(unsigned long long)ret);
521531
put_page(entry->page);
532+
freed++;
522533
kfree(entry);
523534
entry = NULL;
524535
} else {
@@ -530,21 +541,22 @@ static void gnttab_handle_deferred(struct timer_list *unused)
530541
spin_lock_irqsave(&gnttab_list_lock, flags);
531542
if (entry)
532543
list_add_tail(&entry->list, &deferred_list);
533-
else if (list_empty(&deferred_list))
534-
break;
535544
}
536-
if (!list_empty(&deferred_list) && !timer_pending(&deferred_timer)) {
545+
if (list_empty(&deferred_list))
546+
WARN_ON(atomic64_read(&deferred_count));
547+
else if (!timer_pending(&deferred_timer)) {
537548
deferred_timer.expires = jiffies + HZ;
538549
add_timer(&deferred_timer);
539550
}
540551
spin_unlock_irqrestore(&gnttab_list_lock, flags);
552+
pr_debug("Freed %zu references", freed);
541553
}
542554

543555
static void gnttab_add_deferred(grant_ref_t ref, struct page *page)
544556
{
545557
struct deferred_entry *entry;
546558
gfp_t gfp = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
547-
const char *what = KERN_WARNING "leaking";
559+
uint64_t leaked, deferred;
548560

549561
entry = kmalloc(sizeof(*entry), gfp);
550562
if (!page) {
@@ -567,10 +579,16 @@ static void gnttab_add_deferred(grant_ref_t ref, struct page *page)
567579
add_timer(&deferred_timer);
568580
}
569581
spin_unlock_irqrestore(&gnttab_list_lock, flags);
570-
what = KERN_DEBUG "deferring";
582+
deferred = atomic64_inc_return(&deferred_count);
583+
leaked = atomic64_read(&leaked_count);
584+
pr_debug("deferring g.e. %#x (pfn %#lx) (total deferred %llu, total leaked %llu)\n",
585+
ref, page ? page_to_pfn(page) : -1, deferred, leaked);
586+
} else {
587+
deferred = atomic64_read(&deferred_count);
588+
leaked = atomic64_inc_return(&leaked_count);
589+
pr_warn("leaking g.e. %#x (pfn %#lx) (total deferred %llu, total leaked %llu)\n",
590+
ref, page ? page_to_pfn(page) : -1, deferred, leaked);
571591
}
572-
printk("%s g.e. %#x (pfn %#lx)\n",
573-
what, ref, page ? page_to_pfn(page) : -1);
574592
}
575593

576594
int gnttab_try_end_foreign_access(grant_ref_t ref)

drivers/xen/xenbus/xenbus_probe.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,9 @@ static int xenbus_probe_thread(void *unused)
811811

812812
static int __init xenbus_probe_initcall(void)
813813
{
814+
if (!xen_domain())
815+
return -ENODEV;
816+
814817
/*
815818
* Probe XenBus here in the XS_PV case, and also XS_HVM unless we
816819
* need to wait for the platform PCI device to come up or

include/uapi/xen/evtchn.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,13 @@ struct ioctl_evtchn_restrict_domid {
101101
domid_t domid;
102102
};
103103

104+
/*
105+
* Bind statically allocated @port.
106+
*/
107+
#define IOCTL_EVTCHN_BIND_STATIC \
108+
_IOC(_IOC_NONE, 'E', 7, sizeof(struct ioctl_evtchn_bind))
109+
struct ioctl_evtchn_bind {
110+
unsigned int port;
111+
};
112+
104113
#endif /* __LINUX_PUBLIC_EVTCHN_H__ */

include/xen/events.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ int xen_set_irq_priority(unsigned irq, unsigned priority);
6969
/*
7070
* Allow extra references to event channels exposed to userspace by evtchn
7171
*/
72-
int evtchn_make_refcounted(evtchn_port_t evtchn);
72+
int evtchn_make_refcounted(evtchn_port_t evtchn, bool is_static);
7373
int evtchn_get(evtchn_port_t evtchn);
7474
void evtchn_put(evtchn_port_t evtchn);
7575

@@ -141,4 +141,13 @@ void xen_init_IRQ(void);
141141

142142
irqreturn_t xen_debug_interrupt(int irq, void *dev_id);
143143

144+
static inline void xen_evtchn_close(evtchn_port_t port)
145+
{
146+
struct evtchn_close close;
147+
148+
close.port = port;
149+
if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0)
150+
BUG();
151+
}
152+
144153
#endif /* _XEN_EVENTS_H */

0 commit comments

Comments
 (0)