I did a review of the existing lock-free fdtable code and found
a few places that needed fixes for working correctly with preemption.
Never had a problem while testing, but theoritically they are possible.
This patch fixes those. I have tested this patch with some combinations
of dbench, kernbench and ltp on x86, ppc64 and x86_64 with both
preemption on and off.
Thanks
Dipankar
With the new fdtable locking rules, you have to protect
fdtable with either ->file_lock or rcu_read_lock/unlock().
There are some places where we aren't doing either. This
patch fixes those places.
Signed-off-by: Dipankar Sarma <[email protected]>
--
arch/alpha/kernel/osf_sys.c | 8 +++++++-
arch/ia64/kernel/perfmon.c | 3 ++-
fs/locks.c | 3 +++
fs/proc/array.c | 3 +++
kernel/exit.c | 6 ++++++
5 files changed, 21 insertions(+), 2 deletions(-)
diff -puN arch/alpha/kernel/osf_sys.c~files-preemption-fixes arch/alpha/kernel/osf_sys.c
--- linux-2.6.14-rc1-fd/arch/alpha/kernel/osf_sys.c~files-preemption-fixes 2005-09-13 17:12:58.000000000 +0530
+++ linux-2.6.14-rc1-fd-dipankar/arch/alpha/kernel/osf_sys.c 2005-09-13 17:12:58.000000000 +0530
@@ -37,6 +37,7 @@
#include <linux/namei.h>
#include <linux/uio.h>
#include <linux/vfs.h>
+#include <linux/rcupdate.h>
#include <asm/fpu.h>
#include <asm/io.h>
@@ -975,6 +976,7 @@ osf_select(int n, fd_set __user *inp, fd
long timeout;
int ret = -EINVAL;
struct fdtable *fdt;
+ int max_fdset;
timeout = MAX_SCHEDULE_TIMEOUT;
if (tvp) {
@@ -996,9 +998,13 @@ osf_select(int n, fd_set __user *inp, fd
}
}
+ rcu_read_lock();
fdt = files_fdtable(current->files);
- if (n < 0 || n > fdt->max_fdset)
+ max_fdset = fdt->max_fdset;
+ rcu_read_unlock();
+ if (n < 0 || n > max_fdset) {
goto out_nofds;
+ }
/*
* We need 6 bitmaps (in/out/ex for both incoming and outgoing),
diff -puN fs/locks.c~files-preemption-fixes fs/locks.c
--- linux-2.6.14-rc1-fd/fs/locks.c~files-preemption-fixes 2005-09-13 17:12:58.000000000 +0530
+++ linux-2.6.14-rc1-fd-dipankar/fs/locks.c 2005-09-13 17:12:58.000000000 +0530
@@ -124,6 +124,7 @@
#include <linux/smp_lock.h>
#include <linux/syscalls.h>
#include <linux/time.h>
+#include <linux/rcupdate.h>
#include <asm/semaphore.h>
#include <asm/uaccess.h>
@@ -2205,6 +2206,7 @@ void steal_locks(fl_owner_t from)
lock_kernel();
j = 0;
+ rcu_read_lock();
fdt = files_fdtable(files);
for (;;) {
unsigned long set;
@@ -2222,6 +2224,7 @@ void steal_locks(fl_owner_t from)
set >>= 1;
}
}
+ rcu_read_unlock();
unlock_kernel();
}
EXPORT_SYMBOL(steal_locks);
diff -puN kernel/exit.c~files-preemption-fixes kernel/exit.c
--- linux-2.6.14-rc1-fd/kernel/exit.c~files-preemption-fixes 2005-09-13 17:12:58.000000000 +0530
+++ linux-2.6.14-rc1-fd-dipankar/kernel/exit.c 2005-09-13 17:12:58.000000000 +0530
@@ -371,6 +371,12 @@ static inline void close_files(struct fi
struct fdtable *fdt;
j = 0;
+
+ /*
+ * It is safe to dereference the fd table without RCU or
+ * ->file_lock because this is the last reference to the
+ * files structure.
+ */
fdt = files_fdtable(files);
for (;;) {
unsigned long set;
diff -puN fs/proc/array.c~files-preemption-fixes fs/proc/array.c
--- linux-2.6.14-rc1-fd/fs/proc/array.c~files-preemption-fixes 2005-09-13 17:12:58.000000000 +0530
+++ linux-2.6.14-rc1-fd-dipankar/fs/proc/array.c 2005-09-14 00:07:57.000000000 +0530
@@ -74,6 +74,7 @@
#include <linux/file.h>
#include <linux/times.h>
#include <linux/cpuset.h>
+#include <linux/rcupdate.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
@@ -180,12 +181,14 @@ static inline char * task_state(struct t
p->gid, p->egid, p->sgid, p->fsgid);
read_unlock(&tasklist_lock);
task_lock(p);
+ rcu_read_lock();
if (p->files)
fdt = files_fdtable(p->files);
buffer += sprintf(buffer,
"FDSize:\t%d\n"
"Groups:\t",
fdt ? fdt->max_fds : 0);
+ rcu_read_unlock();
group_info = p->group_info;
get_group_info(group_info);
diff -puN arch/ia64/kernel/perfmon.c~files-preemption-fixes arch/ia64/kernel/perfmon.c
--- linux-2.6.14-rc1-fd/arch/ia64/kernel/perfmon.c~files-preemption-fixes 2005-09-13 17:13:37.000000000 +0530
+++ linux-2.6.14-rc1-fd-dipankar/arch/ia64/kernel/perfmon.c 2005-09-13 17:14:12.000000000 +0530
@@ -2218,12 +2218,13 @@ static void
pfm_free_fd(int fd, struct file *file)
{
struct files_struct *files = current->files;
- struct fdtable *fdt = files_fdtable(files);
+ struct fdtable *fdt;
/*
* there ie no fd_uninstall(), so we do it here
*/
spin_lock(&files->file_lock);
+ fdt = files_fdtable(files);
rcu_assign_pointer(fdt->fd[fd], NULL);
spin_unlock(&files->file_lock);
_
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
|
|