Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Dipankar Sarma and committed by
Linus Torvalds
ca99c1da fb30d645

+28 -10
+6 -2
drivers/char/tty_io.c
··· 2723 2723 } 2724 2724 task_lock(p); 2725 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 2731 fdt = files_fdtable(p->files); 2728 2732 for (i=0; i < fdt->max_fds; i++) { 2729 2733 filp = fcheck_files(p->files, i); ··· 2742 2738 break; 2743 2739 } 2744 2740 } 2745 - rcu_read_unlock(); 2741 + spin_unlock(&p->files->file_lock); 2746 2742 } 2747 2743 task_unlock(p); 2748 2744 } while_each_thread(g, p);
+7 -2
fs/locks.c
··· 2230 2230 2231 2231 lock_kernel(); 2232 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 2239 fdt = files_fdtable(files); 2235 2240 for (;;) { 2236 2241 unsigned long set; ··· 2253 2248 set >>= 1; 2254 2249 } 2255 2250 } 2256 - rcu_read_unlock(); 2251 + spin_unlock(&files->file_lock); 2257 2252 unlock_kernel(); 2258 2253 } 2259 2254 EXPORT_SYMBOL(steal_locks);
+15 -6
fs/proc/base.c
··· 297 297 298 298 files = get_files_struct(task); 299 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 305 file = fcheck_files(files, fd); 302 306 if (file) { 303 307 *mnt = mntget(file->f_vfsmnt); 304 308 *dentry = dget(file->f_dentry); 305 - rcu_read_unlock(); 309 + spin_unlock(&files->file_lock); 306 310 put_files_struct(files); 307 311 return 0; 308 312 } 309 - rcu_read_unlock(); 313 + spin_unlock(&files->file_lock); 310 314 put_files_struct(files); 311 315 } 312 316 return -ENOENT; ··· 1527 1523 if (!files) 1528 1524 goto out_unlock; 1529 1525 inode->i_mode = S_IFLNK; 1530 - rcu_read_lock(); 1526 + 1527 + /* 1528 + * We are not taking a ref to the file structure, so we must 1529 + * hold ->file_lock. 1530 + */ 1531 + spin_lock(&files->file_lock); 1531 1532 file = fcheck_files(files, fd); 1532 1533 if (!file) 1533 1534 goto out_unlock2; ··· 1540 1531 inode->i_mode |= S_IRUSR | S_IXUSR; 1541 1532 if (file->f_mode & 2) 1542 1533 inode->i_mode |= S_IWUSR | S_IXUSR; 1543 - rcu_read_unlock(); 1534 + spin_unlock(&files->file_lock); 1544 1535 put_files_struct(files); 1545 1536 inode->i_op = &proc_pid_link_inode_operations; 1546 1537 inode->i_size = 64; ··· 1550 1541 return NULL; 1551 1542 1552 1543 out_unlock2: 1553 - rcu_read_unlock(); 1544 + spin_unlock(&files->file_lock); 1554 1545 put_files_struct(files); 1555 1546 out_unlock: 1556 1547 iput(inode);