summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDipankar Sarma <dipankar@in.ibm.com>2006-04-19 17:00:12 +0000
committerGreg Kroah-Hartman <gregkh@suse.de>2006-04-24 09:56:05 -0700
commit95fb678bf90572414b1c2f239c6a44226049ba8a (patch)
treeb7246d566793a2672111c598a450ba98fdc55b4e
parentbd6b6027eacb8e5ef633aa0e1c2576dc5a464675 (diff)
downloadlinux-stable-95fb678bf90572414b1c2f239c6a44226049ba8a.tar.gz
linux-stable-95fb678bf90572414b1c2f239c6a44226049ba8a.tar.bz2
linux-stable-95fb678bf90572414b1c2f239c6a44226049ba8a.zip
[PATCH] Fix file lookup without ref
There are places in the kernel where we look up files in fd tables and access the file structure without holding refereces to the file. So, we need special care to avoid the race between looking up files in the fd table and tearing down of the file in another CPU. Otherwise, one might see a NULL f_dentry or such torn down version of the file. This patch fixes those special places where such a race may happen. Signed-off-by: Dipankar Sarma <dipankar@in.ibm.com> Acked-by: "Paul E. McKenney" <paulmck@us.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/char/tty_io.c8
-rw-r--r--fs/locks.c9
-rw-r--r--fs/proc/base.c21
3 files changed, 28 insertions, 10 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 53d3d066554e..edaee70b2e66 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -2706,7 +2706,11 @@ static void __do_SAK(void *arg)
}
task_lock(p);
if (p->files) {
- rcu_read_lock();
+ /*
+ * We don't take a ref to the file, so we must
+ * hold ->file_lock instead.
+ */
+ spin_lock(&p->files->file_lock);
fdt = files_fdtable(p->files);
for (i=0; i < fdt->max_fds; i++) {
filp = fcheck_files(p->files, i);
@@ -2721,7 +2725,7 @@ static void __do_SAK(void *arg)
break;
}
}
- rcu_read_unlock();
+ spin_unlock(&p->files->file_lock);
}
task_unlock(p);
} while_each_task_pid(session, PIDTYPE_SID, p);
diff --git a/fs/locks.c b/fs/locks.c
index 909eab8fb1d0..e75ac392a313 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -2212,7 +2212,12 @@ void steal_locks(fl_owner_t from)
lock_kernel();
j = 0;
- rcu_read_lock();
+
+ /*
+ * We are not taking a ref to the file structures, so
+ * we need to acquire ->file_lock.
+ */
+ spin_lock(&files->file_lock);
fdt = files_fdtable(files);
for (;;) {
unsigned long set;
@@ -2230,7 +2235,7 @@ void steal_locks(fl_owner_t from)
set >>= 1;
}
}
- rcu_read_unlock();
+ spin_unlock(&files->file_lock);
unlock_kernel();
}
EXPORT_SYMBOL(steal_locks);
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 20feb7568deb..c192cb2af2c8 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -294,16 +294,20 @@ static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsm
files = get_files_struct(task);
if (files) {
- rcu_read_lock();
+ /*
+ * We are not taking a ref to the file structure, so we must
+ * hold ->file_lock.
+ */
+ spin_lock(&files->file_lock);
file = fcheck_files(files, fd);
if (file) {
*mnt = mntget(file->f_vfsmnt);
*dentry = dget(file->f_dentry);
- rcu_read_unlock();
+ spin_unlock(&files->file_lock);
put_files_struct(files);
return 0;
}
- rcu_read_unlock();
+ spin_unlock(&files->file_lock);
put_files_struct(files);
}
return -ENOENT;
@@ -1485,7 +1489,12 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
if (!files)
goto out_unlock;
inode->i_mode = S_IFLNK;
- rcu_read_lock();
+
+ /*
+ * We are not taking a ref to the file structure, so we must
+ * hold ->file_lock.
+ */
+ spin_lock(&files->file_lock);
file = fcheck_files(files, fd);
if (!file)
goto out_unlock2;
@@ -1493,7 +1502,7 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
inode->i_mode |= S_IRUSR | S_IXUSR;
if (file->f_mode & 2)
inode->i_mode |= S_IWUSR | S_IXUSR;
- rcu_read_unlock();
+ spin_unlock(&files->file_lock);
put_files_struct(files);
inode->i_op = &proc_pid_link_inode_operations;
inode->i_size = 64;
@@ -1503,7 +1512,7 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
return NULL;
out_unlock2:
- rcu_read_unlock();
+ spin_unlock(&files->file_lock);
put_files_struct(files);
out_unlock:
iput(inode);