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

[PATCH vfs-2.6 2/6] vfs: add d_ancestor()

This adds d_ancestor() instead of d_isparent(), then use it.

If new_dentry == old_dentry, is_subdir() returns 1, looks strange.
"new_dentry == old_dentry" is not subdir obviously. But I'm not
checking callers for now, so this keeps current behavior.

Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

authored by

OGAWA Hirofumi and committed by
Al Viro
e2761a11 871c0067

+34 -34
+23 -22
fs/dcache.c
··· 1720 1720 spin_unlock(&dcache_lock); 1721 1721 } 1722 1722 1723 - /* 1724 - * Helper that returns 1 if p1 is a parent of p2, else 0 1723 + /** 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 */ 1726 - static int d_isparent(struct dentry *p1, struct dentry *p2) 1731 + struct dentry *d_ancestor(struct dentry *p1, struct dentry *p2) 1727 1732 { 1728 1733 struct dentry *p; 1729 1734 1730 1735 for (p = p2; !IS_ROOT(p); p = p->d_parent) { 1731 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 /* ··· 1760 1755 1761 1756 /* Check for loops */ 1762 1757 ret = ERR_PTR(-ELOOP); 1763 - if (d_isparent(alias, dentry)) 1758 + if (d_ancestor(alias, dentry)) 1764 1759 goto out_err; 1765 1760 1766 1761 /* See lock_rename() */ ··· 2160 2155 * Caller must ensure that "new_dentry" is pinned before calling is_subdir() 2161 2156 */ 2162 2157 2163 - int is_subdir(struct dentry * new_dentry, struct dentry * old_dentry) 2158 + int is_subdir(struct dentry *new_dentry, struct dentry *old_dentry) 2164 2159 { 2165 2160 int result; 2166 - struct dentry * saved = new_dentry; 2167 2161 unsigned long seq; 2168 2162 2169 - /* need rcu_readlock to protect against the d_parent trashing due to 2170 - * d_move 2163 + /* FIXME: This is old behavior, needed? Please check callers. */ 2164 + if (new_dentry == old_dentry) 2165 + return 1; 2166 + 2167 + /* 2168 + * Need rcu_readlock to protect against the d_parent trashing 2169 + * due to d_move 2171 2170 */ 2172 2171 rcu_read_lock(); 2173 - do { 2172 + do { 2174 2173 /* for restarting inner loop in case of seq retry */ 2175 - new_dentry = saved; 2176 - result = 0; 2177 2174 seq = read_seqbegin(&rename_lock); 2178 - for (;;) { 2179 - if (new_dentry != old_dentry) { 2180 - if (IS_ROOT(new_dentry)) 2181 - break; 2182 - new_dentry = new_dentry->d_parent; 2183 - continue; 2184 - } 2175 + if (d_ancestor(old_dentry, new_dentry)) 2185 2176 result = 1; 2186 - break; 2187 - } 2177 + else 2178 + result = 0; 2188 2179 } while (read_seqretry(&rename_lock, seq)); 2189 2180 rcu_read_unlock(); 2190 2181
+10 -12
fs/namei.c
··· 1454 1454 1455 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) { 1458 - if (p->d_parent == p2) { 1459 - mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_PARENT); 1460 - mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_CHILD); 1461 - return p; 1462 - } 1457 + p = d_ancestor(p2, p1); 1458 + if (p) { 1459 + mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_PARENT); 1460 + mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_CHILD); 1461 + return p; 1463 1462 } 1464 1463 1465 - for (p = p2; !IS_ROOT(p); p = p->d_parent) { 1466 - if (p->d_parent == p1) { 1467 - mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_PARENT); 1468 - mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_CHILD); 1469 - return p; 1470 - } 1464 + p = d_ancestor(p1, p2); 1465 + if (p) { 1466 + mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_PARENT); 1467 + mutex_lock_nested(&p2->d_inode->i_mutex, I_MUTEX_CHILD); 1468 + return p; 1471 1469 } 1472 1470 1473 1471 mutex_lock_nested(&p1->d_inode->i_mutex, I_MUTEX_PARENT);
+1
include/linux/dcache.h
··· 287 287 288 288 /* used for rename() and baskets */ 289 289 extern void d_move(struct dentry *, struct dentry *); 290 + extern struct dentry *d_ancestor(struct dentry *, struct dentry *); 290 291 291 292 /* appendix may either be NULL or be used for transname suffixes */ 292 293 extern struct dentry * d_lookup(struct dentry *, struct qstr *);