Commit 32ba9c3f authored by Linus Torvalds's avatar Linus Torvalds

Revert "vfs: stop d_splice_alias creating directory aliases"

This reverts commit 7732a557 (and commit
3f50fff4, which was a follow-up
cleanup).

We're chasing an elusive bug that Dave Jones can apparently reproduce
using his system call fuzzer tool, and that looks like some kind of
locking ordering problem on the directory i_mutex chain.  Our i_mutex
locking is rather complex, and depends on the topological ordering of
the directories, which is why we have been very wary of splicing
directory entries around.

Of course, we really don't want to ever see aliased unconnected
directories anyway, so none of this should ever happen, but this revert
aims to basically get us back to a known older state.

Bruce points to some of the previous discussion at

       http://marc.info/?i=<20110310105821.GE22723@ZenIV.linux.org.uk>

and in particular a long post from Neil:

       http://marc.info/?i=<20110311150749.2fa2be66@notabene.brown>

It should be noted that it's possible that Dave's problems come from
other changes altohgether, including possibly just the fact that Dave
constantly is teachning his fuzzer new tricks.  So what appears to be a
new bug could in fact be an old one that just gets newly triggered, but
reverting these patches as "still under heavy discussion" is the right
thing regardless.
Requested-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
Acked-by: default avatarJ. Bruce Fields <bfields@fieldses.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 0b35d326
...@@ -683,6 +683,8 @@ EXPORT_SYMBOL(dget_parent); ...@@ -683,6 +683,8 @@ EXPORT_SYMBOL(dget_parent);
/** /**
* d_find_alias - grab a hashed alias of inode * d_find_alias - grab a hashed alias of inode
* @inode: inode in question * @inode: inode in question
* @want_discon: flag, used by d_splice_alias, to request
* that only a DISCONNECTED alias be returned.
* *
* If inode has a hashed alias, or is a directory and has any alias, * If inode has a hashed alias, or is a directory and has any alias,
* acquire the reference to alias and return it. Otherwise return NULL. * acquire the reference to alias and return it. Otherwise return NULL.
...@@ -691,9 +693,10 @@ EXPORT_SYMBOL(dget_parent); ...@@ -691,9 +693,10 @@ EXPORT_SYMBOL(dget_parent);
* of a filesystem. * of a filesystem.
* *
* If the inode has an IS_ROOT, DCACHE_DISCONNECTED alias, then prefer * If the inode has an IS_ROOT, DCACHE_DISCONNECTED alias, then prefer
* any other hashed alias over that. * any other hashed alias over that one unless @want_discon is set,
* in which case only return an IS_ROOT, DCACHE_DISCONNECTED alias.
*/ */
static struct dentry *__d_find_alias(struct inode *inode) static struct dentry *__d_find_alias(struct inode *inode, int want_discon)
{ {
struct dentry *alias, *discon_alias; struct dentry *alias, *discon_alias;
...@@ -705,7 +708,7 @@ static struct dentry *__d_find_alias(struct inode *inode) ...@@ -705,7 +708,7 @@ static struct dentry *__d_find_alias(struct inode *inode)
if (IS_ROOT(alias) && if (IS_ROOT(alias) &&
(alias->d_flags & DCACHE_DISCONNECTED)) { (alias->d_flags & DCACHE_DISCONNECTED)) {
discon_alias = alias; discon_alias = alias;
} else { } else if (!want_discon) {
__dget_dlock(alias); __dget_dlock(alias);
spin_unlock(&alias->d_lock); spin_unlock(&alias->d_lock);
return alias; return alias;
...@@ -736,7 +739,7 @@ struct dentry *d_find_alias(struct inode *inode) ...@@ -736,7 +739,7 @@ struct dentry *d_find_alias(struct inode *inode)
if (!list_empty(&inode->i_dentry)) { if (!list_empty(&inode->i_dentry)) {
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
de = __d_find_alias(inode); de = __d_find_alias(inode, 0);
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
} }
return de; return de;
...@@ -1647,8 +1650,9 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry) ...@@ -1647,8 +1650,9 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
if (inode && S_ISDIR(inode->i_mode)) { if (inode && S_ISDIR(inode->i_mode)) {
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
new = __d_find_any_alias(inode); new = __d_find_alias(inode, 1);
if (new) { if (new) {
BUG_ON(!(new->d_flags & DCACHE_DISCONNECTED));
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
security_d_instantiate(new, inode); security_d_instantiate(new, inode);
d_move(new, dentry); d_move(new, dentry);
...@@ -2478,7 +2482,7 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) ...@@ -2478,7 +2482,7 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode)
struct dentry *alias; struct dentry *alias;
/* Does an aliased dentry already exist? */ /* Does an aliased dentry already exist? */
alias = __d_find_alias(inode); alias = __d_find_alias(inode, 0);
if (alias) { if (alias) {
actual = alias; actual = alias;
write_seqlock(&rename_lock); write_seqlock(&rename_lock);
......
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