Index: linux-2.4.21/fs/ext3/namei.c =================================================================== --- linux-2.4.21.orig/fs/ext3/namei.c 2006-04-29 20:48:26.000000000 +0400 +++ linux-2.4.21/fs/ext3/namei.c 2006-05-06 01:31:51.000000000 +0400 @@ -955,6 +955,38 @@ static struct dentry *ext3_lookup(struct } } + /* ".." shouldn't go into dcache to preserve dcache hierarchy + * otherwise we'll get parent being a child of actual child. + * see bug 10458 for details -bzzz */ + if (inode && (dentry->d_name.name[0] == '.' && (dentry->d_name.len == 1 || + (dentry->d_name.len == 2 && dentry->d_name.name[1] == '.')))) { + struct dentry *tmp, *goal = NULL; + struct list_head *lp; + + /* first, look for an existing dentry - any one is good */ + spin_lock(&dcache_lock); + list_for_each(lp, &inode->i_dentry) { + tmp = list_entry(lp, struct dentry, d_alias); + goal = tmp; + dget_locked(goal); + break; + } + if (goal == NULL) { + /* there is no alias, we need to make current dentry: + * a) inaccessible for __d_lookup() + * b) inaccessible for iopen */ + J_ASSERT(list_empty(&dentry->d_alias)); + dentry->d_flags |= DCACHE_NFSFS_RENAMED; + /* this is d_instantiate() ... */ + list_add(&dentry->d_alias, &inode->i_dentry); + dentry->d_inode = inode; + } + spin_unlock(&dcache_lock); + if (goal) + iput(inode); + return goal; + } + return iopen_connect_dentry(dentry, inode, 1); } Index: linux-2.4.21/fs/ext3/iopen.c =================================================================== --- linux-2.4.21.orig/fs/ext3/iopen.c 2006-04-29 20:48:23.000000000 +0400 +++ linux-2.4.21/fs/ext3/iopen.c 2006-04-29 20:59:50.000000000 +0400 @@ -92,9 +92,12 @@ static struct dentry *iopen_lookup(struc assert(!(alternate->d_flags & DCACHE_NFSD_DISCONNECTED)); } - if (!list_empty(&inode->i_dentry)) { - alternate = list_entry(inode->i_dentry.next, - struct dentry, d_alias); + list_for_each(lp, &inode->i_dentry) { + alternate = list_entry(lp, struct dentry, d_alias); + /* ignore dentries created for ".." to preserve + * proper dcache hierarchy -- bug 10458 */ + if (alternate->d_flags & DCACHE_NFSFS_RENAMED) + continue; dget_locked(alternate); alternate->d_vfs_flags |= DCACHE_REFERENCED; iput(inode);