242 lines
8.0 KiB
Diff
242 lines
8.0 KiB
Diff
From 0c8cd26ab04b1cb1503429536154336d3a92f1b5 Mon Sep 17 00:00:00 2001
|
|
From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
|
Date: Wed, 14 Sep 2016 14:35:49 +0200
|
|
Subject: [PATCH 190/319] fs/dcache: use swait_queue instead of waitqueue
|
|
Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/4.19/older/patches-4.19.103-rt42.tar.xz
|
|
|
|
__d_lookup_done() invokes wake_up_all() while holding a hlist_bl_lock()
|
|
which disables preemption. As a workaround convert it to swait.
|
|
|
|
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
|
---
|
|
fs/cifs/readdir.c | 2 +-
|
|
fs/dcache.c | 27 +++++++++++++++------------
|
|
fs/fuse/dir.c | 2 +-
|
|
fs/namei.c | 4 ++--
|
|
fs/nfs/dir.c | 4 ++--
|
|
fs/nfs/unlink.c | 4 ++--
|
|
fs/proc/base.c | 2 +-
|
|
fs/proc/proc_sysctl.c | 2 +-
|
|
include/linux/dcache.h | 4 ++--
|
|
include/linux/nfs_xdr.h | 2 +-
|
|
kernel/sched/swait.c | 1 +
|
|
11 files changed, 29 insertions(+), 25 deletions(-)
|
|
|
|
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
|
|
index 3925a7bfc74d..33f7723fb83e 100644
|
|
--- a/fs/cifs/readdir.c
|
|
+++ b/fs/cifs/readdir.c
|
|
@@ -80,7 +80,7 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
|
|
struct inode *inode;
|
|
struct super_block *sb = parent->d_sb;
|
|
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
|
- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
|
|
+ DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(wq);
|
|
|
|
cifs_dbg(FYI, "%s: for %s\n", __func__, name->name);
|
|
|
|
diff --git a/fs/dcache.c b/fs/dcache.c
|
|
index dcde8ffe384c..b2a00f3ff7df 100644
|
|
--- a/fs/dcache.c
|
|
+++ b/fs/dcache.c
|
|
@@ -2421,21 +2421,24 @@ static inline void end_dir_add(struct inode *dir, unsigned n)
|
|
|
|
static void d_wait_lookup(struct dentry *dentry)
|
|
{
|
|
- if (d_in_lookup(dentry)) {
|
|
- DECLARE_WAITQUEUE(wait, current);
|
|
- add_wait_queue(dentry->d_wait, &wait);
|
|
- do {
|
|
- set_current_state(TASK_UNINTERRUPTIBLE);
|
|
- spin_unlock(&dentry->d_lock);
|
|
- schedule();
|
|
- spin_lock(&dentry->d_lock);
|
|
- } while (d_in_lookup(dentry));
|
|
- }
|
|
+ struct swait_queue __wait;
|
|
+
|
|
+ if (!d_in_lookup(dentry))
|
|
+ return;
|
|
+
|
|
+ INIT_LIST_HEAD(&__wait.task_list);
|
|
+ do {
|
|
+ prepare_to_swait_exclusive(dentry->d_wait, &__wait, TASK_UNINTERRUPTIBLE);
|
|
+ spin_unlock(&dentry->d_lock);
|
|
+ schedule();
|
|
+ spin_lock(&dentry->d_lock);
|
|
+ } while (d_in_lookup(dentry));
|
|
+ finish_swait(dentry->d_wait, &__wait);
|
|
}
|
|
|
|
struct dentry *d_alloc_parallel(struct dentry *parent,
|
|
const struct qstr *name,
|
|
- wait_queue_head_t *wq)
|
|
+ struct swait_queue_head *wq)
|
|
{
|
|
unsigned int hash = name->hash;
|
|
struct hlist_bl_head *b = in_lookup_hash(parent, hash);
|
|
@@ -2550,7 +2553,7 @@ void __d_lookup_done(struct dentry *dentry)
|
|
hlist_bl_lock(b);
|
|
dentry->d_flags &= ~DCACHE_PAR_LOOKUP;
|
|
__hlist_bl_del(&dentry->d_u.d_in_lookup_hash);
|
|
- wake_up_all(dentry->d_wait);
|
|
+ swake_up_all(dentry->d_wait);
|
|
dentry->d_wait = NULL;
|
|
hlist_bl_unlock(b);
|
|
INIT_HLIST_NODE(&dentry->d_u.d_alias);
|
|
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
|
|
index 6244345a5745..7ee10b7cc808 100644
|
|
--- a/fs/fuse/dir.c
|
|
+++ b/fs/fuse/dir.c
|
|
@@ -1213,7 +1213,7 @@ static int fuse_direntplus_link(struct file *file,
|
|
struct inode *dir = d_inode(parent);
|
|
struct fuse_conn *fc;
|
|
struct inode *inode;
|
|
- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
|
|
+ DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(wq);
|
|
|
|
if (!o->nodeid) {
|
|
/*
|
|
diff --git a/fs/namei.c b/fs/namei.c
|
|
index c00a7e1da4c0..742e7935f777 100644
|
|
--- a/fs/namei.c
|
|
+++ b/fs/namei.c
|
|
@@ -1646,7 +1646,7 @@ static struct dentry *__lookup_slow(const struct qstr *name,
|
|
{
|
|
struct dentry *dentry, *old;
|
|
struct inode *inode = dir->d_inode;
|
|
- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
|
|
+ DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(wq);
|
|
|
|
/* Don't go there if it's already dead */
|
|
if (unlikely(IS_DEADDIR(inode)))
|
|
@@ -3136,7 +3136,7 @@ static int lookup_open(struct nameidata *nd, struct path *path,
|
|
struct dentry *dentry;
|
|
int error, create_error = 0;
|
|
umode_t mode = op->mode;
|
|
- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
|
|
+ DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(wq);
|
|
|
|
if (unlikely(IS_DEADDIR(dir_inode)))
|
|
return -ENOENT;
|
|
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
|
|
index c60b20884c45..7e653c14c7ed 100644
|
|
--- a/fs/nfs/dir.c
|
|
+++ b/fs/nfs/dir.c
|
|
@@ -457,7 +457,7 @@ static
|
|
void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
|
|
{
|
|
struct qstr filename = QSTR_INIT(entry->name, entry->len);
|
|
- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
|
|
+ DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(wq);
|
|
struct dentry *dentry;
|
|
struct dentry *alias;
|
|
struct inode *dir = d_inode(parent);
|
|
@@ -1516,7 +1516,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
|
|
struct file *file, unsigned open_flags,
|
|
umode_t mode)
|
|
{
|
|
- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
|
|
+ DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(wq);
|
|
struct nfs_open_context *ctx;
|
|
struct dentry *res;
|
|
struct iattr attr = { .ia_valid = ATTR_OPEN };
|
|
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c
|
|
index ce9100b5604d..839bfa76f41e 100644
|
|
--- a/fs/nfs/unlink.c
|
|
+++ b/fs/nfs/unlink.c
|
|
@@ -13,7 +13,7 @@
|
|
#include <linux/sunrpc/clnt.h>
|
|
#include <linux/nfs_fs.h>
|
|
#include <linux/sched.h>
|
|
-#include <linux/wait.h>
|
|
+#include <linux/swait.h>
|
|
#include <linux/namei.h>
|
|
#include <linux/fsnotify.h>
|
|
|
|
@@ -206,7 +206,7 @@ nfs_async_unlink(struct dentry *dentry, const struct qstr *name)
|
|
goto out_free_name;
|
|
}
|
|
data->res.dir_attr = &data->dir_attr;
|
|
- init_waitqueue_head(&data->wq);
|
|
+ init_swait_queue_head(&data->wq);
|
|
|
|
status = -EBUSY;
|
|
spin_lock(&dentry->d_lock);
|
|
diff --git a/fs/proc/base.c b/fs/proc/base.c
|
|
index 3b9b726b1a6c..a45d4d640f01 100644
|
|
--- a/fs/proc/base.c
|
|
+++ b/fs/proc/base.c
|
|
@@ -1890,7 +1890,7 @@ bool proc_fill_cache(struct file *file, struct dir_context *ctx,
|
|
|
|
child = d_hash_and_lookup(dir, &qname);
|
|
if (!child) {
|
|
- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
|
|
+ DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(wq);
|
|
child = d_alloc_parallel(dir, &qname, &wq);
|
|
if (IS_ERR(child))
|
|
goto end_instantiate;
|
|
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
|
|
index c95f32b83a94..75f500cb7e74 100644
|
|
--- a/fs/proc/proc_sysctl.c
|
|
+++ b/fs/proc/proc_sysctl.c
|
|
@@ -681,7 +681,7 @@ static bool proc_sys_fill_cache(struct file *file,
|
|
|
|
child = d_lookup(dir, &qname);
|
|
if (!child) {
|
|
- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
|
|
+ DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(wq);
|
|
child = d_alloc_parallel(dir, &qname, &wq);
|
|
if (IS_ERR(child))
|
|
return false;
|
|
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
|
|
index 0880baefd85f..8b4d6c8c1f7f 100644
|
|
--- a/include/linux/dcache.h
|
|
+++ b/include/linux/dcache.h
|
|
@@ -105,7 +105,7 @@ struct dentry {
|
|
|
|
union {
|
|
struct list_head d_lru; /* LRU list */
|
|
- wait_queue_head_t *d_wait; /* in-lookup ones only */
|
|
+ struct swait_queue_head *d_wait; /* in-lookup ones only */
|
|
};
|
|
struct list_head d_child; /* child of parent list */
|
|
struct list_head d_subdirs; /* our children */
|
|
@@ -236,7 +236,7 @@ extern struct dentry * d_alloc(struct dentry *, const struct qstr *);
|
|
extern struct dentry * d_alloc_anon(struct super_block *);
|
|
extern struct dentry * d_alloc_pseudo(struct super_block *, const struct qstr *);
|
|
extern struct dentry * d_alloc_parallel(struct dentry *, const struct qstr *,
|
|
- wait_queue_head_t *);
|
|
+ struct swait_queue_head *);
|
|
extern struct dentry * d_splice_alias(struct inode *, struct dentry *);
|
|
extern struct dentry * d_add_ci(struct dentry *, struct inode *, struct qstr *);
|
|
extern struct dentry * d_exact_alias(struct dentry *, struct inode *);
|
|
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
|
|
index cab24a127feb..73b0d19ef0d9 100644
|
|
--- a/include/linux/nfs_xdr.h
|
|
+++ b/include/linux/nfs_xdr.h
|
|
@@ -1549,7 +1549,7 @@ struct nfs_unlinkdata {
|
|
struct nfs_removeargs args;
|
|
struct nfs_removeres res;
|
|
struct dentry *dentry;
|
|
- wait_queue_head_t wq;
|
|
+ struct swait_queue_head wq;
|
|
struct rpc_cred *cred;
|
|
struct nfs_fattr dir_attr;
|
|
long timeout;
|
|
diff --git a/kernel/sched/swait.c b/kernel/sched/swait.c
|
|
index c7cb30cdd1b7..119a56d7f739 100644
|
|
--- a/kernel/sched/swait.c
|
|
+++ b/kernel/sched/swait.c
|
|
@@ -70,6 +70,7 @@ void swake_up_all(struct swait_queue_head *q)
|
|
struct swait_queue *curr;
|
|
LIST_HEAD(tmp);
|
|
|
|
+ WARN_ON(irqs_disabled());
|
|
raw_spin_lock_irq(&q->lock);
|
|
list_splice_init(&q->task_list, &tmp);
|
|
while (!list_empty(&tmp)) {
|
|
--
|
|
2.25.0
|
|
|