Changeset 853d613 in mainline for kernel/generic/src/synch/rcu.c


Ignore:
Timestamp:
2012-11-16T23:59:54Z (12 years ago)
Author:
Adam Hraska <adam.hraska+hos@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
25969ac
Parents:
9fe9d296
Message:

rcu: Fixed the race of smp_call sampling functions when accessing the pending reader cpu mask in A-RCU. Added some comments.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/synch/rcu.c

    r9fe9d296 r853d613  
    937937       
    938938        bool locked = RCU_CNT_INC <= THE->rcu_nesting;
     939        /* smp_call machinery makes the most current _rcu_cur_gp visible. */
    939940        bool passed_qs = (CPU->rcu.last_seen_gp == _rcu_cur_gp);
    940941               
     
    959960        ASSERT(interrupts_disabled());
    960961
     962        /*
     963         * In order not to worry about NMI seeing rcu_nesting change work
     964         * with a local copy.
     965         */
     966        size_t nesting_cnt = ACCESS_ONCE(THE->rcu_nesting);
     967       
    961968        /* Preempted a reader critical section for the first time. */
    962         if (rcu_read_locked() && !(THE->rcu_nesting & RCU_WAS_PREEMPTED)) {
    963                 THE->rcu_nesting |= RCU_WAS_PREEMPTED;
     969        if (RCU_CNT_INC <= nesting_cnt && !(nesting_cnt & RCU_WAS_PREEMPTED)) {
     970                nesting_cnt |= RCU_WAS_PREEMPTED;
    964971                note_preempted_reader();
    965972        }
    966973       
    967974        /* Save the thread's nesting count when it is not running. */
    968         THREAD->rcu.nesting_cnt = THE->rcu_nesting;
    969 
    970         /* Clear rcu_nesting only after noting that a thread was preempted. */
    971         compiler_barrier();
    972         THE->rcu_nesting = 0;
     975        THREAD->rcu.nesting_cnt = nesting_cnt;
     976        ACCESS_ONCE(THE->rcu_nesting) = 0;
    973977
    974978        if (CPU->rcu.last_seen_gp != _rcu_cur_gp) {
     
    976980                 * Contain any memory accesses of old readers before announcing a QS.
    977981                 * Also make changes from the previous GP visible to this cpu.
     982                 * Moreover it separates writing to last_seen_gp from
     983                 * note_preempted_reader().
    978984                 */
    979985                memory_barrier();
    980986                /*
    981                 * The preempted reader has been noted globally. There are therefore
    982                 * no readers running on this cpu so this is a quiescent state.
    983                 */
     987                 * The preempted reader has been noted globally. There are therefore
     988                 * no readers running on this cpu so this is a quiescent state.
     989                 *
     990                 * Reading the multiword _rcu_cur_gp non-atomically is benign.
     991                 * At worst, the read value will be different from the actual value.
     992                 * As a result, both the detector and this cpu will believe
     993                 * this cpu has not yet passed a QS although it really did.
     994                 */
    984995                CPU->rcu.last_seen_gp = _rcu_cur_gp;
    985996        }
    986997
    987998        /*
    988          * Forcefully associate the reclaime with the highest priority
     999         * Forcefully associate the reclaimer with the highest priority
    9891000         * even if preempted due to its time slice running out.
    9901001         */
     
    15621573                 * _rcu_cur_gp is modified by local detector thread only.
    15631574                 * Therefore, it is up-to-date even without a lock.
     1575                 *
     1576                 * cpu.last_seen_gp may not be up-to-date. At worst, we will
     1577                 * unnecessarily sample its last_seen_gp with a smp_call.
    15641578                 */
    15651579                bool cpu_acked_gp = (cpus[cpu_id].rcu.last_seen_gp == _rcu_cur_gp);
     
    15781592}
    15791593
    1580 /** Invokes sample_local_cpu(arg) on each cpu of reader_cpus. */
     1594/** Serially invokes sample_local_cpu(arg) on each cpu of reader_cpus. */
    15811595static void sample_cpus(cpu_mask_t *reader_cpus, void *arg)
    15821596{
    1583         const size_t max_conconcurrent_calls = 16;
    1584         smp_call_t call[max_conconcurrent_calls];
    1585         size_t outstanding_calls = 0;
    1586        
    15871597        cpu_mask_for_each(*reader_cpus, cpu_id) {
    1588                 smp_call_async(cpu_id, sample_local_cpu, arg, &call[outstanding_calls]);
    1589                 ++outstanding_calls;
     1598                smp_call(cpu_id, sample_local_cpu, arg);
    15901599
    15911600                /* Update statistic. */
    15921601                if (CPU->id != cpu_id)
    15931602                        ++rcu.stat_smp_call_cnt;
    1594                
    1595                 if (outstanding_calls == max_conconcurrent_calls) {
    1596                         for (size_t k = 0; k < outstanding_calls; ++k) {
    1597                                 smp_call_wait(&call[k]);
    1598                         }
    1599                        
    1600                         outstanding_calls = 0;
    1601                 }
    1602         }
    1603        
    1604         for (size_t k = 0; k < outstanding_calls; ++k) {
    1605                 smp_call_wait(&call[k]);
    16061603        }
    16071604}
Note: See TracChangeset for help on using the changeset viewer.