Revert "vfs: stop d_splice_alias creating directory aliases"
This reverts commit7732a557b1
(and commit3f50fff4da
, 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: Al Viro <viro@zeniv.linux.org.uk> Acked-by: J. Bruce Fields <bfields@fieldses.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Родитель
0b35d326f8
Коммит
32ba9c3fca
16
fs/dcache.c
16
fs/dcache.c
|
@ -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);
|
||||||
* 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 @@ again:
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче