summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/acct.c61
-rw-r--r--kernel/exit.c3
-rw-r--r--kernel/fork.c4
-rw-r--r--kernel/kmod.c28
-rw-r--r--kernel/ksyms.c5
-rw-r--r--kernel/printk.c8
-rw-r--r--kernel/sched.c21
-rw-r--r--kernel/timer.c25
8 files changed, 91 insertions, 64 deletions
diff --git a/kernel/acct.c b/kernel/acct.c
index eeab054d0..6eacd87b3 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -75,7 +75,7 @@ static volatile int acct_active;
static volatile int acct_needcheck;
static struct file *acct_file;
static struct timer_list acct_timer;
-static int do_acct_process(long, struct file *);
+static void do_acct_process(long, struct file *);
/*
* Called whenever the timer says to check the free space.
@@ -91,11 +91,14 @@ static void acct_timeout(unsigned long unused)
static int check_free_space(struct file *file)
{
struct statfs sbuf;
- int res = acct_active;
+ int res;
int act;
+ lock_kernel();
+ res = acct_active;
if (!file || !acct_needcheck)
- return res;
+ goto out;
+ unlock_kernel();
/* May block */
if (vfs_statfs(file->f_dentry->d_inode->i_sb, &sbuf))
@@ -112,8 +115,12 @@ static int check_free_space(struct file *file)
* If some joker switched acct_file under us we'ld better be
* silent and _not_ touch anything.
*/
- if (file != acct_file)
- return act ? (act>0) : res;
+ lock_kernel();
+ if (file != acct_file) {
+ if (act)
+ res = act>0;
+ goto out;
+ }
if (acct_active) {
if (act < 0) {
@@ -131,7 +138,10 @@ static int check_free_space(struct file *file)
acct_needcheck = 0;
acct_timer.expires = jiffies + ACCT_TIMEOUT*HZ;
add_timer(&acct_timer);
- return acct_active;
+ res = acct_active;
+out:
+ unlock_kernel();
+ return res;
}
/*
@@ -149,7 +159,6 @@ asmlinkage long sys_acct(const char *name)
if (!capable(CAP_SYS_PACCT))
return -EPERM;
- lock_kernel();
if (name) {
tmp = getname(name);
error = PTR_ERR(tmp);
@@ -172,6 +181,7 @@ asmlinkage long sys_acct(const char *name)
}
error = 0;
+ lock_kernel();
if (acct_file) {
old_acct = acct_file;
del_timer(&acct_timer);
@@ -183,18 +193,18 @@ asmlinkage long sys_acct(const char *name)
acct_file = file;
acct_needcheck = 0;
acct_active = 1;
- /* Its been deleted if it was used before so this is safe */
+ /* It's been deleted if it was used before so this is safe */
init_timer(&acct_timer);
acct_timer.function = acct_timeout;
acct_timer.expires = jiffies + ACCT_TIMEOUT*HZ;
add_timer(&acct_timer);
}
+ unlock_kernel();
if (old_acct) {
do_acct_process(0,old_acct);
filp_close(old_acct, NULL);
}
out:
- unlock_kernel();
return error;
out_err:
filp_close(file, NULL);
@@ -203,8 +213,10 @@ out_err:
void acct_auto_close(kdev_t dev)
{
+ lock_kernel();
if (acct_file && acct_file->f_dentry->d_inode->i_dev == dev)
- sys_acct((char *)NULL);
+ sys_acct(NULL);
+ unlock_kernel();
}
/*
@@ -256,26 +268,20 @@ static comp_t encode_comp_t(unsigned long value)
*/
/*
- * do_acct_process does all actual work.
+ * do_acct_process does all actual work. Caller holds the reference to file.
*/
-static int do_acct_process(long exitcode, struct file *file)
+static void do_acct_process(long exitcode, struct file *file)
{
struct acct ac;
mm_segment_t fs;
unsigned long vsize;
- struct inode *inode;
/*
* First check to see if there is enough free_space to continue
* the process accounting system.
*/
- if (!file)
- return 0;
- get_file(file);
- if (!check_free_space(file)) {
- fput(file);
- return 0;
- }
+ if (!check_free_space(file))
+ return;
/*
* Fill the accounting struct with the needed info as recorded
@@ -330,12 +336,9 @@ static int do_acct_process(long exitcode, struct file *file)
*/
fs = get_fs();
set_fs(KERNEL_DS);
- inode = file->f_dentry->d_inode;
file->f_op->write(file, (char *)&ac,
sizeof(struct acct), &file->f_pos);
set_fs(fs);
- fput(file);
- return 0;
}
/*
@@ -343,7 +346,17 @@ static int do_acct_process(long exitcode, struct file *file)
*/
int acct_process(long exitcode)
{
- return do_acct_process(exitcode, acct_file);
+ struct file *file = NULL;
+ lock_kernel();
+ if (acct_file) {
+ file = acct_file;
+ get_file(file);
+ unlock_kernel();
+ do_acct_process(exitcode, acct_file);
+ fput(file);
+ } else
+ unlock_kernel();
+ return 0;
}
#else
diff --git a/kernel/exit.c b/kernel/exit.c
index e912b75bc..536a6dd9c 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -217,6 +217,7 @@ void exit_files(struct task_struct *tsk)
}
static inline void __put_fs_struct(struct fs_struct *fs)
{
+ /* No need to hold fs->lock if we are killing it */
if (atomic_dec_and_test(&fs->count)) {
dput(fs->root);
mntput(fs->rootmnt);
@@ -437,11 +438,11 @@ NORET_TYPE void do_exit(long code)
tsk->flags |= PF_EXITING;
del_timer_sync(&tsk->real_timer);
- lock_kernel();
fake_volatile:
#ifdef CONFIG_BSD_PROCESS_ACCT
acct_process(code);
#endif
+ lock_kernel();
sem_exit();
__exit_mm(tsk);
__exit_files(tsk);
diff --git a/kernel/fork.c b/kernel/fork.c
index b441988aa..b9cc831ec 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -425,9 +425,12 @@ fail_nomem:
static inline struct fs_struct *__copy_fs_struct(struct fs_struct *old)
{
struct fs_struct *fs = kmalloc(sizeof(*old), GFP_KERNEL);
+ /* We don't need to lock fs - think why ;-) */
if (fs) {
atomic_set(&fs->count, 1);
+ fs->lock = RW_LOCK_UNLOCKED;
fs->umask = old->umask;
+ read_lock(&old->lock);
fs->rootmnt = mntget(old->rootmnt);
fs->root = dget(old->root);
fs->pwdmnt = mntget(old->pwdmnt);
@@ -439,6 +442,7 @@ static inline struct fs_struct *__copy_fs_struct(struct fs_struct *old)
fs->altrootmnt = NULL;
fs->altroot = NULL;
}
+ read_unlock(&old->lock);
}
return fs;
}
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 5e8d825a4..2a78a9606 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -32,6 +32,8 @@ static inline void
use_init_fs_context(void)
{
struct fs_struct *our_fs, *init_fs;
+ struct dentry *root, *pwd;
+ struct vfsmount *rootmnt, *pwdmnt;
/*
* Make modprobe's fs context be a copy of init's.
@@ -49,23 +51,35 @@ use_init_fs_context(void)
* We created the exec_modprobe thread without CLONE_FS,
* so we can update the fields in our fs context freely.
*/
- lock_kernel();
- our_fs = current->fs;
init_fs = init_task.fs;
+ read_lock(&init_fs->lock);
+ rootmnt = mntget(init_fs->rootmnt);
+ root = dget(init_fs->root);
+ pwdmnt = mntget(init_fs->pwdmnt);
+ pwd = dget(init_fs->pwd);
+ read_unlock(&init_fs->lock);
+
+ /* FIXME - unsafe ->fs access */
+ our_fs = current->fs;
our_fs->umask = init_fs->umask;
- set_fs_root(our_fs, init_fs->rootmnt, init_fs->root);
- set_fs_pwd(our_fs, init_fs->pwdmnt, init_fs->pwd);
+ set_fs_root(our_fs, rootmnt, root);
+ set_fs_pwd(our_fs, pwdmnt, pwd);
+ write_lock(&our_fs->lock);
if (our_fs->altroot) {
struct vfsmount *mnt = our_fs->altrootmnt;
struct dentry *dentry = our_fs->altroot;
our_fs->altrootmnt = NULL;
our_fs->altroot = NULL;
+ write_unlock(&our_fs->lock);
dput(dentry);
mntput(mnt);
- }
-
- unlock_kernel();
+ } else
+ write_unlock(&our_fs->lock);
+ dput(root);
+ mntput(rootmnt);
+ dput(pwd);
+ mntput(pwdmnt);
}
int exec_usermodehelper(char *program_path, char *argv[], char *envp[])
diff --git a/kernel/ksyms.c b/kernel/ksyms.c
index 2189d87a4..5a1f457de 100644
--- a/kernel/ksyms.c
+++ b/kernel/ksyms.c
@@ -149,6 +149,7 @@ EXPORT_SYMBOL(__user_walk);
EXPORT_SYMBOL(lookup_one);
EXPORT_SYMBOL(lookup_hash);
EXPORT_SYMBOL(sys_close);
+EXPORT_SYMBOL(dcache_lock);
EXPORT_SYMBOL(d_alloc_root);
EXPORT_SYMBOL(d_delete);
EXPORT_SYMBOL(d_validate);
@@ -212,7 +213,7 @@ EXPORT_SYMBOL(posix_test_lock);
EXPORT_SYMBOL(posix_block_lock);
EXPORT_SYMBOL(posix_unblock_lock);
EXPORT_SYMBOL(locks_mandatory_area);
-EXPORT_SYMBOL(dput);
+EXPORT_SYMBOL(__dput);
EXPORT_SYMBOL(have_submounts);
EXPORT_SYMBOL(d_find_alias);
EXPORT_SYMBOL(d_prune_aliases);
@@ -360,8 +361,6 @@ EXPORT_SYMBOL(mod_timer);
EXPORT_SYMBOL(tq_timer);
EXPORT_SYMBOL(tq_immediate);
EXPORT_SYMBOL(tq_scheduler);
-EXPORT_SYMBOL(timer_active);
-EXPORT_SYMBOL(timer_table);
#ifdef CONFIG_SMP
/* Various random spinlocks we want to export */
diff --git a/kernel/printk.c b/kernel/printk.c
index ca4b14ff9..ff6c727ab 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -471,6 +471,14 @@ int unregister_console(struct console * console)
}
}
+ /* If last console is removed, we re-enable picking the first
+ * one that gets registered. Without that, pmac early boot console
+ * would prevent fbcon from taking over.
+ */
+ if (console_drivers == NULL)
+ preferred_console = -1;
+
+
spin_unlock_irqrestore(&console_lock, flags);
return res;
}
diff --git a/kernel/sched.c b/kernel/sched.c
index fa30b0645..3b007e5e8 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -1007,12 +1007,23 @@ asmlinkage long sys_sched_get_priority_min(int policy)
asmlinkage long sys_sched_rr_get_interval(pid_t pid, struct timespec *interval)
{
struct timespec t;
+ struct task_struct *p;
+ int retval = -EINVAL;
- t.tv_sec = 0;
- t.tv_nsec = 150000;
- if (copy_to_user(interval, &t, sizeof(struct timespec)))
- return -EFAULT;
- return 0;
+ if (pid < 0)
+ goto out_nounlock;
+
+ retval = -ESRCH;
+ read_lock(&tasklist_lock);
+ p = find_process_by_pid(pid);
+ if (p)
+ jiffies_to_timespec(p->policy & SCHED_FIFO ? 0 : p->priority,
+ &t);
+ read_unlock(&tasklist_lock);
+ if (p)
+ retval = copy_to_user(interval, &t, sizeof(t)) ? -EFAULT : 0;
+out_nounlock:
+ return retval;
}
static void show_task(struct task_struct * p)
diff --git a/kernel/timer.c b/kernel/timer.c
index 873fef479..1a0c2ba73 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -162,7 +162,7 @@ static inline void internal_add_timer(struct timer_list *timer)
/* Initialize both explicitly - let's try to have them in the same cache line */
spinlock_t timerlist_lock = SPIN_LOCK_UNLOCKED;
-volatile unsigned long timer_sequence = 0xfee1bad;
+volatile struct timer_list *running_timer = NULL;
void add_timer(struct timer_list *timer)
{
@@ -311,25 +311,6 @@ repeat:
spin_unlock_irq(&timerlist_lock);
}
-
-static inline void run_old_timers(void)
-{
- struct timer_struct *tp;
- unsigned long mask;
-
- for (mask = 1, tp = timer_table+0 ; mask ; tp++,mask += mask) {
- if (mask > timer_active)
- break;
- if (!(mask & timer_active))
- continue;
- if (time_after(tp->expires, jiffies))
- continue;
- timer_active &= ~mask;
- tp->fn();
- sti();
- }
-}
-
spinlock_t tqueue_lock = SPIN_LOCK_UNLOCKED;
void tqueue_bh(void)
@@ -342,9 +323,6 @@ void immediate_bh(void)
run_task_queue(&tq_immediate);
}
-unsigned long timer_active;
-struct timer_struct timer_table[32];
-
/*
* this routine handles the overflow of the microsecond field
*
@@ -682,7 +660,6 @@ static inline void update_times(void)
void timer_bh(void)
{
update_times();
- run_old_timers();
run_timer_list();
}