diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/module.c | 25 | ||||
| -rw-r--r-- | kernel/sysctl_check.c | 1 | ||||
| -rw-r--r-- | kernel/time/Makefile | 2 | ||||
| -rw-r--r-- | kernel/time/clocksource.c | 76 | ||||
| -rw-r--r-- | kernel/time/timecompare.c | 191 | ||||
| -rw-r--r-- | kernel/user.c | 2 | 
6 files changed, 280 insertions, 17 deletions
| diff --git a/kernel/module.c b/kernel/module.c index 1196f5d11700..77672233387f 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -822,7 +822,7 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user,  	mutex_lock(&module_mutex);  	/* Store the name of the last unloaded module for diagnostic purposes */  	strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module)); -	unregister_dynamic_debug_module(mod->name); +	ddebug_remove_module(mod->name);  	free_module(mod);   out: @@ -1827,19 +1827,13 @@ static inline void add_kallsyms(struct module *mod,  }  #endif /* CONFIG_KALLSYMS */ -static void dynamic_printk_setup(struct mod_debug *debug, unsigned int num) +static void dynamic_debug_setup(struct _ddebug *debug, unsigned int num)  { -#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG -	unsigned int i; - -	for (i = 0; i < num; i++) { -		register_dynamic_debug_module(debug[i].modname, -					      debug[i].type, -					      debug[i].logical_modname, -					      debug[i].flag_names, -					      debug[i].hash, debug[i].hash2); -	} -#endif /* CONFIG_DYNAMIC_PRINTK_DEBUG */ +#ifdef CONFIG_DYNAMIC_DEBUG +	if (ddebug_add_module(debug, num, debug->modname)) +		printk(KERN_ERR "dynamic debug error adding module: %s\n", +					debug->modname); +#endif  }  static void *module_alloc_update_bounds(unsigned long size) @@ -2213,12 +2207,13 @@ static noinline struct module *load_module(void __user *umod,  	add_kallsyms(mod, sechdrs, symindex, strindex, secstrings);  	if (!mod->taints) { -		struct mod_debug *debug; +		struct _ddebug *debug;  		unsigned int num_debug;  		debug = section_objs(hdr, sechdrs, secstrings, "__verbose",  				     sizeof(*debug), &num_debug); -		dynamic_printk_setup(debug, num_debug); +		if (debug) +			dynamic_debug_setup(debug, num_debug);  	}  	/* sechdrs[0].sh_size is always zero */ diff --git a/kernel/sysctl_check.c b/kernel/sysctl_check.c index fafeb48f27c0..b38423ca711a 100644 --- a/kernel/sysctl_check.c +++ b/kernel/sysctl_check.c @@ -219,6 +219,7 @@ static const struct trans_ctl_table trans_net_ipv4_conf_vars_table[] = {  	{ NET_IPV4_CONF_ARP_IGNORE,		"arp_ignore" },  	{ NET_IPV4_CONF_PROMOTE_SECONDARIES,	"promote_secondaries" },  	{ NET_IPV4_CONF_ARP_ACCEPT,		"arp_accept" }, +	{ NET_IPV4_CONF_ARP_NOTIFY,		"arp_notify" },  	{}  }; diff --git a/kernel/time/Makefile b/kernel/time/Makefile index 905b0b50792d..0b0a6366c9d4 100644 --- a/kernel/time/Makefile +++ b/kernel/time/Makefile @@ -1,4 +1,4 @@ -obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o +obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o timecompare.o  obj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD)		+= clockevents.o  obj-$(CONFIG_GENERIC_CLOCKEVENTS)		+= tick-common.o diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index ca89e1593f08..c46c931a7fe7 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -31,6 +31,82 @@  #include <linux/sched.h> /* for spin_unlock_irq() using preempt_count() m68k */  #include <linux/tick.h> +void timecounter_init(struct timecounter *tc, +		      const struct cyclecounter *cc, +		      u64 start_tstamp) +{ +	tc->cc = cc; +	tc->cycle_last = cc->read(cc); +	tc->nsec = start_tstamp; +} +EXPORT_SYMBOL(timecounter_init); + +/** + * timecounter_read_delta - get nanoseconds since last call of this function + * @tc:         Pointer to time counter + * + * When the underlying cycle counter runs over, this will be handled + * correctly as long as it does not run over more than once between + * calls. + * + * The first call to this function for a new time counter initializes + * the time tracking and returns an undefined result. + */ +static u64 timecounter_read_delta(struct timecounter *tc) +{ +	cycle_t cycle_now, cycle_delta; +	u64 ns_offset; + +	/* read cycle counter: */ +	cycle_now = tc->cc->read(tc->cc); + +	/* calculate the delta since the last timecounter_read_delta(): */ +	cycle_delta = (cycle_now - tc->cycle_last) & tc->cc->mask; + +	/* convert to nanoseconds: */ +	ns_offset = cyclecounter_cyc2ns(tc->cc, cycle_delta); + +	/* update time stamp of timecounter_read_delta() call: */ +	tc->cycle_last = cycle_now; + +	return ns_offset; +} + +u64 timecounter_read(struct timecounter *tc) +{ +	u64 nsec; + +	/* increment time by nanoseconds since last call */ +	nsec = timecounter_read_delta(tc); +	nsec += tc->nsec; +	tc->nsec = nsec; + +	return nsec; +} +EXPORT_SYMBOL(timecounter_read); + +u64 timecounter_cyc2time(struct timecounter *tc, +			 cycle_t cycle_tstamp) +{ +	u64 cycle_delta = (cycle_tstamp - tc->cycle_last) & tc->cc->mask; +	u64 nsec; + +	/* +	 * Instead of always treating cycle_tstamp as more recent +	 * than tc->cycle_last, detect when it is too far in the +	 * future and treat it as old time stamp instead. +	 */ +	if (cycle_delta > tc->cc->mask / 2) { +		cycle_delta = (tc->cycle_last - cycle_tstamp) & tc->cc->mask; +		nsec = tc->nsec - cyclecounter_cyc2ns(tc->cc, cycle_delta); +	} else { +		nsec = cyclecounter_cyc2ns(tc->cc, cycle_delta) + tc->nsec; +	} + +	return nsec; +} +EXPORT_SYMBOL(timecounter_cyc2time); +  /* XXX - Would like a better way for initializing curr_clocksource */  extern struct clocksource clocksource_jiffies; diff --git a/kernel/time/timecompare.c b/kernel/time/timecompare.c new file mode 100644 index 000000000000..71e7f1a19156 --- /dev/null +++ b/kernel/time/timecompare.c @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2009 Intel Corporation. + * Author: Patrick Ohly <patrick.ohly@intel.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/timecompare.h> +#include <linux/module.h> +#include <linux/math64.h> + +/* + * fixed point arithmetic scale factor for skew + * + * Usually one would measure skew in ppb (parts per billion, 1e9), but + * using a factor of 2 simplifies the math. + */ +#define TIMECOMPARE_SKEW_RESOLUTION (((s64)1)<<30) + +ktime_t timecompare_transform(struct timecompare *sync, +			      u64 source_tstamp) +{ +	u64 nsec; + +	nsec = source_tstamp + sync->offset; +	nsec += (s64)(source_tstamp - sync->last_update) * sync->skew / +		TIMECOMPARE_SKEW_RESOLUTION; + +	return ns_to_ktime(nsec); +} +EXPORT_SYMBOL(timecompare_transform); + +int timecompare_offset(struct timecompare *sync, +		       s64 *offset, +		       u64 *source_tstamp) +{ +	u64 start_source = 0, end_source = 0; +	struct { +		s64 offset; +		s64 duration_target; +	} buffer[10], sample, *samples; +	int counter = 0, i; +	int used; +	int index; +	int num_samples = sync->num_samples; + +	if (num_samples > sizeof(buffer)/sizeof(buffer[0])) { +		samples = kmalloc(sizeof(*samples) * num_samples, GFP_ATOMIC); +		if (!samples) { +			samples = buffer; +			num_samples = sizeof(buffer)/sizeof(buffer[0]); +		} +	} else { +		samples = buffer; +	} + +	/* run until we have enough valid samples, but do not try forever */ +	i = 0; +	counter = 0; +	while (1) { +		u64 ts; +		ktime_t start, end; + +		start = sync->target(); +		ts = timecounter_read(sync->source); +		end = sync->target(); + +		if (!i) +			start_source = ts; + +		/* ignore negative durations */ +		sample.duration_target = ktime_to_ns(ktime_sub(end, start)); +		if (sample.duration_target >= 0) { +			/* +			 * assume symetric delay to and from source: +			 * average target time corresponds to measured +			 * source time +			 */ +			sample.offset = +				ktime_to_ns(ktime_add(end, start)) / 2 - +				ts; + +			/* simple insertion sort based on duration */ +			index = counter - 1; +			while (index >= 0) { +				if (samples[index].duration_target < +				    sample.duration_target) +					break; +				samples[index + 1] = samples[index]; +				index--; +			} +			samples[index + 1] = sample; +			counter++; +		} + +		i++; +		if (counter >= num_samples || i >= 100000) { +			end_source = ts; +			break; +		} +	} + +	*source_tstamp = (end_source + start_source) / 2; + +	/* remove outliers by only using 75% of the samples */ +	used = counter * 3 / 4; +	if (!used) +		used = counter; +	if (used) { +		/* calculate average */ +		s64 off = 0; +		for (index = 0; index < used; index++) +			off += samples[index].offset; +		*offset = div_s64(off, used); +	} + +	if (samples && samples != buffer) +		kfree(samples); + +	return used; +} +EXPORT_SYMBOL(timecompare_offset); + +void __timecompare_update(struct timecompare *sync, +			  u64 source_tstamp) +{ +	s64 offset; +	u64 average_time; + +	if (!timecompare_offset(sync, &offset, &average_time)) +		return; + +	if (!sync->last_update) { +		sync->last_update = average_time; +		sync->offset = offset; +		sync->skew = 0; +	} else { +		s64 delta_nsec = average_time - sync->last_update; + +		/* avoid division by negative or small deltas */ +		if (delta_nsec >= 10000) { +			s64 delta_offset_nsec = offset - sync->offset; +			s64 skew; /* delta_offset_nsec * +				     TIMECOMPARE_SKEW_RESOLUTION / +				     delta_nsec */ +			u64 divisor; + +			/* div_s64() is limited to 32 bit divisor */ +			skew = delta_offset_nsec * TIMECOMPARE_SKEW_RESOLUTION; +			divisor = delta_nsec; +			while (unlikely(divisor >= ((s64)1) << 32)) { +				/* divide both by 2; beware, right shift +				   of negative value has undefined +				   behavior and can only be used for +				   the positive divisor */ +				skew = div_s64(skew, 2); +				divisor >>= 1; +			} +			skew = div_s64(skew, divisor); + +			/* +			 * Calculate new overall skew as 4/16 the +			 * old value and 12/16 the new one. This is +			 * a rather arbitrary tradeoff between +			 * only using the latest measurement (0/16 and +			 * 16/16) and even more weight on past measurements. +			 */ +#define TIMECOMPARE_NEW_SKEW_PER_16 12 +			sync->skew = +				div_s64((16 - TIMECOMPARE_NEW_SKEW_PER_16) * +					sync->skew + +					TIMECOMPARE_NEW_SKEW_PER_16 * skew, +					16); +			sync->last_update = average_time; +			sync->offset = offset; +		} +	} +} +EXPORT_SYMBOL(__timecompare_update); diff --git a/kernel/user.c b/kernel/user.c index fbb300e6191f..850e0ba41c1e 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -20,7 +20,7 @@  struct user_namespace init_user_ns = {  	.kref = { -		.refcount	= ATOMIC_INIT(1), +		.refcount	= ATOMIC_INIT(2),  	},  	.creator = &root_user,  }; | 
