Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tools/memory-model: Add documentation about SRCU read-side critical sections

Expand the discussion of SRCU and its read-side critical sections in
the Linux Kernel Memory Model documentation file explanation.txt. The
new material discusses recent changes to the memory model made in
commit 6cd244c87428 ("tools/memory-model: Provide exact SRCU
semantics").

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Co-developed-by: Joel Fernandes (Google) <joel@joelfernandes.org>
Signed-off-by: Joel Fernandes (Google) <joel@joelfernandes.org>
Reviewed-by: Akira Yokosawa <akiyks@gmail.com>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Boqun Feng <boqun.feng@gmail.com>
Cc: Jade Alglave <j.alglave@ucl.ac.uk>
Cc: Jonas Oberhauser <jonas.oberhauser@huawei.com>
Cc: Luc Maranget <luc.maranget@inria.fr>
Cc: "Paul E. McKenney" <paulmck@linux.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
CC: Will Deacon <will@kernel.org>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>

authored by

Alan Stern and committed by
Paul E. McKenney
de041805 762e9357

+167 -11
+167 -11
tools/memory-model/Documentation/explanation.txt
··· 28 28 20. THE HAPPENS-BEFORE RELATION: hb 29 29 21. THE PROPAGATES-BEFORE RELATION: pb 30 30 22. RCU RELATIONS: rcu-link, rcu-gp, rcu-rscsi, rcu-order, rcu-fence, and rb 31 - 23. LOCKING 32 - 24. PLAIN ACCESSES AND DATA RACES 33 - 25. ODDS AND ENDS 31 + 23. SRCU READ-SIDE CRITICAL SECTIONS 32 + 24. LOCKING 33 + 25. PLAIN ACCESSES AND DATA RACES 34 + 26. ODDS AND ENDS 34 35 35 36 36 37 ··· 1849 1848 before it does, and the critical section in P2 both starts after P1's 1850 1849 grace period does and ends after it does. 1851 1850 1852 - Addendum: The LKMM now supports SRCU (Sleepable Read-Copy-Update) in 1853 - addition to normal RCU. The ideas involved are much the same as 1854 - above, with new relations srcu-gp and srcu-rscsi added to represent 1855 - SRCU grace periods and read-side critical sections. There is a 1856 - restriction on the srcu-gp and srcu-rscsi links that can appear in an 1857 - rcu-order sequence (the srcu-rscsi links must be paired with srcu-gp 1858 - links having the same SRCU domain with proper nesting); the details 1859 - are relatively unimportant. 1851 + The LKMM supports SRCU (Sleepable Read-Copy-Update) in addition to 1852 + normal RCU. The ideas involved are much the same as above, with new 1853 + relations srcu-gp and srcu-rscsi added to represent SRCU grace periods 1854 + and read-side critical sections. However, there are some significant 1855 + differences between RCU read-side critical sections and their SRCU 1856 + counterparts, as described in the next section. 1857 + 1858 + 1859 + SRCU READ-SIDE CRITICAL SECTIONS 1860 + -------------------------------- 1861 + 1862 + The LKMM uses the srcu-rscsi relation to model SRCU read-side critical 1863 + sections. They differ from RCU read-side critical sections in the 1864 + following respects: 1865 + 1866 + 1. Unlike the analogous RCU primitives, synchronize_srcu(), 1867 + srcu_read_lock(), and srcu_read_unlock() take a pointer to a 1868 + struct srcu_struct as an argument. This structure is called 1869 + an SRCU domain, and calls linked by srcu-rscsi must have the 1870 + same domain. Read-side critical sections and grace periods 1871 + associated with different domains are independent of one 1872 + another; the SRCU version of the RCU Guarantee applies only 1873 + to pairs of critical sections and grace periods having the 1874 + same domain. 1875 + 1876 + 2. srcu_read_lock() returns a value, called the index, which must 1877 + be passed to the matching srcu_read_unlock() call. Unlike 1878 + rcu_read_lock() and rcu_read_unlock(), an srcu_read_lock() 1879 + call does not always have to match the next unpaired 1880 + srcu_read_unlock(). In fact, it is possible for two SRCU 1881 + read-side critical sections to overlap partially, as in the 1882 + following example (where s is an srcu_struct and idx1 and idx2 1883 + are integer variables): 1884 + 1885 + idx1 = srcu_read_lock(&s); // Start of first RSCS 1886 + idx2 = srcu_read_lock(&s); // Start of second RSCS 1887 + srcu_read_unlock(&s, idx1); // End of first RSCS 1888 + srcu_read_unlock(&s, idx2); // End of second RSCS 1889 + 1890 + The matching is determined entirely by the domain pointer and 1891 + index value. By contrast, if the calls had been 1892 + rcu_read_lock() and rcu_read_unlock() then they would have 1893 + created two nested (fully overlapping) read-side critical 1894 + sections: an inner one and an outer one. 1895 + 1896 + 3. The srcu_down_read() and srcu_up_read() primitives work 1897 + exactly like srcu_read_lock() and srcu_read_unlock(), except 1898 + that matching calls don't have to execute on the same CPU. 1899 + (The names are meant to be suggestive of operations on 1900 + semaphores.) Since the matching is determined by the domain 1901 + pointer and index value, these primitives make it possible for 1902 + an SRCU read-side critical section to start on one CPU and end 1903 + on another, so to speak. 1904 + 1905 + In order to account for these properties of SRCU, the LKMM models 1906 + srcu_read_lock() as a special type of load event (which is 1907 + appropriate, since it takes a memory location as argument and returns 1908 + a value, just as a load does) and srcu_read_unlock() as a special type 1909 + of store event (again appropriate, since it takes as arguments a 1910 + memory location and a value). These loads and stores are annotated as 1911 + belonging to the "srcu-lock" and "srcu-unlock" event classes 1912 + respectively. 1913 + 1914 + This approach allows the LKMM to tell whether two events are 1915 + associated with the same SRCU domain, simply by checking whether they 1916 + access the same memory location (i.e., they are linked by the loc 1917 + relation). It also gives a way to tell which unlock matches a 1918 + particular lock, by checking for the presence of a data dependency 1919 + from the load (srcu-lock) to the store (srcu-unlock). For example, 1920 + given the situation outlined earlier (with statement labels added): 1921 + 1922 + A: idx1 = srcu_read_lock(&s); 1923 + B: idx2 = srcu_read_lock(&s); 1924 + C: srcu_read_unlock(&s, idx1); 1925 + D: srcu_read_unlock(&s, idx2); 1926 + 1927 + the LKMM will treat A and B as loads from s yielding values saved in 1928 + idx1 and idx2 respectively. Similarly, it will treat C and D as 1929 + though they stored the values from idx1 and idx2 in s. The end result 1930 + is much as if we had written: 1931 + 1932 + A: idx1 = READ_ONCE(s); 1933 + B: idx2 = READ_ONCE(s); 1934 + C: WRITE_ONCE(s, idx1); 1935 + D: WRITE_ONCE(s, idx2); 1936 + 1937 + except for the presence of the special srcu-lock and srcu-unlock 1938 + annotations. You can see at once that we have A ->data C and 1939 + B ->data D. These dependencies tell the LKMM that C is the 1940 + srcu-unlock event matching srcu-lock event A, and D is the 1941 + srcu-unlock event matching srcu-lock event B. 1942 + 1943 + This approach is admittedly a hack, and it has the potential to lead 1944 + to problems. For example, in: 1945 + 1946 + idx1 = srcu_read_lock(&s); 1947 + srcu_read_unlock(&s, idx1); 1948 + idx2 = srcu_read_lock(&s); 1949 + srcu_read_unlock(&s, idx2); 1950 + 1951 + the LKMM will believe that idx2 must have the same value as idx1, 1952 + since it reads from the immediately preceding store of idx1 in s. 1953 + Fortunately this won't matter, assuming that litmus tests never do 1954 + anything with SRCU index values other than pass them to 1955 + srcu_read_unlock() or srcu_up_read() calls. 1956 + 1957 + However, sometimes it is necessary to store an index value in a 1958 + shared variable temporarily. In fact, this is the only way for 1959 + srcu_down_read() to pass the index it gets to an srcu_up_read() call 1960 + on a different CPU. In more detail, we might have soething like: 1961 + 1962 + struct srcu_struct s; 1963 + int x; 1964 + 1965 + P0() 1966 + { 1967 + int r0; 1968 + 1969 + A: r0 = srcu_down_read(&s); 1970 + B: WRITE_ONCE(x, r0); 1971 + } 1972 + 1973 + P1() 1974 + { 1975 + int r1; 1976 + 1977 + C: r1 = READ_ONCE(x); 1978 + D: srcu_up_read(&s, r1); 1979 + } 1980 + 1981 + Assuming that P1 executes after P0 and does read the index value 1982 + stored in x, we can write this (using brackets to represent event 1983 + annotations) as: 1984 + 1985 + A[srcu-lock] ->data B[once] ->rf C[once] ->data D[srcu-unlock]. 1986 + 1987 + The LKMM defines a carry-srcu-data relation to express this pattern; 1988 + it permits an arbitrarily long sequence of 1989 + 1990 + data ; rf 1991 + 1992 + pairs (that is, a data link followed by an rf link) to occur between 1993 + an srcu-lock event and the final data dependency leading to the 1994 + matching srcu-unlock event. carry-srcu-data is complicated by the 1995 + need to ensure that none of the intermediate store events in this 1996 + sequence are instances of srcu-unlock. This is necessary because in a 1997 + pattern like the one above: 1998 + 1999 + A: idx1 = srcu_read_lock(&s); 2000 + B: srcu_read_unlock(&s, idx1); 2001 + C: idx2 = srcu_read_lock(&s); 2002 + D: srcu_read_unlock(&s, idx2); 2003 + 2004 + the LKMM treats B as a store to the variable s and C as a load from 2005 + that variable, creating an undesirable rf link from B to C: 2006 + 2007 + A ->data B ->rf C ->data D. 2008 + 2009 + This would cause carry-srcu-data to mistakenly extend a data 2010 + dependency from A to D, giving the impression that D was the 2011 + srcu-unlock event matching A's srcu-lock. To avoid such problems, 2012 + carry-srcu-data does not accept sequences in which the ends of any of 2013 + the intermediate ->data links (B above) is an srcu-unlock event. 1860 2014 1861 2015 1862 2016 LOCKING