|
@@ -587,19 +587,20 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
|
|
|
unhashed = autofs4_lookup_unhashed(sbi, dentry->d_parent, &dentry->d_name);
|
|
|
if (!unhashed) {
|
|
|
/*
|
|
|
- * Mark the dentry incomplete, but add it. This is needed so
|
|
|
- * that the VFS layer knows about the dentry, and we can count
|
|
|
- * on catching any lookups through the revalidate.
|
|
|
- *
|
|
|
- * Let all the hard work be done by the revalidate function that
|
|
|
- * needs to be able to do this anyway..
|
|
|
- *
|
|
|
- * We need to do this before we release the directory semaphore.
|
|
|
+ * Mark the dentry incomplete but don't hash it. We do this
|
|
|
+ * to serialize our inode creation operations (symlink and
|
|
|
+ * mkdir) which prevents deadlock during the callback to
|
|
|
+ * the daemon. Subsequent user space lookups for the same
|
|
|
+ * dentry are placed on the wait queue while the daemon
|
|
|
+ * itself is allowed passage unresticted so the create
|
|
|
+ * operation itself can then hash the dentry. Finally,
|
|
|
+ * we check for the hashed dentry and return the newly
|
|
|
+ * hashed dentry.
|
|
|
*/
|
|
|
dentry->d_op = &autofs4_root_dentry_operations;
|
|
|
|
|
|
dentry->d_fsdata = NULL;
|
|
|
- d_add(dentry, NULL);
|
|
|
+ d_instantiate(dentry, NULL);
|
|
|
} else {
|
|
|
struct autofs_info *ino = autofs4_dentry_ino(unhashed);
|
|
|
DPRINTK("rehash %p with %p", dentry, unhashed);
|
|
@@ -607,15 +608,17 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
|
|
|
* If we are racing with expire the request might not
|
|
|
* be quite complete but the directory has been removed
|
|
|
* so it must have been successful, so just wait for it.
|
|
|
+ * We need to ensure the AUTOFS_INF_EXPIRING flag is clear
|
|
|
+ * before continuing as revalidate may fail when calling
|
|
|
+ * try_to_fill_dentry (returning EAGAIN) if we don't.
|
|
|
*/
|
|
|
- if (ino && (ino->flags & AUTOFS_INF_EXPIRING)) {
|
|
|
+ while (ino && (ino->flags & AUTOFS_INF_EXPIRING)) {
|
|
|
DPRINTK("wait for incomplete expire %p name=%.*s",
|
|
|
unhashed, unhashed->d_name.len,
|
|
|
unhashed->d_name.name);
|
|
|
autofs4_wait(sbi, unhashed, NFY_NONE);
|
|
|
DPRINTK("request completed");
|
|
|
}
|
|
|
- d_rehash(unhashed);
|
|
|
dentry = unhashed;
|
|
|
}
|
|
|
|
|
@@ -658,7 +661,7 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
|
|
|
* for all system calls, but it should be OK for the operations
|
|
|
* we permit from an autofs.
|
|
|
*/
|
|
|
- if (dentry->d_inode && d_unhashed(dentry)) {
|
|
|
+ if (!oz_mode && d_unhashed(dentry)) {
|
|
|
/*
|
|
|
* A user space application can (and has done in the past)
|
|
|
* remove and re-create this directory during the callback.
|
|
@@ -716,7 +719,7 @@ static int autofs4_dir_symlink(struct inode *dir,
|
|
|
strcpy(cp, symname);
|
|
|
|
|
|
inode = autofs4_get_inode(dir->i_sb, ino);
|
|
|
- d_instantiate(dentry, inode);
|
|
|
+ d_add(dentry, inode);
|
|
|
|
|
|
if (dir == dir->i_sb->s_root->d_inode)
|
|
|
dentry->d_op = &autofs4_root_dentry_operations;
|
|
@@ -844,7 +847,7 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode)
|
|
|
return -ENOSPC;
|
|
|
|
|
|
inode = autofs4_get_inode(dir->i_sb, ino);
|
|
|
- d_instantiate(dentry, inode);
|
|
|
+ d_add(dentry, inode);
|
|
|
|
|
|
if (dir == dir->i_sb->s_root->d_inode)
|
|
|
dentry->d_op = &autofs4_root_dentry_operations;
|