aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/rcu/rcutorture.c254
1 files changed, 135 insertions, 119 deletions
diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c
index 17f480129a78..bcc33bb8d9a6 100644
--- a/kernel/rcu/rcutorture.c
+++ b/kernel/rcu/rcutorture.c
@@ -1650,15 +1650,70 @@ static void rcu_torture_fwd_cb_cr(struct rcu_head *rhp)
1650 spin_unlock(&rcu_fwd_lock); 1650 spin_unlock(&rcu_fwd_lock);
1651} 1651}
1652 1652
1653/* Carry out grace-period forward-progress testing. */ 1653/* Carry out need_resched()/cond_resched() forward-progress testing. */
1654static int rcu_torture_fwd_prog(void *args) 1654static void rcu_torture_fwd_prog_nr(int *tested, int *tested_tries)
1655{ 1655{
1656 unsigned long cver; 1656 unsigned long cver;
1657 unsigned long dur; 1657 unsigned long dur;
1658 struct fwd_cb_state fcs; 1658 struct fwd_cb_state fcs;
1659 unsigned long gps; 1659 unsigned long gps;
1660 int i;
1661 int idx; 1660 int idx;
1661 int sd;
1662 int sd4;
1663 bool selfpropcb = false;
1664 unsigned long stopat;
1665 static DEFINE_TORTURE_RANDOM(trs);
1666
1667 if (cur_ops->call && cur_ops->sync && cur_ops->cb_barrier) {
1668 init_rcu_head_on_stack(&fcs.rh);
1669 selfpropcb = true;
1670 }
1671
1672 /* Tight loop containing cond_resched(). */
1673 if (selfpropcb) {
1674 WRITE_ONCE(fcs.stop, 0);
1675 cur_ops->call(&fcs.rh, rcu_torture_fwd_prog_cb);
1676 }
1677 cver = READ_ONCE(rcu_torture_current_version);
1678 gps = cur_ops->get_gp_seq();
1679 sd = cur_ops->stall_dur() + 1;
1680 sd4 = (sd + fwd_progress_div - 1) / fwd_progress_div;
1681 dur = sd4 + torture_random(&trs) % (sd - sd4);
1682 rcu_fwd_startat = jiffies;
1683 stopat = rcu_fwd_startat + dur;
1684 while (time_before(jiffies, stopat) && !torture_must_stop()) {
1685 idx = cur_ops->readlock();
1686 udelay(10);
1687 cur_ops->readunlock(idx);
1688 if (!fwd_progress_need_resched || need_resched())
1689 cond_resched();
1690 }
1691 (*tested_tries)++;
1692 if (!time_before(jiffies, stopat) && !torture_must_stop()) {
1693 (*tested)++;
1694 cver = READ_ONCE(rcu_torture_current_version) - cver;
1695 gps = rcutorture_seq_diff(cur_ops->get_gp_seq(), gps);
1696 WARN_ON(!cver && gps < 2);
1697 pr_alert("%s: Duration %ld cver %ld gps %ld\n", __func__, dur, cver, gps);
1698 }
1699 if (selfpropcb) {
1700 WRITE_ONCE(fcs.stop, 1);
1701 cur_ops->sync(); /* Wait for running CB to complete. */
1702 cur_ops->cb_barrier(); /* Wait for queued callbacks. */
1703 }
1704
1705 if (selfpropcb) {
1706 WARN_ON(READ_ONCE(fcs.stop) != 2);
1707 destroy_rcu_head_on_stack(&fcs.rh);
1708 }
1709}
1710
1711/* Carry out call_rcu() forward-progress testing. */
1712static void rcu_torture_fwd_prog_cr(void)
1713{
1714 unsigned long cver;
1715 unsigned long gps;
1716 int i;
1662 int j; 1717 int j;
1663 long n_launders; 1718 long n_launders;
1664 long n_launders_cb_snap; 1719 long n_launders_cb_snap;
@@ -1667,136 +1722,97 @@ static int rcu_torture_fwd_prog(void *args)
1667 long n_max_gps; 1722 long n_max_gps;
1668 struct rcu_fwd_cb *rfcp; 1723 struct rcu_fwd_cb *rfcp;
1669 struct rcu_fwd_cb *rfcpn; 1724 struct rcu_fwd_cb *rfcpn;
1670 int sd;
1671 int sd4;
1672 bool selfpropcb = false;
1673 unsigned long stopat; 1725 unsigned long stopat;
1674 unsigned long stoppedat; 1726 unsigned long stoppedat;
1727
1728 /* Loop continuously posting RCU callbacks. */
1729 WRITE_ONCE(rcu_fwd_cb_nodelay, true);
1730 cur_ops->sync(); /* Later readers see above write. */
1731 rcu_fwd_startat = jiffies;
1732 stopat = rcu_fwd_startat + MAX_FWD_CB_JIFFIES;
1733 n_launders = 0;
1734 n_launders_cb = 0;
1735 n_launders_sa = 0;
1736 n_max_cbs = 0;
1737 n_max_gps = 0;
1738 for (i = 0; i < ARRAY_SIZE(n_launders_hist); i++)
1739 n_launders_hist[i] = 0;
1740 cver = READ_ONCE(rcu_torture_current_version);
1741 gps = cur_ops->get_gp_seq();
1742 while (time_before(jiffies, stopat) && !torture_must_stop()) {
1743 rfcp = READ_ONCE(rcu_fwd_cb_head);
1744 rfcpn = NULL;
1745 if (rfcp)
1746 rfcpn = READ_ONCE(rfcp->rfc_next);
1747 if (rfcpn) {
1748 if (rfcp->rfc_gps >= MIN_FWD_CB_LAUNDERS &&
1749 ++n_max_gps >= MIN_FWD_CBS_LAUNDERED)
1750 break;
1751 rcu_fwd_cb_head = rfcpn;
1752 n_launders++;
1753 n_launders_sa++;
1754 } else {
1755 rfcp = kmalloc(sizeof(*rfcp), GFP_KERNEL);
1756 if (WARN_ON_ONCE(!rfcp)) {
1757 schedule_timeout_interruptible(1);
1758 continue;
1759 }
1760 n_max_cbs++;
1761 n_launders_sa = 0;
1762 rfcp->rfc_gps = 0;
1763 }
1764 cur_ops->call(&rfcp->rh, rcu_torture_fwd_cb_cr);
1765 cond_resched();
1766 }
1767 stoppedat = jiffies;
1768 n_launders_cb_snap = READ_ONCE(n_launders_cb);
1769 cver = READ_ONCE(rcu_torture_current_version) - cver;
1770 gps = rcutorture_seq_diff(cur_ops->get_gp_seq(), gps);
1771 cur_ops->cb_barrier(); /* Wait for callbacks to be invoked. */
1772 for (;;) {
1773 rfcp = rcu_fwd_cb_head;
1774 if (!rfcp)
1775 break;
1776 rcu_fwd_cb_head = rfcp->rfc_next;
1777 kfree(rfcp);
1778 }
1779 rcu_fwd_cb_tail = &rcu_fwd_cb_head;
1780 WRITE_ONCE(rcu_fwd_cb_nodelay, false);
1781 if (!torture_must_stop()) {
1782 WARN_ON(n_max_gps < MIN_FWD_CBS_LAUNDERED);
1783 pr_alert("%s Duration %lu barrier: %lu pending %ld n_launders: %ld n_launders_sa: %ld n_max_gps: %ld n_max_cbs: %ld cver %ld gps %ld\n",
1784 __func__,
1785 stoppedat - rcu_fwd_startat, jiffies - stoppedat,
1786 n_launders + n_max_cbs - n_launders_cb_snap,
1787 n_launders, n_launders_sa,
1788 n_max_gps, n_max_cbs, cver, gps);
1789 for (i = ARRAY_SIZE(n_launders_hist) - 1; i > 0; i--)
1790 if (n_launders_hist[i] > 0)
1791 break;
1792 pr_alert("Callback-invocation histogram:");
1793 for (j = 0; j <= i; j++)
1794 pr_cont(" %ds: %ld", j + 1, n_launders_hist[j]);
1795 pr_cont("\n");
1796 }
1797}
1798
1799/* Carry out grace-period forward-progress testing. */
1800static int rcu_torture_fwd_prog(void *args)
1801{
1675 int tested = 0; 1802 int tested = 0;
1676 int tested_tries = 0; 1803 int tested_tries = 0;
1677 static DEFINE_TORTURE_RANDOM(trs);
1678 1804
1679 VERBOSE_TOROUT_STRING("rcu_torture_fwd_progress task started"); 1805 VERBOSE_TOROUT_STRING("rcu_torture_fwd_progress task started");
1680 if (!IS_ENABLED(CONFIG_SMP) || !IS_ENABLED(CONFIG_RCU_BOOST)) 1806 if (!IS_ENABLED(CONFIG_SMP) || !IS_ENABLED(CONFIG_RCU_BOOST))
1681 set_user_nice(current, MAX_NICE); 1807 set_user_nice(current, MAX_NICE);
1682 if (cur_ops->call && cur_ops->sync && cur_ops->cb_barrier) {
1683 init_rcu_head_on_stack(&fcs.rh);
1684 selfpropcb = true;
1685 }
1686 do { 1808 do {
1687 schedule_timeout_interruptible(fwd_progress_holdoff * HZ); 1809 schedule_timeout_interruptible(fwd_progress_holdoff * HZ);
1688 1810 rcu_torture_fwd_prog_nr(&tested, &tested_tries);
1689 /* Tight loop containing cond_resched(). */ 1811 rcu_torture_fwd_prog_cr();
1690 if (selfpropcb) {
1691 WRITE_ONCE(fcs.stop, 0);
1692 cur_ops->call(&fcs.rh, rcu_torture_fwd_prog_cb);
1693 }
1694 cver = READ_ONCE(rcu_torture_current_version);
1695 gps = cur_ops->get_gp_seq();
1696 sd = cur_ops->stall_dur() + 1;
1697 sd4 = (sd + fwd_progress_div - 1) / fwd_progress_div;
1698 dur = sd4 + torture_random(&trs) % (sd - sd4);
1699 rcu_fwd_startat = jiffies;
1700 stopat = rcu_fwd_startat + dur;
1701 while (time_before(jiffies, stopat) && !torture_must_stop()) {
1702 idx = cur_ops->readlock();
1703 udelay(10);
1704 cur_ops->readunlock(idx);
1705 if (!fwd_progress_need_resched || need_resched())
1706 cond_resched();
1707 }
1708 tested_tries++;
1709 if (!time_before(jiffies, stopat) && !torture_must_stop()) {
1710 tested++;
1711 cver = READ_ONCE(rcu_torture_current_version) - cver;
1712 gps = rcutorture_seq_diff(cur_ops->get_gp_seq(), gps);
1713 WARN_ON(!cver && gps < 2);
1714 pr_alert("%s: Duration %ld cver %ld gps %ld\n", __func__, dur, cver, gps);
1715 }
1716 if (selfpropcb) {
1717 WRITE_ONCE(fcs.stop, 1);
1718 cur_ops->sync(); /* Wait for running CB to complete. */
1719 cur_ops->cb_barrier(); /* Wait for queued callbacks. */
1720 }
1721
1722 /* Loop continuously posting RCU callbacks. */
1723 WRITE_ONCE(rcu_fwd_cb_nodelay, true);
1724 cur_ops->sync(); /* Later readers see above write. */
1725 rcu_fwd_startat = jiffies;
1726 stopat = rcu_fwd_startat + MAX_FWD_CB_JIFFIES;
1727 n_launders = 0;
1728 n_launders_cb = 0;
1729 n_launders_sa = 0;
1730 n_max_cbs = 0;
1731 n_max_gps = 0;
1732 for (i = 0; i < ARRAY_SIZE(n_launders_hist); i++)
1733 n_launders_hist[i] = 0;
1734 cver = READ_ONCE(rcu_torture_current_version);
1735 gps = cur_ops->get_gp_seq();
1736 while (time_before(jiffies, stopat) && !torture_must_stop()) {
1737 rfcp = READ_ONCE(rcu_fwd_cb_head);
1738 rfcpn = NULL;
1739 if (rfcp)
1740 rfcpn = READ_ONCE(rfcp->rfc_next);
1741 if (rfcpn) {
1742 if (rfcp->rfc_gps >= MIN_FWD_CB_LAUNDERS &&
1743 ++n_max_gps >= MIN_FWD_CBS_LAUNDERED)
1744 break;
1745 rcu_fwd_cb_head = rfcpn;
1746 n_launders++;
1747 n_launders_sa++;
1748 } else {
1749 rfcp = kmalloc(sizeof(*rfcp), GFP_KERNEL);
1750 if (WARN_ON_ONCE(!rfcp)) {
1751 schedule_timeout_interruptible(1);
1752 continue;
1753 }
1754 n_max_cbs++;
1755 n_launders_sa = 0;
1756 rfcp->rfc_gps = 0;
1757 }
1758 cur_ops->call(&rfcp->rh, rcu_torture_fwd_cb_cr);
1759 cond_resched();
1760 }
1761 stoppedat = jiffies;
1762 n_launders_cb_snap = READ_ONCE(n_launders_cb);
1763 cver = READ_ONCE(rcu_torture_current_version) - cver;
1764 gps = rcutorture_seq_diff(cur_ops->get_gp_seq(), gps);
1765 cur_ops->cb_barrier(); /* Wait for callbacks to be invoked. */
1766 for (;;) {
1767 rfcp = rcu_fwd_cb_head;
1768 if (!rfcp)
1769 break;
1770 rcu_fwd_cb_head = rfcp->rfc_next;
1771 kfree(rfcp);
1772 }
1773 rcu_fwd_cb_tail = &rcu_fwd_cb_head;
1774 WRITE_ONCE(rcu_fwd_cb_nodelay, false);
1775 if (!torture_must_stop()) {
1776 WARN_ON(n_max_gps < MIN_FWD_CBS_LAUNDERED);
1777 pr_alert("%s Duration %lu barrier: %lu pending %ld n_launders: %ld n_launders_sa: %ld n_max_gps: %ld n_max_cbs: %ld cver %ld gps %ld\n",
1778 __func__,
1779 stoppedat - rcu_fwd_startat,
1780 jiffies - stoppedat,
1781 n_launders + n_max_cbs - n_launders_cb_snap,
1782 n_launders, n_launders_sa,
1783 n_max_gps, n_max_cbs, cver, gps);
1784 for (i = ARRAY_SIZE(n_launders_hist) - 1; i > 0; i--)
1785 if (n_launders_hist[i] > 0)
1786 break;
1787 pr_alert("Callback-invocation histogram:");
1788 for (j = 0; j <= i; j++)
1789 pr_cont(" %ds: %ld", j + 1, n_launders_hist[j]);
1790 pr_cont("\n");
1791 }
1792 1812
1793 /* Avoid slow periods, better to test when busy. */ 1813 /* Avoid slow periods, better to test when busy. */
1794 stutter_wait("rcu_torture_fwd_prog"); 1814 stutter_wait("rcu_torture_fwd_prog");
1795 } while (!torture_must_stop()); 1815 } while (!torture_must_stop());
1796 if (selfpropcb) {
1797 WARN_ON(READ_ONCE(fcs.stop) != 2);
1798 destroy_rcu_head_on_stack(&fcs.rh);
1799 }
1800 /* Short runs might not contain a valid forward-progress attempt. */ 1816 /* Short runs might not contain a valid forward-progress attempt. */
1801 WARN_ON(!tested && tested_tries >= 5); 1817 WARN_ON(!tested && tested_tries >= 5);
1802 pr_alert("%s: tested %d tested_tries %d\n", __func__, tested, tested_tries); 1818 pr_alert("%s: tested %d tested_tries %d\n", __func__, tested, tested_tries);