Dear RT folks! I'm pleased to announce the v5.18-rc7-rt9 patch set. Changes since v5.18-rc7-rt8: - Replace the patch adding the swait queue to dentry::d_wait with an alternative solution. Known issues - Valentin Schneider reported a few splats on ARM64, see https://lkml.kernel.org/r/20210810134127.1394269-1-valentin.schneider@xxxxxxx The delta patch against v5.18-rc7-rt8 is appended below and can be found here: https://cdn.kernel.org/pub/linux/kernel/projects/rt/5.18/incr/patch-5.18-rc7-rt8-rt9.patch.xz You can get this release via the git tree at: git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git v5.18-rc7-rt9 The RT patch against v5.18-rc7 can be found here: https://cdn.kernel.org/pub/linux/kernel/projects/rt/5.18/older/patch-5.18-rc7-rt9.patch.xz The split quilt queue is available at: https://cdn.kernel.org/pub/linux/kernel/projects/rt/5.18/older/patches-5.18-rc7-rt9.tar.xz Sebastian diff --git a/fs/afs/dir_silly.c b/fs/afs/dir_silly.c index 502b56597f107..45cfd50a95210 100644 --- a/fs/afs/dir_silly.c +++ b/fs/afs/dir_silly.c @@ -239,7 +239,7 @@ int afs_silly_iput(struct dentry *dentry, struct inode *inode) struct dentry *alias; int ret; - DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(wq); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); _enter("%p{%pd},%llx", dentry, dentry, vnode->fid.vnode); diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 48eb8c30c6dbf..1929e80c09ee1 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -69,7 +69,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_SWAIT_QUEUE_HEAD_ONSTACK(wq); + DECLARE_WAIT_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 1d4b0c9a41ae8..e9ac408b693aa 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -2587,24 +2587,21 @@ static inline void end_dir_add(struct inode *dir, unsigned n) static void d_wait_lookup(struct dentry *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); + 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 dentry *d_alloc_parallel(struct dentry *parent, const struct qstr *name, - struct swait_queue_head *wq) + wait_queue_head_t *wq) { unsigned int hash = name->hash; struct hlist_bl_head *b = in_lookup_hash(parent, hash); @@ -2712,18 +2709,30 @@ struct dentry *d_alloc_parallel(struct dentry *parent, } EXPORT_SYMBOL(d_alloc_parallel); -void __d_lookup_done(struct dentry *dentry) +static wait_queue_head_t *__d_lookup_clear_d_wait(struct dentry *dentry) { + wait_queue_head_t *d_wait; struct hlist_bl_head *b = in_lookup_hash(dentry->d_parent, dentry->d_name.hash); hlist_bl_lock(b); dentry->d_flags &= ~DCACHE_PAR_LOOKUP; __hlist_bl_del(&dentry->d_u.d_in_lookup_hash); - swake_up_all(dentry->d_wait); + d_wait = dentry->d_wait; dentry->d_wait = NULL; hlist_bl_unlock(b); INIT_HLIST_NODE(&dentry->d_u.d_alias); INIT_LIST_HEAD(&dentry->d_lru); + return d_wait; +} + +void __d_lookup_done(struct dentry *dentry) +{ + wait_queue_head_t *wq_head; + + spin_lock(&dentry->d_lock); + wq_head = __d_lookup_clear_d_wait(dentry); + spin_unlock(&dentry->d_lock); + wake_up_all(wq_head); } EXPORT_SYMBOL(__d_lookup_done); @@ -2731,13 +2740,15 @@ EXPORT_SYMBOL(__d_lookup_done); static inline void __d_add(struct dentry *dentry, struct inode *inode) { + wait_queue_head_t *d_wait = NULL; struct inode *dir = NULL; + unsigned n; spin_lock(&dentry->d_lock); if (unlikely(d_in_lookup(dentry))) { dir = dentry->d_parent->d_inode; n = start_dir_add(dir); - __d_lookup_done(dentry); + d_wait = __d_lookup_clear_d_wait(dentry); } if (inode) { unsigned add_flags = d_flags_for_inode(inode); @@ -2751,6 +2762,8 @@ static inline void __d_add(struct dentry *dentry, struct inode *inode) if (dir) end_dir_add(dir, n); spin_unlock(&dentry->d_lock); + if (d_wait) + wake_up_all(d_wait); if (inode) spin_unlock(&inode->i_lock); } @@ -2895,6 +2908,7 @@ static void copy_name(struct dentry *dentry, struct dentry *target) static void __d_move(struct dentry *dentry, struct dentry *target, bool exchange) { + wait_queue_head_t *d_wait = NULL; struct dentry *old_parent, *p; struct inode *dir = NULL; unsigned n; @@ -2926,7 +2940,7 @@ static void __d_move(struct dentry *dentry, struct dentry *target, if (unlikely(d_in_lookup(target))) { dir = target->d_parent->d_inode; n = start_dir_add(dir); - __d_lookup_done(target); + d_wait = __d_lookup_clear_d_wait(target); } write_seqcount_begin(&dentry->d_seq); @@ -2970,6 +2984,8 @@ static void __d_move(struct dentry *dentry, struct dentry *target, spin_unlock(&old_parent->d_lock); spin_unlock(&target->d_lock); spin_unlock(&dentry->d_lock); + if (d_wait) + wake_up_all(d_wait); } /* diff --git a/fs/fuse/readdir.c b/fs/fuse/readdir.c index 5ef0c106fb9db..b4e5657110457 100644 --- a/fs/fuse/readdir.c +++ b/fs/fuse/readdir.c @@ -158,7 +158,7 @@ static int fuse_direntplus_link(struct file *file, struct inode *dir = d_inode(parent); struct fuse_conn *fc; struct inode *inode; - DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(wq); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); if (!o->nodeid) { /* diff --git a/fs/namei.c b/fs/namei.c index b94b5ad7682fb..509657fdf4f56 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1683,7 +1683,7 @@ static struct dentry *__lookup_slow(const struct qstr *name, { struct dentry *dentry, *old; struct inode *inode = dir->d_inode; - DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(wq); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); /* Don't go there if it's already dead */ if (unlikely(IS_DEADDIR(inode))) @@ -3242,7 +3242,7 @@ static struct dentry *lookup_open(struct nameidata *nd, struct file *file, struct dentry *dentry; int error, create_error = 0; umode_t mode = op->mode; - DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(wq); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); if (unlikely(IS_DEADDIR(dir_inode))) return ERR_PTR(-ENOENT); diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 50812ded679ba..c6b263b5faf1f 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -721,7 +721,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry, unsigned long dir_verifier) { struct qstr filename = QSTR_INIT(entry->name, entry->len); - DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(wq); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); struct dentry *dentry; struct dentry *alias; struct inode *inode; @@ -2020,7 +2020,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry, struct file *file, unsigned open_flags, umode_t mode) { - DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(wq); + DECLARE_WAIT_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 767fe79702100..6f325e10056ce 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/swait.h> +#include <linux/wait.h> #include <linux/namei.h> #include <linux/fsnotify.h> @@ -180,7 +180,7 @@ nfs_async_unlink(struct dentry *dentry, const struct qstr *name) data->cred = get_current_cred(); data->res.dir_attr = &data->dir_attr; - init_swait_queue_head(&data->wq); + init_waitqueue_head(&data->wq); status = -EBUSY; spin_lock(&dentry->d_lock); diff --git a/fs/proc/base.c b/fs/proc/base.c index 64cbe3af8a00c..c1031843cc6aa 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -95,7 +95,6 @@ #include <linux/posix-timers.h> #include <linux/time_namespace.h> #include <linux/resctrl.h> -#include <linux/swait.h> #include <linux/cn_proc.h> #include <trace/events/oom.h> #include "internal.h" @@ -2045,7 +2044,7 @@ bool proc_fill_cache(struct file *file, struct dir_context *ctx, child = d_hash_and_lookup(dir, &qname); if (!child) { - DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(wq); + DECLARE_WAIT_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 a4ddc8df10854..7d9cfc730bd4c 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -696,7 +696,7 @@ static bool proc_sys_fill_cache(struct file *file, child = d_lookup(dir, &qname); if (!child) { - DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(wq); + DECLARE_WAIT_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 7c43c64343bb1..a07a51c858fb4 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -98,7 +98,7 @@ struct dentry { union { struct list_head d_lru; /* LRU list */ - struct swait_queue_head *d_wait; /* in-lookup ones only */ + wait_queue_head_t *d_wait; /* in-lookup ones only */ }; struct list_head d_child; /* child of parent list */ struct list_head d_subdirs; /* our children */ @@ -230,7 +230,7 @@ extern void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op extern struct dentry * d_alloc(struct dentry *, const struct qstr *); extern struct dentry * d_alloc_anon(struct super_block *); extern struct dentry * d_alloc_parallel(struct dentry *, const struct qstr *, - struct swait_queue_head *); + wait_queue_head_t *); 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 *); @@ -349,7 +349,7 @@ static inline void dont_mount(struct dentry *dentry) spin_unlock(&dentry->d_lock); } -extern void __d_lookup_done(struct dentry *); +extern void __d_lookup_done(struct dentry *dentry); static inline int d_in_lookup(const struct dentry *dentry) { @@ -358,11 +358,8 @@ static inline int d_in_lookup(const struct dentry *dentry) static inline void d_lookup_done(struct dentry *dentry) { - if (unlikely(d_in_lookup(dentry))) { - spin_lock(&dentry->d_lock); + if (unlikely(d_in_lookup(dentry))) __d_lookup_done(dentry); - spin_unlock(&dentry->d_lock); - } } extern void dput(struct dentry *); diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 706c5078fae80..2863e5a69c6ab 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -1685,7 +1685,7 @@ struct nfs_unlinkdata { struct nfs_removeargs args; struct nfs_removeres res; struct dentry *dentry; - struct swait_queue_head wq; + wait_queue_head_t wq; const struct cred *cred; struct nfs_fattr dir_attr; long timeout; diff --git a/kernel/sched/swait.c b/kernel/sched/swait.c index 25fe514fac960..76b9b796e6956 100644 --- a/kernel/sched/swait.c +++ b/kernel/sched/swait.c @@ -63,7 +63,6 @@ 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)) { diff --git a/localversion-rt b/localversion-rt index 700c857efd9ba..22746d6390a42 100644 --- a/localversion-rt +++ b/localversion-rt @@ -1 +1 @@ --rt8 +-rt9