aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDipankar Sarma <dipankar@in.ibm.com>2006-04-19 01:21:46 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-04-19 12:13:51 -0400
commitca99c1da080345e227cfb083c330a184d42e27f3 (patch)
treee417b4c456ae31dc1dde8027b6be44a1a9f19395
parentfb30d64568fd8f6a21afef987f11852a109723da (diff)
[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>
-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 841f0bd3eaaf..f07637a8f88f 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -2723,7 +2723,11 @@ static void __do_SAK(void *arg)
2723 } 2723 }
2724 task_lock(p); 2724 task_lock(p);
2725 if (p->files) { 2725 if (p->files) {
2726 rcu_read_lock(); 2726 /*
2727 * We don't take a ref to the file, so we must
2728 * hold ->file_lock instead.
2729 */
2730 spin_lock(&p->files->file_lock);
2727 fdt = files_fdtable(p->files); 2731 fdt = files_fdtable(p->files);
2728 for (i=0; i < fdt->max_fds; i++) { 2732 for (i=0; i < fdt->max_fds; i++) {
2729 filp = fcheck_files(p->files, i); 2733 filp = fcheck_files(p->files, i);
@@ -2738,7 +2742,7 @@ static void __do_SAK(void *arg)
2738 break; 2742 break;
2739 } 2743 }
2740 } 2744 }
2741 rcu_read_unlock(); 2745 spin_unlock(&p->files->file_lock);
2742 } 2746 }
2743 task_unlock(p); 2747 task_unlock(p);
2744 } while_each_thread(g, p); 2748 } while_each_thread(g, p);
diff --git a/fs/locks.c b/fs/locks.c
index dda83d6cd48b..efad798824dc 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -2230,7 +2230,12 @@ void steal_locks(fl_owner_t from)
2230 2230
2231 lock_kernel(); 2231 lock_kernel();
2232 j = 0; 2232 j = 0;
2233 rcu_read_lock(); 2233
2234 /*
2235 * We are not taking a ref to the file structures, so
2236 * we need to acquire ->file_lock.
2237 */
2238 spin_lock(&files->file_lock);
2234 fdt = files_fdtable(files); 2239 fdt = files_fdtable(files);
2235 for (;;) { 2240 for (;;) {
2236 unsigned long set; 2241 unsigned long set;
@@ -2248,7 +2253,7 @@ void steal_locks(fl_owner_t from)
2248 set >>= 1; 2253 set >>= 1;
2249 } 2254 }
2250 } 2255 }
2251 rcu_read_unlock(); 2256 spin_unlock(&files->file_lock);
2252 unlock_kernel(); 2257 unlock_kernel();
2253} 2258}
2254EXPORT_SYMBOL(steal_locks); 2259EXPORT_SYMBOL(steal_locks);
diff --git a/fs/proc/base.c b/fs/proc/base.c
index a3a3eecef689..6cc77dc3f3ff 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -297,16 +297,20 @@ static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsm
297 297
298 files = get_files_struct(task); 298 files = get_files_struct(task);
299 if (files) { 299 if (files) {
300 rcu_read_lock(); 300 /*
301 * We are not taking a ref to the file structure, so we must
302 * hold ->file_lock.
303 */
304 spin_lock(&files->file_lock);
301 file = fcheck_files(files, fd); 305 file = fcheck_files(files, fd);
302 if (file) { 306 if (file) {
303 *mnt = mntget(file->f_vfsmnt); 307 *mnt = mntget(file->f_vfsmnt);
304 *dentry = dget(file->f_dentry); 308 *dentry = dget(file->f_dentry);
305 rcu_read_unlock(); 309 spin_unlock(&files->file_lock);
306 put_files_struct(files); 310 put_files_struct(files);
307 return 0; 311 return 0;
308 } 312 }
309 rcu_read_unlock(); 313 spin_unlock(&files->file_lock);
310 put_files_struct(files); 314 put_files_struct(files);
311 } 315 }
312 return -ENOENT; 316 return -ENOENT;
@@ -1523,7 +1527,12 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
1523 if (!files) 1527 if (!files)
1524 goto out_unlock; 1528 goto out_unlock;
1525 inode->i_mode = S_IFLNK; 1529 inode->i_mode = S_IFLNK;
1526 rcu_read_lock(); 1530
1531 /*
1532 * We are not taking a ref to the file structure, so we must
1533 * hold ->file_lock.
1534 */
1535 spin_lock(&files->file_lock);
1527 file = fcheck_files(files, fd); 1536 file = fcheck_files(files, fd);
1528 if (!file) 1537 if (!file)
1529 goto out_unlock2; 1538 goto out_unlock2;
@@ -1531,7 +1540,7 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
1531 inode->i_mode |= S_IRUSR | S_IXUSR; 1540 inode->i_mode |= S_IRUSR | S_IXUSR;
1532 if (file->f_mode & 2) 1541 if (file->f_mode & 2)
1533 inode->i_mode |= S_IWUSR | S_IXUSR; 1542 inode->i_mode |= S_IWUSR | S_IXUSR;
1534 rcu_read_unlock(); 1543 spin_unlock(&files->file_lock);
1535 put_files_struct(files); 1544 put_files_struct(files);
1536 inode->i_op = &proc_pid_link_inode_operations; 1545 inode->i_op = &proc_pid_link_inode_operations;
1537 inode->i_size = 64; 1546 inode->i_size = 64;
@@ -1541,7 +1550,7 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
1541 return NULL; 1550 return NULL;
1542 1551
1543out_unlock2: 1552out_unlock2:
1544 rcu_read_unlock(); 1553 spin_unlock(&files->file_lock);
1545 put_files_struct(files); 1554 put_files_struct(files);
1546out_unlock: 1555out_unlock:
1547 iput(inode); 1556 iput(inode);