diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-11-23 02:00:47 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-11-23 02:00:47 +0000 |
commit | 06615f62b17d7de6e12d2f5ec6b88cf30af08413 (patch) | |
tree | 8766f208847d4876a6db619aebbf54d53b76eb44 /kernel | |
parent | fa9bdb574f4febb751848a685d9a9017e04e1d53 (diff) |
Merge with Linux 2.4.0-test10.
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/ksyms.c | 1 | ||||
-rw-r--r-- | kernel/module.c | 23 | ||||
-rw-r--r-- | kernel/panic.c | 2 | ||||
-rw-r--r-- | kernel/printk.c | 2 | ||||
-rw-r--r-- | kernel/sched.c | 150 | ||||
-rw-r--r-- | kernel/signal.c | 2 | ||||
-rw-r--r-- | kernel/sys.c | 2 | ||||
-rw-r--r-- | kernel/sysctl.c | 72 | ||||
-rw-r--r-- | kernel/time.c | 4 | ||||
-rw-r--r-- | kernel/timer.c | 2 | ||||
-rw-r--r-- | kernel/user.c | 60 |
11 files changed, 127 insertions, 193 deletions
diff --git a/kernel/ksyms.c b/kernel/ksyms.c index 2a8882dbc..b8eb6b4f0 100644 --- a/kernel/ksyms.c +++ b/kernel/ksyms.c @@ -246,7 +246,6 @@ EXPORT_SYMBOL(generic_read_dir); EXPORT_SYMBOL(__pollwait); EXPORT_SYMBOL(poll_freewait); EXPORT_SYMBOL(ROOT_DEV); -EXPORT_SYMBOL(__find_get_page); EXPORT_SYMBOL(__find_lock_page); EXPORT_SYMBOL(grab_cache_page); EXPORT_SYMBOL(read_cache_page); diff --git a/kernel/module.c b/kernel/module.c index 5e5fbfe1b..15efa305c 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -28,22 +28,13 @@ extern const struct exception_table_entry __stop___ex_table[]; static struct module kernel_module = { - sizeof(struct module), /* size_of_struct */ - NULL, /* next */ - "", /* name */ - 0, /* size */ - {ATOMIC_INIT(1)}, /* usecount */ - MOD_RUNNING, /* flags */ - 0, /* nsyms -- to filled in in init_modules */ - 0, /* ndeps */ - __start___ksymtab, /* syms */ - NULL, /* deps */ - NULL, /* refs */ - NULL, /* init */ - NULL, /* cleanup */ - __start___ex_table, /* ex_table_start */ - __stop___ex_table, /* ex_table_end */ - /* Rest are NULL */ + size_of_struct: sizeof(struct module), + name: "", + uc: {ATOMIC_INIT(1)}, + flags: MOD_RUNNING, + syms: __start___ksymtab, + ex_table_start: __start___ex_table, + ex_table_end: __stop___ex_table }; struct module *module_list = &kernel_module; diff --git a/kernel/panic.c b/kernel/panic.c index d6e37fbf7..ac246f745 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -22,7 +22,7 @@ extern void unblank_console(void); int panic_timeout; -struct notifier_block *panic_notifier_list = NULL; +struct notifier_block *panic_notifier_list; static int __init panic_setup(char *str) { diff --git a/kernel/printk.c b/kernel/printk.c index ff6c727ab..72e27f35a 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -45,7 +45,7 @@ int default_console_loglevel = DEFAULT_CONSOLE_LOGLEVEL; spinlock_t console_lock = SPIN_LOCK_UNLOCKED; -struct console *console_drivers = NULL; +struct console *console_drivers; static char log_buf[LOG_BUF_LEN]; static unsigned long log_start; static unsigned long logged_chars; diff --git a/kernel/sched.c b/kernel/sched.c index 361b72491..927bf47e7 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -223,16 +223,20 @@ static void reschedule_idle(struct task_struct * p) best_cpu = p->processor; if (can_schedule(p, best_cpu)) { tsk = idle_task(best_cpu); - if (cpu_curr(best_cpu) == tsk) - goto send_now_idle; - - /* - * Maybe this process has enough priority to preempt - * its preferred CPU. (this is a shortcut): - */ - tsk = cpu_curr(best_cpu); - if (preemption_goodness(tsk, p, best_cpu) > 0) - goto preempt_now; + if (cpu_curr(best_cpu) == tsk) { + int need_resched; +send_now_idle: + /* + * If need_resched == -1 then we can skip sending + * the IPI altogether, tsk->need_resched is + * actively watched by the idle thread. + */ + need_resched = tsk->need_resched; + tsk->need_resched = 1; + if ((best_cpu != this_cpu) && !need_resched) + smp_send_reschedule(best_cpu); + return; + } } /* @@ -276,31 +280,13 @@ static void reschedule_idle(struct task_struct * p) if (tsk) { if (oldest_idle != -1ULL) goto send_now_idle; - goto preempt_now; + tsk->need_resched = 1; + if (tsk->processor != this_cpu) + smp_send_reschedule(tsk->processor); } - return; -send_now_idle: - /* - * If need_resched == -1 then we can skip sending the IPI - * altogether, tsk->need_resched is actively watched by the - * idle thread. - */ - if ((tsk->processor != current->processor) && !tsk->need_resched) - smp_send_reschedule(tsk->processor); - tsk->need_resched = 1; - return; -preempt_now: - tsk->need_resched = 1; - /* - * the APIC stuff can go outside of the lock because - * it uses no task information, only CPU#. - */ - if (tsk->processor != this_cpu) - smp_send_reschedule(tsk->processor); - return; #else /* UP */ int this_cpu = smp_processor_id(); struct task_struct *tsk; @@ -444,37 +430,53 @@ signed long schedule_timeout(signed long timeout) static inline void __schedule_tail(struct task_struct *prev) { #ifdef CONFIG_SMP - int yield; - unsigned long flags; + int policy; /* - * fast path falls through. We have to take the runqueue lock - * unconditionally to make sure that the test of prev->state - * and setting has_cpu is atomic wrt. interrupts. It's not - * a big problem in the common case because we recently took - * the runqueue lock so it's likely to be in this processor's - * cache. + * fast path falls through. We have to clear has_cpu before + * checking prev->state to avoid a wakeup race - thus we + * also have to protect against the task exiting early. */ - spin_lock_irqsave(&runqueue_lock, flags); - yield = prev->policy & SCHED_YIELD; - prev->policy &= ~SCHED_YIELD; + task_lock(prev); + policy = prev->policy; + prev->policy = policy & ~SCHED_YIELD; prev->has_cpu = 0; + wmb(); if (prev->state == TASK_RUNNING) - goto running_again; + goto needs_resched; + out_unlock: - spin_unlock_irqrestore(&runqueue_lock, flags); + task_unlock(prev); return; /* * Slow path - we 'push' the previous process and * reschedule_idle() will attempt to find a new * processor for it. (but it might preempt the - * current process as well.) + * current process as well.) We must take the runqueue + * lock and re-check prev->state to be correct. It might + * still happen that this process has a preemption + * 'in progress' already - but this is not a problem and + * might happen in other circumstances as well. */ -running_again: - if ((prev != idle_task(smp_processor_id())) && !yield) - reschedule_idle(prev); - goto out_unlock; +needs_resched: + { + unsigned long flags; + + /* + * Avoid taking the runqueue lock in cases where + * no preemption-check is necessery: + */ + if ((prev == idle_task(smp_processor_id())) || + (policy & SCHED_YIELD)) + goto out_unlock; + + spin_lock_irqsave(&runqueue_lock, flags); + if (prev->state == TASK_RUNNING) + reschedule_idle(prev); + spin_unlock_irqrestore(&runqueue_lock, flags); + goto out_unlock; + } #else prev->policy &= ~SCHED_YIELD; #endif /* CONFIG_SMP */ @@ -588,19 +590,13 @@ still_running_back: #ifdef CONFIG_SMP /* - * maintain the per-process 'average timeslice' value. + * maintain the per-process 'last schedule' value. * (this has to be recalculated even if we reschedule to * the same process) Currently this is only used on SMP, * and it's approximate, so we do not have to maintain * it while holding the runqueue spinlock. */ - { - cycles_t t, this_slice; - - t = get_cycles(); - this_slice = t - sched_data->last_schedule; - sched_data->last_schedule = t; - } + sched_data->last_schedule = get_cycles(); /* * We drop the scheduler lock early (it's a global spinlock), @@ -705,7 +701,7 @@ static inline void __wake_up_common (wait_queue_head_t *q, unsigned int mode, unsigned long flags; int best_cpu, irq; - if (!q) + if (!q || !waitqueue_active(q)) goto out; best_cpu = smp_processor_id(); @@ -759,16 +755,13 @@ static inline void __wake_up_common (wait_queue_head_t *q, unsigned int mode, } } } - if (best_exclusive) - best_exclusive->state = TASK_RUNNING; - wq_write_unlock_irqrestore(&q->lock, flags); - if (best_exclusive) { if (sync) wake_up_process_synchronous(best_exclusive); else wake_up_process(best_exclusive); } + wq_write_unlock_irqrestore(&q->lock, flags); out: return; } @@ -1029,12 +1022,35 @@ out_unlock: asmlinkage long sys_sched_yield(void) { /* - * This process can only be rescheduled by us, - * so this is safe without any locking. + * Trick. sched_yield() first counts the number of truly + * 'pending' runnable processes, then returns if it's + * only the current processes. (This test does not have + * to be atomic.) In threaded applications this optimization + * gets triggered quite often. */ - if (current->policy == SCHED_OTHER) - current->policy |= SCHED_YIELD; - current->need_resched = 1; + + int nr_pending = nr_running; + +#if CONFIG_SMP + int i; + + // Substract non-idle processes running on other CPUs. + for (i = 0; i < smp_num_cpus; i++) + if (aligned_data[i].schedule_data.curr != idle_task(i)) + nr_pending--; +#else + // on UP this process is on the runqueue as well + nr_pending--; +#endif + if (nr_pending) { + /* + * This process can only be rescheduled by us, + * so this is safe without any locking. + */ + if (current->policy == SCHED_OTHER) + current->policy |= SCHED_YIELD; + current->need_resched = 1; + } return 0; } diff --git a/kernel/signal.c b/kernel/signal.c index 4e6a4d909..c6ec0cb7b 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -459,7 +459,7 @@ static int send_signal(int sig, struct siginfo *info, struct sigpending *signals * NOTE! we rely on the previous spin_lock to * lock interrupts for us! We can only be called with * "sigmask_lock" held, and the local interrupt must - * have been disabled when that got aquired! + * have been disabled when that got acquired! * * No need to set need_resched since signal event passing * goes through ->blocked diff --git a/kernel/sys.c b/kernel/sys.c index 87ee4770c..ded9c6328 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -47,7 +47,7 @@ int C_A_D = 1; * and the like. */ -static struct notifier_block *reboot_notifier_list = NULL; +static struct notifier_block *reboot_notifier_list; rwlock_t notifier_lock = RW_LOCK_UNLOCKED; /** diff --git a/kernel/sysctl.c b/kernel/sysctl.c index c320027fa..70da2a029 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1217,78 +1217,6 @@ int sysctl_jiffies(ctl_table *table, int *name, int nlen, return 1; } -int do_string ( - void *oldval, size_t *oldlenp, void *newval, size_t newlen, - int rdwr, char *data, size_t max) -{ - int l = strlen(data) + 1; - if (newval && !rdwr) - return -EPERM; - if (newval && newlen >= max) - return -EINVAL; - if (oldval) { - int old_l; - if(get_user(old_l, oldlenp)) - return -EFAULT; - if (l > old_l) - return -ENOMEM; - if(put_user(l, oldlenp) || copy_to_user(oldval, data, l)) - return -EFAULT; - } - if (newval) { - if(copy_from_user(data, newval, newlen)) - return -EFAULT; - data[newlen] = 0; - } - return 0; -} - -int do_int ( - void *oldval, size_t *oldlenp, void *newval, size_t newlen, - int rdwr, int *data) -{ - if (newval && !rdwr) - return -EPERM; - if (newval && newlen != sizeof(int)) - return -EINVAL; - if (oldval) { - int old_l; - if(get_user(old_l, oldlenp)) - return -EFAULT; - if (old_l < sizeof(int)) - return -ENOMEM; - if(put_user(sizeof(int), oldlenp)||copy_to_user(oldval, data, sizeof(int))) - return -EFAULT; - } - if (newval) - if(copy_from_user(data, newval, sizeof(int))) - return -EFAULT; - return 0; -} - -int do_struct ( - void *oldval, size_t *oldlenp, void *newval, size_t newlen, - int rdwr, void *data, size_t len) -{ - if (newval && !rdwr) - return -EPERM; - if (newval && newlen != len) - return -EINVAL; - if (oldval) { - int old_l; - if(get_user(old_l, oldlenp)) - return -EFAULT; - if (old_l < len) - return -ENOMEM; - if(put_user(len, oldlenp) || copy_to_user(oldval, data, len)) - return -EFAULT; - } - if (newval) - if(copy_from_user(data, newval, len)) - return -EFAULT; - return 0; -} - #else /* CONFIG_SYSCTL */ diff --git a/kernel/time.c b/kernel/time.c index 843ac0cbb..ffad77ad6 100644 --- a/kernel/time.c +++ b/kernel/time.c @@ -34,7 +34,7 @@ * The timezone where the local system is located. Used as a default by some * programs who obtain this value by using gettimeofday. */ -struct timezone sys_tz = { 0, 0}; +struct timezone sys_tz; static void do_normal_gettime(struct timeval * tm) { @@ -218,7 +218,7 @@ long pps_errcnt; /* calibration errors */ long pps_stbcnt; /* stability limit exceeded */ /* hook for a loadable hardpps kernel module */ -void (*hardpps_ptr)(struct timeval *) = (void (*)(struct timeval *))0; +void (*hardpps_ptr)(struct timeval *); /* adjtimex mainly allows reading (and writing, if superuser) of * kernel time-keeping variables. used by xntpd. diff --git a/kernel/timer.c b/kernel/timer.c index 0dd0a7331..e67783a30 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -164,7 +164,7 @@ static inline void internal_add_timer(struct timer_list *timer) spinlock_t timerlist_lock = SPIN_LOCK_UNLOCKED; #ifdef CONFIG_SMP -volatile struct timer_list * volatile running_timer = NULL; +volatile struct timer_list * volatile running_timer; #define timer_enter(t) do { running_timer = t; mb(); } while (0) #define timer_exit() do { running_timer = NULL; } while (0) #define timer_is_running(t) (running_timer == t) diff --git a/kernel/user.c b/kernel/user.c index daae4dff4..d033c9659 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -17,11 +17,15 @@ * UID task count cache, to get fast user lookup in "alloc_uid" * when changing user ID's (ie setuid() and friends). */ -#define UIDHASH_SZ (256) +#define UIDHASH_BITS 8 +#define UIDHASH_SZ (1 << UIDHASH_BITS) +#define UIDHASH_MASK (UIDHASH_SZ - 1) +#define __uidhashfn(uid) (((uid >> UIDHASH_BITS) ^ uid) & UIDHASH_MASK) +#define uidhashentry(uid) (uidhash_table + __uidhashfn(uid)) -static struct user_struct *uidhash[UIDHASH_SZ]; - -spinlock_t uidhash_lock = SPIN_LOCK_UNLOCKED; +static kmem_cache_t *uid_cachep; +static struct user_struct *uidhash_table[UIDHASH_SZ]; +static spinlock_t uidhash_lock = SPIN_LOCK_UNLOCKED; struct user_struct root_user = { __count: ATOMIC_INIT(1), @@ -29,49 +33,50 @@ struct user_struct root_user = { files: ATOMIC_INIT(0) }; -static kmem_cache_t *uid_cachep; - -#define uidhashfn(uid) (((uid >> 8) ^ uid) & (UIDHASH_SZ - 1)) - /* * These routines must be called with the uidhash spinlock held! */ -static inline void uid_hash_insert(struct user_struct *up, unsigned int hashent) +static inline void uid_hash_insert(struct user_struct *up, struct user_struct **hashent) { - if((up->next = uidhash[hashent]) != NULL) - uidhash[hashent]->pprev = &up->next; - up->pprev = &uidhash[hashent]; - uidhash[hashent] = up; + struct user_struct *next = *hashent; + + up->next = next; + if (next) + next->pprev = &up->next; + up->pprev = hashent; + *hashent = up; } static inline void uid_hash_remove(struct user_struct *up) { - if(up->next) - up->next->pprev = up->pprev; - *up->pprev = up->next; + struct user_struct *next = up->next; + struct user_struct **pprev = up->pprev; + + if (next) + next->pprev = pprev; + *pprev = next; } -static inline struct user_struct *uid_hash_find(unsigned short uid, unsigned int hashent) +static inline struct user_struct *uid_hash_find(uid_t uid, struct user_struct **hashent) { - struct user_struct *up, *next; + struct user_struct *next; - next = uidhash[hashent]; + next = *hashent; for (;;) { - up = next; + struct user_struct *up = next; if (next) { next = up->next; if (up->uid != uid) continue; atomic_inc(&up->__count); } - break; + return up; } - return up; } /* * For SMP, we need to re-test the user struct counter - * after having aquired the spinlock. This allows us to do + * after having acquired the spinlock. This allows us to do * the common case (not freeing anything) without having * any locking. */ @@ -97,7 +102,7 @@ void free_uid(struct user_struct *up) struct user_struct * alloc_uid(uid_t uid) { - unsigned int hashent = uidhashfn(uid); + struct user_struct **hashent = uidhashentry(uid); struct user_struct *up; spin_lock(&uidhash_lock); @@ -136,19 +141,14 @@ struct user_struct * alloc_uid(uid_t uid) static int __init uid_cache_init(void) { - int i; - uid_cachep = kmem_cache_create("uid_cache", sizeof(struct user_struct), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if(!uid_cachep) panic("Cannot create uid taskcount SLAB cache\n"); - for(i = 0; i < UIDHASH_SZ; i++) - uidhash[i] = 0; - /* Insert the root user immediately - init already runs with this */ - uid_hash_insert(&root_user, uidhashfn(0)); + uid_hash_insert(&root_user, uidhashentry(0)); return 0; } |