Commit b5a660ee authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] is_subdir locking fix

From: Maneesh Soni <maneesh@in.ibm.com>

o The following patch fixes is_subdir() races with d_move. Due to concurrent
  d_move, in is_subdir() we can end up accessing freed d_parent pointer in
  case of pre-emptible kernel. To avoid this we can use rcu_read_lock() and
  rcu_read_unlock().

o This also fixes the seqlock uses in is_subdir() as we need to restart the
  the inner loop with the origianl new_dentry passed to the routine in case
  of any rename occured while we are traversing d_parent links.
parent c2d6098c
......@@ -1433,15 +1433,23 @@ asmlinkage long sys_getcwd(char __user *buf, unsigned long size)
*
* Returns 1 if new_dentry is a subdirectory of the parent (at any depth).
* Returns 0 otherwise.
* Caller must ensure that "new_dentry" is pinned before calling is_subdir()
*/
int is_subdir(struct dentry * new_dentry, struct dentry * old_dentry)
{
int result;
struct dentry * saved = new_dentry;
unsigned long seq;
result = 0;
/* need rcu_readlock to protect against the d_parent trashing due to
* d_move
*/
rcu_read_lock();
do {
/* for restarting inner loop in case of seq retry */
new_dentry = saved;
seq = read_seqbegin(&rename_lock);
for (;;) {
if (new_dentry != old_dentry) {
......@@ -1455,6 +1463,7 @@ int is_subdir(struct dentry * new_dentry, struct dentry * old_dentry)
break;
}
} while (read_seqretry(&rename_lock, seq));
rcu_read_unlock();
return result;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment