From: Greg Kroah-Hartman Date: Mon, 16 Aug 2021 08:57:05 +0000 (+0200) Subject: 5.4-stable patches X-Git-Tag: v5.4.142~20 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3c15aa6a6fd6dbbf081d3047b2b0e4f188d1ae22;p=thirdparty%2Fkernel%2Fstable-queue.git 5.4-stable patches added patches: ceph-add-some-lockdep-assertions-around-snaprealm-handling.patch ceph-clean-up-locking-annotation-for-ceph_get_snap_realm-and-__lookup_snap_realm.patch ceph-take-snap_empty_lock-atomically-with-snaprealm-refcount-change.patch vmlinux.lds.h-handle-clang-s-module.-c-d-tor-sections.patch --- diff --git a/queue-5.4/ceph-add-some-lockdep-assertions-around-snaprealm-handling.patch b/queue-5.4/ceph-add-some-lockdep-assertions-around-snaprealm-handling.patch new file mode 100644 index 00000000000..7ba60d86186 --- /dev/null +++ b/queue-5.4/ceph-add-some-lockdep-assertions-around-snaprealm-handling.patch @@ -0,0 +1,93 @@ +From a6862e6708c15995bc10614b2ef34ca35b4b9078 Mon Sep 17 00:00:00 2001 +From: Jeff Layton +Date: Tue, 1 Jun 2021 08:13:38 -0400 +Subject: ceph: add some lockdep assertions around snaprealm handling + +From: Jeff Layton + +commit a6862e6708c15995bc10614b2ef34ca35b4b9078 upstream. + +Turn some comments into lockdep asserts. + +Signed-off-by: Jeff Layton +Reviewed-by: Ilya Dryomov +Signed-off-by: Ilya Dryomov +Signed-off-by: Greg Kroah-Hartman +--- + fs/ceph/snap.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +--- a/fs/ceph/snap.c ++++ b/fs/ceph/snap.c +@@ -65,6 +65,8 @@ + void ceph_get_snap_realm(struct ceph_mds_client *mdsc, + struct ceph_snap_realm *realm) + { ++ lockdep_assert_held_write(&mdsc->snap_rwsem); ++ + dout("get_realm %p %d -> %d\n", realm, + atomic_read(&realm->nref), atomic_read(&realm->nref)+1); + /* +@@ -113,6 +115,8 @@ static struct ceph_snap_realm *ceph_crea + { + struct ceph_snap_realm *realm; + ++ lockdep_assert_held_write(&mdsc->snap_rwsem); ++ + realm = kzalloc(sizeof(*realm), GFP_NOFS); + if (!realm) + return ERR_PTR(-ENOMEM); +@@ -143,6 +147,8 @@ static struct ceph_snap_realm *__lookup_ + struct rb_node *n = mdsc->snap_realms.rb_node; + struct ceph_snap_realm *r; + ++ lockdep_assert_held_write(&mdsc->snap_rwsem); ++ + while (n) { + r = rb_entry(n, struct ceph_snap_realm, node); + if (ino < r->ino) +@@ -176,6 +182,8 @@ static void __put_snap_realm(struct ceph + static void __destroy_snap_realm(struct ceph_mds_client *mdsc, + struct ceph_snap_realm *realm) + { ++ lockdep_assert_held_write(&mdsc->snap_rwsem); ++ + dout("__destroy_snap_realm %p %llx\n", realm, realm->ino); + + rb_erase(&realm->node, &mdsc->snap_realms); +@@ -198,6 +206,8 @@ static void __destroy_snap_realm(struct + static void __put_snap_realm(struct ceph_mds_client *mdsc, + struct ceph_snap_realm *realm) + { ++ lockdep_assert_held_write(&mdsc->snap_rwsem); ++ + dout("__put_snap_realm %llx %p %d -> %d\n", realm->ino, realm, + atomic_read(&realm->nref), atomic_read(&realm->nref)-1); + if (atomic_dec_and_test(&realm->nref)) +@@ -236,6 +246,8 @@ static void __cleanup_empty_realms(struc + { + struct ceph_snap_realm *realm; + ++ lockdep_assert_held_write(&mdsc->snap_rwsem); ++ + spin_lock(&mdsc->snap_empty_lock); + while (!list_empty(&mdsc->snap_empty)) { + realm = list_first_entry(&mdsc->snap_empty, +@@ -269,6 +281,8 @@ static int adjust_snap_realm_parent(stru + { + struct ceph_snap_realm *parent; + ++ lockdep_assert_held_write(&mdsc->snap_rwsem); ++ + if (realm->parent_ino == parentino) + return 0; + +@@ -686,6 +700,8 @@ int ceph_update_snap_trace(struct ceph_m + int err = -ENOMEM; + LIST_HEAD(dirty_realms); + ++ lockdep_assert_held_write(&mdsc->snap_rwsem); ++ + dout("update_snap_trace deletion=%d\n", deletion); + more: + ceph_decode_need(&p, e, sizeof(*ri), bad); diff --git a/queue-5.4/ceph-clean-up-locking-annotation-for-ceph_get_snap_realm-and-__lookup_snap_realm.patch b/queue-5.4/ceph-clean-up-locking-annotation-for-ceph_get_snap_realm-and-__lookup_snap_realm.patch new file mode 100644 index 00000000000..4a9f993ed0f --- /dev/null +++ b/queue-5.4/ceph-clean-up-locking-annotation-for-ceph_get_snap_realm-and-__lookup_snap_realm.patch @@ -0,0 +1,61 @@ +From df2c0cb7f8e8c83e495260ad86df8c5da947f2a7 Mon Sep 17 00:00:00 2001 +From: Jeff Layton +Date: Tue, 1 Jun 2021 09:24:38 -0400 +Subject: ceph: clean up locking annotation for ceph_get_snap_realm and __lookup_snap_realm + +From: Jeff Layton + +commit df2c0cb7f8e8c83e495260ad86df8c5da947f2a7 upstream. + +They both say that the snap_rwsem must be held for write, but I don't +see any real reason for it, and it's not currently always called that +way. + +The lookup is just walking the rbtree, so holding it for read should be +fine there. The "get" is bumping the refcount and (possibly) removing +it from the empty list. I see no need to hold the snap_rwsem for write +for that. + +Signed-off-by: Jeff Layton +Reviewed-by: Ilya Dryomov +Signed-off-by: Ilya Dryomov +Signed-off-by: Greg Kroah-Hartman +--- + fs/ceph/snap.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/fs/ceph/snap.c ++++ b/fs/ceph/snap.c +@@ -60,12 +60,12 @@ + /* + * increase ref count for the realm + * +- * caller must hold snap_rwsem for write. ++ * caller must hold snap_rwsem. + */ + void ceph_get_snap_realm(struct ceph_mds_client *mdsc, + struct ceph_snap_realm *realm) + { +- lockdep_assert_held_write(&mdsc->snap_rwsem); ++ lockdep_assert_held(&mdsc->snap_rwsem); + + dout("get_realm %p %d -> %d\n", realm, + atomic_read(&realm->nref), atomic_read(&realm->nref)+1); +@@ -139,7 +139,7 @@ static struct ceph_snap_realm *ceph_crea + /* + * lookup the realm rooted at @ino. + * +- * caller must hold snap_rwsem for write. ++ * caller must hold snap_rwsem. + */ + static struct ceph_snap_realm *__lookup_snap_realm(struct ceph_mds_client *mdsc, + u64 ino) +@@ -147,7 +147,7 @@ static struct ceph_snap_realm *__lookup_ + struct rb_node *n = mdsc->snap_realms.rb_node; + struct ceph_snap_realm *r; + +- lockdep_assert_held_write(&mdsc->snap_rwsem); ++ lockdep_assert_held(&mdsc->snap_rwsem); + + while (n) { + r = rb_entry(n, struct ceph_snap_realm, node); diff --git a/queue-5.4/ceph-take-snap_empty_lock-atomically-with-snaprealm-refcount-change.patch b/queue-5.4/ceph-take-snap_empty_lock-atomically-with-snaprealm-refcount-change.patch new file mode 100644 index 00000000000..e8932e7664c --- /dev/null +++ b/queue-5.4/ceph-take-snap_empty_lock-atomically-with-snaprealm-refcount-change.patch @@ -0,0 +1,107 @@ +From 8434ffe71c874b9c4e184b88d25de98c2bf5fe3f Mon Sep 17 00:00:00 2001 +From: Jeff Layton +Date: Tue, 3 Aug 2021 12:47:34 -0400 +Subject: ceph: take snap_empty_lock atomically with snaprealm refcount change + +From: Jeff Layton + +commit 8434ffe71c874b9c4e184b88d25de98c2bf5fe3f upstream. + +There is a race in ceph_put_snap_realm. The change to the nref and the +spinlock acquisition are not done atomically, so you could decrement +nref, and before you take the spinlock, the nref is incremented again. +At that point, you end up putting it on the empty list when it +shouldn't be there. Eventually __cleanup_empty_realms runs and frees +it when it's still in-use. + +Fix this by protecting the 1->0 transition with atomic_dec_and_lock, +and just drop the spinlock if we can get the rwsem. + +Because these objects can also undergo a 0->1 refcount transition, we +must protect that change as well with the spinlock. Increment locklessly +unless the value is at 0, in which case we take the spinlock, increment +and then take it off the empty list if it did the 0->1 transition. + +With these changes, I'm removing the dout() messages from these +functions, as well as in __put_snap_realm. They've always been racy, and +it's better to not print values that may be misleading. + +Cc: stable@vger.kernel.org +URL: https://tracker.ceph.com/issues/46419 +Reported-by: Mark Nelson +Signed-off-by: Jeff Layton +Reviewed-by: Luis Henriques +Signed-off-by: Ilya Dryomov +Signed-off-by: Greg Kroah-Hartman +--- + fs/ceph/snap.c | 34 +++++++++++++++++----------------- + 1 file changed, 17 insertions(+), 17 deletions(-) + +--- a/fs/ceph/snap.c ++++ b/fs/ceph/snap.c +@@ -67,19 +67,19 @@ void ceph_get_snap_realm(struct ceph_mds + { + lockdep_assert_held(&mdsc->snap_rwsem); + +- dout("get_realm %p %d -> %d\n", realm, +- atomic_read(&realm->nref), atomic_read(&realm->nref)+1); + /* +- * since we _only_ increment realm refs or empty the empty +- * list with snap_rwsem held, adjusting the empty list here is +- * safe. we do need to protect against concurrent empty list +- * additions, however. ++ * The 0->1 and 1->0 transitions must take the snap_empty_lock ++ * atomically with the refcount change. Go ahead and bump the ++ * nref here, unless it's 0, in which case we take the spinlock ++ * and then do the increment and remove it from the list. + */ +- if (atomic_inc_return(&realm->nref) == 1) { +- spin_lock(&mdsc->snap_empty_lock); ++ if (atomic_inc_not_zero(&realm->nref)) ++ return; ++ ++ spin_lock(&mdsc->snap_empty_lock); ++ if (atomic_inc_return(&realm->nref) == 1) + list_del_init(&realm->empty_item); +- spin_unlock(&mdsc->snap_empty_lock); +- } ++ spin_unlock(&mdsc->snap_empty_lock); + } + + static void __insert_snap_realm(struct rb_root *root, +@@ -208,28 +208,28 @@ static void __put_snap_realm(struct ceph + { + lockdep_assert_held_write(&mdsc->snap_rwsem); + +- dout("__put_snap_realm %llx %p %d -> %d\n", realm->ino, realm, +- atomic_read(&realm->nref), atomic_read(&realm->nref)-1); ++ /* ++ * We do not require the snap_empty_lock here, as any caller that ++ * increments the value must hold the snap_rwsem. ++ */ + if (atomic_dec_and_test(&realm->nref)) + __destroy_snap_realm(mdsc, realm); + } + + /* +- * caller needn't hold any locks ++ * See comments in ceph_get_snap_realm. Caller needn't hold any locks. + */ + void ceph_put_snap_realm(struct ceph_mds_client *mdsc, + struct ceph_snap_realm *realm) + { +- dout("put_snap_realm %llx %p %d -> %d\n", realm->ino, realm, +- atomic_read(&realm->nref), atomic_read(&realm->nref)-1); +- if (!atomic_dec_and_test(&realm->nref)) ++ if (!atomic_dec_and_lock(&realm->nref, &mdsc->snap_empty_lock)) + return; + + if (down_write_trylock(&mdsc->snap_rwsem)) { ++ spin_unlock(&mdsc->snap_empty_lock); + __destroy_snap_realm(mdsc, realm); + up_write(&mdsc->snap_rwsem); + } else { +- spin_lock(&mdsc->snap_empty_lock); + list_add(&realm->empty_item, &mdsc->snap_empty); + spin_unlock(&mdsc->snap_empty_lock); + } diff --git a/queue-5.4/series b/queue-5.4/series index 2b9de514117..45f26adbdbc 100644 --- a/queue-5.4/series +++ b/queue-5.4/series @@ -55,3 +55,7 @@ pci-msi-correct-misleading-comments.patch pci-msi-use-msi_mask_irq-in-pci_msi_shutdown.patch pci-msi-protect-msi_desc-masked-for-multi-msi.patch kvm-vmx-use-current-vmcs-to-query-waitpkg-support-for-msr-emulation.patch +ceph-add-some-lockdep-assertions-around-snaprealm-handling.patch +ceph-clean-up-locking-annotation-for-ceph_get_snap_realm-and-__lookup_snap_realm.patch +ceph-take-snap_empty_lock-atomically-with-snaprealm-refcount-change.patch +vmlinux.lds.h-handle-clang-s-module.-c-d-tor-sections.patch diff --git a/queue-5.4/vmlinux.lds.h-handle-clang-s-module.-c-d-tor-sections.patch b/queue-5.4/vmlinux.lds.h-handle-clang-s-module.-c-d-tor-sections.patch new file mode 100644 index 00000000000..f9a77692977 --- /dev/null +++ b/queue-5.4/vmlinux.lds.h-handle-clang-s-module.-c-d-tor-sections.patch @@ -0,0 +1,51 @@ +From foo@baz Mon Aug 16 10:53:10 AM CEST 2021 +From: Nathan Chancellor +Date: Fri, 30 Jul 2021 19:31:08 -0700 +Subject: vmlinux.lds.h: Handle clang's module.{c,d}tor sections + +From: Nathan Chancellor + +commit 848378812e40152abe9b9baf58ce2004f76fb988 upstream. + +A recent change in LLVM causes module_{c,d}tor sections to appear when +CONFIG_K{A,C}SAN are enabled, which results in orphan section warnings +because these are not handled anywhere: + +ld.lld: warning: arch/x86/pci/built-in.a(legacy.o):(.text.asan.module_ctor) is being placed in '.text.asan.module_ctor' +ld.lld: warning: arch/x86/pci/built-in.a(legacy.o):(.text.asan.module_dtor) is being placed in '.text.asan.module_dtor' +ld.lld: warning: arch/x86/pci/built-in.a(legacy.o):(.text.tsan.module_ctor) is being placed in '.text.tsan.module_ctor' + +Fangrui explains: "the function asan.module_ctor has the SHF_GNU_RETAIN +flag, so it is in a separate section even with -fno-function-sections +(default)". + +Place them in the TEXT_TEXT section so that these technologies continue +to work with the newer compiler versions. All of the KASAN and KCSAN +KUnit tests continue to pass after this change. + +Cc: stable@vger.kernel.org +Link: https://github.com/ClangBuiltLinux/linux/issues/1432 +Link: https://github.com/llvm/llvm-project/commit/7b789562244ee941b7bf2cefeb3fc08a59a01865 +Signed-off-by: Nathan Chancellor +Reviewed-by: Nick Desaulniers +Reviewed-by: Fangrui Song +Acked-by: Marco Elver +Signed-off-by: Kees Cook +Link: https://lore.kernel.org/r/20210731023107.1932981-1-nathan@kernel.org +[nc: Resolve conflict due to lack of cf68fffb66d60] +Signed-off-by: Nathan Chancellor +Signed-off-by: Greg Kroah-Hartman +--- + include/asm-generic/vmlinux.lds.h | 1 + + 1 file changed, 1 insertion(+) + +--- a/include/asm-generic/vmlinux.lds.h ++++ b/include/asm-generic/vmlinux.lds.h +@@ -536,6 +536,7 @@ + NOINSTR_TEXT \ + *(.text..refcount) \ + *(.ref.text) \ ++ *(.text.asan.* .text.tsan.*) \ + MEM_KEEP(init.text*) \ + MEM_KEEP(exit.text*) \ +