From dbf9e337b99125c7132073baeb3e0ded7bc2846f Mon Sep 17 00:00:00 2001 From: gatieme Date: Fri, 5 Aug 2016 11:47:17 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E4=BA=86README.md...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../01-description/03-zone/README.md | 35 + .../03-zone/images/zone_x86_32.png | Bin 0 -> 31401 bytes .../01-description/04-page/README.md | 118 ++- .../01-description/04-page/images/flags.png | Bin 0 -> 6876 bytes .../01-description/04-page/mm_types.h | 620 +++++++++++++++ .../01-description/04-page/pageflags.h | 720 ++++++++++++++++++ 6 files changed, 1491 insertions(+), 2 deletions(-) create mode 100644 study/kernel/02-memory/01-description/03-zone/images/zone_x86_32.png create mode 100644 study/kernel/02-memory/01-description/04-page/images/flags.png create mode 100644 study/kernel/02-memory/01-description/04-page/mm_types.h create mode 100644 study/kernel/02-memory/01-description/04-page/pageflags.h diff --git a/study/kernel/02-memory/01-description/03-zone/README.md b/study/kernel/02-memory/01-description/03-zone/README.md index 00af446..673f986 100644 --- a/study/kernel/02-memory/01-description/03-zone/README.md +++ b/study/kernel/02-memory/01-description/03-zone/README.md @@ -834,3 +834,38 @@ x86的系统中, find_max_pfn函数通过读取e820表获得最高的page frame min_low_pfn, max_pfn和max_low_pfn这3个值,也要用于对高端内存(high memory)的起止位置的计算。在arch/i386/mm/init.c文件中会对类似的highstart_pfn和highend_pfn变量作初始化。这些变量用于对高端内存页面的分配。后面将描述。 + +# +------- + +在linux中,内核也不是对所有物理内存都一视同仁,内核而是把页分为不同的区, 使用区来对具有相似特性的页进行分组. + +Linux必须处理如下两种硬件存在缺陷而引起的内存寻址问题: + +1. 一些硬件只能用某些特定的内存地址来执行DMA + +2. 一些体系结构其内存的物理寻址范围比虚拟寻址范围大的多。这样,就有一些内存不能永久地映射在内核空间上。 + +为了解决这些制约条件,Linux使用了三种区: + +1. ZONE_DMA : 这个区包含的页用来执行DMA操作。 + +2. ZONE_NOMAL : 这个区包含的都是能正常映射的页。 + +3. ZONE_HIGHEM : 这个区包"高端内存",其中的页能不永久地映射到内核地址空间 + +而为了兼容一些设备的热插拔支持以及内存碎片化的处理, 内核也引入一些逻辑上的内存区. + +1. ZONE_MOVABLE : 内核定义了一个伪内存域ZONE_MOVABLE, 在防止物理内存碎片的机制memory migration中需要使用该内存域. 供防止物理内存碎片的极致使用 + +2. ZONE_DEVICE : 为支持热插拔设备而分配的Non Volatile Memory非易失性内存 + +区的实际使用与体系结构是相关的。linux把系统的内存结点划分区, 一个区包含了若干个内存页面, 形成不同的内存池,这样就可以根据用途进行分配了 + +需要说明的是,区的划分没有任何物理意义, 只不过是内核为了管理页而采取的一种逻辑上的分组. 尽管某些分配可能需要从特定的区中获得页, 但这并不是说, 某种用途的内存一定要从对应的区来获取,如果这种可供分配的资源不够用了,内核就会占用其他可用去的内存. + + +下表给出每个区及其在X86上所占的列表 + + +![每个区及其在X86上所占的列表](./images/zone_x86_32.png) diff --git a/study/kernel/02-memory/01-description/03-zone/images/zone_x86_32.png b/study/kernel/02-memory/01-description/03-zone/images/zone_x86_32.png new file mode 100644 index 0000000000000000000000000000000000000000..f6edd78786b09f0a76961f18938b58baabdc8095 GIT binary patch literal 31401 zcmYhi18^nH`~JO~%?2CWwr!k^oosB|wv&yuv2EM7Pi))9iSzDO{eR!*t*ZuoRaehl z)l)q^pSwHkm#i4v59}XbzI=g`5EoYX@&yd+@4X=u#NYFYgBkYU%U4GQF~KiYK-`nR z1#nXV8G$cfYGYvD^uPZtL)(d~JAU~B-~aFUI&52F^yP~Ozl5-WlAF%OyQ`Xtdec?R zCE$_(ly$d$x9<4J)tw34YzJLlZY*ppptU(L9%ZnE`-#JYfdvo-7=4HS5jROmoEHj? zgeD(LDc}I)f)>AZ9G0r7n6_4SRaVtFbKfkM+%nfx7B6b);Um*9Vn`c$jHz&vPH2r-rt=+Phs*Ep7=ueA4T$B z6m-@mrJYh!D>o_X2pB8lMd7`}dh5EdJVt&1O-@fWPw=q~-xyB&nSx(e&C4o_Ymcz< zw^TJh^4e$s3W!f_P`pRa$6q!kqgdya6t$Hlj77eqq18dmH_xy!va3%&5%QIJYIq(K zJflPQFC)I=#Tzz?4V~&L-`>e*jiy*zndRP{Kq<2MLWkN91$&rRSLau$@K<`ncCgkA zhrFJc%X_QJ2?yjaSV^wE5654b>`o{l$jAG(-4S)4^ z`FR`j$s19~UCWF0j1 z=jJ3iWY2YT1SnmFyFAd&;zOHbVr!h;Wb3&eu$mX0QMX*|U`s|Dt~bMe z;SQn%Q9`{fBVrmi@WUU85ZoOCJ}A09_hP)RH`|#%yMY8-+QDt(Xw0iGSk|)JBeOAX zj`fhml3jzn(;t46Yj7PriU{2ynXn&h*KkU)?t&pPo7y49^C%i!`(N*8-IfS0w%+1& z-|rZnn!nR$jGm-8po*GzIO3+ueJ1+8hAg@5#i(RVTe!{ATNmtX>YTp4_5nj+kLa zr&^^9evkQVZYO^>qNPWCZ}_Ne?WxDUHH_JFc|w&q$TRcKL|@YFH5pa8*G8twZt2b* zni$7*y&)nj49<$JRt$BB3FwJ|`$`1ntZJ9?Aoj7xfiunHkX5ioMJoK_Xm&*F^VzOm z@hG0#K$_GqwYk@Pw$7>kk!)_I8z$}hor`JMj?W=DU0Dw6!*Uy^gm5o~{HmiCtR5yv zR|edMKx7Z_8KwJH?YmF#;STo-JeVo)IJ~pC#ADF|etu-X^?$y|>3D8rOrK|?AUzRZ zlLTqitM`X|-hQR2topMAm;@8WI<+Zit4Qe!Fc>>qJ;`*+1Rp?pu2L3+wsr!!%xLI} zti&^0q;#cQbWc9JoPP-UQYU+U+ zxV#|jEI||$Bu7bQn^Wn# z&!X;oPPGA7wuLUQko#iulAI6g!uo4zURF$%r}Dy@wb6BMZAM(i8b(_vKQiKeMOjx) zQ4=!rLS{aZKUZzc>_Rc|CgaB6gxaR1{<3q0cHx1js3ok)UtjcP)vTl{zsu8%nw2p3 z&xgt>jT9y7D_x~U(O!^$49n`4thWqJ=EjCo)4ak*!SAsbc#m!wst3A3in_7~RzB<4449jqe zEOK#8urV^R2p@|Eg)EY3c||nhH-<+xoLmJS8}nuOj|ewn!}dm7HwUX2xY;H8GfC_E z$OUt%4=nG>MkU@@_q>K+ax7m4uQ2-sTm>0-``8H-1(no!{g+pNN&N5U$RZAG=ok@Q zaZs%5w<1R%U%kZ;g4-d6E&bFBvP+OS-)cN`oz|4C&nJF%#{;)*XD5h^nD9)+mZh<9 z_ZT%{WOb=`V4lf-v~77sT)TdP&fELGNkvgbNl?TZhp+7Ux^;pNE-?WuSs^zKCaY68 zFG~ulUS?IjqOUNrtmtxTQ3^WszOnh2CP!-#`%=>^*`1`PP^R93WQZPH?fuyL;u7^v zWOOmFXHfqGT-XfTQ6!$>`sg_7ulqsI`<)2S_j?a!o@DV`M73S9DnAVQ7`3_55qv=G z1ip0;li!Y7Hh2d{%V1;YUhsD^TsHf7vQKxDXQXxKWIB?kOh>7; zX)B~>H1EZ9d`+R#aScYzQD*<(1OsT)Q*KEM2I-^oq{ITGy=92d#9!kl9Yn zAO2K=&h)iZ-WRiwmu&o8gz69m=U4)DSZk{KEra$J(4%bpjV00kNh)BcP;W2L1kc zMvg|L=E(i}MBc&LH0O4B`!hHH^VE{tYky@*R!i^2S#OIO?V%#H*qcc(dQ)s`L&;%4 ztqt~7&`v>@uprje?WHCGi*M96fv#|QxY511+nju+>qiTcx1zR+cSFb?27`T{5gS2w zJ6^=NGm3CoH6=En(bx)*C2PKwoqX9%j)b{mu7kOFx3#+$ePt(V z`t@pRzV~sT&f!NKmw7`*D}n7GZBgvb4#aJLquXoa=kC@~`nJytGDeJ9?Rhgnt=SS+ z-EbDms#Ee^@OVn?Okzz1I>bwso#Cfw65U+yrN_He*3Om(A?4KTIMNdsk{g#3=UYli zWxdS%IXnnp2$K;Xb)$8hSXlJ6~P)LGnU)KX#GTm9kh`!X0p%gPB{ zc~S!ss0|bFF9%Hpn!KdP-)Ovi?S9d{`{f!QhR1eLXSpE>kP(UyN?jgGC5WG2Bza-+^W)h+oeD|7|F80 zd@0-w-uM`dRLA{ZMI^}|EthrSzMsjTCPU*tvU))_Uk@PoqU0VLrau6mpP>1ozH(sFisePcs-Ql2p~A+f#`Cy|l8n8NE24s^5}fmcsb+Ci9w;^D#2G zXF%?$HyP~dQ#jpAeN->xHy=Y4&kHzSb@~X9odKL^nS!G35k|n1**_)2{s1HaydKj*EogO)9MGN^hl3Ze1Fn^HK33d>fW!l(U> zkm8oYIO362_tEExo}g5BI~Fk>$cnM(#hBcX@=22f#A3e0~^dHUxJwM>$ zc(Eu;+H=GN!m7WuuT;R&KOT|rOZZyo5Pb6_mFqP6D z30kV3QA-FqFMonTa=VI2`fb8ConW7k$$}9kbT*u5wa}I*a0|`C-u(#4Un^Ho(i{us z%ZC0jj5`m%k*A@2^Z^!^v2^>&k*trXF4%5ijWfPG4{Uw&DMGSwy`$nLiykI8tRZ8~ zZVGF(O<6TlTg9$Xb8EK;1hIrhVvc4kZoy*fD^BD+rVF0b4!*D_>R$E?ak?aCT(@IL<~kG*Gcn_ zC)1nE(8AGX>{59-^L#9l2)l36Af=FlUDXP|g0(X2n(RfQ2GyGm;k>O8Lo;o(^{#xw zc{%`m27^o)Oa^z!Xf^A8A4I6u7{s#qOB^&bm^e;q$0)N57V#%&(^Pj4rW081xE&x9 zrNKPkzi%v)HApXr?>g{p+}}%>>9vIOM3<*N+lsEU9e)&g(1$xy!48^%Gs>C@A^UnzJDBRt6Qn=~zu zF)J~Nv<_Jsa&>tp8S%CwX%e+EaNz!inlLRtnjHPz|ELrIn{+#5g(8Sbd@X6IVDrR} z=tjkQ9gEh5u-cu6ycfwaw9|CWhb45$985keX7dLr!Z=q0NlSbxr2;GQh*9&2s(z`$ z@IuR3+BL*Zx9L2x(HQxtYBE>^8TsR9$HkKGq_1}!%xemDmW#2Y#C&VB>FJ&)j~w!& z3o{5Ioe@B{Z;(fBSSQk&oVCfnf~+NBl7Io}%po^H1cO1Ve?!r|r}|mNwYU>b+n&vj{;%JtQ$9iN10o9Gu!tlnJ$j=7HSpE4M zti_OegiNU`o+4(aObB`Kq%NLp zI{Z=T>!>EpjA_+SKV}1;5vUGn@Cp%uv#0Q}v3Aa)upS5wVoBwp4Ot+xJh+lDA!WAB zLUxvFoKbu5^XKE%vu(G0zfwZLWi3Cq#kiY-7KP^>4JA;9Xwe(8o=o00*PNAWVP#^V#<8?gx=TP+fnCD5}45owow2|DOqu(>cDC zn-4*iRBd9_LOt;zO`*vMwU?X4pCuh7eesk$@e9ev>3zpb|+VvrJLkz~~E6$G=4?R9xpBy4b zmGPsdp9tt#gU)L>Z!w=BUrFMluk^}Y8BXuT))#+2-bb)(1;||j$bb*f)?Ew>*~-)q zmaQv>7Ce{3^aqsx(JZ9}HR*y-B57mzq>0Vb>$#Zi4envZnw(zMudW^Jy6Ez|7hgJI z(7vHW_Mh@MRCFo+ZP)RPP?Rve7OqUnyM+nOyy#5S-98qaNC@pKD%G{nP0y5Rqg+Qq{sEBboSjw=C@Pf^1Br5K z7&6lqG%<%jemR3@kl|YEb*OQlK}L&s7!fkco;2~NWj7Tz96xl&HW@c@C4Ht|DY5%c zs-yGGpMfI&+D^~M2sh9cdp*VZ=)T_xVypd?g3oiv1+J`ZUiAUFn5wwfov+UTwYI7( zIFCNL#R35!Rx1U^nHLXFpA&%jK6rI)84Jfj(AMWYiU{Pf9(&X6=*R7rb|(lZ(THQI zF+Vg&x^U=uO<_sG!C>uvo+jjh;eW^LR=X6py8$0ZLvzPq@x9@{ zi#eEPYW?na$zx;YeXFSxuT?Xmv5=P{7Le}tOfb5rMd2&h_wAZFIp{7P@0=@E$ncef zcoO}tyxC>(qI^0igv-MVrp$PYYyZdhaVa%{!CECIJ8NTQ8Hr4 zX_Y-{`MLKk36orrO^IX;()BvzQ{(r{3Rqe^rXqP&}hRi6hbk(1@&QQcVq>rYBEdW zFkF}A&&RrC89Sg9=-L{Jn5V$<=Lg%RIzX4tt!;h`)Yc1A_e(xEJAx;stwj98FWeL? z&1rkifbKQ?rm2ic;tj)rMX0WKbzyb7J=JR4-shy>9J-gWGY)ZD>^FJF5W1mEhpE+U)A8dc3C$YDY9N^NSiabIZAE7QDmcu{d)=5X&h^l z9*}tPl+%$|1X(75?l)i-+EjdZ*9SLlVo4-I*`+?E5GJ|SA`1WY&CvZ90|T-9Or4L0 zBmIsk`AR%e@4x`4Too@5y0J%^}dvYH_v&M5z;BC*69NO3xsTr(dx$I;j2y6w0b~Ipfd_Rb) zo}+GV8fuR1POWAWDt(R^K~~Cw1a3dealq+ai+^ zG*|VEtW8?`eSD#pSVR!}j8YH6pofNQ*oX(WcV<`5CaqF2Uf)R2dK_?zuOf|1{yQ5o zAfewwGi6e*jmK-UPmmE#8OE{z?zhE!$EG1wck3livSQ!+wNFx}ytDlw821j6jaI%H zQFdp|Cte9zv#9gAq(!gd=)I99e?W;BPPe*y7_=C-NCN6a1uKFdk;Lp;7)6$zX_sY7 z22@uFrCE61w5p37C8Lk{Xy9iJy0;?%YYQ97@X4868KmUkB?W8B4*DOOTg|!xFEl%i zaqO@5J>gaz#jn@KtCV3<0H)t@<`E=0>#eAp7PUu^A}ZO7L(AnIK)$@*#q;;W{ymia&ZD?<%YCOJ zZFMk|$sWcj-jLd$gfW`BN{^_0TFh|b?4|c8py1!eT&Kw-V}F4Cp8)9KeMp9zonugNcE3I+cqlVZMq4T5@8 z^N=hp{?Byv^AiN``t~c4_`f8S5ADCq)bOmLB;S8#*SCKG;rW%Jmj0J5GZgqq1O`aT zQaJtpnRx#Ky85D2DE|HH|C2uf%)iKM?-LZ{{xh$>{0+zpGKX43mY8u}M^eWEHr72EqST>7{nLTPf*gsj8Abt-Jf&a&eDwStNms3+yc|@G&AhkJE#^a~W-GD%!;u2+G zRO`A#$7En0dX_A1?=xI=?bkLMmKIGV8SgDs+;u*7aou-A8)IepH5PC38xF5vhxUM; zDJ*}}$pk)WlKQ-;O$I!6R$IUyyGo98fXQe;BEYSn$D@qTM zK05<_@-LQmZiwl^Ww`EJpI(u%K;&6uLr!1GL!1Q);*3zorIu7hxhq{}z+2?Y-#G^$ zANZlk(YRMc(q_4N&~0L?cjUt6Vzn_5?2LWhbWPG!lh_s3t1jE;-`Mf!`iW4@z$56e zHXv}2O$RbAu2Fxhe%r9LoQbgXIf;O%TUWW+{CxgSaKSa)pVgh?{Ef}%#a3_eBVMcO zJ$wsc@oxVOe{%+ETj^3YbMOO$_pbU~!j%bRpwRl+@;vzac?rGrO-Eo`Q*7HEka+-V zby!AySRtq#y`q=X;YWAv2x*%bcS||WX|<*~U7KHSvZgpq1OBE+oS{cMZM%v&NdMIR z_yC~ip(u)g#E2JIzC*xclRn)De*4y->Z0FHd97J92aX0L%6XmG*>z-*eqFb zuiMneRqfwxJ2wEcV7e0ESurkiDVc(jg1k3j91;?(B4ZDj27B=mmFL+OkA#&$t`coN znJqM`p)zhib^2MJZGLy9Nh4Ql?~NsjDLFxt;acReQY0>8QtdfVpCCj~(#cX#eNfjf z+5GvFA}x6~xEdE(jaD`{N3Eh3I{CeQbH{KLB{ z=DNN7u+A(|{o#@Mn@GO-&31|PRL3XUL@5H@6wDEvJo4ojS&Z94;5i`W;iA|zmZb6_=5JJI@w~x`3a7jFIGk^Ej7Tluy)E0U2n`7>^5Giwl% zhh)?W&&R&uvi?>I9D8ba>%$#s+;vc%iQ15EGP^M%+JU_IipA^o649ozKN1hao%bHC zY%8XVqAL@kBMu7I6+o_H`|V}Ovlf8;^ExaLvr>12LQ0x5V`lWpj-wJZg}8s>SD6oK z6Aj7b)Pui<0$spsUc_>R3tWwOTKLQyAIe84v7tTuP_}KrsMNnG_PmMckkE(&JUUEO z;3X}$y*Lt!lMf1|RWR4-yGr-dXsil3>X6!aSWIMfroY?hJU!zNjd~EgK0e!%mB%&J zxkX!hNBDj$@XiZLonWJ=Ht@hF8{1y{ewbrH6cZ>eX$aVyBf+a%?Ots84nR7B!Ufov zo-VfE>S+sEo(Y4S7E>siI_E!_vJx`}&5F=HV~nS{RK{h*C?WwHepNyEj;`8-#f}y| zj|JQ2=biVZyL*sI(9kzd>CluW-mQ2&r zAWkhTtaRIh*-qJ8ir8m4riJBOAfy%}IO^7ZzmxN5^Y-$aBi$npeA)_U?0%;KKhJ;6&BzDxtR1f^J*Q(Klwn;0f2b++>21 zE*%)^wLbdO78>gaKBu}Y`iIC+BN^N!d-z%qig|#qrt)@qZ8^>!| z2U&l78-kcY`)8Yz%ypW4qWWGnf$)K+67CwA(Y{~W&7dY^)y4(mg zPvO*OXn7$#!05c5W}_gi55J8Brx(jO?0bOZwRxUkPFD!zvZ;x@5Jflh$s4}maaJt* z$VYSo; zwcqD;ZNAekBum~I2u(3%xBDaOkNadaf~sX+Dat_qkV#p-7FS7U0tc<&0A?}fem!+K z3cR7+J@Sl=XH87Uc%X|2+EY>d;QjmG%)OG%C5ddMwtw`6NL~B51lM-JB)jU3nKx5f z`P9t>JVcfhETcf^Z&yrwu?u^r+Midaq)3=oR6Cooot$JzQd5A!Wow2-Pp{V5w?Th? z>G8=g(b_)ZGce7Czex!k503}q)-+^3BxKMl7zdfEd}ixU#0jSzI3gzEOaG?(-^%bD z;rd&16c`|wq1l;5$0_6bPDI(sw_8^-_QDDqd}i2A=|~@rZ8o*_g!CR0qMWsd&EvV( z9<{dh)ghW0z>(8l6+Q%3poy>^)pV%~$r!+04V~}vG|98sRm2mr&|N4LDDjVTnfs#o zcq%#50NSZ0_;`y#AUEVxZ|i+ev%LDrNIwe2zu(zw!dq-CWo=2d9R{}3?1QTzH;wl{ zza4wsR;~u;M{r@bEO{$D$5esQhS~0$hI9y_oAvPd)5&2!@jx9xJzd4YmB|2|DuXNT z_URSlQ2z%koBakE#D&F#FK>^ReW&~G#L|nk58^+#HkgM(Z1x(LAQ4{kaqsL*8a-$a z`uQ3n9BW(_;a$?&kr3Sia`v(~kHtfKo)C$GymiS>0pne7r=s0)P>~3rStT_=Avq2i zbtdq&76;x_COnjbMg?aMOt>?geIJ27+iuU;aWSt@hVsH&eW24Rn@ArY>$u4!c> zu$)q%56)%EgRt`oUgm%_;H*2w6q1>P-xs1E5@^l|jj&!(mlg$2vZN}n$dnfzqf4bR zy?6KS>m;^+Tqu6i*%XH&A&k#gp>|~D)IWThZwKk;rC?H2!_YyM+yxYqBXIO8`OF!tLF}E+4I2#p>Vxv zp*L>isYwXx^{p_1y~iNAO?-{GsC%mBn(Q2sbda^IpFM$PLYp)2W^?t{n$d8GoKM5f z(rPsAvImzZ>HRd@oLD-8 zxntX#sLj=!uTv$MSI*cW1d3QpqdODtpIP) zc&FQIL^6V9y)=DZJH#^nT5&CS@x!qI6g}&G#JNfCf!h`<10?fQseagYav`yHg*S9p z6ErSuZaH=TlPCy2W|Vo_a@C(Em&9nhg5J>Rn%^#k5(SsHj^%-pu`-lH4D}}A=}m@| z@^N5iPD^o)d)-BApKJQ9flWzKO=ToL!O#kMw7cc*ZoTHU_dETo8)7EI>{O@Tybyk< zbV9GOsp^{naTuqUzazV%uwG5{E~RBt3YXs1Nx(szHs=eeJoC+U^_-_~0MxwBkRtN} zA2Hcwx)XAy;t6jUz;AV8#jA`0UwzeG3n;o{ugVs<DQVu|J-kU|+-4(P;X@+ax z8%6b{T6>`2|L86}e5WF2)WHdS$gobqZxz}TXOn1xWZZC&ocD*g&Bs$`-$L%*7CL9< z>`h(ELq2%Yuh$Ljah{0~T{9DZ&|4eQHY+>JsVQ80~0STFHTy{dx{?17il1@m3xV;!0J z7b=eo_&@~kTG;lTc2lb&y0$B!n1;Yxy#e9b?$8JBLU(?RBGiwIWup34+(D7N+T?Q8 zBDZ@b+>b}yD2s1^ABE)J^(?nIKPGHQa?^Ls&l~9gHu}&`f_y?wHFd{jKAr^l$~b>} zXy8F23~+PEJ8^5hkKMO9yPDy{u(U{W(Mz&62*$G6sdVrPsH((i8gaF(OZu%ND^@ zY64SYv7dt9S{aybYlpQQn@u)~?C@QD?T>opTCTeE=ei(}Fwu$+;A1y0aXWQL#|uxX ziMcLWJsC_C<52?7vPiT>Y&@x;OT+FNZ8NM$s7`H)$tVIcDekC}JGzescb;%(^%r1i z;Ca>yYyy6;D<&V0_RbfDftSp@S&jXelbEF424@;<&nn2~V<^hXy?-;Hg-3MCmu?Cs+jilP_A?-2s&s8_(M6aH?0SkYbs^pc z?~S`Dv-C})iRq4}zJZJV#9HT%rFGl>!VUt=O=LG8{MoM<%2=QWFKC3BEZ=Qw7vglcP>0TGM>oB@U&`Ih@4ymQI;XaO(4NTTL1oMuU6Mn3%@s4JLR{K^Pn)NY#hJPILD#QmbE_9?S5Rh*dz86T81`)PK)c(shhkJObW zy7C61V6PshJUJY$%fn0j{c~N*9%L26_o%i0z^Co2E1?Y|=^MlJwnXsKg5N=N35>)D zLo^=Hz{+b}2|QyU(~nX%{-aF4XOO2N1S1i=>j7!1z#*1NNB%fFJtom#o_)My1+xOhn(ZaLSA^P-7-O^^N7)%v?C;yD3rjko0++U z5$;iS0N2T?j%eL67z}>iByEQEb*9`)&%cd-9i$2U3vr@AoR#%)-*GB9|1$bKqoZLF zP6HFu!6C;)*hda|_Z3J2T|jhZ*TA6TQ46L$Dn_q|)O; zERw}QpKsO__MPT@3}_||O~P-%BPq?(@qB^}IW9iP47XQp30?aLvZLc{f1K|+p=wOH z4_8{P%L_0J)Y-K-7g-U)9?);^&yX6+?V^p%dFM%O1o0xAdbqF7NLBwdhIZvXyOOTfTAq3F&pHhZuff>L zQCPvb^0e|Kb8|EMB*NuKFDeQlNMa-F65}DWx^ltYHS?RD zuviWu;}kR{RBGnM;*RehJ(0E@G36|UBCXar(^dwTe~}ntNV{wD`Ng|a^EHH>Pm?T* zD`W-D=||%}4oq&MD_-PlOP9_3p#-9YsnhjV>LRkA{4*bIaz}WaGP*qt0!k zjJDguJJ#TK92kexg+_QKbEeZ^}L+aq|eDyXjBMNpYti8rfY(4la1{6ELl47?IOa*GGKLdKWef(?;Q|WVbp^mlE30>is>V`ihwkS0k>?>HR}BkdoB<(J2}t%mKh!7)FwW~UR6X1A({OsR1^Ad7PD>_wj; zgns9t67cq(99x}=4i#!oqG~1b27e2&&fGMEGNW9J%H7Uny21!)GB(E2atl z8Cg?*h%aAYiEXYPdz___J2j(ek-M*LPY_S~I0}%jjA=pg^zSJsOYU$UrTjC<$+nK? zNkrIYQuUPGDXAa`7E1)8vb-uFqDigjV6DmqkdGzt4?)TzCeDzaR8aSy6kgcl`p6>~ zCFkG-LW&c(Lak|OBZbpA>mAhuh% zALhzf^SsX)7gz@7wQgN)#AkOKsM%*n;tLqzH6^qkA{p!NNuNZS=&GIey7a|pnm^AG zF>R|0C`qzUt5^A#H6>p}*L>uURf3Q(FwBM_De(k(@M$t z7N%l|US9pd!B0iA$E3|fydOuQ4Bp(S#~ezN@7plz(&Z^N-lCSH5-qaVsa~r?Sxmp; zB}aC?sbON(4ln=a3x2^&Yv0D81Lh!azSpzAunB$x@ZhLoSNvP=Hk~Tc5kv1g9kVkd zrJ3HXv%|Iy?Ih+K_`Pa4Ajl6Ag*bcKP!_X_t)JxlYvWjOQZ;0uL-Jo{-4l}v#cP_= zs6<*onU|l}f{G?{Uzp4&a*;RAD9kwjzi$T#+L-QA*=rGfG{`wdJ>CF4Hf%G z*bH-r!I#to8`CH8w^-Czgm0IMD-8$L|F(2^;rkPCBK>NU68QN)ZMO^mh2mReZIUbh zk$ZsMKYIS{im=e*KXZ%h9~7sbQ65wI59j-n{KNTfkW>qb|C#hi|8Ra-l|s{h8mrt zP=JtUBYamu?eFr$S4*=Gt-bFVxk*;Y@a@~D*m5TEr-Zj(Es$kV^i2F}bBTr^94cz7 zaF6K3!m`KB+)gMTR2#2CK05`$eV)AUNh)^~!}}l9{&L``&m$qB44Xz7SW%-NSfydT zFL-$HPwT~xA=7PLnk`dHhA|>wa1GZz<6om(@j|Vi4k;jf>JOFTTqcrYObAF?-LJ=m z{R9m%>7JeJF|odFRqS6qULHk07NB(Kp)F=fBzO(>2lLdo8r1yB%u*G%e7CW@dypi^ zV%;I(13VtCn?s~FUP0GiQ3 zoFrnQp|#HBI`sx;ATYI(zPP@Z%5e*~j(kA1pPR|(3`SpeD>>Z>ideC6n!vm9o)`5U zCdr%EJpz2ZZr$kyn~IzJxO=%OdhdOK`TQVw^8J`hi+|=*7-d%gmDIjxlAXIe_D&s9 z@^8{}VqKZsL6`#9%Q1#`itRi9au0xI-t{dLm{-U3EkNMcFT}6-@SGm_B&79@7PqH4 ztW3C{Bs#b*_PvuJ-lbdRKx@Cp4$QX=?OK3cG>`IoIN)S=Zp-RxCX z|J4W)?ncMW4GbaWH8@2_hCO`ezyU=y=g7M{%)-f$o$H_1jq12L?g2ARcn*39yOB#m zSr?*#_44?%NS0sT$z}jKcmgz)<6V*I1zroKfvZ+Gljf=IOAjbWrhUWVg3jR%J3j3G z4T>@sC&g5c9|&_oxcphNlfU0bzLd%kEziaBRn4qdn&-9BW?J%Z;yTw3j}4_7-mX`f zYvNcI-Rr>m1A#4ExC3_eI`e^hgH)?$w`3H3+f;ILwCVv zoItkW_W_bqik$Nt>I+ygI_H@gCS=~JIJL#WYhmZpk)C zhhfRkcTN3P#YB*Ow((oD!jqZ5;IWPktPUjx-nrX~)jnHl-uHisO*AwNC^Gg~eL~Y8 zHOtAGeFI%v|<9mv!WJ z`xUKo&St*FO}JJXywPoXm4#8IhTu!#9u$YaYd5`i>6Q$S z38wlVM;8$m)=7re!Z)yI0ZAXiCXHh)Z>N?ul?m%5P&Nfaj*lZ>E1aB|?Ayg9SMI$S zg;mXwO*1B#HY=l|o0t~)m&B`69|b~=-5dfLJq=+8`{%a|{i08NtO6DGvrH9IHEs>P zxN4+e_`cz20ZkNm7%ST%XI@Fe?y3&WEJr{^kT>Bz(tF#kWeDEsfmfQ;Qim!kXs1^jLjpWjE3wUL43?6b@2dwyQguN=g2}|!L3hTAdWUKKxTWP^?*{#bdu&^ZoS0T3i|} zFVCl?!7jG;IHq+aq2|lpJ(mK%+M1A*0?2AfZy#1F*<{v>jV~fyNTEm#W_O9UnbUPd zCVv=wykp#{dG3E*m`vQ?S)}k+qQEOKhe3t={fPd(WF(HH3`koJOb$`DQRT zdU2Ugb%YxI>T(k{!$hys35+^R=JIp{1b^jdS(ug?mvMF4eED8I$vD*Q_GhM6wk&`x z^)p@fW)b+sX5M*bLrri7atA!)0BI6TG7z8HqRrOLpKWv8V zxHz+$E$^Na43(mYT{ldlEM5*4p0h*n5ZKSIWNEKHy1hQzPfP^`3Zl<9K|0pgCC}`H z;C|vFUH7vaP3i$n!Ib6RB=mqcrt7h#x84Ki1=1F z%zd(&#%Sa=8}Pxn4*c2L5Hvo=mxoNMb1O%B4Z1JlbrW|;KnUicv%9{>sJje1aei=by{1kA-DV})~8#JTV4K2({cGMu+ zEP-yU3ZmQTUu$Nz#svsYFm!EiMx3S>SLK8Sc-}i#wALH^j3d~X>=6zVwvga4&xd-h z8SNVbVINTAj5@#O8xq$)_L;RJ;+mqc79zxqY3=NJA*S;IwMHt6Uun?8Kf>Jt*nKD7 z=w9t^;SLKB9bY#r%%HxuX)TC)UMdH;giYe|22>-0_W1uUPif2K+f*IBAjoarrbaSp zXRNsySX%nVQ9n7cjt5LsSnw++C!4_Id+6Nte?hXFhdc64O39uoC=jDo^pwd+_BPW9 ztG9dO99}=KVQ(5>E6qq^keu1_(t8W_ArjtJ$6H|<<@H*Z)|DW2ad|AkoARyQ1`t#f zGxqsSRvopZq{(`;pr8+-FXPD(mg_(*(Nq(8gb%FgHm5lU>jHQSQ$l(@tT=JUqZ-yoA(zAY^r94(@xoWh zp*O`f(N#fJy(14_f?=9#r=E!s2H9g5=Zl1qY6MVBO)U@U?+*;B!aHSA{D02smSD@7 zdmu)ylzD@1Qs$q9pw@blE&9F$tD^Yp#Ci{S%FwB}f9B6iOzfweNf?l0#@Ad1sA(P!Yy6hJjILFJzn@L@j&vUKTyEM_8WH&3>0r8Z1CvoFSER1oykkPOgc71D z<5c#ctt@!)PARyD4AsJ7Kb+k?ghSbR(CZ~b;^eZ7_}n4`ek?nCA?v_Y;#W)(L>l~~ z)UI`W+~TSpS^jH=F|xD@Ut>TB)sC6A&xyO7*Rr#4LbTV-v5`UBVI4jjiYKg=O+;Egk~^O=yx6n#k=kZ_G3UrTKK#QeD7AmwMUTKCTl9tU+GTKK zAbUTH0r;i=9+foiDd$f(hOV=s%g&d2j^MaoI+7-S_^V9UyJuha{BnR;EeM@C|8gEQea`)ktWFO- ztXIyl(~NUWcaK3_7ifG5N=bvkDjz2)Zp*|EJ1JVR683IK8?GyU%bT&WV1_BVz%nqZ zi0Y#WZ^|0YZ{iA+N>{DfpiCJ^8r2-Slikg&9*Vv*xU+sHU9;&^ zL;u|o?SYTSJoIxeUP|%w3-hgGG)~Qd88Ilm7%hGZpY4}>;I9jj3NA!3U;@-N?=V9C zEuv(t*@ z8O~4NJFYXSsRY_v?90$gwuAtq`R_Jai?f@35e+VqA9@7q#-XV}_y_R%xrcH+i_*$< zWZE0geBEAWx@ObwKRJD0;G`pkTk@Yjz5_=8Le!{TjEq@}jF&R>LzC3g+76vGPkmRd z!zV&Bt_@wpUu3R%px^?^B<%ICe3RNITY(wmob4b?&Vowr9 zHlJ2dJ11>#k-@J-_@NKJ_TWf1cxVM(S(SBUlk^)~_%(ha*kfM@u!cUPQMgr!2kKbV zCb?bK-R4a0%>Wk8HSr|@Ngk>UqKV}8_b!V;N(?Y-E02IdX@KhVTTm@wZj)I08~GqL?2bQy}xFuUDW7c+?JWRmVa81cNJ;uUX4608mWO zaZ?M?J;}^4*4M9`!0J6k2$dnUq_;HJQK-8K8$jD_+d(k-44~dZTw6Q8Y|5g1RQQ?Y zDN`T{ylniO^)R2fPXSOwFJ+%Ee}`?9Oy;t`5SMyc8OSRlMKKPL2l22?jL3_arHOci z!JhI-XareR9K@U&j=-D|$DNDqbcm35#A^aUyCJnr9Qe^#UAv}0l2I#W>56_ynsH2S zdGtUw`B+~6=#k%va0L1lLt70$ILW;p_{cBL z&xAEAjmjntNNyF{qt_1{Tj=_7>d~nFNczN3Hz@H791LUfpCRH4n&z~-4;!Yhx}7y# zX?H?OuN}7hh0M}@0&eJdE4A^uY3Yy}3ySQp5Hu>Q8E#vojLzyCkJa*T^gDVbytEvF zF&Zx6mzBH@2(tM$tGgjL;2S5C!6xbLElwpg^XXSzbh&YL`t@lKCnJ<&7LYGFe0&uR zW-f*8T0_FayX9B8gRGfZMs8Sh0tm&%QrY0RM!hHzt9q<@`AguOKtA6I>5nB|&1NI$ z@uW)AklOr_LTEO*le^D_COX%BQ-TPQnQ0dG8WY=l;~LncDI5amq&ZV0-RZ#8D*JKU zDUVbZ`Tc$qxMuqzs`NDO+zCa))7a=CmACM$I+{PJ-Kq8j6_I^E8!(`)v2ElutVQ=kXT^ie3c7CLpzRc-T|<=gGu+2#r9@k z113{Nz%0fLJLhNb22K4ViX%!_bb)7n_N8GMB zX`nlu5IHS+vKHl`WAZ0)TeQP@b=WE2KC+-OG!aOQ74HryE-`SALEuPdruejVZ};u` zCU`Yqh&TNPhgh^T5yjE@8G;FLL65I)erZRLjueE4yN!xac*EM z*3YyxLijGhFRK*iezWt+p@NMjVqa^?c1eOrGmD>iwz0kiKJ?aS{2>yM`~qV|9knsd z(2Uw=M9N)cH-;9ANrZ6c#sA9Q;7kIAf&m3_q{$8*(%IIrxoo3kHs67*f)U88xNbxJ z^ws+Yri&>iytRcf##m1ikuO=2bv3?`<3~nxOvOAsZw+jVXl~3ui;H)gKy^~@)|f=$ zupLT%PxXM$U}zIvmmQZ|Bo-4VB6^;n=3XQI^)ouBT{LD~TeGQ}y~oJ3QjNnyX%PeO zxP*uYp_EI)MncN`!uxDEQJ9x=|R|m@*!rR8zt2Deb2#U(i}|s{QkmJs9Ut zHYDKO1CVQVLIvmIRpiRTf1%NZAF?Upj_s5c^NoLGk6cNh#I`cV)sIp?1NqHLCzQHtu}wmA)mcOl`B`62?`3S8 z+q3~W-#NN8eSh{0uH}r)EMAU@^L${toHmyVCH7uexIkX`l2vyKC~V$=Ku)0U3nuP- zn)sa)x#VVxczbW;_56wAx9sjCZjJSl5u2`%$*kfQW%%@wv`%}LjjwcZq%XqZhDz&8~lt4k_g^JoB(yz2GTN*KXk-l*L$Vi=cNiz9?XtmfdjLcj@rG z(^3SHVqorZucY_yhdh9yn0@nitBo}e`2)5qS4QsW{OHzgpP!=b`6DI1f)%L#e1?_@ z_nbE)ia2D76Ag$c+cua|YUZ@;U~$dH5w9>_4aT{#q>-asdHv@{GX<~9DtvG@>cxfsq`!w`&ruFH zZ3N*KD53PZ^$hRFOEc?3qwWg#dYTM&eBi(;K7gx$EfhDuO;y(T&3I_0&}l{&ep zPw%_wi@Kf_)7rEuyl{M_ELO1t^Lk&$A6!TBf*3u?ODSG2T<7+agpQTz>x^?3fm39u z*PE*2=)HA$upqCP&e*|6&@gc8lmcG(ZkO(Xjw;NW>a9hKOp==P6VXHW;0|`GNp-6; z&pQCCUl+*l7t!fS>bKD*I#!8kS4fWPH3D@KssfO)ifGvA95NloSobo#5mw2r9TK4N z|H@cegdz33YCd#jd>qf(S|_v0v*ajQ49{^v;f_ z^H*($E;Sm!raCngU_Hji5#v|?rSX(C)h9*xqoCCBZvl$dj=MzQ8~JrBjYFqJGjWF2;WoYL1UeI1hG zsTkw0Nu6e7-X)bcboc4WZLEm>aD?|m^vupgZSILo%sm#R*$E3c88P!+iwHtT%sc}| zB#tPev@L2OH@SyHe*1XwXTBuQ6H5sDT2JF}|M8^o|BO+tc!F8etcu}agfhijKXG+-J; zNn%}o*S+J{RT*q(P`U!5x|7_f(0GIh#5!sV&o@u0YqBaUz%KbB7jj`W6Syus?*It@HJV5-e zyGC5&se_Aaui@WM$gPi#YQVVFcQq+=;LJu_;Bqt9cD&MH&pf=+>nX&VBy0bQ*t?Q_ zHg+Y(|3VnT&eS(kj|OfoLN}-j8)QAGmovs0ZkzhH;=NR*YyMXW%S_>{fm9&<+zt6CSRgQ z#v;7lUjf<~ln)n0;^fu$G{Jx~8{O_$TWyYd(MjB!{ALrJpYX##Qa1^xjUpzN;!r{T zC-x2j-N{~Mh>HAcWn_CCVV8R%d#r1jp8!rQ^`}3Y)()^Zj5REg5-4OG6@PjtV*`*L zR%-reMcdY^8R9ETXp8f_OAqotlr^C=UH7b^RiY5IY6$=fiSH0J=S?Hiu#lJ2{|>Z6 zKbL?X`Zc`}@RzI1@Axqj1b6=qxzT{ux?~hK5!;b0tq7Rok+$>bAP@F6 zP8%`XbiCu$eGQmD`8B#@<#M~f%0F3YH`SWXn>9%b?J&oIAYZH;)P|UaAz<~iAr+Uq?NYP@_^mj8W4RPG!7fMUFF*kU1#ac}f zshVju){EGnU}|K3IHAYkZ$~~8s`(TafY!0kkTzzOPmMCAz9hfRSqw-NU5wpLLgl5zvrf+6V;L3986vJlFKjzBE`W@w) zPlBJH%zYf#7tM;F)k=qvNBx-x`7iNWb;*F%tl)Nc*-qJq?L$Cby zJ|CA6m>>5fO zL^CScY)^@blPx19^~tqNwlKdgk%2V?aq*rW;yb4qOS1QenE#5h+3xp#6>!H+D$j;+ zjJ&+;VS0E^Y*2!RMN%#z*?fI_>bFvwsFgPZBM?NF^+QhbV1a{e^ygU>@j()~3k6j? zs$cvqDfmhT*OIZa@EiF?%T(ho+xch#Ux8B4n#gl^vdnAeOWoiVcImQ`gt95O{DX!( zJLEyB1^e6R;5bfej7R2)rRMGuoUC`1r(=|d|ARevH)SAm!Uk|)>L|b*TM#G$`R16u z*1Sh{+$*cd??j`eUpu+~!WQ4X3(3D#+rNHvBuV6Bq!Nf=Ue}UXofO|yb(IID*I`xA z1f<7Oar@B3l?>>B;3jYF$^GeRvpdAEuXDj&aS4mXlPc?2PwiFOPP{69UX&Pv#_&W^ zK#-Ie06$^3jjgppHD{zP-ZT8Xg`k z{79E`;z&%rj@(#$kkc`wF0=gT%ExIeJ!ONBn@$^wh(g4XM<*c^0dAchWLdtABV$AQ z&IljAbv3RN*(r3J$|^!>ro76rcz*?0&060-Ze^W2mtZK~SJcUn7E|O7N>%4_9Y~n0 zQ_$`3RP|+C8#c=4zA)=4vt=NVvr5>4{KzD~AId;a$Iz*g@M}htt=5RcSWp=V@Bo3L zPCdAt8PcpD1^~XnYhSYwAQR#36N8tqa@oZ=%UYACEBAu#wSp()Fc`D=k+TW_u+nB zJ(%6AxnbQ6AcfxQ;2OLBjcSrqGcBz5=PzO}AAYT_mT~3*FzM{QYm=y7z;>ecUpA=x zH~Iy>shpgykm?Z%Z)lfoL$~Ei@-v=fQbq^G!WCUqdyXv4H=8yB&@6qc2aXb9~ayt*;u4|kBm3sa5Z|ZfLFbAmj-}KA>Fhf+&WA*=WJ6-1g zB07BTKd(Lh*EGhz)7gi#)BlSZ%KD#W)<2Ey{I6;Gf2V!&s)5@7E%X1{$ancyh!5!C zl3Ba|6%?+~WI+;+Q)O_6%o{btmwOlD=CbU;yqx)Z>D2aPbUcK@cZVM@|40p%Bm~8| zNJEamo3fag@}+)_HH)`#zSz}wN60Tw0C!(=6ze`c(DB&qcQ^);Um%iV*((k))1025 zRSeZm!SNDEbKUkg;1=u2?q&9LR#R2 z!xeM|J7=xMly?%nUSD0%O-i>5@AJ93#{!2V`PTHcQfSX~-P&J{$a9GX^X4qP6BPY} z-Zz)?;z8%D6_N?gvjLuMz+k6ex~F$#G0?v7@t%(xsy(ntz}@$m76HHT`WJmuyZg?y z1Z7e$-u3k9mhKr-o}U7euc`3+7(UFm37)Am$UQ+A&0c%4;0}-;yj4;~7^UZ4@*v@i)akIIB#L$MDv*R6>a$JlksUHM6$~|$4I&n9(ljt6e ztPwu^_JrYE?iR;|oZ#@VK+;sky-7qrJS5=J^A@O((R5^VkSPPH=KzG@GVNTvf9>`# z{t7s%l*z8Ce14i=S3stFr+U}#)*Klc@#OC9$bNqj*SwD9_v&C6+cl_*zYPfhPt|o^vmZy~zu!?F-rQUxb4T$~G~6V-K%l z^PSqfV)DVrEGN2l5lwEr%-EtLdH)vG=9W#PeJM8n8$F`yZmh#T>Z-PTjdMJop1-<8 z%YI~IY+Hh5@LtzvE<%@qQEwc)uijkGIX76au8Myz5vM%UY&NX?ZF_9TPFN&ixkJxk z*qiVG2TF3E2`jnDpLiX5JW-z4n)0n}diBclGvw*Bc=lDMh^u9H>Y6Ed+RQY*;T!Lr zj{q_awvFt=NyKaX4%|4-YKC{bVc4B62K$#RDwa)>eg4VK4f)WlBq8zGWiV#(6ji-^ zDt2AeXkN+KspXXH1O!gX$-0%K8yH{w%nu;EZ`waqLx|~hh~9Pny25PC`w`PpVxB$L z)4F)h>9i!HeaIj!to!@Ym}LKWJ7w|}@$BB%=b+GZQ#Kgik#V>XMF_5WUNVIMi_pTfZY>SFoG>9Ti`Y>!E#9^$Br2S9@ z73#Qum<5f26c}QBV+OA9#rL-6l^#gWOB$Pw6xn8r?)j0JdUs}j_6zB6iUW`iL^RNzjm$m~P`-(sS9=GoOxX+#vxtE36M>~Gl* zXrv9FHOxk= z@Dxrj4(H^P8pd4)ESkH*?zmwv{~-~tWJ*08k2Manap|Y1gZdKXNguwT0)5`FF265m zQO~D3ttpUl`pXFV9Lq69&kg}m7ajzpVUehPrzML3zySL+LOSA}@ho1}Wr z@NWP)O1hMtfm!Rs?1yWW#YD-D`+H^?IT6%D!+^adQE#9h751?5_cW#(M=?CsP(GW9 zq`k8H3BwI3pHsPwV(+}}UBS8{#HyCVI>S+@{YmYi?Ln9oPhG0=viRHs-Gz-rQDNbC zhOh-Ac5$Ker5QfaYcXvWFiu6&M0!8e(;1De{L}{l7M1D?ia>Fn^*;Dg^&`1OYv#RC z-j;xtJG%ZI+bo4j;Y|tjo6|*}w!EWeI^A=m2~2CvO)^ov)4bI_Kq@!KS_{i!v#OYt^5QL4 zb2ZH-y6oV|gXj(Avqt+!c+CrAC2c-P=Wb>ERMvdt_%8^c@FqoiSy3LtrL62dJ>Xp3 z5m)wV5v7%$Z|W8tl1bX=g5`Wsf@GJ=Om3E}prbMn&s)rWiuH3mhy|uSI|g7j;$`nW zK-4(x&|H@pRYWJ3&byU^Cg!P2d&Yi54qz3TXN)Q!0Eww$B_2`LTwM=s)-kmTcttWT zWDZX%XPqv(<5;C?$V%x}u*3vv8niMQ>;55AqlOXJCw zlj-RUk{s~lb$Yz!17Kk*KNrOGy^y4g|Jpms{-LdotSGJvG4=4TDB{oJJ1Jm4z$|J9 zUPXD!2>XzJ+DCXQ=3L6#N*8~S5YV-(Dwzg_`)ScnaFu6HHMz)vT5`?tB+UvN>g#^h z4cE3*U+!)<>Rj7-8Sw0MKko2&{gMvBJ)_<(x`Q|Cykk!9w2S+5v%@kswHtuDs%4y2 z61T_Sp4I$&!1>B-0!4p+2pWe@=H38vtt<`hkh;zPqOCI{G`i1z9%$xQ1HH4E4)nc^ z*@aa{#>LxlD|Y*}qRY(EyTP47i&8%_)*&5{3|-XzfS&S4PF@%NlQX|zP#f(JPUjI2 z?xW<@ac(6Ra6-+}a!j#23F%oI;?#~nSG zZ_7SRXeh%k+qQGn!P~iZ{_^X>PIdL8a(v+j45h{TK+twvgP!X<5Uqt+q~{jVG1@ej zZE0YDB~WE?n@?k)a(=3UIg+w?CzZ~JQJ2s1ORD|B8D!{@oS&4I&tE#EL8D0v$@bxf z+{`4NWF-|ZC719@*z~@@;G8yJU$rNB3@sAhJRek>M`C8P z@8-*M)Q<0riEOI=5964SL8P;`MHDbLoi(=p$)j)EECwr(-R?Igmo+>9~JJH zrq9wrT^sdH=(}SwM|{xVRxrHkC@gy!B$MC##Twys7(k=L)^*h~79dm=_06 zs}y+ApNoVYxZX91<%fT(R%KWph47=f%pyAl-dgg8_t&5f88T6$`6870l==8;^>f)i zdK81+A#Td%W?uB_AkR=SxJQUH>Q4r|I-j4^&6@)9T3QZag7n&mKE>B}i^!c1@~)se zD`Nx~pyD>F*iCN|{JeAK8{3X?mB61?&uEl?G~FnaNW|fDr-X_{v$6i|nuo_?3f^S? z6K4e*A~$xraHmJx)9@6AUAjcTF_kcqimv-0M^)f)E{T?secZ=Brc#~@9eaKyy$Yo#e4;Zv5Il8xqocg2!vksiD>UhK12j_pENVz0=&@N#= z@_efs;ng!SRP8Kl^`VXv)@!{5Yt1R5jtAYY>0Ha^YuKUt znuNKXqi*ec%;SEkm8w3O4t6qoE;rll?M#-wh^qD9aI%t+8&WQ#&UnIP(Y;bBO7B4} zI`4}d_{DM?_LCZJ7=%dJ?qEISh-q1TTX9yi3#}rl9`UBk@3?dhn?hIf zr6J340M{UE$<~C$1;wY9U(@?F$nbKf29Z8YI94x55$z^t;;OZ`jWS-nZ> zy{c5m^I;Y3rlam3^KiQZq;(`Zh)Jf{$wzF!K$(Bz+rVAg(U(Y4QY5yS)gy5uL&|0H ztmmV1)&f~h8@BkFGv1lsWM!+37#?^wqVxrqtQQp=@F#as9$=v)tc#%fUI4PW%nrNY zFunZJ1nqDC2p$4xMnCK;77EHnB8vfh2g}q zhttuNX_TE-bn5qD)oB<@V0X4KfA1H4#J)e8A+{JFMG(C*eoKBV0nHolfud#WK_J%0 z!?V_kh5G}~eiVAgBYSg(kLUR5>}X~n*TAI$Jxaj(r32D|r{-UizTtYFF{SA6=CrB! zsA-g(Eb%%)0B_&ktJT=Nup$aJh))to?RBLA;NMm20rgc>%S(w1lj7*FjN{3INzRzX ztg|@2`k+%2#0BQZR%6s3<*-noc7k}BAjXlIorK8P$8<{0TMjmNCXYtPcviH#!HpO= z^W()rP}iale54-)D6dZAro7&Cwm|ZqNT!)ZX}|0-?Q*J{jIU|VZU$ZU0{3nlr+?}L zo{on_loCoUBs$(wSaAv4CkO@T)hv#|pT0VBzT-ZladL6?G961IIR7y2qTKhoWmeLU zo+?EQTMNd;Cn~09j*-TBgX8j3?ARK#z&*-$Ce>U($M3T@Qz}u)@)KG95TpJ+%0P9q zci3bB^}k_;01UD{uEp~hF%#cDOv^}lGaJT5n&DnU%9Xs|iza5R z#N{WEJSn};?A|o8NYpWvj>=t<3YlS9uy%cEyQ0Q$Qpr z`nw-^eeE%2Wcuenjwfs60Bc!{Xq^CBbEaAfB*=-GG$mloyY)B!Gl*SKwRNLCqo%?5 z?c931yR54CmLJjNjWin0-ppvs^EoEI$*ltNO*mCb%07N@-JCIP9J|(FNhkK=&(1@) z-ZXOi%dg}C?SA@HOUJ~BrX#rO$d|8fx!smTz0~fZ2rJ|3Z=;wG^3koHO7}Ly63buO zg_}~|wgf;o#?PZZ9Kl_+Q^`0NLSB0yp7@7$*w(^5r@-29ws+oU4c{}*>@S~lR^0NNYR z$z-$z`g@w{zs3c+;*c;4cVy4taC6?C5s5~L#L>XfZ53~-FSa2kKr0VOA|Rjtiku3C zkfOFj&E(y{Es#I2q!K(=FGqm|`=*unC4HZ>IEv3^m$a!ER@OPYf&F_1D$ZzGRjj#+Qo1uT?KrDQ zp>&7kBR?9>RH#j=yzMpGt$v7k2#f@>#PMqKL)HJ5Nk~MkhR*o{?Qd#cm9OY5{-zwca^4-fq_g zrrJd99;sw0l<&ePApnDbnBi9mWjIV)Q z7Vzd(VT3k!LRYJUQinAa*WoGG$he`0@MTPaMYAkggZ=Y)!E`$P!KTtHIYrTfvtOLF z2Q8_i2Y#C%)JMq0Y7yThIGD!XDk~~dFVc4+%Aocu2778*lziWkv}0j@M;Ci?;RN8^ z3{I<5O_N<_T*U&kq~=5KAR)6$vL&emNvMjobTj%1(9a&|=b^tT$-G&zeeKQxRpI-a zQe+cn@sy)yH-=eF%gVZ1LYAszm1iIk{A1^yJ#=oee72!BgLXxv_JyeA{Y$iC(nyG{ zdrD4*P+hc_LBl{a?-^fSO;)eVKILswwK>@JyP>8}L}J#E@^vUBxW^@`2Te$S3Jq14 zXD2W`(D6688s9sY={=)jb5TSv&XZ;b#n{v@Lm7oURg8U#mt2v7<>zmlaEh+KKXI?3 zqV*<=giM}l6|YjX=C}@AakZz}R$=f;TD&4;htFf@ffF~yM;VQ4W5s{#0Aw#JSFwXP z=ao6%pNW&0gA&4>nO5o1bzeT`$%$^^XHa#`WOru?;7C3#Y0_21Q~C-xBKpB!cw%<+BINRG4upAncx(acBNotI0f%j0ThypA21owklWkm3q1^7? z`zH&~Y)MeEy-}#V!X=enR6d{jD}3@BSTSs!-61(+6AMd6S++a4+#G_N3JylqUz4>yBHKonrU=Q6 z>Ts}rt>z>C8xq$?CVXodwwFR8tCG|h z8vFZWI-~;4h7$cc3&+Xu#_cpCZ#07v%2b_VRyKhBhdXr_PT1CZXG;cchL%M72pmU@ z2(hG5_=kQaQRuO*k}KO&WDgT8j~(1r+#jK$-`BhH+5RsEK|J|%rS)gYY?g`GV-N3UpFSe@7mP*XT>q0P zE?m6rSoTyp4OGifDwyI>EDGB`wt6{(_FG#$eKYBict+7_s@Stm;h#ZB<&9OL&DCvz zumvymo?QrC;CT_^%uAp9isk5S-;W9+3PY=lQkycWxR)#?pSORkvMbCx@A%S!X(b+( zx8CHD9OcV$tW}=#U!mO4#h07pbBpSKdf>Qjq;@9nprn~(gfHuSq$9M*WIE54^suP_ znUu5y+r_X)T*A;eT!)VS2(4$gdm&pUd4t%0>A>|-EbFnt86QZa$2j7L4v6sp7LijK z&vL3Fnw^O^Q#5}9pDYsY@mpHxErFa-Tf`fZbxqhrv9HnAc_GVE(j<|cVY@Oqq&1nV zs!2GG#QvK2ff;&GmCZ$3FY;JTlBfOLY;=F|T&FZ6=l=SJfMJzj&qfE0e)55P=fpqN z56=}tgD=1Od)ViCw{6_#OJ_Jc{r(BRzUByK8pDK;*{&6f6Jv`lxfqFCl<;GV^Vp8^ zYL_h27n?Z7s4G?s*fbdlh?f+6T1dcuiJV^QWRs{UchD%GCBM{AH-RKU*237v!#LtZ%Kk zvIIIA{Gic1h6FX~7^Jc5U0PvaIO2|cH-E~6TG`BTib}IBDN23^Q9}BdyIuyInTAEw zQ7{m$pz>}??5q=~PzH>ar8YG4z*R?=SA2_|Dzhb=I3`oKWpXkU3~|bC1cBr( zLXXKEiy1x3&I}}^&RVcQRNW`Zr!Dx-tSj)#ieXt-*r1n)oE zo&JP(r(jiAjDjCQ@X7}}>yQR;j3D}97h*`OKu9L=Z(;!it<+jWpv=Gx?K1swZ%t+?DaZ9^ zHUL+lFQiK)JHC`BL8LK9w$c6AUJRYYQ0{QLjh~w@5lNs1MetYZ)DM8ssz8&1$TSoE zip7Covq_VEBP2G+W0>0i%;Wz^? za`QM?%u+X`6d78mGEqqJ_Y$Z}vZm6aEI)uGr^RS+Pe@0^-HZ`u<&^&r1 zc@@97R4D>yL}sx#Czk1rwh&7%tjJDvZJ3fw1dYej7jBc|0d`~J)<{gOi-NY3Q2d$o zXp_Rs>$d1ZlnAC7)%+LZefEvwnUS>EOvYWORoqSi5oW5~lTV*_qU-K^gu)Job<76~jqJw02DhdIsn)1q8Fwm&t&v9hkBo=xttoLnVE|YUP zc(k#vW+PPVFn+kXB}hSC)Wcje@)&k_enK#xGP>82e0HiIREQg;e2 zMd_*-@=q69%=&%0&MECmDvU?N6P}4m%RPKV?h!a%j?Sc$yVQiEaus@(k@35;B_2Hz zc3dGS$1)TM$nbCiLqp%<$S#+}uYEBfSFB!?to&HRB7emDnhCunHy_Ux-+utNutWs0 z^Ue7h)RyNp{s&BDw^JOM|8st5+OX^-$q^$$l3ghbvW7rXry`9A= zGHx`IYb-9i&v4etE1UG+BWv+eaJ+j<<;8nhogD80KvBSa#XEcI;?BRS{YojDf>e`@ zPJWdOm8x-t!P#?UhM}H`f%=TD-*B<_sq}oqz4i6QGuO3?J=JvUO{5X(Gta{u;Y1r2 z6m=_~yQ0#{c<|OdzY(AbEv(7q2NGCWrCXfGfTbE)b6aEE@IZFT__nt64QvZaf7Zb< zo1@a$*Ih|srQ#Tbe4V#$|UE)5F$i-OX_o8dY^S3e+q z^Te)J2~OE>Ep8vzn!6c@hG>w4AI0F{HFcp(jYV>hu@ev43;MKkOZU$&v1<>9S(NSW zR;DVW!IhORt_VxY&eP6E{asaRX)nQp=E(xclHKab%1XB;N?NCfdF{pV*rP|dgx?CP zH66~9|7JhFaZT^GS0%|6P2NAH+(sV*7T+*fOsNQM8Etp)@pH;^X z7uU(S{iDh@_wKSwfnu3pt{b_KQ1)CGShwo-tUpzk6qH|F>r|Ibi*JFGeqobDfKR<6 z?Jb^2hH5&9_*;;4E=!?2?oiswBEexZTvOETxnVIu+Dqk8TDM)LMapZ{lxnV&%%aML zcz2(yj$-LW1M9*E6FhEa8!<5zPcJn7nB$SFT8QCFAN!{nsblvH&P{%e{76}~$y;9w z!gcjF%_{UtwUl>|r-ghs&&hOMe0D2OZ%p%ITa_y`G_||JSS%ICtlyM;z!K85oTyy( z+*KeH$6?C3lJB5z-5f>T=})*J5`f8k{|Hk5z^DU+N$2v2?eq1G=Osfpu7^xfx( zOuKmE3<@^hV>4jUvY!;>FAM3_$`k?^7^d4+Gxr+&+~5dVLLWjVq?PHchs&R_LHj5GX>QFqh=!o zIfNEo%d~Zuaimy>AFGkg?e>OM_Vsflags描述page的状态和其他信息 + + +```cpp +struct page { + /* First double word block */ + unsigned long flags; /* Atomic flags, + some possibly updated asynchronously, 描述page的状态和其他信息 */ +``` + +如下如所示 + +![page的flags标识](./images/flags.png) + + +主要分为4部分,其中标志位flag向高位增长, 其余位字段向低位增长,中间存在空闲位 + +| 字段 | 描述 | +|:----:|:---:| +| section | 主要用于稀疏内存模型SPARSEMEM,可忽略 | +| node | NUMA节点号, 标识该page属于哪一个节点 | +| zone | 内存域标志,标识该page属于哪一个zone | +| flag | page的状态标识 | + +其中最后一个flag用于标识page的状态, 这些状态由枚举常量[`enum pageflags`](http://lxr.free-electrons.com/source/include/linux/page-flags.h?v=4.7#L74)定义, 定义在[include/linux/page-flags.h?v=4.7, line 74](http://lxr.free-electrons.com/source/include/linux/page-flags.h?v=4.7#L74). 常用的有如下状态 + +| 页面状态 | 描述 | +|:-------:|:----:| +| PG_locked | page被锁定,说明有使用者正在操作该page | +| PG_error | 状态标志,表示涉及该page的IO操作发生了错误 | +| PG_referenced | 表示page刚刚被访问过 | +| PG_uptodate | 表示page的数据已经与后备存储器是同步的,是最新的 | +| PG_dirty | 与后备存储器中的数据相比,该page的内容已经被修改 | +| PG_lru | 表示该page处于LRU链表上 | +| PG_active | page处于inactive LRU链表, PG_active和PG_referenced一起控制该page的活跃程度,这在内存回收时将会非常有用 | +| PG_slab | 该page属于slab分配器 | +| PG_onwer_priv_1 | | +| PG_arch_1 | | +| PG_reserved | 设置该标志,防止该page被交换到swap | +| PG_private | 如果page中的private成员非空,则需要设置该标志 | +| PG_private_2 | | +| PG_writeback | page中的数据正在被回写到后备存储器 | +| PG_head | | +| PG_swapcache | 表示该page处于swap cache中 | +| PG_mappedtodisk | 表示page中的数据在后备存储器中有对应 | +| PG_reclaim | 表示该page要被回收。当PFRA决定要回收某个page后,需要设置该标志 | +| PG_swapbacked | 该page的后备存储器是swap | +| PG_unevictable | 该page被锁住,不能交换,并会出现在LRU_UNEVICTABLE链表中,它包括的几种page:ramdisk或ramfs使用的页, shm_locked、mlock锁定的页 | +| PG_mlocked | 该page在vma中被锁定,一般是通过系统调用mlock()锁定了一段内存 | +| PG_uncached | | +| PG_hwpoison | | +| PG_young | | +| PG_idle | | + +内核中提供了一些标准宏,用来检查、操作某些特定的比特位,如: + -> PageXXX(page):检查page是否设置了PG_XXX位 + -> SetPageXXX(page):设置page的PG_XXX位 + -> ClearPageXXX(page):清除page的PG_XXX位 + -> TestSetPageXXX(page):设置page的PG_XXX位,并返回原值 + -> TestClearPageXXX(page):清除page的PG_XXX位,并返回原值 + + 2) _count:引用计数,表示内核中引用该page的次数,如果要操作该page,引用计数会+1,操作完成-1。当该值为0时,表示没有引用该page的位置,所以该page可以被解除映射,这往往在内存回收时是有用的。 + + 3) _mapcount:被页表映射的次数,也就是说该page同时被多少个进程共享。初始值为-1,如果只被一个进程的页表映射了,该值为0 。如果该page处于伙伴系统中,该值为PAGE_BUDDY_MAPCOUNT_VALUE(-128),内核通过判断该值是否为PAGE_BUDDY_MAPCOUNT_VALUE来确定该page是否属于伙伴系统。 + 注意区分_count和_mapcount,_mapcount表示的是映射次数,而_count表示的是使用次数;被映射了不一定在使用,但要使用必须先映射。 + + 4) mapping:有三种含义 + a: 如果mapping = 0,说明该page属于交换缓存(swap cache);当需要使用地址空间时会指定交换分区的地址空间swapper_space。 + b: 如果mapping != 0,bit[0] = 0,说明该page属于页缓存或文件映射,mapping指向文件的地址空间address_space。 + c: 如果mapping != 0,bit[0] != 0,说明该page为匿名映射,mapping指向struct anon_vma对象。 + 通过mapping恢复anon_vma的方法:anon_vma = (struct anon_vma *)(mapping - PAGE_MAPPING_ANON)。 + + 5) index:在映射的虚拟空间(vma_area)内的偏移;一个文件可能只映射一部分,假设映射了1M的空间,index指的是在1M空间内的偏移,而不是在整个文件内的偏移。 + + 6) private:私有数据指针,由应用场景确定其具体的含义: + a:如果设置了PG_private标志,表示buffer_heads; + b:如果设置了PG_swapcache标志,private存储了该page在交换分区中对应的位置信息swp_entry_t。 + c:如果_mapcount = PAGE_BUDDY_MAPCOUNT_VALUE,说明该page位于伙伴系统,private存储该伙伴的阶。 + + 7) lru:链表头,主要有3个用途: + a:page处于伙伴系统中时,用于链接相同阶的伙伴(只使用伙伴中的第一个page的lru即可达到目的)。 + b:page属于slab时,page->lru.next指向page驻留的的缓存的管理结构,page->lru.prec指向保存该page的slab的管理结构。 + c:page被用户态使用或被当做页缓存使用时,用于将该page连入zone中相应的lru链表,供内存回收时使用。 + + -因而struct page中使用了大量的联合体union. diff --git a/study/kernel/02-memory/01-description/04-page/images/flags.png b/study/kernel/02-memory/01-description/04-page/images/flags.png new file mode 100644 index 0000000000000000000000000000000000000000..54d0f020b99684cf5e79513aeaed720674d27529 GIT binary patch literal 6876 zcmb_>cQl+`+b=>yFNqM*OC%=BD@qV8h#*Q3j80oOu zFVT(OJKsIydCvEqwa%Ystvz$kweG#IzUR7rdw`GlUFaBd70UdrEg-;U$cBlN8Bb@LJ`mqgf@;@xw5fa1- zvV_>drcNMa2NzCM#Zj_^Z*MWZ{yz z|7a2!X%T}LbPHCgSBeTIBBDVUft_zM_P|H$=-zD%@(liYOPG-T%+l75YRJ6k;hteroejP{sq4$W2)2cCtrxQ2t^YZzE-?T1 z>&-Mlya4U?mQ0q>uSamnl54q7uzrb2#@qP*xAQiI(Q|K-{cGI)ut5Gimvn;yK@g8` zkFCxFR5&e@k4i~jaOXv6;*jR@21|Bry&ilRk-)(h<$eg_>FmGT07ssXrQKq+G9rHA zjg7(=YJ8(ZXZBfCC@Awr;`>}s9sIYuZO#uwW6`oG|6`u;w8Ux$c1TJJMRrSC1-qPU zPdJkFuTOus<$q%N{?yADh`vwUKY3+j^>qgbd4hU#H?_0-4(Hw)YV&#W;6PbDd4XV& zK$8b7(Tb`Vc6g2P;d1B8_fEXEX{d%F6c=g^)w$DP;t6SOlfSeH_^7lns3CJc8zG?b zB5M(_noiBEH$$rI({xizU1;kPFY}5kBiT=_I4&pMi7qGx{xdv9WKWAWH}OJMeuVM6 zTi1BQMQEI-%-IrREtZPm@!^7`HnkNE(sjgpI^Oow&g&x92UC!DaZf`j?HI+*G z=u1LKVHF@NQE{d@=vwcST~uGDyqMDzQ&+n;n5l^;PD5$bxvMNR@6d~Z-yjbLxr8lqmz@h#E1 zP!z_f=Wc7y0>3y4V^Z>(IitYav~Dira(f&bR%~-gs1j*V&t=rCg$3@d# zET>Y^V;v)pqaXKj^ZHd;dC2v>fuQr%Jvo=L{>vdZk|12OWNmFP1+h!>c)7G ze{RSsy|A!*YtRwjp=Yy4;hHS^MwiFS^zSV=ac+r z66Jt>|A63#=Tmgowh5DS<=>61j5|$j4Db9p61TW%4|6{Dc#Crfjp$9`xjwRTP)yOWaAw5Gt$ zyLWp6ikg>D6FNuEiaxme$TxH6_0!EJR(H3%Hw#m5e2`V7ZjK1|0x_^6wx=vs#BzL* zCt_!3b_V0!2ARo&zoLCqx;uF=4W(r9wKDrN8xU%vy))UH>ds}fezIN1Ih#6*nbzl4 zw7!%rl02E*Z*+aHE0C~m@2ux>UIgHIM@w`|cx}zxc?7YaZZv+Xb~YV$osGbf6EAa? z6c6b*URC@{J)#%9J4LbKl{`p$Cu!K@b>edgx{-aD z6m8KH&gCoL`JE`RrLT=CAXY4GhedRP{)Y@NN#&lK!5xJ!Pf2E63_n2@x;QfHTh@h& ze(Jjbc4!3t0sc;|Q3fmr7&{N_ScM9MZ0nG1mmG*DljT*h#@ZD&XRn7X!x8k-6$6u_1gwwXmlrohye>TwOPg-6f_lWB>m1>u%mc6SI7*^>Gtg-OD$ zC?eoJx*JS(er$7TD6Due?~Tb!J1@C>OfXuqUSoB69V4Dd>a;We?w9{x~#*f9FL zR?fPALHPG09y$ngm-PF&;Tg;_Hf-G@;c#3;u}->lT9E+vTSP>1piYjbx84Hm0D2=zaQYrpynN*ly*K=XUw^()j8BLV9>&I z8#tf@FcRftA;q8OzP=2{)$;$(i^puy<4%n5!^;I-^M{1~f@g*LJNK1M2xJ<(zqXIi zF!&8ZJvtJP!&xJ56G{@4ojL8k9IqZijFg=l-sb&u18=k8@Hz{8L|N>!*P$KI#EKQp`uD~K)pC%So7$qm6H`){Y^-VuZj;TsTB2AnD`f z%H~h697wPk$LE8KsSIvTvk%%3h(IMZt}jsT8z<~IX~RLTDpo|Docv0Ggk-9!He49+@u6zf;YuudK~$$0^OEioICsjq>jGU-06vr z*OK&y4ZY1R5-%!<3p#AB!zFoBEoZ!abMBV)Ve7slgRv`Qy{v+LG$?V(hjbC)jx^+D zH$$uXeAcCrcMtj1pT4VpsS-WdBX!#ieQSeg>%w){35Z=e#P}|DtF$0qMt34wd2-fa zNVL=httSHJN9;IcGFHEIbhpHJDf#C4*%2LdB$QMn-Z9)G@@ZB2BM;}fosRr(zL?^n zYRW(`jlP`lcj0Rb%dN%rPwv0*e_wag|4ZYTO5KK_!x;^74 zI2+^BL?>e5KAD&wRt)8>S@cudgV(MXHbB06pNxJ#O%GIi4h{Y2Rec8WGg}GE%=TYv zt67QgD^p7~^y!Ywez)H^b0)19eKBeuFqk#8naS?o{t{neaG>T7`;p(}+8;pDr?!^f^Jr$ai({$X@kD3Egit^CI-MYC3bN?>Egz0-(o7 zc7vsP+2wXDDytZ$beW9(0tXoxtz+(d<-{ybQF9_+f)B}oT}h8thb$w4UiW^z<&@^b zFWHKs<4y_L8OGFstbf7A8@p)jEk54mQWG~H{d{`I)icDj&)Ii zhfZQ5_vlhwg4ZVpZ@b}T2T0s)GLhc8E|&3kuJAnWK}0!ZeXO`GW_;6}Syz^2IP|G; zjV+JrJ!!27(h`5zp|BlVL=N`)Omoe}`FDrh>-EeM0V$B7*JRFnm2Y(J)I*$9cmM8S z(5{G@*hf5ZN2j#i;6*9531FK%Qx!Z_c&s*1&!b+v|9zEL^QZqg;d$zHWRESF)vBUL zgj1aT+Zy5a=;_&pX539f4?HMiU9q@1E2Hfy-2LM5Z3{b(C?BsT|DNLAHs)LFnOwwB zW*&U8Fa^}R-My(EDQYf{JHIWJr)i{o`%g9+JXMjI_6AsmefYKiG=qxi1CC4nt9Ik)&Z8@xe-|Ht){tH!^QLR zp&^Ui`a92qLB%4+Ni)dwsKJMmiyL{L?D^WlLGJ_Q#qZkg%s<@CAlQUS3Uypp8}+jZ zx%;f*7c0AMmNe$uR`dyF3)fI-bFEXkWb2gV7x058UL}wL)1!>+<8MP$ruMDe^plK2 zc2kRM2@-i=x0~oFdtI@~(7#V16ykBD^DmO67wbObL;XSbev#9O7|#q_7YQAS$RP)^ z9bNCZew86stW?VIq2Ly_vnIf#(WPnPYwIIwwkC}rP4_I&ZAInrJ#xt`i(M}ANa)c@ z7nQmqJLVLsd9Ra3-(|tuEo%8QkCpg>fgEIg+xPWwL8azm+0P>>$ezMB884H-= zzV*ls9Wq&&Gf3MpzlfLy8Im*kJnM0$uV*QXqD?@~e*w~k*04-nSU#WbX5D*)@1OAY zNeceyjBG$8$=x^)*K;o_gQ{u|%CuZ22xz$?n)d#9~Cj_5zkL(fG@)X=auxYZo>$9p`9+PO>)xR)m zw(Z!6U6nc(x7)2FjST}D3;M>@hh#nR>-Hax>q z^P_eB>02fFV#%X6);t^asu*J2=1uwPNA^FsCwzfp1MtKjR1#fK+gv(VP0Ianykueh zz8yL;(lScC=^X{F)Mj~+{CQRC{?>ML?0u_l0Ec3ZimlOzu&zdJZ=VEQjRqqdValS7 z()X;;+!T%snY6Y;ubNfRh}V#EY2Bj}+Vt?mjH0x-NzP#(;P2%i2!hl%k>cQKDqFUg zpb}`4P$6|suAJ#;^V^yI(?Iv_!K$%SK5=)dTGR(oCEg~wuzp)z0cBx_Pr|N{?}he% z#mg(TH9|+@KuT~@g6bZrHdd`o|F)&KX~oSa`HQ@$5p?pVa4oI6epi*Yq6EQIDqs!e zV>$`=dC~CGbFHjh)2WrtGIf{o`Nj#j`_}s55yd&F3@qL+Yb0PKUug4X=0@P5sU8uw zQSmuRgS`o1S+DxqLcyu?<3YiAc&ac+^>Kun2R-TjR6nZDXSDa3ksG`JfQEisthLu{ zo4yjeaG1W7op5#5n*-xv$wUk0L}I_ChobL8*i{Ygv{dD<#l1(Jcnw8bN8LjNe%3!U z=0~a*tjeoJ6^MWSUFYR|uuf^3<4>gHHeKWr79lEE$$sdMJS*XA0z377$NMyn?BjZU zqU|nxQ>-OBf!}{ecWcBZV%%C+Cp#mybChyb(2=9$s(VVbK(EFBIk`ryA3da2>={Cp zy076HZM>pKXkv}gs$}ENS`UQe5Ez>kVjw{=+?_6hXQX>2P8N&S&b^PanV$RjDeL&aC7MewRR(){bu7QAb{;PmKor}``dD?tzhZZ<1GojJ&o zn|3rrH65!2M{-a-QDZ$-c4W~@PXIUR(*cdh%s{{x;MX}jAnQ9+8L?U4rcu0*Zt|OT z$?+_Ua`kgXeg;(Y;X)^n^tXI8g22Nl`zT34P`c0#X4KQ9y8a-qf8KF5scj?N(ILN< zn1V*1#6gi{0Fu{GiyyG_vd9QH$S2dQqj{ z@Bd*|(PZImnA_gHKH+|%HrOcT?f1Fi=g)gODK)dS_T6c>)2?frT*t7z%H%>zQZ__8 zjTrZ&RPRiF7Vzzlw$Ug#B;MMZcBns}dQUv<(W?QGVPE~*9nn;;-gRs?k6)t_0EzqO`3U^dd#{&X@fAOa?(F1r zX;1m5dQLN<$V&JM#r^5izyhqxT*vDFYNUN~v*r?BskIr2h5K7FNkSkh2loN2Fx6my z1tq#rx+`Eq)^K^Ig|j!$u@?w-JK~;-YKIjOY-le8isD5w+LV&p0F6El5lIw#SN;eE zz=8w1)x917Z^Bk0`$ed+{_Z+k10>MaUu>gnYqYT1&=33NW6|2>-YTxmt9Qb3|7zA# zhbc{?6TJdid|Uj5r<(tQzs@W8RLSXM3;{Mogow!pVjMa7uh`yaH9#VpvcG0I-9) z{{}7p3u`+8BzLb;Nm&+BDQY(ufo0z_6+ewdu3S!NKTr{1v#T3g8XKN^vq^pcS*=yB zKmiM{;8!Ptd35#vg2_ArSg6+QGjJCRz+tZ-LthWDs1=xW&>3?DrgK{m+6TotDb(%V zU;%9`C^}yC0I~sZQ%0H<5RJF_(di9PeYDKb$+>IVBh=0Pelx{gS5To|^YI9nK9;XcnZauB&>KC~XK?1&KgeUu}RtaDmIax0?jcb4DOtcAdJ4(MFjO9+m zeRL-oON`{~vrza_R@Q$XIS?GUm6~z=2dE*J5D{Ok3ROZ(NF)6ZMy=5G!?4}W$@=O? zn~nR8WTg+x|KXHb#o1YIOgCnQ_Q=t-{O9sxITSdiQTOVr?7BLa2?OkruTkN{o#FJ6 z03J@?`eK)?h`R(K2goqzL<8)Nfx?%YzzvJ!U%6p^>;X~W4F-Uu_{&>)b= +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef AT_VECTOR_SIZE_ARCH +#define AT_VECTOR_SIZE_ARCH 0 +#endif +#define AT_VECTOR_SIZE (2*(AT_VECTOR_SIZE_ARCH + AT_VECTOR_SIZE_BASE + 1)) + +struct address_space; +struct mem_cgroup; + +#define USE_SPLIT_PTE_PTLOCKS (NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS) +#define USE_SPLIT_PMD_PTLOCKS (USE_SPLIT_PTE_PTLOCKS && \ + IS_ENABLED(CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK)) +#define ALLOC_SPLIT_PTLOCKS (SPINLOCK_SIZE > BITS_PER_LONG/8) + +/* + * Each physical page in the system has a struct page associated with + * it to keep track of whatever it is we are using the page for at the + * moment. Note that we have no way to track which tasks are using + * a page, though if it is a pagecache page, rmap structures can tell us + * who is mapping it. + * + * The objects in struct page are organized in double word blocks in + * order to allows us to use atomic double word operations on portions + * of struct page. That is currently only used by slub but the arrangement + * allows the use of atomic double word operations on the flags/mapping + * and lru list pointers also. + */ +struct page { + /* First double word block */ + unsigned long flags; /* Atomic flags, some possibly updated asynchronously + 描述page的状态和其他信息 */ + union { + struct address_space *mapping; /* If low bit clear, points to + * inode address_space, or NULL. + * If page mapped as anonymous + * memory, low bit is set, and + * it points to anon_vma object: + * see PAGE_MAPPING_ANON below. + */ + void *s_mem; /* slab first object */ + atomic_t compound_mapcount; /* first tail page */ + /* page_deferred_list().next -- second tail page */ + }; + + /* Second double word */ + struct { + union { + pgoff_t index; /* Our offset within mapping. */ + void *freelist; /* sl[aou]b first free object */ + /* page_deferred_list().prev -- second tail page */ + }; + + union { +#if defined(CONFIG_HAVE_CMPXCHG_DOUBLE) && \ + defined(CONFIG_HAVE_ALIGNED_STRUCT_PAGE) + /* Used for cmpxchg_double in slub */ + unsigned long counters; +#else + /* + * Keep _refcount separate from slub cmpxchg_double + * data. As the rest of the double word is protected by + * slab_lock but _refcount is not. + */ + unsigned counters; +#endif + + struct { + + union { + /* + * Count of ptes mapped in mms, to show + * when page is mapped & limit reverse + * map searches. + */ + atomic_t _mapcount; + + struct { /* SLUB */ + unsigned inuse:16; + unsigned objects:15; + unsigned frozen:1; + }; + int units; /* SLOB */ + }; + /* + * Usage count, *USE WRAPPER FUNCTION* + * when manual accounting. See page_ref.h + */ + atomic_t _refcount; + }; + unsigned int active; /* SLAB */ + }; + }; + + /* + * Third double word block + * + * WARNING: bit 0 of the first word encode PageTail(). That means + * the rest users of the storage space MUST NOT use the bit to + * avoid collision and false-positive PageTail(). + */ + union { + struct list_head lru; /* Pageout list, eg. active_list + * protected by zone->lru_lock ! + * Can be used as a generic list + * by the page owner. + */ + struct dev_pagemap *pgmap; /* ZONE_DEVICE pages are never on an + * lru or handled by a slab + * allocator, this points to the + * hosting device page map. + */ + struct { /* slub per cpu partial pages */ + struct page *next; /* Next partial slab */ +#ifdef CONFIG_64BIT + int pages; /* Nr of partial slabs left */ + int pobjects; /* Approximate # of objects */ +#else + short int pages; + short int pobjects; +#endif + }; + + struct rcu_head rcu_head; /* Used by SLAB + * when destroying via RCU + */ + /* Tail pages of compound page */ + struct { + unsigned long compound_head; /* If bit zero is set */ + + /* First tail page only */ +#ifdef CONFIG_64BIT + /* + * On 64 bit system we have enough space in struct page + * to encode compound_dtor and compound_order with + * unsigned int. It can help compiler generate better or + * smaller code on some archtectures. + */ + unsigned int compound_dtor; + unsigned int compound_order; +#else + unsigned short int compound_dtor; + unsigned short int compound_order; +#endif + }; + +#if defined(CONFIG_TRANSPARENT_HUGEPAGE) && USE_SPLIT_PMD_PTLOCKS + struct { + unsigned long __pad; /* do not overlay pmd_huge_pte + * with compound_head to avoid + * possible bit 0 collision. + */ + pgtable_t pmd_huge_pte; /* protected by page->ptl */ + }; +#endif + }; + + /* Remainder is not double word aligned */ + union { + unsigned long private; /* Mapping-private opaque data: + * usually used for buffer_heads + * if PagePrivate set; used for + * swp_entry_t if PageSwapCache; + * indicates order in the buddy + * system if PG_buddy is set. + */ +#if USE_SPLIT_PTE_PTLOCKS +#if ALLOC_SPLIT_PTLOCKS + spinlock_t *ptl; +#else + spinlock_t ptl; +#endif +#endif + struct kmem_cache *slab_cache; /* SL[AU]B: Pointer to slab */ + }; + +#ifdef CONFIG_MEMCG + struct mem_cgroup *mem_cgroup; +#endif + + /* + * On machines where all RAM is mapped into kernel address space, + * we can simply calculate the virtual address. On machines with + * highmem some memory is mapped into kernel virtual memory + * dynamically, so we need a place to store that address. + * Note that this field could be 16 bits on x86 ... ;) + * + * Architectures with slow multiplication can define + * WANT_PAGE_VIRTUAL in asm/page.h + */ +#if defined(WANT_PAGE_VIRTUAL) + void *virtual; /* Kernel virtual address (NULL if + not kmapped, ie. highmem) */ +#endif /* WANT_PAGE_VIRTUAL */ + +#ifdef CONFIG_KMEMCHECK + /* + * kmemcheck wants to track the status of each byte in a page; this + * is a pointer to such a status block. NULL if not tracked. + */ + void *shadow; +#endif + +#ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS + int _last_cpupid; +#endif +} +/* + * The struct page can be forced to be double word aligned so that atomic ops + * on double words work. The SLUB allocator can make use of such a feature. + */ +#ifdef CONFIG_HAVE_ALIGNED_STRUCT_PAGE + __aligned(2 * sizeof(unsigned long)) +#endif +; + + + + + +struct page_frag { + struct page *page; +#if (BITS_PER_LONG > 32) || (PAGE_SIZE >= 65536) + __u32 offset; + __u32 size; +#else + __u16 offset; + __u16 size; +#endif +}; + +#define PAGE_FRAG_CACHE_MAX_SIZE __ALIGN_MASK(32768, ~PAGE_MASK) +#define PAGE_FRAG_CACHE_MAX_ORDER get_order(PAGE_FRAG_CACHE_MAX_SIZE) + +struct page_frag_cache { + void * va; +#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) + __u16 offset; + __u16 size; +#else + __u32 offset; +#endif + /* we maintain a pagecount bias, so that we dont dirty cache line + * containing page->_refcount every time we allocate a fragment. + */ + unsigned int pagecnt_bias; + bool pfmemalloc; +}; + +typedef unsigned long vm_flags_t; + +/* + * A region containing a mapping of a non-memory backed file under NOMMU + * conditions. These are held in a global tree and are pinned by the VMAs that + * map parts of them. + */ +struct vm_region { + struct rb_node vm_rb; /* link in global region tree */ + vm_flags_t vm_flags; /* VMA vm_flags */ + unsigned long vm_start; /* start address of region */ + unsigned long vm_end; /* region initialised to here */ + unsigned long vm_top; /* region allocated to here */ + unsigned long vm_pgoff; /* the offset in vm_file corresponding to vm_start */ + struct file *vm_file; /* the backing file or NULL */ + + int vm_usage; /* region usage count (access under nommu_region_sem) */ + bool vm_icache_flushed : 1; /* true if the icache has been flushed for + * this region */ +}; + +#ifdef CONFIG_USERFAULTFD +#define NULL_VM_UFFD_CTX ((struct vm_userfaultfd_ctx) { NULL, }) +struct vm_userfaultfd_ctx { + struct userfaultfd_ctx *ctx; +}; +#else /* CONFIG_USERFAULTFD */ +#define NULL_VM_UFFD_CTX ((struct vm_userfaultfd_ctx) {}) +struct vm_userfaultfd_ctx {}; +#endif /* CONFIG_USERFAULTFD */ + +/* + * This struct defines a memory VMM memory area. There is one of these + * per VM-area/task. A VM area is any part of the process virtual memory + * space that has a special rule for the page-fault handlers (ie a shared + * library, the executable area etc). + */ +struct vm_area_struct { + /* The first cache line has the info for VMA tree walking. */ + + unsigned long vm_start; /* Our start address within vm_mm. */ + unsigned long vm_end; /* The first byte after our end address + within vm_mm. */ + + /* linked list of VM areas per task, sorted by address */ + struct vm_area_struct *vm_next, *vm_prev; + + struct rb_node vm_rb; + + /* + * Largest free memory gap in bytes to the left of this VMA. + * Either between this VMA and vma->vm_prev, or between one of the + * VMAs below us in the VMA rbtree and its ->vm_prev. This helps + * get_unmapped_area find a free area of the right size. + */ + unsigned long rb_subtree_gap; + + /* Second cache line starts here. */ + + struct mm_struct *vm_mm; /* The address space we belong to. */ + pgprot_t vm_page_prot; /* Access permissions of this VMA. */ + unsigned long vm_flags; /* Flags, see mm.h. */ + + /* + * For areas with an address space and backing store, + * linkage into the address_space->i_mmap interval tree. + */ + struct { + struct rb_node rb; + unsigned long rb_subtree_last; + } shared; + + /* + * A file's MAP_PRIVATE vma can be in both i_mmap tree and anon_vma + * list, after a COW of one of the file pages. A MAP_SHARED vma + * can only be in the i_mmap tree. An anonymous MAP_PRIVATE, stack + * or brk vma (with NULL file) can only be in an anon_vma list. + */ + struct list_head anon_vma_chain; /* Serialized by mmap_sem & + * page_table_lock */ + struct anon_vma *anon_vma; /* Serialized by page_table_lock */ + + /* Function pointers to deal with this struct. */ + const struct vm_operations_struct *vm_ops; + + /* Information about our backing store: */ + unsigned long vm_pgoff; /* Offset (within vm_file) in PAGE_SIZE + units */ + struct file * vm_file; /* File we map to (can be NULL). */ + void * vm_private_data; /* was vm_pte (shared mem) */ + +#ifndef CONFIG_MMU + struct vm_region *vm_region; /* NOMMU mapping region */ +#endif +#ifdef CONFIG_NUMA + struct mempolicy *vm_policy; /* NUMA policy for the VMA */ +#endif + struct vm_userfaultfd_ctx vm_userfaultfd_ctx; +}; + +struct core_thread { + struct task_struct *task; + struct core_thread *next; +}; + +struct core_state { + atomic_t nr_threads; + struct core_thread dumper; + struct completion startup; +}; + +enum { + MM_FILEPAGES, /* Resident file mapping pages */ + MM_ANONPAGES, /* Resident anonymous pages */ + MM_SWAPENTS, /* Anonymous swap entries */ + MM_SHMEMPAGES, /* Resident shared memory pages */ + NR_MM_COUNTERS +}; + +#if USE_SPLIT_PTE_PTLOCKS && defined(CONFIG_MMU) +#define SPLIT_RSS_COUNTING +/* per-thread cached information, */ +struct task_rss_stat { + int events; /* for synchronization threshold */ + int count[NR_MM_COUNTERS]; +}; +#endif /* USE_SPLIT_PTE_PTLOCKS */ + +struct mm_rss_stat { + atomic_long_t count[NR_MM_COUNTERS]; +}; + +struct kioctx_table; +struct mm_struct { + struct vm_area_struct *mmap; /* list of VMAs */ + struct rb_root mm_rb; + u32 vmacache_seqnum; /* per-thread vmacache */ +#ifdef CONFIG_MMU + unsigned long (*get_unmapped_area) (struct file *filp, + unsigned long addr, unsigned long len, + unsigned long pgoff, unsigned long flags); +#endif + unsigned long mmap_base; /* base of mmap area */ + unsigned long mmap_legacy_base; /* base of mmap area in bottom-up allocations */ + unsigned long task_size; /* size of task vm space */ + unsigned long highest_vm_end; /* highest vma end address */ + pgd_t * pgd; + atomic_t mm_users; /* How many users with user space? */ + atomic_t mm_count; /* How many references to "struct mm_struct" (users count as 1) */ + atomic_long_t nr_ptes; /* PTE page table pages */ +#if CONFIG_PGTABLE_LEVELS > 2 + atomic_long_t nr_pmds; /* PMD page table pages */ +#endif + int map_count; /* number of VMAs */ + + spinlock_t page_table_lock; /* Protects page tables and some counters */ + struct rw_semaphore mmap_sem; + + struct list_head mmlist; /* List of maybe swapped mm's. These are globally strung + * together off init_mm.mmlist, and are protected + * by mmlist_lock + */ + + + unsigned long hiwater_rss; /* High-watermark of RSS usage */ + unsigned long hiwater_vm; /* High-water virtual memory usage */ + + unsigned long total_vm; /* Total pages mapped */ + unsigned long locked_vm; /* Pages that have PG_mlocked set */ + unsigned long pinned_vm; /* Refcount permanently increased */ + unsigned long data_vm; /* VM_WRITE & ~VM_SHARED & ~VM_STACK */ + unsigned long exec_vm; /* VM_EXEC & ~VM_WRITE & ~VM_STACK */ + unsigned long stack_vm; /* VM_STACK */ + unsigned long def_flags; + unsigned long start_code, end_code, start_data, end_data; + unsigned long start_brk, brk, start_stack; + unsigned long arg_start, arg_end, env_start, env_end; + + unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */ + + /* + * Special counters, in some configurations protected by the + * page_table_lock, in other configurations by being atomic. + */ + struct mm_rss_stat rss_stat; + + struct linux_binfmt *binfmt; + + cpumask_var_t cpu_vm_mask_var; + + /* Architecture-specific MM context */ + mm_context_t context; + + unsigned long flags; /* Must use atomic bitops to access the bits */ + + struct core_state *core_state; /* coredumping support */ +#ifdef CONFIG_AIO + spinlock_t ioctx_lock; + struct kioctx_table __rcu *ioctx_table; +#endif +#ifdef CONFIG_MEMCG + /* + * "owner" points to a task that is regarded as the canonical + * user/owner of this mm. All of the following must be true in + * order for it to be changed: + * + * current == mm->owner + * current->mm != mm + * new_owner->mm == mm + * new_owner->alloc_lock is held + */ + struct task_struct __rcu *owner; +#endif + + /* store ref to file /proc//exe symlink points to */ + struct file __rcu *exe_file; +#ifdef CONFIG_MMU_NOTIFIER + struct mmu_notifier_mm *mmu_notifier_mm; +#endif +#if defined(CONFIG_TRANSPARENT_HUGEPAGE) && !USE_SPLIT_PMD_PTLOCKS + pgtable_t pmd_huge_pte; /* protected by page_table_lock */ +#endif +#ifdef CONFIG_CPUMASK_OFFSTACK + struct cpumask cpumask_allocation; +#endif +#ifdef CONFIG_NUMA_BALANCING + /* + * numa_next_scan is the next time that the PTEs will be marked + * pte_numa. NUMA hinting faults will gather statistics and migrate + * pages to new nodes if necessary. + */ + unsigned long numa_next_scan; + + /* Restart point for scanning and setting pte_numa */ + unsigned long numa_scan_offset; + + /* numa_scan_seq prevents two threads setting pte_numa */ + int numa_scan_seq; +#endif +#if defined(CONFIG_NUMA_BALANCING) || defined(CONFIG_COMPACTION) + /* + * An operation with batched TLB flushing is going on. Anything that + * can move process memory needs to flush the TLB when moving a + * PROT_NONE or PROT_NUMA mapped page. + */ + bool tlb_flush_pending; +#endif + struct uprobes_state uprobes_state; +#ifdef CONFIG_X86_INTEL_MPX + /* address of the bounds directory */ + void __user *bd_addr; +#endif +#ifdef CONFIG_HUGETLB_PAGE + atomic_long_t hugetlb_usage; +#endif +#ifdef CONFIG_MMU + struct work_struct async_put_work; +#endif +}; + +static inline void mm_init_cpumask(struct mm_struct *mm) +{ +#ifdef CONFIG_CPUMASK_OFFSTACK + mm->cpu_vm_mask_var = &mm->cpumask_allocation; +#endif + cpumask_clear(mm->cpu_vm_mask_var); +} + +/* Future-safe accessor for struct mm_struct's cpu_vm_mask. */ +static inline cpumask_t *mm_cpumask(struct mm_struct *mm) +{ + return mm->cpu_vm_mask_var; +} + +#if defined(CONFIG_NUMA_BALANCING) || defined(CONFIG_COMPACTION) +/* + * Memory barriers to keep this state in sync are graciously provided by + * the page table locks, outside of which no page table modifications happen. + * The barriers below prevent the compiler from re-ordering the instructions + * around the memory barriers that are already present in the code. + */ +static inline bool mm_tlb_flush_pending(struct mm_struct *mm) +{ + barrier(); + return mm->tlb_flush_pending; +} +static inline void set_tlb_flush_pending(struct mm_struct *mm) +{ + mm->tlb_flush_pending = true; + + /* + * Guarantee that the tlb_flush_pending store does not leak into the + * critical section updating the page tables + */ + smp_mb__before_spinlock(); +} +/* Clearing is done after a TLB flush, which also provides a barrier. */ +static inline void clear_tlb_flush_pending(struct mm_struct *mm) +{ + barrier(); + mm->tlb_flush_pending = false; +} +#else +static inline bool mm_tlb_flush_pending(struct mm_struct *mm) +{ + return false; +} +static inline void set_tlb_flush_pending(struct mm_struct *mm) +{ +} +static inline void clear_tlb_flush_pending(struct mm_struct *mm) +{ +} +#endif + +struct vm_fault; + +struct vm_special_mapping { + const char *name; /* The name, e.g. "[vdso]". */ + + /* + * If .fault is not provided, this points to a + * NULL-terminated array of pages that back the special mapping. + * + * This must not be NULL unless .fault is provided. + */ + struct page **pages; + + /* + * If non-NULL, then this is called to resolve page faults + * on the special mapping. If used, .pages is not checked. + */ + int (*fault)(const struct vm_special_mapping *sm, + struct vm_area_struct *vma, + struct vm_fault *vmf); +}; + +enum tlb_flush_reason { + TLB_FLUSH_ON_TASK_SWITCH, + TLB_REMOTE_SHOOTDOWN, + TLB_LOCAL_SHOOTDOWN, + TLB_LOCAL_MM_SHOOTDOWN, + TLB_REMOTE_SEND_IPI, + NR_TLB_FLUSH_REASONS, +}; + + /* + * A swap entry has to fit into a "unsigned long", as the entry is hidden + * in the "index" field of the swapper address space. + */ +typedef struct { + unsigned long val; +} swp_entry_t; + +#endif /* _LINUX_MM_TYPES_H */ diff --git a/study/kernel/02-memory/01-description/04-page/pageflags.h b/study/kernel/02-memory/01-description/04-page/pageflags.h new file mode 100644 index 0000000..bcbae20 --- /dev/null +++ b/study/kernel/02-memory/01-description/04-page/pageflags.h @@ -0,0 +1,720 @@ +/* + * Macros for manipulating and testing page->flags + */ + +#ifndef PAGE_FLAGS_H +#define PAGE_FLAGS_H + +#include +#include +#include +#ifndef __GENERATING_BOUNDS_H +#include +#include +#endif /* !__GENERATING_BOUNDS_H */ + +/* + * Various page->flags bits: + * + * PG_reserved is set for special pages, which can never be swapped out. Some + * of them might not even exist (eg empty_bad_page)... + * + * The PG_private bitflag is set on pagecache pages if they contain filesystem + * specific data (which is normally at page->private). It can be used by + * private allocations for its own usage. + * + * During initiation of disk I/O, PG_locked is set. This bit is set before I/O + * and cleared when writeback _starts_ or when read _completes_. PG_writeback + * is set before writeback starts and cleared when it finishes. + * + * PG_locked also pins a page in pagecache, and blocks truncation of the file + * while it is held. + * + * page_waitqueue(page) is a wait queue of all tasks waiting for the page + * to become unlocked. + * + * PG_uptodate tells whether the page's contents is valid. When a read + * completes, the page becomes uptodate, unless a disk I/O error happened. + * + * PG_referenced, PG_reclaim are used for page reclaim for anonymous and + * file-backed pagecache (see mm/vmscan.c). + * + * PG_error is set to indicate that an I/O error occurred on this page. + * + * PG_arch_1 is an architecture specific page state bit. The generic code + * guarantees that this bit is cleared for a page when it first is entered into + * the page cache. + * + * PG_highmem pages are not permanently mapped into the kernel virtual address + * space, they need to be kmapped separately for doing IO on the pages. The + * struct page (these bits with information) are always mapped into kernel + * address space... + * + * PG_hwpoison indicates that a page got corrupted in hardware and contains + * data with incorrect ECC bits that triggered a machine check. Accessing is + * not safe since it may cause another machine check. Don't touch! + */ + +/* + * Don't use the *_dontuse flags. Use the macros. Otherwise you'll break + * locked- and dirty-page accounting. + * + * The page flags field is split into two parts, the main flags area + * which extends from the low bits upwards, and the fields area which + * extends from the high bits downwards. + * + * | FIELD | ... | FLAGS | + * N-1 ^ 0 + * (NR_PAGEFLAGS) + * + * The fields area is reserved for fields mapping zone, node (for NUMA) and + * SPARSEMEM section (for variants of SPARSEMEM that require section ids like + * SPARSEMEM_EXTREME with !SPARSEMEM_VMEMMAP). + */ +enum pageflags { + PG_locked, /* Page is locked. Don't touch. */ + PG_error, + PG_referenced, + PG_uptodate, + PG_dirty, + PG_lru, + PG_active, + PG_slab, + PG_owner_priv_1, /* Owner use. If pagecache, fs may use*/ + PG_arch_1, + PG_reserved, + PG_private, /* If pagecache, has fs-private data */ + PG_private_2, /* If pagecache, has fs aux data */ + PG_writeback, /* Page is under writeback */ + PG_head, /* A head page */ + PG_swapcache, /* Swap page: swp_entry_t in private */ + PG_mappedtodisk, /* Has blocks allocated on-disk */ + PG_reclaim, /* To be reclaimed asap */ + PG_swapbacked, /* Page is backed by RAM/swap */ + PG_unevictable, /* Page is "unevictable" */ +#ifdef CONFIG_MMU + PG_mlocked, /* Page is vma mlocked */ +#endif +#ifdef CONFIG_ARCH_USES_PG_UNCACHED + PG_uncached, /* Page has been mapped as uncached */ +#endif +#ifdef CONFIG_MEMORY_FAILURE + PG_hwpoison, /* hardware poisoned page. Don't touch */ +#endif +#if defined(CONFIG_IDLE_PAGE_TRACKING) && defined(CONFIG_64BIT) + PG_young, + PG_idle, +#endif + __NR_PAGEFLAGS, + + /* Filesystems */ + PG_checked = PG_owner_priv_1, + + /* Two page bits are conscripted by FS-Cache to maintain local caching + * state. These bits are set on pages belonging to the netfs's inodes + * when those inodes are being locally cached. + */ + PG_fscache = PG_private_2, /* page backed by cache */ + + /* XEN */ + /* Pinned in Xen as a read-only pagetable page. */ + PG_pinned = PG_owner_priv_1, + /* Pinned as part of domain save (see xen_mm_pin_all()). */ + PG_savepinned = PG_dirty, + /* Has a grant mapping of another (foreign) domain's page. */ + PG_foreign = PG_owner_priv_1, + + /* SLOB */ + PG_slob_free = PG_private, + + /* Compound pages. Stored in first tail page's flags */ + PG_double_map = PG_private_2, +}; + +#ifndef __GENERATING_BOUNDS_H + +struct page; /* forward declaration */ + +static inline struct page *compound_head(struct page *page) +{ + unsigned long head = READ_ONCE(page->compound_head); + + if (unlikely(head & 1)) + return (struct page *) (head - 1); + return page; +} + +static __always_inline int PageTail(struct page *page) +{ + return READ_ONCE(page->compound_head) & 1; +} + +static __always_inline int PageCompound(struct page *page) +{ + return test_bit(PG_head, &page->flags) || PageTail(page); +} + +/* + * Page flags policies wrt compound pages + * + * PF_ANY: + * the page flag is relevant for small, head and tail pages. + * + * PF_HEAD: + * for compound page all operations related to the page flag applied to + * head page. + * + * PF_NO_TAIL: + * modifications of the page flag must be done on small or head pages, + * checks can be done on tail pages too. + * + * PF_NO_COMPOUND: + * the page flag is not relevant for compound pages. + */ +#define PF_ANY(page, enforce) page +#define PF_HEAD(page, enforce) compound_head(page) +#define PF_NO_TAIL(page, enforce) ({ \ + VM_BUG_ON_PGFLAGS(enforce && PageTail(page), page); \ + compound_head(page);}) +#define PF_NO_COMPOUND(page, enforce) ({ \ + VM_BUG_ON_PGFLAGS(enforce && PageCompound(page), page); \ + page;}) + +/* + * Macros to create function definitions for page flags + */ +#define TESTPAGEFLAG(uname, lname, policy) \ +static __always_inline int Page##uname(struct page *page) \ + { return test_bit(PG_##lname, &policy(page, 0)->flags); } + +#define SETPAGEFLAG(uname, lname, policy) \ +static __always_inline void SetPage##uname(struct page *page) \ + { set_bit(PG_##lname, &policy(page, 1)->flags); } + +#define CLEARPAGEFLAG(uname, lname, policy) \ +static __always_inline void ClearPage##uname(struct page *page) \ + { clear_bit(PG_##lname, &policy(page, 1)->flags); } + +#define __SETPAGEFLAG(uname, lname, policy) \ +static __always_inline void __SetPage##uname(struct page *page) \ + { __set_bit(PG_##lname, &policy(page, 1)->flags); } + +#define __CLEARPAGEFLAG(uname, lname, policy) \ +static __always_inline void __ClearPage##uname(struct page *page) \ + { __clear_bit(PG_##lname, &policy(page, 1)->flags); } + +#define TESTSETFLAG(uname, lname, policy) \ +static __always_inline int TestSetPage##uname(struct page *page) \ + { return test_and_set_bit(PG_##lname, &policy(page, 1)->flags); } + +#define TESTCLEARFLAG(uname, lname, policy) \ +static __always_inline int TestClearPage##uname(struct page *page) \ + { return test_and_clear_bit(PG_##lname, &policy(page, 1)->flags); } + +#define PAGEFLAG(uname, lname, policy) \ + TESTPAGEFLAG(uname, lname, policy) \ + SETPAGEFLAG(uname, lname, policy) \ + CLEARPAGEFLAG(uname, lname, policy) + +#define __PAGEFLAG(uname, lname, policy) \ + TESTPAGEFLAG(uname, lname, policy) \ + __SETPAGEFLAG(uname, lname, policy) \ + __CLEARPAGEFLAG(uname, lname, policy) + +#define TESTSCFLAG(uname, lname, policy) \ + TESTSETFLAG(uname, lname, policy) \ + TESTCLEARFLAG(uname, lname, policy) + +#define TESTPAGEFLAG_FALSE(uname) \ +static inline int Page##uname(const struct page *page) { return 0; } + +#define SETPAGEFLAG_NOOP(uname) \ +static inline void SetPage##uname(struct page *page) { } + +#define CLEARPAGEFLAG_NOOP(uname) \ +static inline void ClearPage##uname(struct page *page) { } + +#define __CLEARPAGEFLAG_NOOP(uname) \ +static inline void __ClearPage##uname(struct page *page) { } + +#define TESTSETFLAG_FALSE(uname) \ +static inline int TestSetPage##uname(struct page *page) { return 0; } + +#define TESTCLEARFLAG_FALSE(uname) \ +static inline int TestClearPage##uname(struct page *page) { return 0; } + +#define PAGEFLAG_FALSE(uname) TESTPAGEFLAG_FALSE(uname) \ + SETPAGEFLAG_NOOP(uname) CLEARPAGEFLAG_NOOP(uname) + +#define TESTSCFLAG_FALSE(uname) \ + TESTSETFLAG_FALSE(uname) TESTCLEARFLAG_FALSE(uname) + +__PAGEFLAG(Locked, locked, PF_NO_TAIL) +PAGEFLAG(Error, error, PF_NO_COMPOUND) TESTCLEARFLAG(Error, error, PF_NO_COMPOUND) +PAGEFLAG(Referenced, referenced, PF_HEAD) + TESTCLEARFLAG(Referenced, referenced, PF_HEAD) + __SETPAGEFLAG(Referenced, referenced, PF_HEAD) +PAGEFLAG(Dirty, dirty, PF_HEAD) TESTSCFLAG(Dirty, dirty, PF_HEAD) + __CLEARPAGEFLAG(Dirty, dirty, PF_HEAD) +PAGEFLAG(LRU, lru, PF_HEAD) __CLEARPAGEFLAG(LRU, lru, PF_HEAD) +PAGEFLAG(Active, active, PF_HEAD) __CLEARPAGEFLAG(Active, active, PF_HEAD) + TESTCLEARFLAG(Active, active, PF_HEAD) +__PAGEFLAG(Slab, slab, PF_NO_TAIL) +__PAGEFLAG(SlobFree, slob_free, PF_NO_TAIL) +PAGEFLAG(Checked, checked, PF_NO_COMPOUND) /* Used by some filesystems */ + +/* Xen */ +PAGEFLAG(Pinned, pinned, PF_NO_COMPOUND) + TESTSCFLAG(Pinned, pinned, PF_NO_COMPOUND) +PAGEFLAG(SavePinned, savepinned, PF_NO_COMPOUND); +PAGEFLAG(Foreign, foreign, PF_NO_COMPOUND); + +PAGEFLAG(Reserved, reserved, PF_NO_COMPOUND) + __CLEARPAGEFLAG(Reserved, reserved, PF_NO_COMPOUND) +PAGEFLAG(SwapBacked, swapbacked, PF_NO_TAIL) + __CLEARPAGEFLAG(SwapBacked, swapbacked, PF_NO_TAIL) + __SETPAGEFLAG(SwapBacked, swapbacked, PF_NO_TAIL) + +/* + * Private page markings that may be used by the filesystem that owns the page + * for its own purposes. + * - PG_private and PG_private_2 cause releasepage() and co to be invoked + */ +PAGEFLAG(Private, private, PF_ANY) __SETPAGEFLAG(Private, private, PF_ANY) + __CLEARPAGEFLAG(Private, private, PF_ANY) +PAGEFLAG(Private2, private_2, PF_ANY) TESTSCFLAG(Private2, private_2, PF_ANY) +PAGEFLAG(OwnerPriv1, owner_priv_1, PF_ANY) + TESTCLEARFLAG(OwnerPriv1, owner_priv_1, PF_ANY) + +/* + * Only test-and-set exist for PG_writeback. The unconditional operators are + * risky: they bypass page accounting. + */ +TESTPAGEFLAG(Writeback, writeback, PF_NO_COMPOUND) + TESTSCFLAG(Writeback, writeback, PF_NO_COMPOUND) +PAGEFLAG(MappedToDisk, mappedtodisk, PF_NO_COMPOUND) + +/* PG_readahead is only used for reads; PG_reclaim is only for writes */ +PAGEFLAG(Reclaim, reclaim, PF_NO_COMPOUND) + TESTCLEARFLAG(Reclaim, reclaim, PF_NO_COMPOUND) +PAGEFLAG(Readahead, reclaim, PF_NO_COMPOUND) + TESTCLEARFLAG(Readahead, reclaim, PF_NO_COMPOUND) + +#ifdef CONFIG_HIGHMEM +/* + * Must use a macro here due to header dependency issues. page_zone() is not + * available at this point. + */ +#define PageHighMem(__p) is_highmem_idx(page_zonenum(__p)) +#else +PAGEFLAG_FALSE(HighMem) +#endif + +#ifdef CONFIG_SWAP +PAGEFLAG(SwapCache, swapcache, PF_NO_COMPOUND) +#else +PAGEFLAG_FALSE(SwapCache) +#endif + +PAGEFLAG(Unevictable, unevictable, PF_HEAD) + __CLEARPAGEFLAG(Unevictable, unevictable, PF_HEAD) + TESTCLEARFLAG(Unevictable, unevictable, PF_HEAD) + +#ifdef CONFIG_MMU +PAGEFLAG(Mlocked, mlocked, PF_NO_TAIL) + __CLEARPAGEFLAG(Mlocked, mlocked, PF_NO_TAIL) + TESTSCFLAG(Mlocked, mlocked, PF_NO_TAIL) +#else +PAGEFLAG_FALSE(Mlocked) __CLEARPAGEFLAG_NOOP(Mlocked) + TESTSCFLAG_FALSE(Mlocked) +#endif + +#ifdef CONFIG_ARCH_USES_PG_UNCACHED +PAGEFLAG(Uncached, uncached, PF_NO_COMPOUND) +#else +PAGEFLAG_FALSE(Uncached) +#endif + +#ifdef CONFIG_MEMORY_FAILURE +PAGEFLAG(HWPoison, hwpoison, PF_ANY) +TESTSCFLAG(HWPoison, hwpoison, PF_ANY) +#define __PG_HWPOISON (1UL << PG_hwpoison) +#else +PAGEFLAG_FALSE(HWPoison) +#define __PG_HWPOISON 0 +#endif + +#if defined(CONFIG_IDLE_PAGE_TRACKING) && defined(CONFIG_64BIT) +TESTPAGEFLAG(Young, young, PF_ANY) +SETPAGEFLAG(Young, young, PF_ANY) +TESTCLEARFLAG(Young, young, PF_ANY) +PAGEFLAG(Idle, idle, PF_ANY) +#endif + +/* + * On an anonymous page mapped into a user virtual memory area, + * page->mapping points to its anon_vma, not to a struct address_space; + * with the PAGE_MAPPING_ANON bit set to distinguish it. See rmap.h. + * + * On an anonymous page in a VM_MERGEABLE area, if CONFIG_KSM is enabled, + * the PAGE_MAPPING_KSM bit may be set along with the PAGE_MAPPING_ANON bit; + * and then page->mapping points, not to an anon_vma, but to a private + * structure which KSM associates with that merged page. See ksm.h. + * + * PAGE_MAPPING_KSM without PAGE_MAPPING_ANON is currently never used. + * + * Please note that, confusingly, "page_mapping" refers to the inode + * address_space which maps the page from disk; whereas "page_mapped" + * refers to user virtual address space into which the page is mapped. + */ +#define PAGE_MAPPING_ANON 1 +#define PAGE_MAPPING_KSM 2 +#define PAGE_MAPPING_FLAGS (PAGE_MAPPING_ANON | PAGE_MAPPING_KSM) + +static __always_inline int PageAnonHead(struct page *page) +{ + return ((unsigned long)page->mapping & PAGE_MAPPING_ANON) != 0; +} + +static __always_inline int PageAnon(struct page *page) +{ + page = compound_head(page); + return PageAnonHead(page); +} + +#ifdef CONFIG_KSM +/* + * A KSM page is one of those write-protected "shared pages" or "merged pages" + * which KSM maps into multiple mms, wherever identical anonymous page content + * is found in VM_MERGEABLE vmas. It's a PageAnon page, pointing not to any + * anon_vma, but to that page's node of the stable tree. + */ +static __always_inline int PageKsm(struct page *page) +{ + page = compound_head(page); + return ((unsigned long)page->mapping & PAGE_MAPPING_FLAGS) == + (PAGE_MAPPING_ANON | PAGE_MAPPING_KSM); +} +#else +TESTPAGEFLAG_FALSE(Ksm) +#endif + +u64 stable_page_flags(struct page *page); + +static inline int PageUptodate(struct page *page) +{ + int ret; + page = compound_head(page); + ret = test_bit(PG_uptodate, &(page)->flags); + /* + * Must ensure that the data we read out of the page is loaded + * _after_ we've loaded page->flags to check for PageUptodate. + * We can skip the barrier if the page is not uptodate, because + * we wouldn't be reading anything from it. + * + * See SetPageUptodate() for the other side of the story. + */ + if (ret) + smp_rmb(); + + return ret; +} + +static __always_inline void __SetPageUptodate(struct page *page) +{ + VM_BUG_ON_PAGE(PageTail(page), page); + smp_wmb(); + __set_bit(PG_uptodate, &page->flags); +} + +static __always_inline void SetPageUptodate(struct page *page) +{ + VM_BUG_ON_PAGE(PageTail(page), page); + /* + * Memory barrier must be issued before setting the PG_uptodate bit, + * so that all previous stores issued in order to bring the page + * uptodate are actually visible before PageUptodate becomes true. + */ + smp_wmb(); + set_bit(PG_uptodate, &page->flags); +} + +CLEARPAGEFLAG(Uptodate, uptodate, PF_NO_TAIL) + +int test_clear_page_writeback(struct page *page); +int __test_set_page_writeback(struct page *page, bool keep_write); + +#define test_set_page_writeback(page) \ + __test_set_page_writeback(page, false) +#define test_set_page_writeback_keepwrite(page) \ + __test_set_page_writeback(page, true) + +static inline void set_page_writeback(struct page *page) +{ + test_set_page_writeback(page); +} + +static inline void set_page_writeback_keepwrite(struct page *page) +{ + test_set_page_writeback_keepwrite(page); +} + +__PAGEFLAG(Head, head, PF_ANY) CLEARPAGEFLAG(Head, head, PF_ANY) + +static __always_inline void set_compound_head(struct page *page, struct page *head) +{ + WRITE_ONCE(page->compound_head, (unsigned long)head + 1); +} + +static __always_inline void clear_compound_head(struct page *page) +{ + WRITE_ONCE(page->compound_head, 0); +} + +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +static inline void ClearPageCompound(struct page *page) +{ + BUG_ON(!PageHead(page)); + ClearPageHead(page); +} +#endif + +#define PG_head_mask ((1UL << PG_head)) + +#ifdef CONFIG_HUGETLB_PAGE +int PageHuge(struct page *page); +int PageHeadHuge(struct page *page); +bool page_huge_active(struct page *page); +#else +TESTPAGEFLAG_FALSE(Huge) +TESTPAGEFLAG_FALSE(HeadHuge) + +static inline bool page_huge_active(struct page *page) +{ + return 0; +} +#endif + + +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +/* + * PageHuge() only returns true for hugetlbfs pages, but not for + * normal or transparent huge pages. + * + * PageTransHuge() returns true for both transparent huge and + * hugetlbfs pages, but not normal pages. PageTransHuge() can only be + * called only in the core VM paths where hugetlbfs pages can't exist. + */ +static inline int PageTransHuge(struct page *page) +{ + VM_BUG_ON_PAGE(PageTail(page), page); + return PageHead(page); +} + +/* + * PageTransCompound returns true for both transparent huge pages + * and hugetlbfs pages, so it should only be called when it's known + * that hugetlbfs pages aren't involved. + */ +static inline int PageTransCompound(struct page *page) +{ + return PageCompound(page); +} + +/* + * PageTransCompoundMap is the same as PageTransCompound, but it also + * guarantees the primary MMU has the entire compound page mapped + * through pmd_trans_huge, which in turn guarantees the secondary MMUs + * can also map the entire compound page. This allows the secondary + * MMUs to call get_user_pages() only once for each compound page and + * to immediately map the entire compound page with a single secondary + * MMU fault. If there will be a pmd split later, the secondary MMUs + * will get an update through the MMU notifier invalidation through + * split_huge_pmd(). + * + * Unlike PageTransCompound, this is safe to be called only while + * split_huge_pmd() cannot run from under us, like if protected by the + * MMU notifier, otherwise it may result in page->_mapcount < 0 false + * positives. + */ +static inline int PageTransCompoundMap(struct page *page) +{ + return PageTransCompound(page) && atomic_read(&page->_mapcount) < 0; +} + +/* + * PageTransTail returns true for both transparent huge pages + * and hugetlbfs pages, so it should only be called when it's known + * that hugetlbfs pages aren't involved. + */ +static inline int PageTransTail(struct page *page) +{ + return PageTail(page); +} + +/* + * PageDoubleMap indicates that the compound page is mapped with PTEs as well + * as PMDs. + * + * This is required for optimization of rmap operations for THP: we can postpone + * per small page mapcount accounting (and its overhead from atomic operations) + * until the first PMD split. + * + * For the page PageDoubleMap means ->_mapcount in all sub-pages is offset up + * by one. This reference will go away with last compound_mapcount. + * + * See also __split_huge_pmd_locked() and page_remove_anon_compound_rmap(). + */ +static inline int PageDoubleMap(struct page *page) +{ + return PageHead(page) && test_bit(PG_double_map, &page[1].flags); +} + +static inline int TestSetPageDoubleMap(struct page *page) +{ + VM_BUG_ON_PAGE(!PageHead(page), page); + return test_and_set_bit(PG_double_map, &page[1].flags); +} + +static inline int TestClearPageDoubleMap(struct page *page) +{ + VM_BUG_ON_PAGE(!PageHead(page), page); + return test_and_clear_bit(PG_double_map, &page[1].flags); +} + +#else +TESTPAGEFLAG_FALSE(TransHuge) +TESTPAGEFLAG_FALSE(TransCompound) +TESTPAGEFLAG_FALSE(TransCompoundMap) +TESTPAGEFLAG_FALSE(TransTail) +TESTPAGEFLAG_FALSE(DoubleMap) + TESTSETFLAG_FALSE(DoubleMap) + TESTCLEARFLAG_FALSE(DoubleMap) +#endif + +/* + * PageBuddy() indicate that the page is free and in the buddy system + * (see mm/page_alloc.c). + * + * PAGE_BUDDY_MAPCOUNT_VALUE must be <= -2 but better not too close to + * -2 so that an underflow of the page_mapcount() won't be mistaken + * for a genuine PAGE_BUDDY_MAPCOUNT_VALUE. -128 can be created very + * efficiently by most CPU architectures. + */ +#define PAGE_BUDDY_MAPCOUNT_VALUE (-128) + +static inline int PageBuddy(struct page *page) +{ + return atomic_read(&page->_mapcount) == PAGE_BUDDY_MAPCOUNT_VALUE; +} + +static inline void __SetPageBuddy(struct page *page) +{ + VM_BUG_ON_PAGE(atomic_read(&page->_mapcount) != -1, page); + atomic_set(&page->_mapcount, PAGE_BUDDY_MAPCOUNT_VALUE); +} + +static inline void __ClearPageBuddy(struct page *page) +{ + VM_BUG_ON_PAGE(!PageBuddy(page), page); + atomic_set(&page->_mapcount, -1); +} + +extern bool is_free_buddy_page(struct page *page); + +#define PAGE_BALLOON_MAPCOUNT_VALUE (-256) + +static inline int PageBalloon(struct page *page) +{ + return atomic_read(&page->_mapcount) == PAGE_BALLOON_MAPCOUNT_VALUE; +} + +static inline void __SetPageBalloon(struct page *page) +{ + VM_BUG_ON_PAGE(atomic_read(&page->_mapcount) != -1, page); + atomic_set(&page->_mapcount, PAGE_BALLOON_MAPCOUNT_VALUE); +} + +static inline void __ClearPageBalloon(struct page *page) +{ + VM_BUG_ON_PAGE(!PageBalloon(page), page); + atomic_set(&page->_mapcount, -1); +} + +/* + * If network-based swap is enabled, sl*b must keep track of whether pages + * were allocated from pfmemalloc reserves. + */ +static inline int PageSlabPfmemalloc(struct page *page) +{ + VM_BUG_ON_PAGE(!PageSlab(page), page); + return PageActive(page); +} + +static inline void SetPageSlabPfmemalloc(struct page *page) +{ + VM_BUG_ON_PAGE(!PageSlab(page), page); + SetPageActive(page); +} + +static inline void __ClearPageSlabPfmemalloc(struct page *page) +{ + VM_BUG_ON_PAGE(!PageSlab(page), page); + __ClearPageActive(page); +} + +static inline void ClearPageSlabPfmemalloc(struct page *page) +{ + VM_BUG_ON_PAGE(!PageSlab(page), page); + ClearPageActive(page); +} + +#ifdef CONFIG_MMU +#define __PG_MLOCKED (1UL << PG_mlocked) +#else +#define __PG_MLOCKED 0 +#endif + +/* + * Flags checked when a page is freed. Pages being freed should not have + * these flags set. It they are, there is a problem. + */ +#define PAGE_FLAGS_CHECK_AT_FREE \ + (1UL << PG_lru | 1UL << PG_locked | \ + 1UL << PG_private | 1UL << PG_private_2 | \ + 1UL << PG_writeback | 1UL << PG_reserved | \ + 1UL << PG_slab | 1UL << PG_swapcache | 1UL << PG_active | \ + 1UL << PG_unevictable | __PG_MLOCKED) + +/* + * Flags checked when a page is prepped for return by the page allocator. + * Pages being prepped should not have these flags set. It they are set, + * there has been a kernel bug or struct page corruption. + * + * __PG_HWPOISON is exceptional because it needs to be kept beyond page's + * alloc-free cycle to prevent from reusing the page. + */ +#define PAGE_FLAGS_CHECK_AT_PREP \ + (((1UL << NR_PAGEFLAGS) - 1) & ~__PG_HWPOISON) + +#define PAGE_FLAGS_PRIVATE \ + (1UL << PG_private | 1UL << PG_private_2) +/** + * page_has_private - Determine if page has private stuff + * @page: The page to be checked + * + * Determine if a page has private stuff, indicating that release routines + * should be invoked upon it. + */ +static inline int page_has_private(struct page *page) +{ + return !!(page->flags & PAGE_FLAGS_PRIVATE); +} + +#undef PF_ANY +#undef PF_HEAD +#undef PF_NO_TAIL +#undef PF_NO_COMPOUND +#endif /* !__GENERATING_BOUNDS_H */ + +#endif /* PAGE_FLAGS_H */