Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ca99c1da authored by Dipankar Sarma's avatar Dipankar Sarma Committed by Linus Torvalds
Browse files

[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: default avatarDipankar Sarma <dipankar@in.ibm.com>
Acked-by: default avatar"Paul E. McKenney" <paulmck@us.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent fb30d645
Loading
Loading
Loading
Loading
+6 −2
Original line number Original line Diff line number Diff line
@@ -2723,7 +2723,11 @@ static void __do_SAK(void *arg)
		}
		}
		task_lock(p);
		task_lock(p);
		if (p->files) {
		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);
			fdt = files_fdtable(p->files);
			for (i=0; i < fdt->max_fds; i++) {
			for (i=0; i < fdt->max_fds; i++) {
				filp = fcheck_files(p->files, i);
				filp = fcheck_files(p->files, i);
@@ -2738,7 +2742,7 @@ static void __do_SAK(void *arg)
					break;
					break;
				}
				}
			}
			}
			rcu_read_unlock();
			spin_unlock(&p->files->file_lock);
		}
		}
		task_unlock(p);
		task_unlock(p);
	} while_each_thread(g, p);
	} while_each_thread(g, p);
+7 −2
Original line number Original line Diff line number Diff line
@@ -2230,7 +2230,12 @@ void steal_locks(fl_owner_t from)


	lock_kernel();
	lock_kernel();
	j = 0;
	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);
	fdt = files_fdtable(files);
	for (;;) {
	for (;;) {
		unsigned long set;
		unsigned long set;
@@ -2248,7 +2253,7 @@ void steal_locks(fl_owner_t from)
			set >>= 1;
			set >>= 1;
		}
		}
	}
	}
	rcu_read_unlock();
	spin_unlock(&files->file_lock);
	unlock_kernel();
	unlock_kernel();
}
}
EXPORT_SYMBOL(steal_locks);
EXPORT_SYMBOL(steal_locks);
+15 −6
Original line number Original line Diff line number Diff line
@@ -297,16 +297,20 @@ static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsm


	files = get_files_struct(task);
	files = get_files_struct(task);
	if (files) {
	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);
		file = fcheck_files(files, fd);
		if (file) {
		if (file) {
			*mnt = mntget(file->f_vfsmnt);
			*mnt = mntget(file->f_vfsmnt);
			*dentry = dget(file->f_dentry);
			*dentry = dget(file->f_dentry);
			rcu_read_unlock();
			spin_unlock(&files->file_lock);
			put_files_struct(files);
			put_files_struct(files);
			return 0;
			return 0;
		}
		}
		rcu_read_unlock();
		spin_unlock(&files->file_lock);
		put_files_struct(files);
		put_files_struct(files);
	}
	}
	return -ENOENT;
	return -ENOENT;
@@ -1523,7 +1527,12 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
	if (!files)
	if (!files)
		goto out_unlock;
		goto out_unlock;
	inode->i_mode = S_IFLNK;
	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);
	file = fcheck_files(files, fd);
	if (!file)
	if (!file)
		goto out_unlock2;
		goto out_unlock2;
@@ -1531,7 +1540,7 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
		inode->i_mode |= S_IRUSR | S_IXUSR;
		inode->i_mode |= S_IRUSR | S_IXUSR;
	if (file->f_mode & 2)
	if (file->f_mode & 2)
		inode->i_mode |= S_IWUSR | S_IXUSR;
		inode->i_mode |= S_IWUSR | S_IXUSR;
	rcu_read_unlock();
	spin_unlock(&files->file_lock);
	put_files_struct(files);
	put_files_struct(files);
	inode->i_op = &proc_pid_link_inode_operations;
	inode->i_op = &proc_pid_link_inode_operations;
	inode->i_size = 64;
	inode->i_size = 64;
@@ -1541,7 +1550,7 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
	return NULL;
	return NULL;


out_unlock2:
out_unlock2:
	rcu_read_unlock();
	spin_unlock(&files->file_lock);
	put_files_struct(files);
	put_files_struct(files);
out_unlock:
out_unlock:
	iput(inode);
	iput(inode);