summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-11-23 02:00:47 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-11-23 02:00:47 +0000
commit06615f62b17d7de6e12d2f5ec6b88cf30af08413 (patch)
tree8766f208847d4876a6db619aebbf54d53b76eb44 /kernel
parentfa9bdb574f4febb751848a685d9a9017e04e1d53 (diff)
Merge with Linux 2.4.0-test10.
Diffstat (limited to 'kernel')
-rw-r--r--kernel/ksyms.c1
-rw-r--r--kernel/module.c23
-rw-r--r--kernel/panic.c2
-rw-r--r--kernel/printk.c2
-rw-r--r--kernel/sched.c150
-rw-r--r--kernel/signal.c2
-rw-r--r--kernel/sys.c2
-rw-r--r--kernel/sysctl.c72
-rw-r--r--kernel/time.c4
-rw-r--r--kernel/timer.c2
-rw-r--r--kernel/user.c60
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;
}