[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [xen stable-4.10] evtchn/Flask: pre-allocate node on send path
commit 1719f79a0efd36d15837c51982173dd1c287dced Author: Jan Beulich <jbeulich@xxxxxxxx> AuthorDate: Fri Oct 2 12:38:17 2020 +0200 Commit: Jan Beulich <jbeulich@xxxxxxxx> CommitDate: Fri Oct 2 12:38:17 2020 +0200 evtchn/Flask: pre-allocate node on send path xmalloc() & Co may not be called with IRQs off, or else check_lock() will have its assertion trigger about locks getting acquired inconsistently. Re-arranging the locking in evtchn_send() doesn't seem very reasonable, especially since the per-channel lock was introduced to avoid acquiring the per-domain event lock on the send paths. Issue a second call to xsm_evtchn_send() instead, before acquiring the lock, to give XSM / Flask a chance to pre-allocate whatever it may need. As these nodes are used merely for caching earlier decisions' results, allocate just one node in AVC code despite two potentially being needed. Things will merely be not as performant if a second allocation was wanted, just like when the pre-allocation fails. Fixes: c0ddc8634845 ("evtchn: convert per-channel lock to be IRQ-safe") Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx> Tested-by: Jason Andryuk <jandryuk@xxxxxxxxx> Acked-by: Julien Grall <jgrall@xxxxxxxxxx> Reviewed-by: Jason Andryuk <jandryuk@xxxxxxxxx> master commit: 52e1fc47abc3a0123d2b5bb7e9172e84fd571851 master date: 2020-10-02 08:36:21 +0200 --- xen/common/event_channel.c | 6 ++++ xen/include/xsm/xsm.h | 1 + xen/xsm/flask/avc.c | 78 +++++++++++++++++++++++++++++++++++++++++---- xen/xsm/flask/hooks.c | 10 ++++++ xen/xsm/flask/include/avc.h | 2 ++ 5 files changed, 90 insertions(+), 7 deletions(-) diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index b41096a65f..84d58454d2 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -726,6 +726,12 @@ int evtchn_send(struct domain *ld, unsigned int lport) if ( !port_is_valid(ld, lport) ) return -EINVAL; + /* + * As the call further down needs to avoid allocations (due to running + * with IRQs off), give XSM a chance to pre-allocate if needed. + */ + xsm_evtchn_send(XSM_HOOK, ld, NULL); + lchn = evtchn_from_port(ld, lport); spin_lock_irqsave(&lchn->lock, flags); diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h index 2a299f7569..d0b4b097c0 100644 --- a/xen/include/xsm/xsm.h +++ b/xen/include/xsm/xsm.h @@ -59,6 +59,7 @@ struct xsm_operations { int (*evtchn_interdomain) (struct domain *d1, struct evtchn *chn1, struct domain *d2, struct evtchn *chn2); void (*evtchn_close_post) (struct evtchn *chn); + /* Note: Next hook may be called with 'chn' set to NULL. See call site. */ int (*evtchn_send) (struct domain *d, struct evtchn *chn); int (*evtchn_status) (struct domain *d, struct evtchn *chn); int (*evtchn_reset) (struct domain *d1, struct domain *d2); diff --git a/xen/xsm/flask/avc.c b/xen/xsm/flask/avc.c index a3e6108a34..8917329225 100644 --- a/xen/xsm/flask/avc.c +++ b/xen/xsm/flask/avc.c @@ -24,7 +24,9 @@ #include <xen/prefetch.h> #include <xen/kernel.h> #include <xen/sched.h> +#include <xen/cpu.h> #include <xen/init.h> +#include <xen/percpu.h> #include <xen/rcupdate.h> #include <asm/atomic.h> #include <asm/current.h> @@ -341,17 +343,79 @@ static inline int avc_reclaim_node(void) return ecx; } +static struct avc_node *new_node(void) +{ + struct avc_node *node = xzalloc(struct avc_node); + + if ( node ) + { + INIT_RCU_HEAD(&node->rhead); + INIT_HLIST_NODE(&node->list); + avc_cache_stats_incr(allocations); + } + + return node; +} + +/* + * avc_has_perm_noaudit() may consume up to two nodes, which we may not be + * able to obtain from the allocator at that point. Since the is merely + * about caching earlier decisions, allow for (just) one pre-allocated node. + */ +static DEFINE_PER_CPU(struct avc_node *, prealloc_node); + +void avc_prealloc(void) +{ + struct avc_node **prealloc = &this_cpu(prealloc_node); + + if ( !*prealloc ) + *prealloc = new_node(); +} + +static int cpu_callback(struct notifier_block *nfb, unsigned long action, + void *hcpu) +{ + unsigned int cpu = (unsigned long)hcpu; + struct avc_node **prealloc = &per_cpu(prealloc_node, cpu); + + if ( action == CPU_DEAD && *prealloc ) + { + xfree(*prealloc); + *prealloc = NULL; + avc_cache_stats_incr(frees); + } + + return NOTIFY_DONE; +} + +static struct notifier_block cpu_nfb = { + .notifier_call = cpu_callback, + .priority = 99 +}; + +static int __init cpu_nfb_init(void) +{ + register_cpu_notifier(&cpu_nfb); + return 0; +} +__initcall(cpu_nfb_init); + static struct avc_node *avc_alloc_node(void) { - struct avc_node *node; + struct avc_node *node, **prealloc = &this_cpu(prealloc_node); - node = xzalloc(struct avc_node); - if (!node) - goto out; + node = *prealloc; + *prealloc = NULL; - INIT_RCU_HEAD(&node->rhead); - INIT_HLIST_NODE(&node->list); - avc_cache_stats_incr(allocations); + if ( !node ) + { + /* Must not call xmalloc() & Co with IRQs off. */ + if ( !local_irq_is_enabled() ) + goto out; + node = new_node(); + if ( !node ) + goto out; + } atomic_inc(&avc_cache.active_nodes); if ( atomic_read(&avc_cache.active_nodes) > avc_cache_threshold ) diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c index f01b4cfaaa..211cfb9a4b 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -278,6 +278,16 @@ static int flask_evtchn_send(struct domain *d, struct evtchn *chn) { int rc; + /* + * When called with non-NULL chn, memory allocation may not be permitted. + * Allow AVC to preallocate nodes as necessary upon early notification. + */ + if ( !chn ) + { + avc_prealloc(); + return 0; + } + switch ( chn->state ) { case ECS_INTERDOMAIN: diff --git a/xen/xsm/flask/include/avc.h b/xen/xsm/flask/include/avc.h index bfc69f4acd..8426b36c72 100644 --- a/xen/xsm/flask/include/avc.h +++ b/xen/xsm/flask/include/avc.h @@ -90,6 +90,8 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, u16 tclass, u32 requested, int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, u32 requested, struct avc_audit_data *auditdata); +void avc_prealloc(void); + /* Exported to selinuxfs */ struct xen_flask_hash_stats; int avc_get_hash_stats(struct xen_flask_hash_stats *arg); -- generated by git-patchbot for /home/xen/git/xen.git#stable-4.10
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |