From: kernel test robot <lkp@intel.com>
To: Nicholas Piggin <npiggin@gmail.com>
Cc: kbuild-all@lists.01.org, Nicholas Piggin <npiggin@gmail.com>,
Ingo Molnar <mingo@redhat.com>, Will Deacon <will@kernel.org>,
Waiman Long <longman@redhat.com>,
Boqun Feng <boqun.feng@gmail.com>,
"linux-kernel @ vger . kernel . org"
<linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v2 06/12] locking/qspinlock: merge qspinlock_paravirt.h into qspinlock.c
Date: Fri, 15 Jul 2022 00:42:27 +0800 [thread overview]
Message-ID: <202207150022.DkhjTAWE-lkp@intel.com> (raw)
In-Reply-To: <20220713070704.308394-7-npiggin@gmail.com>
Hi Nicholas,
I love your patch! Perhaps something to improve:
[auto build test WARNING on tip/locking/core]
[also build test WARNING on tip/x86/core powerpc/next linus/master v5.19-rc6 next-20220714]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Nicholas-Piggin/locking-qspinlock-simplify-code-generation/20220713-151009
base: https://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git eae6d58d67d9739be5f7ae2dbead1d0ef6528243
config: x86_64-rhel-8.3-func (https://download.01.org/0day-ci/archive/20220715/202207150022.DkhjTAWE-lkp@intel.com/config)
compiler: gcc-11 (Debian 11.3.0-3) 11.3.0
reproduce (this is a W=1 build):
# https://github.com/intel-lab-lkp/linux/commit/91668ee1ed703d7ea84e314136dc732da05ec9e7
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Nicholas-Piggin/locking-qspinlock-simplify-code-generation/20220713-151009
git checkout 91668ee1ed703d7ea84e314136dc732da05ec9e7
# save the config file
mkdir build_dir && cp config build_dir/.config
make W=1 O=build_dir ARCH=x86_64 SHELL=/bin/bash drivers/nvme/target/ fs/xfs/ kernel/locking/
If you fix the issue, kindly add following tag where applicable
Reported-by: kernel test robot <lkp@intel.com>
All warnings (new ones prefixed by >>):
kernel/locking/qspinlock.c: In function 'pv_wait_node':
>> kernel/locking/qspinlock.c:513:14: warning: variable 'wait_early' set but not used [-Wunused-but-set-variable]
513 | bool wait_early;
| ^~~~~~~~~~
kernel/locking/qspinlock.c: At top level:
>> kernel/locking/qspinlock.c:705:1: warning: no previous prototype for '__pv_queued_spin_unlock_slowpath' [-Wmissing-prototypes]
705 | __pv_queued_spin_unlock_slowpath(struct qspinlock *lock, u8 locked)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
vim +/wait_early +513 kernel/locking/qspinlock.c
504
505 /*
506 * Wait for node->locked to become true, halt the vcpu after a short spin.
507 * pv_kick_node() is used to set _Q_SLOW_VAL and fill in hash table on its
508 * behalf.
509 */
510 static void pv_wait_node(struct qnode *node, struct qnode *prev)
511 {
512 int loop;
> 513 bool wait_early;
514
515 for (;;) {
516 for (wait_early = false, loop = SPIN_THRESHOLD; loop; loop--) {
517 if (READ_ONCE(node->locked))
518 return;
519 if (pv_wait_early(prev, loop)) {
520 wait_early = true;
521 break;
522 }
523 cpu_relax();
524 }
525
526 /*
527 * Order node->state vs node->locked thusly:
528 *
529 * [S] node->state = vcpu_halted [S] next->locked = 1
530 * MB MB
531 * [L] node->locked [RmW] node->state = vcpu_hashed
532 *
533 * Matches the cmpxchg() from pv_kick_node().
534 */
535 smp_store_mb(node->state, vcpu_halted);
536
537 if (!READ_ONCE(node->locked)) {
538 lockevent_inc(pv_wait_node);
539 lockevent_cond_inc(pv_wait_early, wait_early);
540 pv_wait(&node->state, vcpu_halted);
541 }
542
543 /*
544 * If pv_kick_node() changed us to vcpu_hashed, retain that
545 * value so that pv_wait_head_or_lock() knows to not also try
546 * to hash this lock.
547 */
548 cmpxchg(&node->state, vcpu_halted, vcpu_running);
549
550 /*
551 * If the locked flag is still not set after wakeup, it is a
552 * spurious wakeup and the vCPU should wait again. However,
553 * there is a pretty high overhead for CPU halting and kicking.
554 * So it is better to spin for a while in the hope that the
555 * MCS lock will be released soon.
556 */
557 lockevent_cond_inc(pv_spurious_wakeup,
558 !READ_ONCE(node->locked));
559 }
560
561 /*
562 * By now our node->locked should be 1 and our caller will not actually
563 * spin-wait for it. We do however rely on our caller to do a
564 * load-acquire for us.
565 */
566 }
567
568 /*
569 * Called after setting next->locked = 1 when we're the lock owner.
570 *
571 * Instead of waking the waiters stuck in pv_wait_node() advance their state
572 * such that they're waiting in pv_wait_head_or_lock(), this avoids a
573 * wake/sleep cycle.
574 */
575 static void pv_kick_node(struct qspinlock *lock, struct qnode *node)
576 {
577 /*
578 * If the vCPU is indeed halted, advance its state to match that of
579 * pv_wait_node(). If OTOH this fails, the vCPU was running and will
580 * observe its next->locked value and advance itself.
581 *
582 * Matches with smp_store_mb() and cmpxchg() in pv_wait_node()
583 *
584 * The write to next->locked in arch_mcs_spin_unlock_contended()
585 * must be ordered before the read of node->state in the cmpxchg()
586 * below for the code to work correctly. To guarantee full ordering
587 * irrespective of the success or failure of the cmpxchg(),
588 * a relaxed version with explicit barrier is used. The control
589 * dependency will order the reading of node->state before any
590 * subsequent writes.
591 */
592 smp_mb__before_atomic();
593 if (cmpxchg_relaxed(&node->state, vcpu_halted, vcpu_hashed)
594 != vcpu_halted)
595 return;
596
597 /*
598 * Put the lock into the hash table and set the _Q_SLOW_VAL.
599 *
600 * As this is the same vCPU that will check the _Q_SLOW_VAL value and
601 * the hash table later on at unlock time, no atomic instruction is
602 * needed.
603 */
604 WRITE_ONCE(lock->locked, _Q_SLOW_VAL);
605 (void)pv_hash(lock, node);
606 }
607
608 /*
609 * Wait for l->locked to become clear and acquire the lock;
610 * halt the vcpu after a short spin.
611 * __pv_queued_spin_unlock() will wake us.
612 *
613 * The current value of the lock will be returned for additional processing.
614 */
615 static u32
616 pv_wait_head_or_lock(struct qspinlock *lock, struct qnode *node)
617 {
618 struct qspinlock **lp = NULL;
619 int waitcnt = 0;
620 int loop;
621
622 /*
623 * If pv_kick_node() already advanced our state, we don't need to
624 * insert ourselves into the hash table anymore.
625 */
626 if (READ_ONCE(node->state) == vcpu_hashed)
627 lp = (struct qspinlock **)1;
628
629 /*
630 * Tracking # of slowpath locking operations
631 */
632 lockevent_inc(lock_slowpath);
633
634 for (;; waitcnt++) {
635 /*
636 * Set correct vCPU state to be used by queue node wait-early
637 * mechanism.
638 */
639 WRITE_ONCE(node->state, vcpu_running);
640
641 /*
642 * Set the pending bit in the active lock spinning loop to
643 * disable lock stealing before attempting to acquire the lock.
644 */
645 set_pending(lock);
646 for (loop = SPIN_THRESHOLD; loop; loop--) {
647 if (trylock_clear_pending(lock))
648 goto gotlock;
649 cpu_relax();
650 }
651 clear_pending(lock);
652
653
654 if (!lp) { /* ONCE */
655 lp = pv_hash(lock, node);
656
657 /*
658 * We must hash before setting _Q_SLOW_VAL, such that
659 * when we observe _Q_SLOW_VAL in __pv_queued_spin_unlock()
660 * we'll be sure to be able to observe our hash entry.
661 *
662 * [S] <hash> [Rmw] l->locked == _Q_SLOW_VAL
663 * MB RMB
664 * [RmW] l->locked = _Q_SLOW_VAL [L] <unhash>
665 *
666 * Matches the smp_rmb() in __pv_queued_spin_unlock().
667 */
668 if (xchg(&lock->locked, _Q_SLOW_VAL) == 0) {
669 /*
670 * The lock was free and now we own the lock.
671 * Change the lock value back to _Q_LOCKED_VAL
672 * and unhash the table.
673 */
674 WRITE_ONCE(lock->locked, _Q_LOCKED_VAL);
675 WRITE_ONCE(*lp, NULL);
676 goto gotlock;
677 }
678 }
679 WRITE_ONCE(node->state, vcpu_hashed);
680 lockevent_inc(pv_wait_head);
681 lockevent_cond_inc(pv_wait_again, waitcnt);
682 pv_wait(&lock->locked, _Q_SLOW_VAL);
683
684 /*
685 * Because of lock stealing, the queue head vCPU may not be
686 * able to acquire the lock before it has to wait again.
687 */
688 }
689
690 /*
691 * The cmpxchg() or xchg() call before coming here provides the
692 * acquire semantics for locking. The dummy ORing of _Q_LOCKED_VAL
693 * here is to indicate to the compiler that the value will always
694 * be nozero to enable better code optimization.
695 */
696 gotlock:
697 return (u32)(atomic_read(&lock->val) | _Q_LOCKED_VAL);
698 }
699
700 /*
701 * PV versions of the unlock fastpath and slowpath functions to be used
702 * instead of queued_spin_unlock().
703 */
704 __visible void
> 705 __pv_queued_spin_unlock_slowpath(struct qspinlock *lock, u8 locked)
706 {
707 struct qnode *node;
708
709 if (unlikely(locked != _Q_SLOW_VAL)) {
710 WARN(!debug_locks_silent,
711 "pvqspinlock: lock 0x%lx has corrupted value 0x%x!\n",
712 (unsigned long)lock, atomic_read(&lock->val));
713 return;
714 }
715
716 /*
717 * A failed cmpxchg doesn't provide any memory-ordering guarantees,
718 * so we need a barrier to order the read of the node data in
719 * pv_unhash *after* we've read the lock being _Q_SLOW_VAL.
720 *
721 * Matches the cmpxchg() in pv_wait_head_or_lock() setting _Q_SLOW_VAL.
722 */
723 smp_rmb();
724
725 /*
726 * Since the above failed to release, this must be the SLOW path.
727 * Therefore start by looking up the blocked node and unhashing it.
728 */
729 node = pv_unhash(lock);
730
731 /*
732 * Now that we have a reference to the (likely) blocked qnode,
733 * release the lock.
734 */
735 smp_store_release(&lock->locked, 0);
736
737 /*
738 * At this point the memory pointed at by lock can be freed/reused,
739 * however we can still use the qnode to kick the CPU.
740 * The other vCPU may not really be halted, but kicking an active
741 * vCPU is harmless other than the additional latency in completing
742 * the unlock.
743 */
744 lockevent_inc(pv_kick_unlock);
745 pv_kick(node->cpu);
746 }
747
--
0-DAY CI Kernel Test Service
https://01.org/lkp
next prev parent reply other threads:[~2022-07-14 16:44 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-07-13 7:06 [PATCH v2 00/12] locking/qspinlock: simplify code generation Nicholas Piggin
2022-07-13 7:06 ` [PATCH v2 01/12] locking/qspinlock: remove pv_node abstraction Nicholas Piggin
2022-07-13 7:06 ` [PATCH v2 02/12] locking/qspinlock: inline mcs_spinlock functions into qspinlock Nicholas Piggin
2022-07-13 7:06 ` [PATCH v2 03/12] locking/qspinlock: split common mcs queueing code into its own function Nicholas Piggin
2022-07-13 7:06 ` [PATCH v2 04/12] locking/qspinlock: move pv lock word helpers into qspinlock.c Nicholas Piggin
2022-07-13 7:06 ` [PATCH v2 05/12] locking/qspinlock: be less clever with the preprocessor Nicholas Piggin
2022-07-13 7:06 ` [PATCH v2 06/12] locking/qspinlock: merge qspinlock_paravirt.h into qspinlock.c Nicholas Piggin
2022-07-14 14:16 ` kernel test robot
2022-07-29 3:49 ` Nicholas Piggin
2022-07-29 3:49 ` Nicholas Piggin
2022-07-14 16:42 ` kernel test robot [this message]
2022-07-14 20:28 ` kernel test robot
2022-07-13 7:06 ` [PATCH v2 07/12] locking/qspinlock: remove arch qspinlock_paravirt.h includes Nicholas Piggin
2022-07-14 13:14 ` kernel test robot
2022-07-14 16:21 ` kernel test robot
2022-07-13 7:07 ` [PATCH v2 08/12] locking/qspinlock: stop renaming queued_spin_lock_slowpath to native_queued_spin_lock_slowpath Nicholas Piggin
2022-07-13 7:07 ` [PATCH v2 09/12] locking/qspinlock: rename __pv_init_lock_hash to pv_spinlocks_init Nicholas Piggin
2022-07-13 7:07 ` [PATCH v2 10/12] locking/qspinlock: paravirt use simple trylock in case idx overflows Nicholas Piggin
2022-07-13 7:07 ` [PATCH v2 11/12] locking/qspinlock: separate pv_wait_node from the non-paravirt path Nicholas Piggin
2022-07-13 7:07 ` [PATCH v2 12/12] locking/qspinlock: simplify pv_wait_head_or_lock calling scheme Nicholas Piggin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=202207150022.DkhjTAWE-lkp@intel.com \
--to=lkp@intel.com \
--cc=boqun.feng@gmail.com \
--cc=kbuild-all@lists.01.org \
--cc=linux-kernel@vger.kernel.org \
--cc=longman@redhat.com \
--cc=mingo@redhat.com \
--cc=npiggin@gmail.com \
--cc=will@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.