diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/autofs4/root.c | 31 | ||||
-rw-r--r-- | fs/ecryptfs/inode.c | 4 | ||||
-rw-r--r-- | fs/exec.c | 12 | ||||
-rw-r--r-- | fs/signalfd.c | 14 |
4 files changed, 33 insertions, 28 deletions
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 2d4c8a3e604..45ff3d63b75 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -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; diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 131954b3fb9..5d40ad13ab5 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -357,6 +357,10 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry, ecryptfs_printk(KERN_DEBUG, "Is a special file; returning\n"); goto out; } + if (special_file(lower_inode->i_mode)) { + ecryptfs_printk(KERN_DEBUG, "Is a special file; returning\n"); + goto out; + } if (!nd) { ecryptfs_printk(KERN_DEBUG, "We have a NULL nd, just leave" "as we *think* we are about to unlink\n"); diff --git a/fs/exec.c b/fs/exec.c index ce62f7b65f1..c21a8cc0627 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -780,18 +780,11 @@ static int de_thread(struct task_struct *tsk) int count; /* - * Tell all the sighand listeners that this sighand has - * been detached. The signalfd_detach() function grabs the - * sighand lock, if signal listeners are present on the sighand. - */ - signalfd_detach(tsk); - - /* * If we don't share sighandlers, then we aren't sharing anything * and we can just re-use it all. */ if (atomic_read(&oldsighand->count) <= 1) { - BUG_ON(atomic_read(&sig->count) != 1); + signalfd_detach(tsk); exit_itimers(sig); return 0; } @@ -930,12 +923,11 @@ static int de_thread(struct task_struct *tsk) sig->flags = 0; no_thread_group: + signalfd_detach(tsk); exit_itimers(sig); if (leader) release_task(leader); - BUG_ON(atomic_read(&sig->count) != 1); - if (atomic_read(&oldsighand->count) == 1) { /* * Now that we nuked the rest of the thread group, diff --git a/fs/signalfd.c b/fs/signalfd.c index 7b941abbcde..a8e293d3003 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c @@ -56,12 +56,18 @@ static int signalfd_lock(struct signalfd_ctx *ctx, struct signalfd_lockctx *lk) sighand = lock_task_sighand(lk->tsk, &lk->flags); rcu_read_unlock(); - if (sighand && !ctx->tsk) { + if (!sighand) + return 0; + + if (!ctx->tsk) { unlock_task_sighand(lk->tsk, &lk->flags); - sighand = NULL; + return 0; } - return sighand != NULL; + if (lk->tsk->tgid == current->tgid) + lk->tsk = current; + + return 1; } static void signalfd_unlock(struct signalfd_lockctx *lk) @@ -331,7 +337,7 @@ asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemas init_waitqueue_head(&ctx->wqh); ctx->sigmask = sigmask; - ctx->tsk = current; + ctx->tsk = current->group_leader; sighand = current->sighand; /* |