diff options
Diffstat (limited to 'arch/x86/xen/multicalls.c')
| -rw-r--r-- | arch/x86/xen/multicalls.c | 177 | 
1 files changed, 51 insertions, 126 deletions
diff --git a/arch/x86/xen/multicalls.c b/arch/x86/xen/multicalls.c index 8bff7e7c290..0d82003e76a 100644 --- a/arch/x86/xen/multicalls.c +++ b/arch/x86/xen/multicalls.c @@ -30,12 +30,13 @@  #define MC_BATCH	32 -#define MC_DEBUG	1 +#define MC_DEBUG	0  #define MC_ARGS		(MC_BATCH * 16)  struct mc_buffer { +	unsigned mcidx, argidx, cbidx;  	struct multicall_entry entries[MC_BATCH];  #if MC_DEBUG  	struct multicall_entry debug[MC_BATCH]; @@ -46,85 +47,15 @@ struct mc_buffer {  		void (*fn)(void *);  		void *data;  	} callbacks[MC_BATCH]; -	unsigned mcidx, argidx, cbidx;  };  static DEFINE_PER_CPU(struct mc_buffer, mc_buffer);  DEFINE_PER_CPU(unsigned long, xen_mc_irq_flags); -/* flush reasons 0- slots, 1- args, 2- callbacks */ -enum flush_reasons -{ -	FL_SLOTS, -	FL_ARGS, -	FL_CALLBACKS, - -	FL_N_REASONS -}; - -#ifdef CONFIG_XEN_DEBUG_FS -#define NHYPERCALLS	40		/* not really */ - -static struct { -	unsigned histo[MC_BATCH+1]; - -	unsigned issued; -	unsigned arg_total; -	unsigned hypercalls; -	unsigned histo_hypercalls[NHYPERCALLS]; - -	unsigned flush[FL_N_REASONS]; -} mc_stats; - -static u8 zero_stats; - -static inline void check_zero(void) -{ -	if (unlikely(zero_stats)) { -		memset(&mc_stats, 0, sizeof(mc_stats)); -		zero_stats = 0; -	} -} - -static void mc_add_stats(const struct mc_buffer *mc) -{ -	int i; - -	check_zero(); - -	mc_stats.issued++; -	mc_stats.hypercalls += mc->mcidx; -	mc_stats.arg_total += mc->argidx; - -	mc_stats.histo[mc->mcidx]++; -	for(i = 0; i < mc->mcidx; i++) { -		unsigned op = mc->entries[i].op; -		if (op < NHYPERCALLS) -			mc_stats.histo_hypercalls[op]++; -	} -} - -static void mc_stats_flush(enum flush_reasons idx) -{ -	check_zero(); - -	mc_stats.flush[idx]++; -} - -#else  /* !CONFIG_XEN_DEBUG_FS */ - -static inline void mc_add_stats(const struct mc_buffer *mc) -{ -} - -static inline void mc_stats_flush(enum flush_reasons idx) -{ -} -#endif	/* CONFIG_XEN_DEBUG_FS */ -  void xen_mc_flush(void)  {  	struct mc_buffer *b = &__get_cpu_var(mc_buffer); +	struct multicall_entry *mc;  	int ret = 0;  	unsigned long flags;  	int i; @@ -135,9 +66,26 @@ void xen_mc_flush(void)  	   something in the middle */  	local_irq_save(flags); -	mc_add_stats(b); +	trace_xen_mc_flush(b->mcidx, b->argidx, b->cbidx); + +	switch (b->mcidx) { +	case 0: +		/* no-op */ +		BUG_ON(b->argidx != 0); +		break; + +	case 1: +		/* Singleton multicall - bypass multicall machinery +		   and just do the call directly. */ +		mc = &b->entries[0]; + +		mc->result = privcmd_call(mc->op, +					  mc->args[0], mc->args[1], mc->args[2],  +					  mc->args[3], mc->args[4]); +		ret = mc->result < 0; +		break; -	if (b->mcidx) { +	default:  #if MC_DEBUG  		memcpy(b->debug, b->entries,  		       b->mcidx * sizeof(struct multicall_entry)); @@ -164,11 +112,10 @@ void xen_mc_flush(void)  			}  		}  #endif +	} -		b->mcidx = 0; -		b->argidx = 0; -	} else -		BUG_ON(b->argidx != 0); +	b->mcidx = 0; +	b->argidx = 0;  	for (i = 0; i < b->cbidx; i++) {  		struct callback *cb = &b->callbacks[i]; @@ -188,25 +135,28 @@ struct multicall_space __xen_mc_entry(size_t args)  	struct multicall_space ret;  	unsigned argidx = roundup(b->argidx, sizeof(u64)); +	trace_xen_mc_entry_alloc(args); +  	BUG_ON(preemptible()); -	BUG_ON(b->argidx > MC_ARGS); +	BUG_ON(b->argidx >= MC_ARGS); -	if (b->mcidx == MC_BATCH || -	    (argidx + args) > MC_ARGS) { -		mc_stats_flush(b->mcidx == MC_BATCH ? FL_SLOTS : FL_ARGS); +	if (unlikely(b->mcidx == MC_BATCH || +		     (argidx + args) >= MC_ARGS)) { +		trace_xen_mc_flush_reason((b->mcidx == MC_BATCH) ? +					  XEN_MC_FL_BATCH : XEN_MC_FL_ARGS);  		xen_mc_flush();  		argidx = roundup(b->argidx, sizeof(u64));  	}  	ret.mc = &b->entries[b->mcidx]; -#ifdef MC_DEBUG +#if MC_DEBUG  	b->caller[b->mcidx] = __builtin_return_address(0);  #endif  	b->mcidx++;  	ret.args = &b->args[argidx];  	b->argidx = argidx + args; -	BUG_ON(b->argidx > MC_ARGS); +	BUG_ON(b->argidx >= MC_ARGS);  	return ret;  } @@ -216,22 +166,27 @@ struct multicall_space xen_mc_extend_args(unsigned long op, size_t size)  	struct multicall_space ret = { NULL, NULL };  	BUG_ON(preemptible()); -	BUG_ON(b->argidx > MC_ARGS); +	BUG_ON(b->argidx >= MC_ARGS); -	if (b->mcidx == 0) -		return ret; - -	if (b->entries[b->mcidx - 1].op != op) -		return ret; +	if (unlikely(b->mcidx == 0 || +		     b->entries[b->mcidx - 1].op != op)) { +		trace_xen_mc_extend_args(op, size, XEN_MC_XE_BAD_OP); +		goto out; +	} -	if ((b->argidx + size) > MC_ARGS) -		return ret; +	if (unlikely((b->argidx + size) >= MC_ARGS)) { +		trace_xen_mc_extend_args(op, size, XEN_MC_XE_NO_SPACE); +		goto out; +	}  	ret.mc = &b->entries[b->mcidx - 1];  	ret.args = &b->args[b->argidx];  	b->argidx += size; -	BUG_ON(b->argidx > MC_ARGS); +	BUG_ON(b->argidx >= MC_ARGS); + +	trace_xen_mc_extend_args(op, size, XEN_MC_XE_OK); +out:  	return ret;  } @@ -241,43 +196,13 @@ void xen_mc_callback(void (*fn)(void *), void *data)  	struct callback *cb;  	if (b->cbidx == MC_BATCH) { -		mc_stats_flush(FL_CALLBACKS); +		trace_xen_mc_flush_reason(XEN_MC_FL_CALLBACK);  		xen_mc_flush();  	} +	trace_xen_mc_callback(fn, data); +  	cb = &b->callbacks[b->cbidx++];  	cb->fn = fn;  	cb->data = data;  } - -#ifdef CONFIG_XEN_DEBUG_FS - -static struct dentry *d_mc_debug; - -static int __init xen_mc_debugfs(void) -{ -	struct dentry *d_xen = xen_init_debugfs(); - -	if (d_xen == NULL) -		return -ENOMEM; - -	d_mc_debug = debugfs_create_dir("multicalls", d_xen); - -	debugfs_create_u8("zero_stats", 0644, d_mc_debug, &zero_stats); - -	debugfs_create_u32("batches", 0444, d_mc_debug, &mc_stats.issued); -	debugfs_create_u32("hypercalls", 0444, d_mc_debug, &mc_stats.hypercalls); -	debugfs_create_u32("arg_total", 0444, d_mc_debug, &mc_stats.arg_total); - -	xen_debugfs_create_u32_array("batch_histo", 0444, d_mc_debug, -				     mc_stats.histo, MC_BATCH); -	xen_debugfs_create_u32_array("hypercall_histo", 0444, d_mc_debug, -				     mc_stats.histo_hypercalls, NHYPERCALLS); -	xen_debugfs_create_u32_array("flush_reasons", 0444, d_mc_debug, -				     mc_stats.flush, FL_N_REASONS); - -	return 0; -} -fs_initcall(xen_mc_debugfs); - -#endif	/* CONFIG_XEN_DEBUG_FS */  | 
