aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/dcache.c45
-rw-r--r--fs/namei.c22
-rw-r--r--include/linux/dcache.h1
3 files changed, 34 insertions, 34 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index c6fd1f27da57..64024005da43 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1720,18 +1720,23 @@ void d_move(struct dentry * dentry, struct dentry * target)
1720 spin_unlock(&dcache_lock); 1720 spin_unlock(&dcache_lock);
1721} 1721}
1722 1722
1723/* 1723/**
1724 * Helper that returns 1 if p1 is a parent of p2, else 0 1724 * d_ancestor - search for an ancestor
1725 * @p1: ancestor dentry
1726 * @p2: child dentry
1727 *
1728 * Returns the ancestor dentry of p2 which is a child of p1, if p1 is
1729 * an ancestor of p2, else NULL.
1725 */ 1730 */
1726static int d_isparent(struct dentry *p1, struct dentry *p2) 1731struct dentry *d_ancestor(struct dentry *p1, struct dentry *p2)
1727{ 1732{
1728 struct dentry *p; 1733 struct dentry *p;
1729 1734
1730 for (p = p2; !IS_ROOT(p); p = p->d_parent) { 1735 for (p = p2; !IS_ROOT(p); p = p->d_parent) {
1731 if (p->d_parent == p1) 1736 if (p->d_parent == p1)
1732 return 1; 1737 return p;
1733 } 1738 }
1734 return 0; 1739 return NULL;
1735} 1740}
1736 1741
1737/* 1742/*
@@ -1755,7 +1760,7 @@ static struct dentry *__d_unalias(struct dentry *dentry, struct dentry *alias)
1755 1760
1756 /* Check for loops */ 1761 /* Check for loops */
1757 ret = ERR_PTR(-ELOOP); 1762 ret = ERR_PTR(-ELOOP);
1758 if (d_isparent(alias, dentry)) 1763 if (d_ancestor(alias, dentry))
1759 goto out_err; 1764 goto out_err;
1760 1765
1761 /* See lock_rename() */ 1766 /* See lock_rename() */
@@ -2155,31 +2160,27 @@ out:
2155 * Caller must ensure that "new_dentry" is pinned before calling is_subdir() 2160 * Caller must ensure that "new_dentry" is pinned before calling is_subdir()
2156 */ 2161 */
2157 2162
2158int is_subdir(struct dentry * new_dentry, struct dentry * old_dentry) 2163int is_subdir(struct dentry *new_dentry, struct dentry *old_dentry)
2159{ 2164{
2160 int result; 2165 int result;
2161 struct dentry * saved = new_dentry;
2162 unsigned long seq; 2166 unsigned long seq;
2163 2167
2164 /* need rcu_readlock to protect against the d_parent trashing due to 2168 /* FIXME: This is old behavior, needed? Please check callers. */
2165 * d_move 2169 if (new_dentry == old_dentry)
2170 return 1;
2171
2172 /*
2173 * Need rcu_readlock to protect against the d_parent trashing
2174 * due to d_move
2166 */ 2175 */
2167 rcu_read_lock(); 2176 rcu_read_lock();
2168 do { 2177 do {
2169 /* for restarting inner loop in case of seq retry */ 2178 /* for restarting inner loop in case of seq retry */
2170 new_dentry = saved;
2171 result = 0;
2172 seq = read_seqbegin(&rename_lock); 2179 seq = read_seqbegin(&rename_lock);
2173 for (;;) { 2180 if (d_ancestor(old_dentry, new_dentry))
2174 if (new_dentry != old_dentry) {
2175 if (IS_ROOT(new_dentry))
2176 break;
2177 new_dentry = new_dentry->d_parent;
2178 continue;
2179 }
2180 result = 1; 2181 result = 1;
2181 break; 2182 else
2182 } 2183 result = 0;
2183 } while (read_seqretry(&rename_lock, seq)); 2184 } while (read_seqretry(&rename_lock, seq));
2184 rcu_read_unlock(); 2185 rcu_read_unlock();
2185 2186
diff --git a/fs/namei.c b/fs/namei.c
index 068a9e50c8c0..b7cd65224d60 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1454,20 +1454,18 @@ struct dentry *lock_rename(struct dentry *p1, struct dentry *p2)
1454 1454
1455 mutex_lock(&p1->d_inode->i_sb->s_vfs_rename_mutex); 1455 mutex_lock(&p1->d_inode->i_sb->s_vfs_rename_mutex);
1456 1456
1457 for (p = p1; !IS_ROOT(p); p = p->d_parent) { 1457 p = d_ancestor(p2, p1);
1458 if (p->d_parent == p2) { 1458 if (p) {
1459 mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_PARENT); 1459 mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_PARENT);
1460 mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_CHILD); 1460 mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_CHILD);
1461 return p; 1461 return p;
1462 }
1463 } 1462 }
1464 1463
1465 for (p = p2; !IS_ROOT(p); p = p->d_parent) { 1464 p = d_ancestor(p1, p2);
1466 if (p->d_parent == p1) { 1465 if (p) {
1467 mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_PARENT); 1466 mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_PARENT);
1468 mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_CHILD); 1467 mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_CHILD);
1469 return p; 1468 return p;
1470 }
1471 } 1469 }
1472 1470
1473 mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_PARENT); 1471 mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_PARENT);
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 74c64ae30cf0..a37359d0bad1 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -287,6 +287,7 @@ static inline struct dentry *d_add_unique(struct dentry *entry, struct inode *in
287 287
288/* used for rename() and baskets */ 288/* used for rename() and baskets */
289extern void d_move(struct dentry *, struct dentry *); 289extern void d_move(struct dentry *, struct dentry *);
290extern struct dentry *d_ancestor(struct dentry *, struct dentry *);
290 291
291/* appendix may either be NULL or be used for transname suffixes */ 292/* appendix may either be NULL or be used for transname suffixes */
292extern struct dentry * d_lookup(struct dentry *, struct qstr *); 293extern struct dentry * d_lookup(struct dentry *, struct qstr *);