From 4173ab052b893702bbee55febef3ccbf615550f8 Mon Sep 17 00:00:00 2001 From: Rmys Date: Thu, 30 Jan 2020 23:22:12 +0300 Subject: [PATCH] perf ver bump --- .../perf/files/patches/linux/patch-5.4.16.xz | Bin 0 -> 600184 bytes .../files/patches/mageia/CVE-2019-12379.patch | 37 + .../patches/mageia/fs-aufs-5.4-modular.patch | 321 + .../patches/mageia/fs-aufs-5.4-version.patch | 12 + .../files/patches/mageia/fs-aufs-5.4.patch | 37876 ++++++++++++++++ .../perf/files/patches/mageia/fs-vboxsf.patch | 3410 ++ kernel/tools/perf/pspec.xml | 18 +- 7 files changed, 41665 insertions(+), 9 deletions(-) create mode 100644 kernel/tools/perf/files/patches/linux/patch-5.4.16.xz create mode 100644 kernel/tools/perf/files/patches/mageia/CVE-2019-12379.patch create mode 100644 kernel/tools/perf/files/patches/mageia/fs-aufs-5.4-modular.patch create mode 100755 kernel/tools/perf/files/patches/mageia/fs-aufs-5.4-version.patch create mode 100644 kernel/tools/perf/files/patches/mageia/fs-aufs-5.4.patch create mode 100644 kernel/tools/perf/files/patches/mageia/fs-vboxsf.patch diff --git a/kernel/tools/perf/files/patches/linux/patch-5.4.16.xz b/kernel/tools/perf/files/patches/linux/patch-5.4.16.xz new file mode 100644 index 0000000000000000000000000000000000000000..f9ea9df04f228895428ab47f744b6215e56d4e77 GIT binary patch literal 600184 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%0A##i-(J)7K4#tB|GmXFJ6Nxq%^u;(<{-tDK7_p4 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 `;=lKU9ydRNs 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 zçR>1U0n-KJE2HI>$ zmHn+q#Pw~cmGKGcx_56|TmB^lL@IU$CX^8B+}vO_sV``EzOU5f-^Dke6JFolth^wjR9~;|kaU@Mtu*Ux@mB=m~tt=o- zs@%v&r*6)*+-j=7O%t|au~L-=@)!sBrRx^;CJ)rP`&-j+wL|{jZN-Q5Ybc%Qy0yWG z-FwYSwjbQs<^2fiv(U0Xh(RPaLsc_v&YIdki$&$({8@Q~ zW=Dsj{XRB!8wq>b>sUa^8 zw%BZ4O?Xr@{=SUXG(*3ZP;GZ(5U8)iase&GvIssxcZiV;x za-Wgq1^9R6OSK8lCwqNi@Vick(J{YTbud|s>#d%e(zE3h7NFRntPt)k3WJl5+PH9? z;pXvV{8kcIl3rjwoRn#NNYUn(P#)|6+qf!FtioUDekGvOD~DRe{LAd`vFO{Qav(7} z<`R5%MP&$-_6Pp_8B3(uGW&6f@9bGmU`<_WlK}Q$6B*)MDzv9}pSEej4I#_R?CC(! zT`Dn=UiR4rjSB}_Go&!SxV(ffi{Dx1$SdayE`Iqd2iQVB!3-1&neer;(t>L96)hv* zR-Ch|Ga@Bk6IhwQAW)v!G}z>P9?S1>^bTTg?tOcxiR0ZUEc9A1- zXwXnPR5%)R#Q}>$ojhxM3VuNEHMUnxpq3jVW1}%ulv-77#dg#hN))B4oO$SdZco|>RtXdTi)jn49OZIkv5?MAUO_(2w%!yI{ILmQ$n2XR!d9AV$y#li6m+32 zA(1Vmk~wkXN&c*jY?ll4FfZTE*=>#-oXt%_b0`_m>Y}FYPOkd39`-u~Y&_d8r6Aqw zYH#bFo9OC!W+g55ti96?>+)nG{>dhCH(OMSN!3xzgZ_3wJa`l-u2I%{SR{6ZA6j-? zT-JUS%(K`Pn*NMl&CSTbR6|L#j|7({w(xAC+_^MP~g$PI}&YxL0!kH~U zlq;pI8+YFfC`Mq`0Uyr;gk7rWga;o@===Je1k^_?sbIiIg*2BO64dx1a8=@il@jdWd}l!MX(3#0W{{Nec)-qMzT5;~`He+&ZjoCaGE(`-ziF zYg)+;&HS$mwwZXt&iT3Vy87g&;d#dVc!)y9|k?C_Fgfi$oRB2h7g78`Xx&Q}qHSyt(4Xuity|be5PDb#`=5YRd zLh{Vz0Eeppo>k?PwNCkn-jHP0OAC*8fnZNw=?biepe_?8N|H z#v6hfDD7sZ8f%ws$m4KHOf_WkEf;bRLS701t-k>3hvKwDc~LgcRm8~WKUiW@tZ#Z5 zH<;NSP<2JrbaEd2%3+_`Zcca!|3rGh4Kq9DlvO9Q?i;>>lVC&w+R9KOE9%se4psZ_ zrJ_Yu8JGU4sJx#0=9^5 zd4bDn@@A$+jiE5Feo>VajS$&Z2&4q?$uf#uQ<0DMNFuH5I91ot?<#z)-~^aDn4(<>aZF7zg~ zRuYDCzm?;nogYGX!{4hNDJx3|@w_qbDSjFm-WU(E?SFqc36~yMC5L*T9RE z#|n5-XXnY33}lt*2mI<1g<>^-nH~(YkkjY3nW&f@Kby1p0GQSAFo#uZUlXe-n1YC5 zKnQ0XM#Ip~rgGICsLm2Ah<`#dx!7>@eb$my) zZK=FV0P8&TIc<)x#uv2N&mi3F|MJ(ABQ%zeB(+SBf}Lf|KRg0o&D^Ik;u}BLi&dgg zr!O@z3NIe>Iia5tw`LS*%!kr&2TMgS*0!18U&h>n(;H6A{<|!KQK7e39TsH$RP4-= zJ7-sMDHgSZ{TmOK*$>#CT28gMR^~us5>_W{OEsnYnHuS&bho34ihC+JhF^em#dRB4 zXu=WAz2yC@OkmD|^M&N;WVF2z&zRDX4P@U@!qTp>_-e5_<4w0*6$8{p984|R22pI0?KAG+tyx_)KIaK7qZJ3RB>30crk>~HP_tWdde$JN z=fL!%BI8X-rlk+u2b!k+mopmizO}0$L zKT6{WI9&kSw9t}usG06#x|zqBK{G{3uf8|X$wwufDH`5|JtsBZKJYA5_rRRgk4WK=CO?3<=#vhlmtDA9BCY|Dme{*6x79>2;+s)6l?RbZuoHvh9AWUM+|c+9a?SR8LQj z&oGL=+}I1_85oMMs$Bbc>NI;ALW?m<=;Gfi#E3n=zX1}kxT4j^bRXg#st;9m!DAoK zmhuN2v*E;==ub?KpvR->TvHLBvNZpH*;U!`3T9oL`q)&U&>SsA-H>u{4x8eN6 zwC0FsQM|K5+$$lbV?B85J~4~@1NfO)#!BnQAgl+VG>?_$^Vo3-u&R9(?zmE%YMt#s zTN~G$c-hyd8jLxmn79UHcPUJi`KVXg&NMwu#zoQziZxXmz?~z_2Zz__qOeTs96qLO zLJIiDB-OsI%=Fi5kk_-S0uyAuRGmhi>?aO8--$Ir^lrJdZQX}14Po9&UGm|U9a$qo z0bgYxfk%F)n10>eK265qcEoiE2@lP9|98FaB1&s6f*Tsx$#l9lQy+@)1WhN{e`gz% zv*MoiW^LMaPzLmv7vCp7sB7xR7gK%GyY1RX#**xr@IJkpsr)d#mr*ij%4zN7+j2;q zmhBT+7rINMzQb(5hU}Y94w=^nFpsL1Js6Ak6OM|ijO?76JWc_gq>bUqI!;uqoFa+| z8<0?h5)PkDkTqhT#f3+Qq329)m+fXb-#V$bIS_glY$uJd47nRLwX;6!rIGQ4{(%Z* zontynEZ%D6xCLfUj_QSlCu|y0X9qtDR-RyDHt z2D!kPTqn`pV_JjZp2wM@v4z)8p@M`+S7op7;A4=4hS$M2?LzS{i?8u{iOkBKSb zB|5O68WjF;gSA+yddLsQr^lIBHRn8J*3}x{MOUSx6Gsa{EjQiHyoMxP0wP>}Z?cv*w7l}?_zSq zK2O(d#=vvBLsb$V^#PB8(uHJ=} zoLUj7pWb;lWcNIF=d4JondR>5<@~-Ywl)7VmsD z>_<~P#pnKZ#-|gqRYb{dhJe;yM$wgt=)>Rjt&u#PLq`s3={9xxk9;;5rITjf$3o}$ z8K%K1D$LAnH)0WSJSp)R5CZ0K{BRJmOy^{WmE;X$Jaw4XT@7 z@Jt^JU%L;GE2}27ux41rSg&-8fM&Nr@0&HZQ?odrduZqt8`yS~Pm?D&e)Cpv6F~BZ zeT=R+jkk>$7Euy7UjAD3lJImy`n0?kHDZtk>K)52p`f!Eax3^090K+IAp0d(5~Rij zmu}Z9rxv!$#TD~J3trwmAA$+FC^ys$*Mb$)Q^rM`MH+|+(%XRy$ihnBj=(S6OxeMo zz${YITu!vLcm};~cBPUkbDOGlvq9gAE!3D%P9E9yR(|AIzShj|G{tdkt-OcP1&@7!xAC121i=Z@kXelG@ zCQMf%jd~tDu*Oh&^HzX>+yInYCO&Eh_d?X(q6NnGK6J&~qh^1DH-d>$5a~(YQO#(;Gd)LghpZxZ^Pz_= zBQ#PvwGQTe?ZDIaUIXgQ8G;Q!J(xCoGF=61;is!6H^ChsAYQglk5?Pqn!34CZ?^*+ zfva<7TDo$&Y%}Gx@)W=~7r;p_b%#GfTEnv|zQw)KO0fQAsyM$mZr}4OGziZA9E{Dg z=9`A#R!up`F3|gM4PfB;14oEhGIm!Hs;kJW5bk%WDG4&WLG&98(hNJ&6QQkOK{|`-4t4FjS|1MZ#!H&n>US^q`6)lj zai!qjmXgl?@G#M)lJ%D(hS@IrfncD2X|{fVG2eadTsg%6F{aVBJxtMSK$@w5;DQP~ z>O;`nSv0Gqa;?VAr_e&*Ice@#s-DmJNEB}=;?msBV?AGd@+QI4P2>i^VeZclRig11 zR*uVH_fj}OTeOT%($un*T?el7-?*|GIXGe>WLTRGV>P!}b&vSCsk(ZcBv-(4KUY)~ z2O3dlvX*qL&%bPvEd>YrwC`hYdN~nt!XvormzGFXD{vpJ*-70tM8d9zQH~&n5dNL} zUJHq2V$)gN#bkhFN~GgE(u!D-Glh>0l|r|e{~^0mOdr;pi+u2fS+(%ctBuoaQGG!R z6OW!Z;bd|L9LG$*Vz8V$t}2F^is02dNDlHyZQY1ojK zgGR3x+hTC*9M4~QuFN-hFFrRL+9Wsut^Lh}9Y=;KiL@uz_)-U7Za@l_$JNR;19+HB z= zou5kTCxn}G?-C48kvN$^UE=SB>jSwFPPmR3QLlrOq%rk_tLw3<=)Z*FzR|(`X>Eok+ymKl=TZ1YEro@VUcD4vVL*rsS@`g8 zw_(eLbZdj&$p2&#t71dj-^r`jFd~O~kpzq?xeR)!-PA)~bP{fyUKayK-XHt6H9H_wn z1SFi!Gmgjl0>FFf>UC(+0f^cs1*RUwF#QEe4TqWD=wl#qCFd=19I6B967Y8th&2~D zxcd5`tB%~>-vm^&Z25r{)w7YBLHtQZa4Md0u{%?bF0GZ8I3Sc1Ob}2A11hki^c?cY zzCGps=OfFj*XGA%`+Pyx#(zZUVDpg4U&Yrqle5ak)=s<0&v>RPJH0Q=EWFV-lYDLS> zAlO%)=FX^_f8}Z_H%w_H4L<+UZ+Ws@5j?WX)6@@?I}-fC_%#?sCYPX;d?-rgQ>H9e&~K|Sk4r#)I;SI7KZFZzrN&w!GG_oHkR zYxQ2L$?_ufuK^;C1Jab8%u56efC#hyCcyBut#-g=+g%cQvp^tH9%L7xvZ{$U^TPGj zsd#CNU?CGg94mdDzvhOEf_=Hs3npIw%xCizfIWiio60B(VY)a0ncAmChIK2kQwbR% zx(&iiv>k3RWANIJhtxp@!~3pPXF?wr#*io?;tzNPkzyh)DUxT&J1tGxzq(|1Cm zhVL8vNl=y?#2YJ^#qbRh4OLP6J8Kyh9G8^Ckh_ZamNg>VF^4!Z|LI0z1DsDiO=P8_ z3a{2*eO4%`_74l7Z=~A;Gq+RuBjL~LP7+Nf?sFP|LAEW=$B~vi$Wt5JEN{_I z$lc4}`eDl73Z88dYdpm^O_KYQAX*CUFgV51OwCFUSJ!Uz8r5%n-bWh_?U(0`3F5m? zv2xkOC{J$R*T{w`b%ymXYhyjiWGBPa8SsvQju^sp1Es8o2dkrMI20GV?80^YsfzEC z1Uy6RVqDkJW-th+-JaIv3iAMq=zzKPMFzmg28-2G+HJ*L$szjBvDT=b+5hbhq7s}U@Y!4lSYTeA zwx`t^7sHLpP2!tf%dCEa(7#lz87XOvaT0W=Zkwc}TrK$SWTs2ffxcQw)V|sbdP+=% z^I6Tvb$6B#GT+C=6=xe7-`JoJ^yMgS#E+r+7rcT2?tkK{W1~MXahoc^H-Y3{kPueX z5!0(7()Z?*2mE>8)m6~fW~!g`Do--U1Ts5%SkPMfg#+$3h86o`HB;bAz`2(*rbF_`ZS66;m8Tx-HjaJksfQ??}k**w7V{czA9!&XeWlkI0~E0;;zI= zb>j+I8nG|DMyvFZf=N?>y5+fDR=+A=obYsOttZvDj&Jf_;kD?3`xx&LETqMU&gf;t|Zd$s& zZ^uv22f6|IveiO+MNLCLi&ALFxm3`aO9+Yo7#4<1Z2}rXa$tqC%>G>b*b$v=)ZI|5V5x9+VprYSBxoRt*Fw0j2n1K*bYHOQ zbvv#U*x;r2KRjS!oeT5?{&hN49?Q3ONJit{@bbWRuI-FoDZR(LQOjGb)0(N zb|V6)31-lO$@x5zeEiG#*8CB9kum$==7om*{>go(3n-zYmCd^oXxl-2=u}37mMH0} zHx?w5`hTYV;29KSo3JhJ`s|38M13&avD_DWNJ1~f{gj;E1QL|lE>0?mT1V&~pQ(DH ztZ7ZXD66#w-xez8#8d>d@+BD?9Rq(7WJ7QCLZwoLKr!iwOq3tZdEbCnUMkp}p=ql` zdYg=FLdKrPzoYy+jb^Z66{1vCy-NGFiS$;8N-dm!Oi#ax?H${yr)2Yuc?TWg#Ieqb zdo4lIMWNZ;^^H=S$1UL*CuVf@IySuXT%5ieH3@D<(3`N0^_>LF+yD&~Y)T?l$fwV8 zw2pc~Am_XF7S#=Pef5Ieh#PDytc?KY83U*{)THNiJ+Sqz=Hz$}$mPCvlDgl*Vt33J zq-!@jffLOA&PH)ebobK36+-|9EHs*O+Rwn!7epvh847%~rdXcC=T8gnbEaCWhxE8QyVkv6)^K2!; zl@%fd@eXy4&VGTKaWPYMZF8-}K z@n1=J241bwTjxURiMT?!`?o%mf*e_L0t^BeV2qQ0{(0dxeJTo*NzanZIQ#{KPAp?g z##{1|kM=HWQ~UzreI(N0{i{fQCFFI#A2?}j=%Ws!eHcaphOiVgWGd!IY z95ALu>ucMwTs`Rt0H<%>1K*0rxcFLCCS*iiHgL^H>oK)J2B;wRI^?j^K(q=`I_eRs zcf@jzzesptOIsb#N2CzuDB=-s=a*%`?Onkmm;9$vjVW7Wqg%G-J;19( zG|1Z0hG433@~^q#L^Bns;Pu(s&CI>KsKM#jPFA6+pS{3QbO>Va$X@k4!YNU`FCweK zj5LJxdPzW4rY&;?FDEdxw^kRAN2-Kch}J(RvSkx`Si}YT>G(C%aM!u0aaqjD_&8|a zzY;#OFR{B$CR7y~RI9_IH!1>Ip!9MCeI~v-zbuoJmpxrL`TtVqS1a2#t>S-%KZ^Ec zG$(iF@te6dOo6T+E(n*v$MOA%*tz_N;cmeCQ&hHXwzB3<{e~rAV0Bb1*dQ~(kNF1> zQ2@TZ7+E>pmADQ(EM!}>!S7mf&XO*?FoJdwo8(Cjna4>H<=qL-RRC(#S}bR|t04i} zY*bg>@UJ!|qrv36ibFReW-?e=^aOPZg$tlc`IuVV(m#1&Em^@fI{<>F*@)i#iYrTj zFS+G4vA)>t_qEoHu>e|&2Zki;zk5rYHNzSG3_btLE&2CVpd+~M@Innc6e9iO8DxpP zR!$)}*J;>yMqs3pZ^v0_xgMo1MzgWKo zu>Xa>CPr*G4^gTESC;7TZ0i(OxZO>^F(WQJ{T}2yRGmg_)-Pu6Ob{~d@Cam=f6osT zS?526z8wJ+Tr;u90k`E0>vZ@Fj|RKCNgS&){hm5Jh`W8J z5<{f@Vu3}?pe7Vto3G_Pi2#urKJC-`bHfX0mfB>KWW(#EYm|y}_7{hk(6w7GJSANy zgE^}Ja;ofuKW%Mw$%)3eSHrSxn1UbB9w0>fnI)zbvJMVRaGOH*dCqv*k0qOfdpL6K zM|eblclWO15FR6M;$j#^q1CZRJnXzw_Ba;gx`pVSyOrs0gQ!8EauI}1nkgm*%JxcD z!)5d1hasVRV*ck4072R=Gz^N@N! zKt9}w&8&=uaZ||)V-U>S&2U_snu0l`?0e=a8vzC*=|8F%f?HeuQ;+NxCoDK?j(#A& z`ZAAdP6O{T>RZ((bj@iH1Fp%90w3QDQ(@Y_D*|pSlp-k>JbT)0u!o9#@(A3!MAbh| z6qQuK-~f+Ips0i^U8DRqWVJCSBgBugG{RfM7RhbiLEnV2%MHc1hme1NcVG^-=8C$Y zjJfwkV(eF-hQ*TN(bb&$9>d+gjyULQ5BC~zJ7_DtS00E#olLrSawxgz6XLBrp`ySh z9!Nw!!Ya>o!btA;)s{w`GoeudHbUp$v{(zJ_nh7-M4eFx+_EOlki=iRI7yug;p$DS zq5(i}r?L{n4ecUMOjQQRZBG1CY~IyybHXcoP;(DQC@{Itit>gA*B|R{wI})KCMw8) z0)R$`YlUXqrlmqQd|3Sh6Lhw12o~W1-r5ueK<#gBzLj<0fCsW1yZg^GQa%lsy92R# zZEA-Nr0C|>jh$<7{;Y@DXAMOMRsewhp&uc*QmAeuqYf0rLfH`r6=U(hwD{{jzoK3? z<^a>4@rq&hU}Bf|g+PrEsWw#jYzlz4YA__7}3u&5x23J6`~P_itv_&6|B9 z1mU8xwJhoOwZ;RYRNV#^Bw#x?RewwXRr%KTG=%UQdp)L_zRQ0G21a#mchUaxYQ@`q z^b(YvdQ)INd~;4aCh?@f;@EMOpV3!N6?cugPy?!4@e9ucKrGuvTjH=(+ETimc6mfb zrlXHbPOXp8LW_BzySe79vt0e3<7{O-8J~(xuQ-(p%_+Kzhtk+3u8|Jc%#HS&uL$)s zA)^cKKke$28nj7J1i%Ppmm70}pRhE^U~BP^8Q38M457_RyA*dn-^=}AE?Lu(fmG-n zTwz4>bL0jliAMmb4f`)aw}51ZoM<%|)70VoWA@ksRwQ-MDz6Z#>=**+31it-Xr5YK z+4Ugu^NTBQMC8Z5@<5lEbJCq}gAW;VFK8whrsQL>f>)k^)oMKvu1D`6uR5iXr}SOP zYByf-QH$J|9U?yEH6xgYx20$eKovKNYNgVq;`gYZP+Fh^yCixy(Yv0ZyvNykUs@zZ zdRfVhi87-G+U<`m*BH!9opbkC5HBa@^&)$W0C95rQ2NOUOEZ*} zC1U#cN*7cFFJ*p1YHGO_2#}ffU1@oE#_LcGLLMEKC9s^b<{S!-lEEGVbi+T-ccT)R( zZUp__43oF3gJ?Y5Yq|b{i^)W3TCM_zcXBjwwwak=?bYDQZe*~ zHz|d9OtYXcLE|Rxk^^IB9u6kp0;FtJ04-25De$Z?l|aUYV+g}Zsw!U@wX^>m(LC5` z-A4#hDVU!+!xM~WICxn#dj-Ckjz>y?y4x#HZGq|EU&o!1#kwQ74>c5E8@Wy_+6oBT z?65mvYfvf!K>~Kk66T`XVD%xj^(CWR0YmG zuLOBXKnMrWd@=858)_`btP#efKdWTFcjFE1?K8Xh?ucEco6|Ka=>$!FNu;qa30MDa z4OBiG@}LwptovX=!htsFIg5VJ{_WdjP(|XhV~+$=8F}8`umA;YlWjbXYQk&j_rt6X zSCS^sXjS5g#W9Ox|MCJ%Cwg;|Ge1)4Pm>WLUzelN630GM%^Yf&3xxhv2WHLv(W=Nj z3@Ofc`8z@lg%MK-ZD$|D!2F*FD50UZFH*@ZU(W6cXp3VTl}z-`TZURqq@%A$z9;a- z>dleTspNqc#}?1k99to_V64_+dy=Z%0T z#CFMEx$^0Zd}ZCUp2{*YQa%96Rl{1rj8#8nzNtVgm}3S7W@R}@8a9`*>UCWsw|SPn zt8Or~Z%);?7bX3O<;IM+0EGao@5UfQbMt0S{00NflQJ+Bio$Nqxv&qgj7P!|5>Co# zDW6mE?b}IXL2cGmxixmjG!0DC)UJS_?h!E!j`^$Y&yt0S8A)OL%9ArTG@)a?4TK|` z+@Yhsiw}t$eX#4Sm{xkM1DQ3ggUfO}=`Z9}7ufes8)@lqcePbGFqIt7C`wePDQ#Fk zh*#UtYvq*F^ISuk)A2&x-W7H?e`su2vt=lq9P)&bizBJ*QTCGv zei3yl@BU>*93kl?^4VPu9%gp2<{aeBuwuOm8k9?JT~R;DZu(Lkehv>i^S1;9uBj%W zRd&7fuu*)igdY4o0ep4WX~#mX=Sa1sfkLf%>Qv%~VQm_2(Jrp>EV}R_4g3zR$<_ug z(Tn*t3EF6!o1qWPqdc4}?Gx>kHJ)|<`;=MXEmsHeyO3`DRFD$Y)ybnu;p?k6LNbZ3I&Q*Wsh=|Wdfs3hx+Mx18PFT&C1!?P--j3K+s)Eij7Md~r!SrG+Y zJpWP=)eo0A>^}GgrpW1j7f;qQZ+dwh%`Zx1c#Be9>r|!HBX8F%l3yUHtY?Pv&&o4Y z5rl*6y`-)nD^~}D`5<`&gM&lGG2zxQ+4^7W#UPAz3jP3VMtC`!AkYCWDbh1d{C8sJ zWKgczU8x;k8;vh_66zdBgP!FnZSk;7StFKF-Vl85GYR00rF65)!JC%8@=}>G7ENn4 zdt-v?3-BJH*es7j4-~I4=nNYqDg=AKO0^UgFH;^#_};k}4B3EMPhI9iQFdZg;jD(_ zGAex$o)1kd>-ncV3R2PsDX?x4aF$T4#-4ai&JP109wZ&IFf|?Nbs*F_chw)Gq;q+) z?yH3Ea3S81(NzN&9J(zzWGA2A)6+#D&3cf7`G>hM}wf3{65+a}Mm$iX1D<^H`ZN&z^ z$oK@TMV+_P`z$)&)v5F9?)2)Y)QLE@-+QOE>^JjIMze{-`YKKot|28fX&l17$s*C6 z#K`+FulyfExX>hlkkpoSdXa>H?2%g6N^Sn zROw|4mE#=S$9Za#GB$Hn!BjNdZuN%0a0YR>-_Y6CUQ#FHLLTbOEp17NsNx1!M@)(2 z53yP8Q8pVEzty-xJhJ9S%^GF1tn(thy z`8%^+vv?po>>Z>#InWFfQP*{iYn3P=Bh9~`aj!D|v$_8#5Q)9RJgVH#c%GCV@d4@Q z8GJ8m%)E49GJzm<;9oBq>hM4Tw`=z*l8#2BQs1)VJIPl9O4KaJMA)i&A zsMM#Xv6Iw?<$&qy6PtPtdXQJZHi`AE;0?J(_yN7PU1A!&VH+0hZ<-s)d>G{(9I6@P0~eD||&jB4T{9}+VOy?UKCUw64N zn|1sMb6)Mssa_1>ZY*oz+-#_176x^bdz;I1Lsvm-w7i9GUw!?l9U`3F=Hv^*p*6)E zbU$q*I%{W@wch3_x3q4`m(WW&6ZmkP$;`9vTDKsuTAiJ4+BOy#ixQk@Rl;;Vqd}@P zTDK_C$BjJJXOtsJ@;QP;c{vM-`AS0{ZA^g&Gd=B!QFG6O{t*+T;HJ0tah1(oy=I=c z)cVc{%Ee$E{li}y==G(MjH7M}gO-eTBe0(ViDa0hQhIY@$$6hzHI2{am2P4k0nY2~ zpr2=!OhtN3Y$kd3>uqi#0s06JcF*}RiDHtNImZ}gb23)n1PNnh_+47IXq}I57QmJ! z#XDspe9yLV#y=03tizhMRAt3Xr<9r0=jqSE7oA#h4#Sth`+zvk})h z$~-}{KSgaBYN=6FhJRMvJGI()X|Uzv1^coAeP@@W(c-R>%pN%tR0mAyba}pd&+QpqmM|h-=swi)gTIEEcH@y)}`onc3j)T^^kZRlUG*SEYjU{$_ zRB#Z@O!fU7(qf?cwa1aHE^q4yJN-ZaC>#h(aAH*NeE6LMh>?Xx(2 z5aKZs0tE>`j2}brX=~;TRUoHAlm^#^N~G|D;ofUjosT>kV5L31h+RmDZ1ek~b#4H2 zE!poG-9okie;9bKs|hl=o_(hG1$=Z2H`}Hz$tg*c zGS_YxqHlF71HJWt9g{LrK5&GU03^H~ELY5bs|E@C%psy7l8|pkmw!H$jD_!>T8@+KUS6*u=oM#xj*Ym{zAZiFzzo3-?{9I8)7E|X*2T3f_ zBBl!|w;!MSaD1$U&%?xF6-f?GfrKAsooS|FmfHnIj%TPiywLwz33+tI&D2vWpUKJ8 zdb41WUHz9Tz+NFB9*3u+AF`{H=o5?HV{nTL@_!d1`{-7ZhcS=K-U$dFz&)o}37~w{ zZ`ZPAKIuL(8nYLO_YD$g+PRT<{?^wjy9psUE4`7?U^ z&Inm3B3oI`jM$I7y-ibzP{kNR5&JO(lF71nhMiBcK<=TnE0!CvK~ZR)C4~Z7NINIC{+$}`CgTmVs)O{lB^srp-fMrEUGP9L=76*xr(Yw zpgcDkLd)E0y)8;liuZp3Jz<(9H}sOU?W;Kk7DsCwwKoH>aZ%qYYYeyjX8OW7Zs{I0eA5(on~lV!$&6=oP~<&ZdDa)TLh@{FbDVRyM-o#EYL^s>-%&$AO=2tDg9grPxj;Fn31XHi+8+n&qPXf5$OBhY$3};-gOJg>Ha%F#~ zD^FT$h_$O*`q==8HRCmBrkrn``^Xx>l(ytZ9$b=Z(j7$!zUr21T9MZvS!2TowU0vj zO4hsS^P+#|Bba`6)KB$?y)%aV`Z6NX(|hXwRLIfi@q)7@0U8#|6(tugP)pl)c177z zj@%j?TcCEkpTm|u4NL*xnRQt4$yWuL_6QdsubRk-=W~6U)B|U5AMF9Z(ZbUw0)<0F zKE_6{4P~JjqP6w{F--v|dVV)G)Qi|V^}vMJg!1s7$g>(rSId&AQ$C( zUW0EskfKCS3y)tjHQdfTytM+QQ=VFs`shjN5L5$j?-Y7!^{fKv6e zcwhd<)jygb8VywYsi6I0hp&YZY8-*Yr#2FZez`!d>9g(h{j5uazX3eGP`OS7vI=nO z0H9rOWP!V95Rj)RgB(?>{F!73O?KhtGP1+iRIWaC1b?(?LK>|$ig+{J6%`&pm zc1;8uvey?A!}#Ij)n~IlM^_)aF604r_6w=;&z#)*cyxyPrtaBJITiiKB$@5=azn3V zUXq#{tR#XBf|r5O*7z8SEjWjwkG_?-Tr{2)*68fF0t-P;ErYXD#WtwPnOn zj_~7F9A8(jY}aB6pT(n`V7E8gHVjpzvia)z!UN(oiH$hKdGVvoW}Lbi3IOhNS%;A; zPNhI$oI3L}tTrChRd!?Ig%+tR>x3USv2%m6`?BRSd~}YE`g10R1J{_v?$?fiFqr)< zQF%s7P^)8H8DRMKE;W`$wVteL|4_Q9W82@uf?ZX2noE*BJtlEIQ(|Eu2`<$(;e3Ht zXZf3@Jm1Bc2*pHz{U**SwY4Ywm9@j8AH2!S z?*g8Y?F}}q;s;LEbC_h;u7{1j^9b}cND91<`D%;pJhr?PD&%EaLR~TIv(K> zUK!gT>y@S`Hs+eLPh-uz>a#jebqv|TD~!McR!z%jQh++#HYoXb|MDfVPgxU3AV}Lf zX(`nRKG^UMyQEXX>yT90C~(Qh_)d}Fv~0Gj3&TlJqC@;pv2sftcAI z%E+!;ul3wvLA%#owDnNdZm|)uI%X#api)iOsQd)}hk7gWzSj8tgWeEm<~_J+rT??@ z)!zhhwIeG;KHe;>bhMJpoM|0~tqIus5)Uld%LjhmG}92bXY7U?b}hlLbMduOiwJVO z$@tph{Q^X4$qCw76{~3GTXULiB!7R(UPRB!kX3KJoqOHP(;Nv+mJc z;*e>F6LEI^$A8r0;-NVCR2jO>1X%s+!7sDJBqPX?nt^b&h9+M2w!d)8c+&*})wYti z^_mj0(CN&=QWME}`m!r=$6B|A4})o!d56yL(pkOIbh#^fS^RYv=xwqw$J{OX`EE}Y zJC@wI4lHP|?jvB+sxxWU!+-HT342lT2TII9OU$z1olXkgw2-cV8WNivRhy)(icU{@ zX3U-4MH9d8F0>`*jG@9O={UD7yJgidNY>69)_H?vK$7`oecwI7IZHzwk!&9v=%9t+ zE$8W5+!pfBC#ZC>G8MAlc9wJ(^r!^82G1gtu$xCpmS0SH&GR285X-QHK1w0mz(z5u zc9R1d{FvE-HP?VgrnPVeavRQoxhd*$)I@|UsbF*s91c$DszBiRCDDCc2Z7VguzDZU zl)jtv@}>1Y4B7Pp1SxKBG)`E*P4|qj@+%W_Jz5&Fz$@j6olO971V;J&?jyudE`d_c zweN*gjf_F&4b_1zEJ04gBNs*bP@`GH@J`7qZL;(55(wRg?Q|*3`jXWpuN6zo-2q zSx`FnL*169hU9{l;+fB`dw`Dj z`$kdrIASamWNFQ)vs4_~hOTyE^HsJ*t)8ooa6LZR7XXe^4|#q$jLE49!Ixh^q6q_G zA=Y5JBigtv->%s0TbEt^IIQu=2HM$7W*Mk2W+&tNfQ1i@E$)w}JZ40lNnU1Ji3@}0 z#2|w6v*wTN$&|v@y=fE(01rC_1(221W0H}4SRbHm6nWz+AH(mkCjuof(MX*|bmhDo z+}X)6cbtPYvbV2O0(-&C4D{Z08c?~Lv1h$Uw%yZ|r~yP9B0E35xg|KSkee#H2xZhz z6ZD>zemQ4F?XF1UkH@I~$Aa=$p)|XR@p8ta(~TAekpGaAR?N7Ey}v%8db08I zIsy|=|8b8%$=B?qc-2c#3v78?d``SDJ!(r0Y zu{YGgsdV^jjCZ9*5$EhKbEf@p2v521mR}6023X0~#F*b0@GyjryZ}yjVb6(t&cs-xQ%F+j)R;F*e+4}NGwz@raDOApA{lB>mmuCmoX%%v*9*) z>ew9$M?$_sx)Up#_Gtl&-GWNuA>9_ai`zl(L`=RuswBHxc^Hn5zwe7Mz!l}I&UDR9 zkOzST`st}yJpD+LJ-NEWi1#s968^=9#%KYtN7&HyN?^Lp>wW1&U6y5Vc~9qT=u zR5bzgF&js{eTG01{n4*vT$}X4QgwzIzx+N%YvSc7VnK>@O016rbT$WcJMi z4|%Mtv2hsZtcDuxFIut%1)+kVxNIT%#(JQZTMyUg;@&y68Hh}8p8yq2iDk#ooaQ4| z^zkj{y7xUY;(q_JNIJ9axJL#O-7=vH(1D`DSOkJUk2AkLm11XU*%;C1+hIfYYFEsB z21;PwZzyJ&H;i#QZ7%Wp1yJ;;v4Oe$D8lrOL4sbRD%HtW}usK`&{nuI4zgBwOUX zkgJ}6dHl4zz9R>M@&E~N=^ptaZFX+wX%QwVBY9+I^sJ_$h5K*!ex9&p!}BgF3Jp~H zsNU}$5sx!A@4ZqAW58a(Z>o|gb4Ce-t`x!k#HNG`|G@O*$Hy#Z<2lMdPSiWS8r12~ znl^mAQ)(72p4SMd1*s2hxP!$EqKRo_Dc>b z$a7n+!}Y9`SlBWpi}4sMjY$(%LZ4EV=|3>sQP}9+n{QH*3aAj=bSxMvJhJPG1@hzH zFiWKhevg8{)vIPx$Wd(@g~&O6b!tO)_A6iu1k^A5%@R(v_k7mVJ4Pwf^dH9h>us-y zk__9zDuhHJ=+tERFcyX2`y6bbI!Eo z+RzHaPN$(4KRI93fr|EdA$aw}yI-tpkPSrQfSF;Npv%?wyqssEG>*w!4N{6cSvS==`1QMl1|GFpCR&U{9{)PC6?xIDY08FSmo?+8zj&WR0MreO zym^GZ3FuBo;tXP#(=UEP-3xjO`_EW0ekW>_2?wG7gt%rY^`+$N1G_)Of=$_9!|vyV z?~Ow0tYrY^kL_xMm!Z|X6~vX@)vsO*ou{W!)mLc>k?x`b|FGYmTJ@}eAz)p-6wZv% z{=eNgokC={J* z=q=(rQBAI{G;LVy5(G3NSIw+E-)r1mU?K3~WXdR)W1os!+A;6-SBm+Lsr&zrL?qtkj`0p081fD$6 z?R!vkrP+Ql;TYFaz3BrB#!46@7w{F9s>@AEQy{@{mU1HJ)CR% z3z|)u8g|`o*cqbY%~orELO`^ZJGWpQi+5tg8{P+kAm>CiQqMJb z7AI;ACXjn9#*tc(!|&ky$MfOolk7#7>Cq#s^lT6K-`c-Ws z_=2$5G*vHMNZK4gX?~RL#%6s+Edfukdo6gn>G4~NAtR-H>sUbqJmmtFynX|Bc z(@q7#mOLli=R)B77F@=qZ9B%2uIq!9{p0eondpM^>=yRttb9En?@ApiIy_9bocH^! z6JS5M=}=H}dlrd)c1-x(DYNf5$ zkv`Z85pt)X2t>726bj3YXM_y_C@`(l$mE}-u8pLx54&I#u@&8++= zLFHZ~j>K`M5!u@`?b8~a-6}3R<`wqZQf!94$CDs>5);?mc+uozvtf(`tovW zaaf6!PSowWMbd5ZQ}WTAobZdwU0vBb6M8F*%>I$X`mUidBYiB0h&7biI!)~U(DUept$vZ zH-;TNwcfGPOFwNz$B7*}U(y33PUlw$`&nJH*oF%+Z$4{v&Tbt8X>P@f;C`Xe;&yl* z2kG&!X~@|z&2!YZF*EA}y>2>|1_F@hI)74OImJt7t|xIFo&DZD*pCnmg|idkFU)O#PN-Iaz)#I~#-C#&T{E7Z zlUDXGGM7kbiK??*eIca&U0o3GI!{gZg0ey2&WHVDd9p#r+v#s8$$!9*na`Q|P)w`PJH%-o;jVex!uf}84+)6kl z(qfnB$sv1op9V~ZGF~<4shp0ZwmFD5)w1kJO^9qB*kBMMSOxI#`Us7#$Q#XFpNTws z!=L&t9gNGL+}ADCO-xyLeVbI5KHFd00Ib4xcw$}bBVD5{7p%mHS9|z)=kI26V+Skz zcqC|>V3^LiSnfGSgZm!Oe%cM^BNs6Hw8tt_dblnY+`>i&9FqQUq2^KlE+THsVhb`vx2;X zg}wh3&Nm7)h!J`sL^u`_{MdAN>`SgAI)Hh=r+~twpcnoqh)v%tIQn5riug#qE?;D| z8x>#!lsC{E(prNcQERZ`NP{Eh`BC5Fo1utzu;3^ z*Ng)2mY9c+*Bp(RU7N&quw02R9awW91D6R0&?hx>+982nK>AAlS^UE$+&jK)3X0en zuDh9A?{0200{Qpl=l55)h05Hk^S8ON>?>uBQEmhA$~%<-C@XnnjMM_;&8mHj6Et7ub3J>hqEGHeU zC@?O!g!*q{AMGI+1-t8wQ>3BP8c!9%AD)1wJI_|2I~jN+0?;)kdEH6f1NhKEJ2(9~ zoJ$Me+gm0FDrS4VZK5I7BkC*7Bj~TBKL*m|pHhqnjL05~v8>SdM*2!S42l^308Qpo zeE68Ypm!kX%;MKc(E{I13e9q8Vw@>EYwHBbmmzB15hEQ8@%!V>)18zvg;%b2-DXP4 z`QcNvfhFYff+{A0S!OzbBdXyr%{C6)Be#|#;J#WsDJ6KH@c}xe_~5YW`-qp<2^CeF zlHdWt3bHD3voc=B9OyuwE~>yuL&eGzShG_6wbV3z6Jwci?7hpQ-|#J->i7D|W+htM z<84lN=`A~_WJ00wr8-}Cvh;3m=OpqEAH-6PFs=iORmVp}NOlXXEPYoNdmpPv-BGjP z2Ujvy^V@u`#f2&sD`Fu1Fz}+-Q0=p+LOeZ?BoAH$dT$CxcM}4waFmmgglBi!I`HG1Q8ADvQ-xGtY4w0`l{;*?j#Od>_0zrI-CxFZYsPw@ z>UAjVh~{%GVb~ch;gBO}SIUUk2EWLl$h1C={B zG!xc&09?KsgKZ~Jp_iN^kTJOI?_t8i8JF*Ccp)7JCVcB%ywrUoQ9XjB>T8~l&Rp{E z2-yzR2mKueR;xk@0e9|1>jHjUv?ssWYnmfcsDx({e8fbjF$Q7U5w{}6f9 zsOX;dqsP;*MAxdC8=*Fd|0Px`RPC)b%|a!M`HYz-sY32xUX@SYg~)2_J}$3bfN4Rf z1fcT(`L)b}4Jm(%_B6&+k5;tT3^Jk^{cO?TqmC44;q`G(29IiR!WY4fE&s}u4}{=3 za@_xRO;tow)ASo;&74_M+U0}~w8U!iMld5*yU+@v$5sd)DiFNy`cUjMD$yXBfPjas zxb{DoGyfZL75@DNyx$_Kg40yR;Su|*vBbLgl){&oF%uV3WJ+}-CMLk*qCS|%O+Wsu3v!q9fK0^|uI7DE7 z^&jkn0Q)D~i05Z-WuBm2zJagBNv3FRk-`y=rM!?`;W&HeWF0Or7#l9AZecBALTx-8 zGt@cUTG+&^@qy!*w1mupurFKga#jNJZz1duiW@~s1rsrzUqq-&-KLnC>>%0^%` z8i#UiehWNH0Pdldnpu`I*qP6pq1x-uHS_P-X6gmeMWlKp-%Jk)Bf5(_4n>2>_3Vu- zuVgHQTw4#DyH!O#z4UZjNc3w-9c@o;>=@s|Iw7-wqKn%OZF0N^z%V=PBH~X~taM)) z%$@3FJ^_75D<+@q0`@%G2qjdSm@xXX<4>C-DW7CLaR%xCZrkgY@Kog$W6bL=oYJX- zWi^V2su`N+-dAg0+ED4Q=-05<5>oS=3!f->Ek(9zl6i%O_23USF_CKw%(b2hh{-WL zY0hU=`!54qrr-)A@B%B~eRdx&nG$_v6=`hw%Fqk*mJMf5&YwM}mk%UdY8I-6v$6hhhx6wws3oNPshq^GS4p(_jBD)3o@ zhzr+~FGts|N7^q(vu5@XYtN1eMAlZ9&8vlzEBN9g1Qfre^8e~YyT(MRKOCNo!D{f@ zCbi2=&d5(kp3l;6LNT#}C!WwXcsG)4)l{>VHUDmnt87D1n6iOls2dd;Fix)THowsp zgDawr?L43EFn5y3MT|9|m{Lu7y)78vBeryApV#FQXSUvg>sJ7XHOND=dq4BQ&$}`% ztFl9sqrMow{R@ozLV+*h{C0^|ocm3SfBv3ZK13pkm*Q}^tKUh?JauhGs3Drvkl&cK z$-bZZ;g442V2s2qxV_5@A-G>+I|`=vx6?eo6=k|iaDE^H!9TE&b$Za3MFZR znzlG}JK4r7OWXP?RHZ12gslj9<;7QZ*1y)xqY=(oXmhc<(M1+$KSBgXplPA%hiX#_RA<+(D~4f5jyGBE|L%)& zFt;otH9FnuLs7G9az64Z3O(S`v#qE{s&p9*G8Uw!c4C-+*|L$^eIdAKf%~wFb1w+R zU=*2q+e+0rI$Bh`|9J-d~V+zJmS z%_iFWWc?ap?;^9LpADjZvTXGj(w{D)P>0U(cl5#+r(UE4l}{ijUt=Hz^{Dv`H(@{% zo*Q$--Ds)!0;P%pO`%uziVrB0SARr!HPYQKrtT=-{*|;$Aw=@IOQT}<+gpt_^i+Ne zb3mx2Hw47k>W_`}QI}2nsbA#O5-v_=7kl~8 zS1qMhZ&xVWBgDMBqjG5SW{fZ+4bWIHqtU_ksPJ~TALH|D(xbk&uqC=l1z!*~haBta zygS~Wq*}GBBsa+Opuk`n(g;nLE}yZ(MaBaXREZ@-1nmfyC&*kcP-B|t4gN2BW`}VR zLv*r$Xh}CAk<=ULRc#3tL|{4Dgde()f;Qn7t8KA1Dc7v4$XECRfbUTZw2~ghGqvyf z0b3Nm8%c_Fb+5AI)_Oc)!iXm}8F+Q?a#vz8Ozg zr@CgXLkh+e!`?B#Xrp^C%v?$({l`0xk(|?#`_wFrzt-5>3%spZ4mG}}*#`_Q3BWmg z_5qL*PdWnVxxB*{xbD{Ujhn%w_>UQnhr)74g9I&HVW#HLV{;42fn+n9ON#eD&JT3= z_XB-$rOSnKYfGLrs7MH9a00%Q8e^(|T=;K)lG+kj_8_9(*ok~eS*VD@T{fQn`a?mU ztS*cy-YA1Sj2K-KvT3UZ(nvv~e4^N_4bYkPQTT6R(Po=`fPu2b;tXF;50jsKYRq%v zvVi#gjd6a^32>No87^1Dtq~;~X3g1f2 z=$u+hKAg%IzR5Y`URfUAAV-=!Z6ro74@N7!F&xmxZSGaiGHPb{+ex6Y9!E115kJWP zHu5Uyedmw$<7*s3Eu)SpGg286pWOxaABdx=7)($$dcS9)K){MnHfGS?O6!uJS0ecw z0tl`^mpl9v%%P?&Kv^>Y=?2cr5F=dEq@>I|bgs-;cZWbsbj=5pUp2oNSCioW zVBOW3qwiBT^|IM;ek_^DHi~*%^p2tGO_uooc%wRj44`e7zq*{cU$`Y=wBn!wEtHs7 zYIM!8jr{Dc(AcoA{r(NqVdZO6qPlu9DYi9uuAzG$K7-kPVVyUMwDif5D^e zWRA{egn6Eg1?-StP`H?}81m~!r29y#Jv;A(Dh-ysY*P zVDfsgG$s*(qkZMWeZnz$*%G9Ky&8zzUiVk@VE2CrwA{1r0DT#^!E6PCB&E}u@|NDH z{|SnKUEb10LO%rfv<-;U)>_)Q^N!|EIsb+2yNaou+EiclC(N_+MF4gQu672(9k;b5 zwHqv6^j02V>Ps{%oo&u9|s=? zi*7oh$DDX?h>+m3FuY%Pr2JT;Uz5Q4#49}qScmSbLM*P4cj1bJ1beY$c!eapOgI${ z>h@ZPe$B3valf9YvaINL$FVtiR^sDR8DaqCXwQXX)kIT)BR>;!i!7`xW*U_pE(YEC z7+dKRdT~S?-W)QKr&U#cU=3K0UgI^mSl)a|WRTnEgnG65l!`JJ!>UxdzzeqKc2-F( zq_Q=C&=Y3*{KyH`tjYL}kI;hAs4;tS#NNubgm<5{Pn`z1+MQUt(|1=OtSM2-Q6s0f z)E5ZnoIk^mHZr8#eC~XeqLk_VQc0$9+XH`ix9{4-zVn z`OfGcq7CtdNdT#=c%YL6Ntip&L`!Ic>0s&;5B#2k6C~~|9>#4HGetHlBpGF&tDXd@ zt17y8*BC?x-Iqd&f^?CElOu!NfhC8ASz$8|KoNxi3lA`U8Sd=B0u%0QFZb>RZ4_QnKI;2@2?cD&vAbKo zfpbsmmz-xW-BJ^^f?q0y^D&Mtg(|RY3J(~&O!0L=i+sLzi#NxPP*NC~$&%#XFT}cs z07#sH4`p+)5>uH{ru?^fRGK)#4PAcr z(1`d6WwUD-sdl{QO~i}t>uPGV5ZpWzY>yxMpq=+?lVlkT9{YLUTOC(Ib(-1J)ZDk^ zeWfakMe-WxP}sJP_?wo4L%EDOTQ2E6FV>+AMM2^03t8Yh%cW+wiPA%n$T+v?Xx4z+ z{CH$@@a)f;a@j@e!OF(go|2S~zPnJDrd zfu7Tn+g~in9SD;YNZpg3)zi$o{%I=wgp$W;q7%cGjNT<0@UxrbKiH<_B!d?hKf`%peOaK)ik6 zG?p`9W;U0PFC!5u_qf5&}aD30XIgufJ6fB)9~FteNC1SS}owP8keAY?~= z5&t8I{*enQf-!6k0S`I3X~)2H;5}hsIl>~F!@N^)utvyJg;w4JB;Du zXJu$n~rh*GG3TT`^)Q;3sS4F8bpDWR*d0U~&j*jS$%k zusi~acJxnFd3tDXJK7zNV`H&lOxvA3J5%xa0)}MQ@mo@;7*;AN1!}3mR;hQX+N4ha zy|u_|(<}3ULYUsGtYq&W_re5V6FMyOwK;S6zJX8SwPlkz+RV%blI82*Jk3^w(^TA3 zrOYoPx`59Y=MJ^Ku_HOlywfF4{dXP+A$hMNx=}SO8R};K4>I)?5)G<2QKz~viqQ+c z3z~VD4F-X{_@kX!svP5JgIlkiz7!C>T9zYcZ=f(pc&JHerIz+k(}iME=lE>W_9cKH z?)%ravog<~_2X{z^3UV;O`a}AGuI6Y4Ao1)B2>##|C=`}eFL}HRk2k?^tBOAuU}1) zP$fyAYMHN8*;e53&drmPWRbuBabV}H>|ZOA`Gew0k@H_P5TTt$o)hK!bxayTpcWr& zr?(XxGiG{iy0IlDfrIA5+qh#)o&&;kTz5=d2VfOoc{L&Wym;Enxq(FW4JX-g35X4i zKIu!LqYdf&EA503xNKndYy`T*RHQrUr8@_l5zeQvTW?X5HZGrqLP?<{loq+^%>$IY zAQ+cP2{-O2)UV_c1G+)r+t1FvifUWDSN5s+X?`xINJky ztmD&afV}iQb1+CrZSO_F=7~yu22fbj3q~v^1ib+NcuINKSp31v@SqX`7m}^NY@tiw z>d%vwTtIRB+7(>Y)%JnL1Ha?Zg71Y>N%1O+){QLuf%LLl`BnNr^m^F}I0r%TL%rzm zq>3CFLrF!8O7$)d_D)n1SH-ug4aI02RkPqx+w#G9OQ1&r@Y9@~#gW^t`~{q=q|NQr z=Dg=8%E7{l0yDKApPfe&Q8G+{tIdy6Q@D_2y==^e?35l@))bgZ_Oaw5FHu(gGljw~ znNqM($87{#qP7*b`v)Yt-xicuBO#ELrfobjF_5UCnajVeXtytV*C7!qp=P%vi)O@M zXa5B${y19^KDxu3PJ|S^km1W55y9b@Y#HD(FR{8mwaU%`ChB-hh*z=Ch?Od^BcgJY zQj6_P{b|K=P)xRahv+{48F`hO z4>UyyatX#7!~u^3ypdS?QhKMyvUkaS!jHy&2nK96Xou>lbAKxr3R=F1d)3qF9srYGCZn2vfQYnR*0O**J>SHQ^VpmP3ZQr& z#Ck1DCqifg?r^wRjnv{H>xSH&BlmDf-!kLYpijQ|iVg?dge(2;SN+!py6hJ6kYAs$ z*N(}GcJa3!J}NzEU5sgc6(g%EubIp`d{_mV&JXJYsB?{eOVSXSi38dnT)^Mg(YFI! z0IRN&s>&Wx0N$n`$XJ2l+PBZz~S)p$I}W zqAH^p!w-w)1o#1QVhm-Z=Vur={aD0C5`DlYdf@qAx|2ohF>q_G9M|*%2Jb*5D?dS4 zK<33n8WPcsZ5+JfYt)lW2GIu#2b%EnfQB;TiR`_U7^64|_4j2Ac~m}@qCIn52#w#B zR(Y>KZztNDU1uqZ1$YjP=FHB9IWE`yjZN!FRem$UvrfYswMuAmb`HQj&{5SDAhL8O zsxebUKxg^zdVk0$edKL&4&95j@ak4u^A0j4ymO6B=Zca6a%41qqYlfe|-9%jPzbUImxq)&D&O`i?%cxlboT{)J<5hAP`TD(qxB zJm`B-R{e;pCTdeC#R8%wVY2j)7r{vbFd>?o|IYxO!1LKCX_Yr*g(96N*St`{E?(PD zd}Y~aP!Y=fq{LBz zF)VcU+<%vF>CTwCdfsPV4P^qa`EXX&T;Q zdRnNcNe)hqSewZT-Mi5EBrAJm0)Nu=T9dE>?!Oj9(!oJ9HS5#Jntskq@`}-ZP zu&#=Sv`5dr91q>mp{8arV3%5J1m_ET4*g02R09j0bIP^TtuE_L> zBaWt3A5u`6%G=gmAa$cgL&1hx`d{`KihI!ET}pNs(pymx3=o6+hd&zpx=hr>mX`8_ z@qrm?(G(d=(Kix_CLjBr=n+EBUU;X*zUX2g<(k^HvOG8kjfAKl7U2Ml*Z}ydh+>I_ zrQWvGY!3j)PS*+omY8aLnmIfF3wlE4&lnIqN{Vuz9t|ngegx=sH`i+F$U2K|`X==a zq{n2N(^Kg&HhmjrNe{7B<9wbnqa<-z;{izTb!?uEC}VxWys%4YQtX75nV3oJ=-S2w zt+LPn+b|Tvj|)H$bIEl0=`VKSh+2cGy50LM2^vc=jLa}4kRsq6!*`FX;P$<`mFB2I zH?pMSs{zTG-zZCLDC*1sGr+erQ!IE2*FXIf3q5Fcuwh>u)!4&F>zdP^Z;5lFiZHU$ z`DjL=Jil}d=cCg>*JAX?F8t@-&bLWZyKUc68u0|(31)-TPDmR6(g0&GgQm+bc5l6+ zV-j^rj@M^wr45fgfMbf=b01r|(+-sjorAC&yQjKnTyHs1U)!@`m<42=3n*2^d+&B4 zUa_iaTWnGZUs+BkG(3@GtaqcLYEW)Q5*wernK*0Iv@ z@PFeeBX6^W#V?Y3Bs9NBE)hVW)(VEkCO3fsyfzAu^wJGKF$eRDfO)4jb($?Liwl0g zzRS(480+9x8rMb`SLpf^5R!FB3-CDoM)3Wqm7B02Sdn8&@?tK($1VpQGitgKT@Wm0 zf*{p+v+C1gm7}NiiGNim7kmg+>W>vm#Fc-$j;J#xV_6>T4uL!tZt?Jdg+e|?nQ$$A zC^AVsJfC2~F30$b3q*5Vqb8pKWe`r#&pcW+_*$F0axW}#a4N!10twx?ZYd5@n`n{!~efA-{!HhbFY^)*^b~E|M%8#z|C#G|*BX9qX0?&oRnA z8-%otw*UK~Z)D$;A~i0sZ$B5LW_?QC#4Q+$D;N+yF`T*o{bu zyB)-vVhv^3=zU=Ts9t%uZ6}&~K3&1Bm2I!E;q-GyXPi+ii>!>Zo6oJVU=zNMA!S(K zw|{0s7Ua*Fs0U;c9`Qi94((AbG-NDb!ZU=NX+%3+*M7x7=D4IhhqQy-8N$b^r|mP@KiIF7s4 zY`-h%Q(~;NIb!Zxq3=nIA%VP9MAYvEbI>hyWs$4})$bN_b=Uoq>!Y;Ni)K~CajR{G z_ZHptZIa5URerVG6XqMF6yyxgsj~Q@$N{-O`o115{6?YfeIFnL@ftTj;|^pg&4t~5 z<2)bcJGzwKt{l9r@6-QD?KBkB_VAt+Up8}az_)(T5-gx9&{^8Lz$^) z)oQ#ENGW}eHf!ULk6$PN&0AUMK3cHFW~wUB9sLrS>lNZS-Md{0Pa*>7*Gk&kWsJBe zZcO4sej*dp%gKZX8=5p>LDm~?PUOqypP4gNY|Z?kKSGM(a@cS$*#$y=x?D7agJVB} zj*#QK4DesbsauC*EekxccEE$01@`ebF}3m<2@-7iK!?tP=<-ANbD;pWo{P!5NF!&~ zz$;GNu6dMrtRz&~lqB+c_0ooNy(Q~tB`APCwca0Q_V(XZ76mPzKDL5{d;Gtfak=r; zWuA8qt11C~fF!5=5AFBI=SG~)jWN!_Ysh8xND&H?%3fBP@A1jnYr3oJlQr|VKL~Kj z1#ic9D}Gz@XpfoP{Fn+tMZ}k|@;p#Jvgmg@N9uK7Zr1LiVq-CT_J)Z{f?FY>kt(jikN;!}iZ@O@#c&XD{bCEoHX$UB87dbls>V|-QD{>s(Z8Jg$~_|^%@BV)_{ z)hUTxj$UD?hQ)mVz>?k?Bi93n50(Ab9Ov68Ge0^rgY0>wLfIKY_CaN2hc|6Y-bR`c z69{Xi15k@hQp-U-kG=TK?4=mvb`nAYrGOfOR06f8`gtDuwAMK~cz0}>P(v1-e^kM0 z9eYXEZ0fXfv_yh~%lx-4;n{{PTYk!kCn6k!WCcYg60<$?iA%I!QBCx~2_i~7w@b-M z&SZJhj+%S)n@psA4?%4-(@5+w4QucVB><2SzJMRy=Eb?_S;SuV$8o0=O8|Scv^Z4o z(2p;8BifbY|BmW~NL-DQ;Pj516hGR@;6P~zcx4Rx(Tnkw&Pq}L`S=pI1wFYUc=#qC zTF0vUH&v}kV*DBRw!n7*g3NwOO3+Z3dCbYgP$2{&){QJDB#volvfN%*)EUGCg_6Zqiob%VpThl0tzZ`4 z=>ziwRsJ~puC;~`cPeIeox}_8b)4F(rfAXL_InI>rRox+bNj_bW~ya$Sl#4RcQiV9 zCGkS-7gCz0te#`Lf*w4({h@QEz0l_MT|8;5ydisOQ1Dnobv&bo6HR%DSIRCn@9=pN zyU9Y0OS}B?l`C$a4TRze^}zb9>4PfO1%s2OXhLY`=OzuEDTMWDl~IwD4N&op<3`FN zVEUq_F0Of;>+Krhw@yh1#<7uQ;8CiDiRZE%Xa8rrSf-bpzE*rwM|ErCJ#3*A-ZAGM z=$Hk>@(ML7EODJ^1#d2KgYex>^t(ivuAIJq9O$2Chr_%_(4{h+my+~em-7D5V)kIBQC%zbXY=1yBFIyYLxX>wmB4|``uK+U?iz}hVo{vpjbH@Ri3bA85j zh{|ZJh;U%M{oJ_a$o5f9ldNV=qVtr6^agZ}cyh0N3%<${)SaWjD&)F10Dx%(S_>&d z?$(3{yB!^{T~_7Ik!0cH>lO_>Wz~u*B?hPS5njnsV&$gJQn%(A4S&k^}kr8yRIjEei1qpB5tmY_*D9IwJt*Zgs!J&0{SLI77E!d;=`ry=% z<}R|@}6lBY2EZ$j0z*j(nu&(JYB&Hmb zS;%XmT_pM8ih#R$jR!^na&?OUrZYd#OSWVRPoJIjk7ce4-#? zn1>@!$h4^N1Q{;T2q_xN~L@oGPRSR}aRAcnQ$n)7+-;IxajX3uQG2`BMq7 zt-EoFwgO8%3d1*0Luv^-ifj#P>Va0@tl%lkW{Tb;Hdn@K=xJL)wfBrloGZ0Eck$mE zWQV41=8k7lK@)PA{5wO3KhM~-9~)}MVA2r#AnD943!Lg-)i5`D{wNUW!#F}idQ*2* zEbsst>;LK!$AMYWJDj*8~Z1*|x~4ylLoBb#2vxj=?fzZhj3 zb3yWK~?Ob&rww)-C z1-LThSM;31nPJbjp@h+=*$fRx3419O2U+(04!<(k@>5Xvmz8ShZ2DxX(2%0j2Y3Ur zQFF1LJCfnCLIXM5K9k#Ig_85oIdwOTO>i=N=6tnTek!-DAhYCC>4*9aUXl6o6Z_jO zlh?)`WZ?D6bw6yMMSba=prlzkBXLdUL}AxRSL=%RRKt$su~tpY=GB_?#_EUxZ*mFXZBSXM|6%E z>((-^mm}~B;R`&iwIBQSeXlm$tM<#lamu;OxmL{<25_JK;Y-D6nh#XAV?W)wySq$h zKFo=>R+3Z(eC?8u^euC7{CsOyEu~I?VJMuH{TYYS29@4KO6#h*_BL>Gm8Y#m{%Nb| zVA1W?|FEbZ_u_ly17w2}p|dSryIkhTvClcusK$0| zadp8zI_X;IxJ}ivd)?_Anp^&Hvc-JaIsRtb(9!D24TBxaYS$LJ=I;dVb+IVejV~2o zTSch1wdi71|7y&VMo3wL?136#DU^Am2?n9Vo3W|_wlZzU;?pGaKDY4|mr#d)L`4UW zSo#{paq5B467mb9L_miR#di7vy|#H$qYI1x^Pkt&gJCC_UN0@P-+A52(h z0=hbb)P`hZqV?g#?J=}d=6Vxmj&!lHy~{sW6Ht-sxYuiQL~byMgyNUaf-nEOn+{R$ zWncZIfmZQcC;cmAP=51FySZwMIaCcw?C*`co+dy#;I`@ar2v=Sx}zzEs{szfNDDxC zEJUI~W?8^X3}7ZF+4*XzRWWUE2278rTK?0AfNmF~6-dLHmD z8ALF8JnPTGg!;kqA+4)X$osmPb}CDZ~w;XrqS1# zy`k+EYiNutA2TpdnF+ zMvDbo2J);?q?0#}meEF|ZMS4ag!XhKJ9PLO=ZHkDD(2dgB$MbX!8ETZq=leaf*Ox< zj5KV3sQ-OQ{GEKPjLROUXi54t&Db$gqy{L&PjmC-Nc?e_QKuuxA%^N+zVH*7J;%;`2j zA#dfWnN8fyRMT6B-dT;{4dIZ`O@A~3%gm7h`5Nc}o;@te`CRQ~{8tYLc9>QOqi+f2 zStOS8Vx}0VwAAOCH(H>izCf*KF3X$Q+@q0sO?<|l&KX&tMmX&am{COJpPmd1ThHSc z(BSx5dz(W$lKAq~CWRg~UVC(wCXVr{eFbsG@F#T(tXMr62jt4x64v_LudC8Y7dhUk;5_>p9e9~)HyHFSvEm#P+Bmm(jx^J3$;p9W;%Y*c^ zkQP!A%Ouz?D=n1%uWha8#R^xlrychc~Aoz}98!KxiF^36{n8BwF;(}Or?NLyt z)AE-i3kt9T#Q|%qo(Z(^7X6xU+;)iyfIz__Xhf4l!>RTz3#q~Hu&p6yNUl1zRd?Ia zfnEs6q=#Dyv!of^y({yOzubJ4ONeb7SW^Q)jpsPiA%S&4;q~H{1^-3Iwg!9*5!YZ^ zkiLp!ni)m3@NHc|N;X8{QJAtpb~*}x0!W}M! z=EN``9ubhn)dnwmzE;TH{5*590=h; zINY%L*qsXto(e$LaEW47B?!`Sh;n?%bU6sAyLuWkyvq(ZaT_>;IRm%rX)AB@x1sGSmKOcO%8uLMdJ9b)9&wDyC8O5BK0+`0_aUw z&C~Xc9|NUJ|1lcK((jxhyf}!oTMneQld(LRTiPB(vHP(}%x~1ZMvA0Qi-;l1tCO1} zoh}(}R1dCa8Y^q#3++yscrDNUcW?v^LkCgwmi!u9M#{p*Y^nu9ZuwW9n_?&=~G|D8MeyATexq2wTU`MIhH3b``~U{*OgxIy3{742MP)zxCKL{%U*q@K7~m6_+e z=1kQ|&XHxEymeHXG0!0pzEyamjSIYt{C@J*SjCy{k+M@4E4^$>`0L8{8J1gFUN$yN!H5LadznZ1N8S|{=&^=7#qN*0GDnXQY%&PH z5DA~(O`Ib5Fnl=wl~)Mtkuzkq)J1{owupk%VJplKn{DP>0NCxLc=gCN|W?72-V%mJ2)=eqykwK(Ba;L^b?_OpLw(z@Ot99%O?A zfmodT8~;w2u7bjEHrLWCcD}n=7QM53B)FxIahvqB%{*JGRW!|d2W{d=eeDy(g>c2& z(BB)S&RvqZ2qb}uHB0zGd?sbj`ON>4sFF{(Mm{`G?BmSvCRo<+(&SmQ?3b^;q}{=l4i+-xzExmq~jz!NW<>{ z-J@xTO*^YdCbUL0^0htv@tV{~NjQhmydk5pJ6`3HHlW0mFicedk?&!HT(GROJHd5Z z=+RH%GEBhoD?U+3ve_{?bK7uV-s>kex?_MyNPdk}^{@eWsSCBflXyd> zuCwa5>};rnO8||XCYqxfGoz~`{Vb>UzEq5Cq{jG!z|b5yFz?;+HcmpTOa z1_&(>BiBs9G{lrRMy^`$2e}ZOH8n!gX>==u_62J9BX(Wl{q+<+2G{9he~gkTK=c<^ zS%k!#<9hJN`y7%m=h~tPRBQ@m-J>UZ ztho#GuoYB0m^xh98v2dTctf12?XL;9Szoz^B??A4-x^z(BJ0(_xMn_?s`Gd9ZWH5@ zk1fK1c{VHg&Iw8sUd})F=8SOUjJ^I6J_6qR{8uDPaI+7^p|)N*ua*uKo1#C4V2C9{ zdL7=hlHg8RyLG;@qDZoUU)TL;7v3_JV8`d*PO18Q64SCz8JBF?6dQ>Ux@H&B^NDw5 z4sMgoZ*xtdlR*{New&FpwkxzgRu`hmMrt-Kyp$=hn|tx61?Mdxg@RGi8+1wSZ6I!0 zDAWpg+KS7X_3`-`ZAqtmFP9!e=^JXvRUrc#+?_{iOt;fK4o&_Hs_6}xj;unrOURLb zbh6Drn0POjq8F!YfA{PzDKy*Pi&noIjCpx8GA-lZT%s^ro0cwH09brv`-nt-xtD_O zr>7Xi+<^wB8^k<_V-$}&LW_FLiw>vtY}d;86>+Oc;%de7deK6kX2wAN;IgA8uDhfY zT`er`tIM!z@G$y?%jh!#8c7yNu1pBk2;-8u_UGzf8M1{uHDmU>RSZs6?LF^;5~`uz z8`F)|RFo6|OjGJyn=VfP$<=4=j(^gRfc97Gpyg#VHhm7&Gt)jxnUq%IH=#3pTurJ& z?}ikQjz(NI9mL@1cq%#IgqB%UYxmuG)xH?=k5DpYvzl<%j47kbz|(46P}IRhVO3Uv z;@4B613sY;57u7ga349E0LYsw7$w?pQan*e&K0(?h9>X$?Am?W;bJCta%LRcR*0e| zyEfg{hWFBy#PXJ>p93E5yMj1L{F`GeTPi8&d1a-~MvsuYbnlDRS^{7gwe6NHcHvf) zXVn5I_8sxd*;{_X;UajPoXcFMyS<9CXg26G{9qHDTcN6kW-kYDX2Ds#TP%%~!5OF! zQGfG`%yUjMZp0*Y%B~%d*r7f*k`SnJo{P!a%Z0MZR;xXD57($sbjd@3Jds)K1WWzW zCW`QMb^r~+m43|qS1VpE5du%UV)!{r%rSqZM|dW^@D66M+4CBDcPG2_=?wEOYyOC} z_qo97Ko#gURSMlODQwP>*4%*RI6M0YlwA`;iH&K=tNaeo%6ifWdD!_VrrLW|?s@^< znYQmjOws;+1UlRG=9^euC4wDf(6;rq9_e+EJRF=;tVrsrIbFY!H*xsTPTLZetEl0% zCm!X7wh$G7l$0@o>ag=Jb8!fW%$_ zuR}@M9RSo*;HOkx{?}VqVo9J6!m=c95&$hXZS{J4&%BXl8cj>)TK7JLe1t++pB9M~ z3#Ab0lbkO3;93tl9w<|{YQGCnsWn7oyWP8!_W*j(aBE+(i%wVd8iV1Xth~xUqp-43 zo!KqW(76WwpU3IpWb8xSI#@1P&9Os#EQWY>^E*OVm&>f236cQ~g7YlOHQtB#xQYt$ z7w=V#I{XX%!tALVuAaXHWlr{er6PU3){fC2MyYAhN6NbioG-O+NB4yChHk_dkB<7y z+*02X9G^r!MUDSPfVFja*hYJL24vZ#tlr57Eo|K3&6lQwBFRF`9QJ4^_n#5?gK2`J zUxOCs@3^O%3d?65%E5Iu5RU?&K@MpT6v^NUhwiOtQLx0IwBVJqWSOhAT+9ILDjMkj zXPHU;Y}z(8?Rg{}w)kkx`zWTj5^0SvUe#Y@p~U}Oah&;S=!&ZzeNWV}k&W zvt>#0k8Z%WQ9$o?OY7z9A2g+VcvC59kC0G$%7+k7ZQC~37cu!2Wb%=XE1>9l8z83J zZz>uMtauCK?3LF4QuhU(xq=T zFULHVA^b}}PS>Sz#=PsubEiGdycGpw2a@F6!K3puy1gHwgjF$N#bql^~DJxAN|L||PLJ99f zn(6O_Uz#@Fa9@6;WE<9ceG$47hUb61j^ygQyDPD|M(2Vx*=NbtW4T35^d(7HzNg4P zZZUC%sFZ$VnYV%jG(}I~R&(5okw3Zs5-DT}8P>fulZL1RKkj`K*T!k;hv$lzN`B z`Ct<{rK;fnHKDmTG}MY2A~xHy80MuEfN)m|p4mDpG}YJ^UC|^^Kf{U*hN!tIc)osi zsPD68Vd*p~-iX z%%G2-ioX{ZY@qKxQ;qjoWpa~^WM5Lt0h(HKKbPN_dG#$SVpp`XV@?I`Z+{K`%aX8a zmF5BwHcNRVBuc=>?|^jpYJgV4mn!Gi2cmL^hrXzd`DP^a?rYQ;W|G+K)r@hHG1N+< zE*|OKT9(e-XQyd_2^RCk)`a7p;kkeSK|sF0-PILz5S8Tg6C^h*8V++hDDT=Y*l6q! zm_+P@aQ(>hJIo0`o}HWt{X6&p-@rzosX0|+L)QD7I3j1$pj|xKRt6ogV!@-)LD@GH zj~LM92ZcD$3w{C|X~+A4=?`q`0LxFFopQEf)w5e6I0?n zCT^hGx~!s5?A+t}tg9>5%rBfFIVpHtMNMob%XM=X0cT3Nd9h7@S!C}TjAHSo$%&eD z2TB4K9Gb&)M5iXvplmnYkT6M?1!AV<^qB;CmY3VPD!RF{h|odi^plWPCkzNYmd|!H zpim;7`5HIfdgC|HIc8qS?a}r2wQ80LP*9()V0EHlDsJ-#>-fpi7_%Fs0jH3 z(C}Ic1o7p$epxb@8aIZn5)Lcma7@Z^0W$$6z6%sbN}~iX8_FLeTTC%4ncxHu3J7~l zDN-2i-6?Dt?X7D0*COlZ2$_o=Wi}GiFDvP);02F&q2Xa@bV?NeA#W!^ho=Rx>%XBG zkxfKJ5VEgoIAet8vLC*=3+jy1vlFOnA+I1DF8?$L6ZMheK1x9kq4sc$59%4pqwH_Z zafWur+a+pym|>Q%ubQpx7n-nr(EK$Aq*P|cegk4?Qo8nYwOEfAc^8#~>N%E~#p=q@ z{m?$rfCDqzhA^%h+2&yI`~mvi&L;UAB&384gf=s_)s!aT%ZZVM!8EvDxJ-1-Y1y@GR*V1X4qpEz zuE_IAhr-7yr{$%spn~NUkeuK^W3n-f{k4@5jLs$fit>p@5sDg@*GMgbuX^n|9qg9H zj&uQ{JN0>0+B1tG{vvmevZKVJ`gon6d5=?!&v3Y6F>b^1;n_6UVV^{I7P+}3G$t(a z)@)Chu*TUT!VAGu+#{z0+gok9o`B*6nJ1qy{}%W`BuNZl^W=HslnqdhP(n-$pk(_%0B>a1^_P<#6#To8#mhS?i15>kdCOtdj$ zUq$FX{a&p!z{})xL$3ew5$11mzxXV4BGe;kNX&T++^QJx&HdDh9KM>~=RX+Wo?|tp zG0{d_9MdNmh8R?*40A<&cGF@i<;IyB@0b^U+dsx(UZFh>sV6H>rCx;BxJ|p#@5C`6sEf2I}mc z8^vG>zy0tr)8?$a7DDfCi$5C-u?NAffX`H{`sHFug?k%w78#qf8n>Ssn&Hy;HbGW} z%!E{X&R-!CUuElR%{LiohYk<0UCmo%qITn^dhqqt`9zW+tDERd$GwNaG)bjcBGeR0JfPLpFrMQRMkzL%yvoS%8p zs|NMjWl8}OdBtn}GLQ1V(PAs$>={nP1Xf)reGy6+KnDeicY+{h`VUnrF(5RwpX>m= zq%pvyq9eExyQJjWOTr{OS8B*~Haz|67+h&4(1()&jRLAnZWPvRg4K;IK?!euu!dSL zf~SHC%ghrN`xFXy@^Z@c0kF?ML0-&HI2cP0R9}4XBwo&;`H%|Qfu07#2>L8H?eQBl z$w5*_tG92pI*F#x44faPbf3((lgq3Ta%^R0^Yf{ zqje)C|1|BCK8Z-SnOzM#z>PJth@N%&$ix-IO!5^uC^eNL`}6F0&g^4=&Oqm`e%}>M zOA^qONy)(`0b{n0qQsh0Mc>CVD=fOnv5_(UPlTF_{&}j~n>p1QJz^WWXHBYV(5u;W zGApqBC#`Mo4>$lskyBUFoKwHOHiqiqS)v)@x3^<=1q(pmlv<6sOY#&+)79JTKs(!( zH8j6(`@~aLETdunHT-&6soFE;b>cPa8|8(OrfrnKYV5kImpD5r3a>q&@kHXD%p{+V$zT2WCnk zNq}ji-(}J&+SXcgAD>=)`ctM(+sPuZrk2-3ZfkbK1|HIl;|8w*OVTXjC^C3z6Xu^oZ5lF{XZFV04RpVNmupu=Z06x`4dLGV|<}=att+$%1$iBb*bF?R!YH8A}o%hp+ zZU)^};u`kIOajTGPm9(iiL_xSiWRB5eL)tFX#KU?3jT0&v5BtwZ*<^~a=Nyms*Anu z&BBJg?$QU(xN+lhJ7i>ov@wqx->ye^!Ek-8A=(yd08U7$Ryuy4aK4-+=4&=3c$)7N zDP(;PxW&eix@TK~_)#y8g|7Aw`|Y8!Y{_n4qPK_|h#rN!4~<%u9!2yP7rDW+(ws%W znf^U*ryuf_77x!!CWt5lKAh$?TJL}oRB7>`$hr5r+;*dij(YyO`2jFT^mYbwF@N)UQYWyR6om7vc< zvv3Kz!MD?Y3b__G{!Y&CWy`=<9B|p8D$f#WV(M1Arn$bh8tPy6-3!Y*wWm2_J0%Tr zRBF2ac+tKi5`XxPMH%#>c#`BVlfRU8y!3d1ZvwZv7_h5+lLV5hxKO(fBBH3AxxP(j zG64QSMgoQVi>yk$zaw=`;z`!1ntHWxuwnE##(Nd;C)tNy_YCGslbk4vy^RWwrJCiw zBI${y!q`?A>!eS4$_hjOg~7ywQV>_N*=_V(!0RfteXj1(G)IHc#W5P30Wkf)B89Tp z!3ilo0FD*zTUfbZ$hb!o=2bz_*9;%E{-?G-}X|GW`#?j}&?=RBTNIw)>-=T$p< zgps&WXVkV^p#ChJKM1R%aE=Oi(WWhB*~Ptpk2I|_94`TBo{jkwC04Qw{9lSYl;w&J zV*nXA|4u@Z*5vEgP!D;vRZ8Gi(hwAo7HO2*EIlU+Pr2#f5GBTth9s;o@&`vC5pM|e zhnAE7X$F&au%4TFBU=OaAE<5By4;G&d8~iymgxrJGZd;d2O@VeIH~_EBp3}`)*QUm zUIHv9AUSs4y)BP1=w1v_2nx;+GE2SMdzUA@$Bi+Og1@S^T%w8RLf!51P9?hCk|iA< z)_?wZL);1F!iQ;7>teG4Soj3tfDZHhIBPoZ1u^e4h$U$F|4L*vEXlN;$EIsU7)Y}Q z?wQCSXLyw;7#B1ve-U0iSA8wXe0L@ZiHd-Hqs7L7EB{m>FU|;BW<`rVLt?pqFY8?W zL^Ye6(da0Qm`$O$H-ab1rai*{xD~J@d*2DUksl)J{fR5z`QRJ2Me3(fP!mx8g zpz?WaMRthV&HyNoqCrTv*b8+PmYC00%97~J^b2qriYPfMbDRdD@Z_xE)*KuYNM{Q? zs>Fi22&~z>9du?x`)O6&y@fny0f>xLC{#E! z)^o;>qCyI2ZW`yeGWRvGNWMqzbrr6T$}Tj$M-5)jdR#N33f^7>C&p359(R{#Yvm|K zI3J1i<+%feOs*2GA^((~~%usvfbw045|Kbti!X|Ap4FFMZ=yxPlJ+;P1{MB4Y0xm{eM zYME$4p8O7*jO%(YcuUt^3m^S-jg82PDRpRcx_?^BnIvj>ZT$o9S_u`2Ry3Q3w( zas`oM1og5@N+$|Tv8)~hxI|85hO~|dM-Rr&{5h*H2j~U>ej2g*?^K+!eovasq<%Uz zUW>xX0NduR4#WN6EA>5_rC=9H*$F{0%{jHCIya>by5jaj*f5ya^luXX`+pjQLI?!S zSN*v+KzA6!0dNrJKew-=$RN(b@y!C&BPb6 zY6}uZvHq01Ry`>M)?E|!QeLE<4LOt)6L4U#>`_gY$+iB9z;k*#V52{~#6C+xupSRf z6$g$0(!4~Lh`y<3{IJde)s9My1A95qUTO}vU{ZpfzgV8+XJZ~xBFBGqeQwVs76lFC z0mj+iD0PzQIKLd$r7`rFSHjT>{m`i=s_d&k*q}*f&%$cwA>iUvdNvO@5tea^Im>|x z1b^~|qT{f;-ntp%ce98#js#uf4~}%CYoAEX`%!M*p5Ih1?Fj4qh2`S2#i(e*u9e&b zk=m=LXfTP)RDThMp8>IvSNbCyOqVlVO@&F2l-$6H@+hm+y#uxu_+9D$9DPC!Lw{zu z|AuB>zIIh&{?%1Udlsi*e?n$#$>ym~jXFBtSZ8@1cJwszh>UIJ&fcXVxh$FCFXx># z%#6;)lfZ@?TcW1I)})7fW#vs*3ewih&y@OE*)^;loKZLe=9OF$ik@YXp*javbYX+} zR-bJ)+hSg2(TB+F^2Lxr-Mk7Ym|@{a5HX1B$dY#g3cNB#;aThDi8-Yo_y<3Xm#U>? ziW*m#LAGXw_@y(Z2q1(xB8$SCsr`>wk=^g;(ynx8iBIxrCciNRIA~1kp0W*sxDo72 zC~@MYS$zVk-b!HfRT5*Kz}y$oVgwpRC`k|^j@uVyQ$NQihju5kJDJGyg};hY@95Pw zk+M|83_c_^#dGsc=K;XOmYM9G2eniCHavF&n;EBy9H$2);IEVGi)OQ?zN=+&17_w& zcgx&0rW-w{sLJ)R|6-p*jGIma{lfZC+b)lxyX2pWq7y#MSu0NCr%26u5DEarnkF=f z3q3J+v}H1g{aWTfik6mzmn_CMqGfA~IutrJ5RqG9xV5i{!2mI;%fu--uJ?TSzwNw1 zAv`BpFy=VDmx$?t!+Q;{NRt>1O0- z_OpIQ_y|+b{5H-N>(8XpE;9bA>VDNFZaX#E^;O zuz$TyTuMwfTLM($3yO-tWGAkU|D0jcA*&jGFBFU3mT~+zUg>|uFl~9_j{$BOfZ2zjdpC!8B% zd74>Q&9{Z`!NFL*Kw~kqU;fFPlCZa+%&&)LvN-64>URMTXg~`C6WFQD-)5(O5l?(wsh}rms}9-?|cYBkrkT|e;MO0$b0d(I$Ng&*%!(U2n6cC=Q*XvVhG9MlgjXu z>Hh)x2M5nn)s2|LgVo8SC}Vv7{RXe^*^x`F+Ka8k_DKPlkpa;OSPi;gbT2cGSs&|) zwLPQ(*}(w^av5-o@ocLsm;JuePm=Bzi+(F;%uS?$7F?j12NI(V+@ee8MS;mB|Mhr~ zG<%;#33|F*H}z+92zKnR##eYy=zR;tGu}o1Lope8xRZ+ zZxA^rRebK08{elL{`5-r)&z`8dw8l`Oxt9q6|vI)gujr!`U*t5ZZ>Uv$LELV z^tHF(c4m9V7Z0XLN$(*^%TaQ5W{p)70pq!TQqchV$i(69iay8mG+oS+-90|eAct5* zW}b*`UGE1Ndpn4$ydk_ifQ2oRv^Il+wG*u~w3oyWEyri?#EiZNlTsT(C5Y*Jgl9vG zn?WF_5}hZ{_tneM`4w&eg@rb+rT1i;&Ug8CMK354#ynWTn%pke7jGAROhJ$!d1dxe z9(M~iJdxzSReR+C?^S9zWes38oa+Y5|7On5F3(0_3PEi z_HJCV@S+KRL(SqSE>ws#w{8f*{wI8)nAtP!W_F+&95nFrj#M>E6~3PF-yo`RmM<7> z??2_44Y>C)Hk>A z4hqYO+sx^RW4gW=bl!NT5`MSvNpB1@x}bUiSaZuqu`Klg>(LII0YpoY?{w{j=|x<}x7Jp&40h&hPtRPar|tat_x2B&hW`gG z=btzoCY&|-{nYIq@uY4z`?c$=2iPxBud*b3*&I8rL=`v)fyo%Gt1X)E4U>nR>eBK_ zOIhKU7|f>36%*n2SQ7^yswPy3{>WQj-pID&bhc+Lx))?qTuUrYxeE(wPoLLoI3sm z=@MK6HR`$bN|j6yO*e_~J>mB(c}iiME;glyHeOvg3@dCrjWH{q;ulZS^IXm)VFrYt z17N+sWuL1|3>gaANWmd|>Csq38ejhd*;iKWG$LT9R3CVXFw@?^G6$4up-9h}^v4szGzjrDDtZlS|f<3l#yuWrmP)n2=(6|&As0rF~q zQqoBNHsygGSGiD;8S&mED%y+T9#Aol2xswoRF+WggJm|hZ~gwL4JmRadidVg^4e^F z3gsrvGMZS*UOog=Uu!yFngpWn;^$2Z+Ch63ro>UJ3>djG8KoyCOw)4LEGcTN6s63G@J}goRhIEUAlgZamfV1IIhTzM!oJd)6^knv^$S_q^1+i(A zC=oU^_iNgkkv$}8@A?Y{^G{OWg;-dZ5x|;ZXGGmYMKC=)_&KN0T zRXP|AhklbO#?J(k6UbTTg*)`-1|)f(FhRod8bGIl5l{OP=5DFg`N9mXT*0ngGhmh> zxGdCFO=bh(oTPOteJQ_1D*6eH-zh(_&^7Dg6lAZNvW<13`NvEYBL6znhD)HQI1@#D zhcyd$q0dOTbbWAn0Nx!>o~Y0@%K&#BiE+6jOqZfM(eX)VAv(_!i_V!MJ-Zv_m{Po{ zFQnc$uyVgI0o&vCt#9<%d|duH!I4*^sh!bmF^dRTuFzp2Cyl3i9dF)^rEanmi^XOg zB|_tl;QMyDP<5ESxjsY0y2g3uoYam7UIZ2W$00ai3{VL#hD_;1W zxum_v>qYQI#jV6$q$fU0y;MTEt@eO0_J{SFbD&RYB7N59vzvh##cLOozdV`ce3>J>*lIuvN zq?|?sR8>oLYCKVb6gMgcOUZq+P&pAnxsqgdmqH(OMPobm@9az1=***g+CZIwtYnhR zKJ(0XY(Oe%m=?`4)KQ8ULNTSkC)$cH1)4~=7GFy4;Fr!Qhg$Xs5xp92+GExzM=0vG zFex(yN5B1p=c~Y`yo83iNX1O;)qw#ZR-|b*)yquG&T=!%`#XK^-|CA!{$&3Z<5_9f z6XHAIZZ}D;NFL$=yoI7VyXimA6tz~%NTc(2I0XPDtEylkk~&m+N%R>7yCH>7dxseU zJ0agPSj8W!tzDOnB?!CUz$f*c6axBZ!|V)-2}I7eG-yPe&5z!{bb#k3eHT($jRwX# zbOL5zV9o@=HcgdeZFr$AzPILB8Pj9Na=SLjPS+2|sf9_UZTHS<)9#l=U{l1v*$(5C z1m7IPdsolIn~v}8$LQ2)}??Mm|iV+4=c7-w!k}% z$T;lL=s2&q3Eg+5|o$@uIPpPI+C5`2b-&w{l)v z=X%Vg&4Qui`bQKKUoZh#n5VkH1LP+>&_ELHC0ty>KT*`&zl>mJjgctXj0?_6dgFVJ z!X9Yv#Fd-AhV(Q|*p<%S1pEljayb_GfrzK+V~bNnB!`pc+^a6L1`>NNM0bPZlX5i( z?MRHNaH`~!HK7tI0-Suh(j8`Yyo-tX{8!>izTrC>dD`$#Z8}N}Q}VhDqm;CqfNw{c zkcJ}{1QT4a&Dq#{quLFmrX(Zj@ToLmufObw2Wf0M6_L=ht1rjOVIXyN@wP!}FS1{Qm zgRcWg2s;+|KNPR;V7PGFmDQ*seX>3?cb+Q{+`3}0S3Rz_T-Zc|=wr`?<)tP*k0e}2O(QoYM{G(DfgxY{$_W%QH_hDk->nfwr1#^8AQceS z5|B{?|6F|?1Fds`zoDvRe}9l2mR+IwF{CL{q%)|v^9a(}AU36oPPF67^1^n$U~}0q z*_Dk_J80eATdtNY#*^ME3IaLzm>}`psFWK=hKLA_T-%o7Crlu z?`-MPMJJa#nZwT%!`fDZa?}PH1RL`o z1oi*9)!x#-)N)U{wsT{$NpiFrxM>(`Q?}M-V!;~$<9U6kd$|38*dG)kiG%T zV{)zr9|h8fxJe{FOp4flQi`AeGn&{&k!L>hn{`<3q^-@ab7u#dtX9#X<*hf5{1-{S zA2U+RduARLd#VdBN!f()u3fn#jQ&A^54h0{!XD!zLWsZPLwmp9f&bmM062nleSjS_ z7to7HHgeGD?jG}dLbp@vH+YK*J$S7`u4tulo=7A;B5p_z>o)3v3Ru=15S3r@fMqN^ zU`-IY^JF$M$nq(PF6V(FSVzUPKL1|LXmk80+DrwKjB*Q=zsV?5 zn&>2o-tM~|;bZoGVhJf6MR|Yir()Z(qoo>H&O@RIbJixGW~I`GCVayUn?GP*po?wP7oh#%58K!4U!^S<*frC1R;wxRa@(oQWVJ);Ui)b7OBywv zZlQ#w2+)!`2cp7PfuX3LspbX+CmbF)mPv*fT$_@b`lytVk}?5tIh7YNu^i(E61Tlujyp}x9PeWz-k*{UXbC`uM~~0SEh`tlAT|=xeNZPA+ZC_heM6 z-W-i58lgvB-g%ykXl}x?O&rezcCiRu*k%@&y~=ua{Um7hqtgU%Hm!m7=R=+5_Z*cKNTB0by9ceBY`G)|}xQIb=!6`2`;I&bf zGEgq?2|RvkL4rZ*zZlP-Y{Mkm>i>qbXoGu&1Umph{CV$}C~E(5lB7+Ioo-qGqNs_{ zD#Om;_)f*+-7oh1rsNHsw+svD4qkvu0=?g7go1_15P{_=urZ5#1`Vr=fJkv&i?z)z zg~fCNjK+1nIxDXC*Y02`NfI(x$K+N*h2pa>!@qFo%D72c{aEr?syKTW_RA&tL@TSS zndcrLL%7t5MqM_Bmjit3VW2a}@7!gN(}MrD;pB^j>xFs+tZqS{7J!vs_Xi$5w62*8 zj8!f53I2dgsca)h+eC<~f*RXx>M*>K3{ZJ;l#+mJHW_+}rX;~+JQ&jojg7nFzA#a& zap+gM_oNkw4n+2Hd#!saz_F1fcCjk(E7ehYqjUM`=R zV}f6EU(q989#KR-P&{4QGotvcoD4l zVhx_>p zreg(VWE|W}JVQg-R1d&llbr)H{t?hZ*xD#L|ETMNF?^${N3LTbE9C#qUkr515s+Q_`;hn7TQE5!8){q zQ1PbmgHWs&B#P|lOVJ}IV5y@PSxJQC_K9f#Kx?~ai28}d)LAiubx*)#mRX9i%651C2iSSFndUU^a{lhjoTgS_$TF$nTp%Y%^| zworSZzXFq4?VmS+R_$(2gMk!$?7>*mdnC>t&Q`@m9q&$%Tvit%0L%^^TKqD?tcCzh z>4<<&W0##PuQr5hp9t`FT2IubBAp`YxnajH`@um48GQye#kCs}UFd5(8{P?0uyYet zaz+qXFjtMi?ibs{6xVR^vgI1$#wsjx$~=dg*lV-#9B1n8VfmdCYgZ;%o?oU+Z_91+ z69;g)@kZA&M%&px$4h5A9ijtD1HYqkBRywRYO3o4q`C;BrAF+I-yB|dr$n+mscfmS z2xF$Y8$bNsp?p!}Mh2bz-LC%xmbN7&ulRqAln(~0qRI{GT9dj$;Ci$3)fDz$hZ*!u z3Tu}m<_Z@jt?F;D@ghy+>4%_jvN#g{wwbbAVp*2ENQ^+$&PNw|RoUX8sZ&#|se+IE zMFF8jpm=nVCm;?$s-I4_=&nOy?p!Rt*Dj_q41MB~klX#jho6+zdwN5Y^Av~|k=m+w z6ducS9BCRT4sC#B`n;+0q~@3RnYNPr=aXLKZYwxm>wuRN3VfJ~RN3hCM682CJ?N)U z>6v}M3kr0)6WZ)}sJqQ5N_?Q!(2$}JII6EkHDD0qkWj;pY=TrVSaaZI`&b6gwy1%R z3yaXUd}c9wb_O7(_N>U=O0C;8Sxo-`@wtTK=V=tK#PF`-+bE%>F(RS{h8jN;(ynVrA%M=W`a+KuBdOwjmYO26ZS zw!bK*!P45DC7}ZEsX2S}AS5eZASwe{AUWv`rI0?#0o2SO;2yh+q4=E+ne#90$;qLo zQGE1z7lpSw5DtigN;l6rRl`4SbF#Q+Y2()(>9tWJJ3{j+7Lh7=#yj?XW(&LZDuYhi zG2k=uE9Y9`QS-@_PAa7{uaUu8QHjFZ=|r3mh$JjtSS%qkqeZcde>7VR{0XkpJGi2T z$P2RH0Z~j;G2qk)CSmD*XdF5ef$^TwvpPpYOiSN=uum=Zq`{)fVVO~bl5HxD{a)8Q zPnx=XkHkYWU?0)_3VXSxJrz(kmn{2YS)RCA&o`T5q6F|i^gZ_IcrlvOOA6$b1U#R0 zA3mEgO23ICoJ_D+KP*NE$!RU=C@vSUXvMb|_W*5ch|FT>=|7GOP7@-{o<9z>}a@y0H97e?& z+=v^Z$mD&>XV~V)g`GErl5aGYi9)SA!%ghJf^aJ*RMLRGn_fOHJZb4tzT&5)O3udNFq%d}1uau+RjaSY zD$4K!RZrpAFXJakm{3lQNVT$JL&&+Vu?0hME-M1Ndc#692SrSac~Y$!=ZH+Ku-)*> zV2q1Bq=%Q`*9=&f8gr$xx5ig``f;>FlI|6Q&Qh7#0Vbq47asY5;RcRr8!9Z;e3nKK zCzLnVu#1Efl-1#tWx{^eW+ga)4<0ZnN!s+(ADz(T@W_AFi^dPOvRbKPxi;LqG01#C zKrjQJq{durvlku+dY4C<$JYbi%uYiY=UcwhYk6`B;T)L4)u9W8!haY!kzaD3iYaau zL7o>&0@E2ag@jV=T?2NMu^8vpyVblO4PN`~2|6CXrb|tvaqxS2`%0@sOq2G3yhEX;>>ifw*qShZOs{NK$jK0gH*oQVAK zvA4!JXaBhMRZ;0dR$ZG`WpoGtCD`l?5q<;0E;&4yfoL+5NKDr!E`0@+;_%doN)Cb& z&DGQ|O5hw0MJfZ~&!H$fZWhcXYUSEaob;X0Yj>2`PdH(UgKkIm>F9QsK2a+UIS}`~ zF?C>iV-LpOgJb6L+ufijcVj)?oqsp&SY$t&n8{ClZKHHjY$<|#svpV3n1z!i%;Maf znIU~bdlTOu8rl*=(@^Z&{Yl%~E<3nqNb&B7ImjWL?g$xxFr1JvAH-tqt7?{2L<{5? zSuHbIjU)HnW~#r*oy;U*hylh_&<83cE$Xx7KB&>Az8dF2pw@ZKSfm^;Y3$JEnWRO{ zs}YEk3LTOS(1A=n7#Gshc^coo+fIr)!UJVK_)cwh-@*K6hdg-eHX0he$P~v3#T9Oa z;bDKrKHkJY(HhyHX8^M$6`TtGDctYp-sVa`jfvoT7X0`nc1Hk>&Zky{?QK*iHxcgi%U=M|K_(&6H06$AWh_+Spj zJAsVvw5wQ|!tCA3)RfSmdz~Uxd;`zP^_}Xe+V^xu+NoxHd{`=8T2v-n$YjEPo}(^? z(_(29``W04$9!^h)#n8SO+Ss-;8CGTL?ikUittH*o=i2vaz=MdA=}w@Qo6%8LS8TY zjHeP<*l7cS_WZZGbx1V{F=ffk<;NMF4E~g|)qa_?m4$eD?t+yXXc0E$I_Puu&_1M) zRrF{Gk^quwAE2JMP0-|1)Q4u)aguhl8Dsl6ALXH0f25vQA0~Se4KD_oV@ftKei1aa zRju+2z9otCP>N(njslBRi5%LU6nN0MMXl%PFr6ngpJRww>ngK8sPywi`PHVFx1Kn` zx)s|}Nh_Um{fphl2{;tW#EL?^OD?ThhnXKChjazmuF z;o@~_nK9Q3F?)?$b$mE`Yg5AtdubW7F%jHZz(kMIR^*>wNYMHW(C(8}hxLg*g8daf zexn~oa7+HdtcPAVm2$TZGojUv4%b34=sV}4I)9N)#owF(s}^D|!>1?tfBNJU#TW!4 zF-}AfU;3}|SdF`zM4bEfQI2}ve8qryY^rj2QtHP?m3HwlcXRGL`}43yiqkTuagYiV zB$-Qz7OMXll1TS3E}a)-GSf?p6jnu|$O@WZRD?1&`OB6fMu{T zMEI8$jHJIwL$rAD=q;Iv3lQeZ1bX6@L!0+PJEaA>i;mAs>$Q;6fZo0)F0-bRERX%g zmcUz`s}-ly%44jKi}QcMrz;Zr0kfX^jmKj;bWe%bh6lPgM8x0oF>kvr^VtZ;4G zK1Zc++*j`GAuYlN49?+k`ntQuY`7jqP$}U+=J9NyCGQn`p+}TSdNf zQrX{(eSUFwe;hl7S6%7(4X=|_bcstZif^`4;0oM=?f!wbd zOqt2%V?ItNxX(-%F#tNguAp%Im*lcVmt{+_o-^Mpm1HJ~B-s!5N4#GDUPJN<1~05^QRL``_k}>s7z^ zi)rao3J@1DMCnJw>5~mlKUMZPK{$2*-*5mAr#Pe$ip?f^3!)|S=;6^M2`5H~IDr%} z=>Jwi5-kKIY)M7fQ?|yu+j0B!5>##uHX%YzD5P|s)y_Ie-z;IY1^2rB?nd2Q>__0rWw}Nm?Ji^6%=OoCoz{7y-MA zL+u<2z?Pmqym(zOdQSjSBkAiI{Knzy(UywLAqZ$$j+YI!lv?(u^Ln$8xDBH@R7h zHj6BJXOV~Mr0)F!sMk3-WiEd=qP%Q&haM#s={f6-zEY6e^g!Km*dKZU^&dW1^lTIs zEC1-o)meB5k|prV3;!ukN7D%=DBM*4zX(Yft6u$1hepm15E*wF15kNSS$pv0y!zL zOs(B2xn&>^jX32BA&9$P6>dKorFklQr+DIY2usJm9eXsyX^%g~=dm@ZBB5)+n@0m4 zG{;91bU zQWGWvI+01COI;xS5IKzz6ncArH`+6WqGaDDe14hjVQyD9WJ4UPztgNAz%P_oeP3_IcmV-TE!iOy>NZ+p zlT5%vXtWu7?|rN?*gvV?8r@4)y74 zXqUq&KVeyDq65>P`5ju?uQiEGev^PVU-r=3WrdJ_yA}U)TaMYB3}ZFnH(;&E&$mG6 zcI)uy?s!cK$5;F~s5^}diXbpU_5xOaAf5&jvzluZj|1$C31%j>b(T9p_SmT$ z?$kKtPU%-unv{$TW2ui8K^Eq1t#E-Xq|@Vgh+%gZP`Ebf9G(Bd2$zBMVeJMpxDm<5 zv=o}FNg5xpK?t7tCD>76ek00o7M#R?+BYQJJ|C{|hAftr5Ls5pWRe-aTl-gSw+PXh zO0cYGEE^vO%f)aN*wo{><{q1T&+=3fYgovtMtUt$t~P(sf|wa)Vnp>*an@z0i>eVNn`+~6>$-XthYRX zfg4{m#cR>o-J68U^0mfuls%TE8bJ%-`6g$Uno9uZ^{$B(QYy@Jg0!&u;k1S(AwoK) z6-zpUBY*23-pBsVt)=pp4TF6=RD|+BF1%BS3*Oy_k7Vm6a?d4d)NW_uXXBv>!Pq21 zs53fPPdd+%J4u8-7Hd}Hr@0;_;STsJ4o$p}IYgg4NAXoK^V~4&i9opqC_X7dE zuVoj*;ilz}FFE)nf9d6Y#Rwz+FKhvXCA`npX|!;T#Dj;ZA5}Ml)%pWpO)KB6PW|#j zSI%bLglOzew-{Lwd%h7Bu35H`FFxF~UBpNFsDuX0FTgMp)e-08>^&1gwTKiv6^}M~KLJw(M*Uo@v684ZG{iMnuuAs? zw~A9a24*?xew_n;6iY8@^tK9{f6Br5IcrCU-ALRPNP+*&;agx}{0jH41SZkq3OyEN z^F(1V!3W3@3;T^Q&AMd+?Aq#9xirI;j#wZ6ogN+}qtKjF1iUz_Kx2Wc?AOkX73Ho4 z;I`%eGrgxOwf|=41T$I&rjLO)dO!)HtOsr0(NKRREn2T`BDy}+kz<98`R%<|Sn!^Q z*)N(yQn(-@gygOVp%wv_R^$^;mcpM3DcZE|oW?x0jcDbF|*t^ zk@i@#JbO3ovFBvx{9jS?UJqF|~U%@&3s-}F>mmG4+)ib5GcI(_```?k%$j4Q1 zT==Wc@|Hz{Iap1q6~g|3+x@Sp_pk?NVlL`8BBgn2S>%piRN`Wy1kWqn>mM5dt>nYi z^wzwLl{%?vrL?a11t|AmiHGOY>3ca_a%t1s!UJ4oSbrl99!!~E&l44{mMVI{tjd$S zxWnF%y!s!In?!WAI3*DC4kkcXhl%!G;JRow=9*=DICJ&=6F!Xb!G)nF9{+1K3aE?v z`lG)HlLJ$of0H@Y83qZI-$ai6it)qW&uqi0o})2O06j7kGnfdxV*!i-X@oM(J1YEY z`gpl%2`rkO6*!l(LjG_ytlS@{j_a(6aJJ5%@QdQq#L^Yfzt89f@|qshccDc;p*t}$ z&AMKCR>HscNqauYpzMWn|MMcB9Ut?%@^OEy{p4i-ZZbK8f!eDH0Y}5DuVNE`hVN1W7)bh;Jd{bO zFNP;ZoOUIAjJu0^9{Km;?;++5RRxO0B+0nut^tP^oDI54qs1KfwrMq7ad5Ju%S+7< z90#k|M9zcM-Z zF!2U9NH{;;d#=4EkVo6ntIS_@rQQFDD`xsblC+nRMRHkhga4ZbFGDA16BRloFV{`q zEGuNDZ+jzI2X&fTNX_A-)t5+otexE?49#b1{Wb<*H}7xtJvW{fep&aQfcVR zwB>dlq0PPRh!qpKs7cMjbhdht^=Z{(rMKHx>=Xo3TH@^&fBgv>VkEL`(XYpGSy;T_ z-A8nS=Axm<$e?5UNr6S;U_S)9`N z)DaTY9uthuR$|9^U81sY>Lc&j!?!{Y5;lE;DneV&z~gU%4QEp~vU8Y>O~%zH5HmC& zE_zQF6hxTECzKM2bW)FT@JGn!LclnxBIgDM)Rx2PV+WX(gg^`C=vZ%xF0REKc25pF zTW^cI&4!Lc&@YZXEFxd6l%_I>hN zSDUzM0Iqh@Wra0=@$`5W}6*- ziP>;*x$S{uY&$)+?SI+EM{YnHbyr;gC#6wgkky|U_>S>jN_pY>S+|G2Ys*nzlz>0? z9Vwup=g0va8#eVNeqOU0jV1pwzN8QiSKfn?QlN?p3!+^P$+54$f+tuepk$nST|73o zB>S?pHgtK6F%W4_axrQeN{6uY*^%lzX^di*XKW6_9d9!7gDUuH{2?BQsMhpU@pvd& z-CQs8TEV?aZDTZV-%}@DRr#|9DXIRzTYz{;6LBR-qEeU33usM+n+_#D*OF{q%Nz{%m zFZ-xbB&kmfe50^_ZacvOsjR}FpLg&zGf zUag!LoTSqi2=zGo=k8F3f1PMTwLKLV+vVJ+|4K^tyR)egB@J8g%gD zBON|z74)DhcemGydJ`WyuUDHLz(X-HZQDW&JRds_t4Gy*O5r2od}E% zbFLg(TK~Y$_)AP1jL(s{oMO7^CjElzjn%G2SLC0vW+pz|nh!F)5u`?W#))o@3^9m5 z>crWxF3Uw@M}P*YR(6;IOhGwGOYTauny)WS6x$a%M(ci2{E!sXv>IvZeFR}I%$^Qw zk&bPxKuoa=k7`GoWV6bY=7NJ4JMU;TtyFOScoZgx_gkMI|9e4Z%`d7$ExMs&-T3DL zE*X4e*==5isT4Fav?1DUru_v3rA8luoHvL;)d{|N%Y_av%uWaVQX z)}nK3j>Fk>G3cd7`zUil_{-FOISPtpx)Ra6S$>gtZeC3xX%-AlI0^8Gs`_mVk-+m0lfH6Ny;3?J^|TQk(yE8vuV9wP@8b2LgkN=rE1YS<5aC<11XU)2%Kw=%Um%T@ayQse2iDq}u|6%Px|>j0p#TSZz)`M#nXKjz>OEekoGu+nFNMTC z@VFnlh`?nTYDemYKG%UqWm1KZ2-zzcI+LaG@UUiLm_amwy||lHGb9yA6ZtEo!%khK z_uVX0L(&Nt8pm*`rt_hixNKGGoX;_)kf(|9Q^Z*;uHRbnk)*<(jCg?I&yQfhP~P4f zKRt9*IW}S&93j*|o0n*7JoAbu*aPQ5908Zc&iC^t=GTpKj<$=9hZ28!z7SnsTQL4Z z3QPry*COl;CSD5E%6>kfZz2>A2k*Dr!e+#;Ym|G$mNC`MxR#mrRFH7m>{zcw4{uzx zWc@iCo2EcjDwf1(a^VX?{DdxqXv}?OzxEZx31NeY330sD`hB;VArt9F+;2<(>TJ}4 zqSH%w^Pr_{SxSZ9|9fhFc3paM{LbA|FY)yzkP;PVPt>Gp4^utoDirhEs*aLQEDcr- z--WBgY()?DgTE82Sl^iYg%yw=IDHv#x=gk%NdZ3`xIG(&p~!$o{o}8n%v8T3YfZlo zX^Mo6!6tcSqmH7!1*H@M4IvPV zHdB%A+|CWF;7jz=jNf+uPt*^aLFsu+l3DyY(pgd8sq1riESrc8XkJ*r&3D z)}Uz5(_0RHmImuLAdMmDG%AVe`W*S0LB9B3y9@&BK0^PZW*s(%Fq@oMl-~9i(|1Ze zL=9*sIn1{NH@_2-v%+iFimt}JM5mJTBs5$SOVAP)x&dqkL7zg-nDw~SWGUKRf{#u5 zB@W8Xea-=MW^vJo(WW)jv{#40x^LYI#B-lyi?shr;7h%x!n+%t7377jC+xH<=7xb< zAhmOKaoe|-hDKHV%5R}hq&XtrW=VPIhtzQxVQm) zN(A}mmBdpO4=U@@`v^Jta+wj5$C!?vH>jW=51>Iii{e`Zjt*RJnoM2R1@f4sCrO`c zG}sVL{p^Fx?qlbCs=C%OyKRPihlUo5J;R#7I`#`2{t(f*-73W6yWBa80WjOI_dwz?$+hPez-MNA7Wdhgg^)3oacxO zI#U6wo$)8t`p+HQw?+D@j`){vC=EU?4NG>WSo2s~b`*(clXu(;j_R!8(r$a2+=iV; zz+jQ@i~G(6h53+n8xtakb(ol-KvF3avAV~zAcwQ^!|0sl{1niFqQG(-A7}`WCgw*K zi?oxvh&PdMWa5^_&v=})ZD7j&`qhqgV z0SU4W2%coF=wVUFo|r`kXUA&Fs|RU)J(a8LUp13r0TiKfflCzTZ!PBFAcOh!vX*Z@ z80NP^>9*#FUgZJ~6Bg^IG@9#J5j55_G@v@<8m`Qvk-e&STd8>yM=JTp!DKeuJ?k|` z@YXiAT8ubF4^^<>gMfWwMWr6$sa>neYUj1x#s%h?z{k^_l1yD>D2TT1M0p8fH2tq| zr)$cKtxUKSzig?vH_5Y*@wSG7oI>eol-`I`_b@!nD%V-8YQV?i9Yu-wd2i!Vj`h@+cA@8;Pk zt;vO=d*y80%07(Af}mXeu0BJIgoBcD>&Vv5xrbX>1PsH`S0$FUH$lnn27uR*{4mp8 zpCHB${kjrTsD!HK}m3mgfQ-x2%aJxe!TJ=1! z#!&jxjT0^UY%YUw4$nm1bC~jaYbn6GlOJ!<=?E6M)2W&;RRrz6a3>ZTsZ;H5t-eHXJ7{dJjq48x`jr7%l}J_D#rr?^Jf6 zbl#Zja)m&9C$dgPlQkJ3{$@_wp2DdjiBoWP_!+VrsVCjJq}d7af_qmPnBYqnX>{rb zJ@kBlJp)|3cz~=osWRE8la4&?mrQnRp;*(QE zr~OmUT1(=GxuF|bJVV&-nDwxl)&M;7)dfF0ND%xsw)?vG>?1>PUM6+={+3hG821_^ zFNXb0@cf9{rSKbN!Qpo|5tST=;-P?k1kxrVoVj3Af>2p#>s0YaV!boCJ z)y%9gi~NKMKrzg6XAI0PSym#{#3Xf=A3HCdRo@;cEof`QgZy0Y4sTqh%Ed<@#3)6al#ytd|a z>HTp#f95A04QK|wJ5A6ntXC67qd*{<{@}Y-HORn$-l&Q0Tj|0z4Y;lRdNbF$kVl7@ z7OK^}J-3{X)=>WbvB#EK5X0N&{Df={XWa3~5U*3!xen4xfolumSLR=N&j97-I4=m< z$AJ=zjzU;A)1>aR7`_s*cI!<_U)EITHXdlM5z8n*rX+u`_m*?7PU{y~73O79Hn&vC zM6R?6;sf2u>%><=;E*zGoP%1YB<2+uVVJ;)dc|OHXLu2Oqd`Tg&Jtl7P*Bj<{Z+6YOTwR8^RY$jw15a#^YH}McPx`(RdC+fq4@33JLbuTRL_;}7d^zy ztlt_VG#BWRwE8hNQV2bB$XmH4p8=O1qqrea&atIe%wtbL_ey%@A~C-Xh-P=QX78Gh zh6|=92aQJ?k~AT9Pse0zHM!|?rFF2T{Gr!$_U%O)YZ#@v_ec7!K$cgX=t0IU#-1S_QQpq? z^}5bda_TzOO)~H@Q&>J}xbH9F4j7BB_7x0NA#)-vYd!85PlXpDJi8K`@_Z;4t;JTM z3L9Fq#T4}r8LHjl#ROiw7K{tihJLbqw|wnh{{B5Hwj3-_AI>h!fP;u8|BGloT?xL6 zjtbRxoWt@8eiFFHyB#vz!&|)L8S*M7Cj-}zProH}eyz#(_~fCo4X|IvQZuG+dWka6 z1ozq?S6+;~F3BaW_b0N?B|>U;;a;-|Uu9?P%G|1q910Wz&#u)Gwx9brq<&YFUhby| z;yKijl^`jGK{Wh5dcw_kvTE7&fEuc;_nx{gED9S5tpoY>*2~l!y*5e^hUTvfbUV7X znUzXt+lYzC%kC2!krfJ7I`kS-%Hqh8E=X`Efdu(nND#2&597)ACiBBM@)ZK%_fjg% z1v~wngXn%2*}6{*=Cg{+<55L;M!mo6&0Ows^3gLCfLq(Wkx70n?0SZh5IK0 zpQO*``oy^YKnB`rb=~*ajtnT<2{!tF)pFkEnnAvSD@@9Cbo+^uq7s2uMT8<3UDVy~ z+O&SJ{~I27L-H(QALuAhb8nb)S>Q&2ozWM6Pl?I-B%WGxGxKPa<$mPD^_eWBC~t~; z%w^jmI!rlp;I!|*oDM-rft))dxmb=*%Nou>kzYKNkx4a@R*5`{r05gh`^GlZIQg&P z+3fqC7~H=5gsJD(9ahjrA|seCY@$kknWL}4LBX$?5g>;>-)Bit0t?S+XgDVjKl|R> z{|Tj4h;eOTo>&NI>4RRZkl?{}#GH>Tgq;Ss@B5%KT@lD>^^V$4 z1$6@O-1d6JI@vgA%gXA1jAUfIVbje^3A9AvIDD1?!0=20(${t*nQ$G|(;OB=vK=NF2apt0}a@b9>O@Lm; zNeb`{7>fm6t;{a&9{k(;(oRM*Ji?}U9)JXQFNtn3xH9eLdC|a0%b2MW{6&H(B)4zK zsX{pf|93)X_IP@`_Y%?(=hs_MHJliq>0=@>FQ01#B=Q4?evlAHz0l**fpZt2`JWTxpDDL@6pcQ5A>cXnX@l)I3$Y z&fmn1Mvw_59~q3p5t2y!OfvYUDpKDlmZWGpH6nj&>8YXQII>6CdKB;suFYqfAfRN>@9pr*_;AmL8N z5PAIM*IzjF&7f`ZqKy4It4;U@j-$ESA#9y-qCOIOkx>lCB zK`&*}yNTkcd8fRB1`%H}@F-Bx7+C!VjXKfx?2u;Wb2Gcw>R2D&fIJbSc1f7T2 zKXK1{gY1iaS40un8G#R9I1(GKcRp3O5+o!bRK8cI7Y^B|w1{z?BTwf*;`fBF7OCJi z(w>0DXKz12j$0FY+@dK9R43#BWq;{_F$*i8DtVn?hE!3!IhaaPe2QMg@YpuK!6y*l z{snTP)3V{L4Vv?v7NXnSNa{bbEp<$*=1!!vugbsg zym&9CT>Ty<^|MP%`WnNr0cG|Dlw=@=@y~A-q|{t*Oj+j`!~e)N$5IcO zYwLOD_N_PZXXm_y+S{!`!UG^@Yh;rSVEahl^`q3#nA16JJ;WoDLe*7{65T z*To<5k;svvG>+}ASP-|=!xko@Z7|Dn?AS+(Gp|_iYYF6VWvM%w1-~_b8{e-&kp9RD z5a<4+XgnYtdp5-Jedws&6(|HONx{j4H9=h_@ECO|W$a4V1oKZiz>n&Yz6T` zXScQzOsN3_dCk3lkN5=?f4&#n0?>IyXF}if6;NYuwz=ml$XCAykkK zNSO+`?F8!_*ah*v$G3oktr^I`Ceysx>K~TA=f4~?C_SS^V;8N{;22{zBsp22%RO4# z#|r3eZ>_qr&}UFkxi_#>fN;TI)5Pm(j^d%^El-=$m?TMTD*smiNo;=UkO& z(`8}S0v%lDy^>5X3RXgK%Jvdon?3#J#%5hDqlKBSc=lmk z%#Ycb7!RvsmF~&L^n$rIInncgT@6O6) zGsD{b95^37Y4awea=Lei^v71&+pvz8`8pYsceOOB9nTw?$ z!Mb^-{XJ|GztjOdXy^Nh3H%QQ?g;Tg1K=;s-Y_id2*?m4DNl`8|CF$f+3Sn8Ya~tO zOD7IT|k5i#G)S33orl-$U^YZ-$YHOwe_G7`$-unk-r#lov0OOop8`cdM zqyDTJr(=nOTvTRbAKXI>`=uWd3c^E4;G`~>%iqz);;|xd_o}X$&uC(93L*1OY#;yn zC4_ZBd*Y~j*bxvwB`-*FnMh^TG`+bw7tgQ{y%ZBx=OfnNmB1(S>sL4C<~SPQ&bC_? zeIxYXBRwdtIGu_Z#x{Q`kLlj=ploUKdUu97{h=5CXUCx?ifXW90`Sr~&zH~F?AV-Z z;$6BakH|}Z``{MpV>LdgBvvZqnfBS?3iYupcK$kTcf0x|v&=bt~Z zHFMuEGrmYP6Y-pEcpeJA$znl4Uy*W;aqt8-)y_E4G&Im%5#3~#jObzUg{y_~@2I1x z|Co4F^D&ZyYo*mM(8!$yw271cdr$q4;gbt}ChrI4VjC#CQ|24$4YqUMIvZa>^|e*8 z6xwTiSr*KHR5u$&=qynwCmG6cI?ob(7t(MJX7nZ>m;=z4VZ-NFWU)<-4Gh}G3WC!DQXMwA-+H08APxtVVcT6lv6#V`ltUp+e1GjS zLFNjyfSBE+=ruN7M|t9HqFo7$K2?;)8w$k-3748P0E!C#f?!Y9KuCaEs0}8=JdVQS z$N!Vt=4=va6aCz@VOP&67eEqMtSM-bPru?AEwE6s39AHzTl-WqoGA1;oG(xx8 z&d--To57rd@umG2tTA7)Li%^GQ&xjX7-SK+m*lkv4`J%$rQi=F--1zbGU^k60HTbF zixB%p|A%(C&84vG?N><9I_}r#KQ~{+InFSAmwAb6HO#p$z`2+hvrne=iPPW?%NS#uoC^imXqwf&ihmGz(j|z3#Ej@(jAz#;bkskm z(E=38TjU6CN<ug=_2n>POQS=A%ZQvm!4t{rBOw&`SRL!=^4jDjWM^m$Lzw6RwFW zYyBt8_hvUifrL{;lbRP@JYrBDg&j8w&{!+PG3c&O|88X17Ia~#iA)MdZBB$HajaP1 zqozH=%Vg3VYDPBK-FtE$x{)k5m}LC2S7FUMp=tzqlRZds;qWc~GZP$Cw#4UpUcS92 z7v7}|{TR3WlXIY%ur)B5_szlVUUF!&G)s)A**%8ES*_?gZWTwyK9LLbAQO{EEcx}? zWK;57ZXT8O6@EG7o$ukxr@zBXVY&D{#+PbGJ5w+uRh5*}Uq=ePbP$XrFt`5+wTy%M zX~hUO32DVuI%~pIPHI)zn4A~Wp`y6mGtQv;DkpR*0cyibOC9d!qa~YUru#^|Ph&*o z4DyI$`>2?)kvH5L{eX)d-kxZ*0VQ*$0n;4Q})RH zAQjz)+054qtB=`WkLsAN_dUbY2tJD*CCrX>7pKpOj_7FyxyEG1{h|**N?=7sDK}CY z>9;OjVh~$%xYc({BOVe*xQnK_(U^i8>^DZS?c#?-cEYbHgKO_h@Ag3Y(OAm}(TV`^ zx!aozHmx)0+r~(2PN`qOZOMlq6vax$N|J#L;_aoqS4N>oUEqsapvJg%p)#8-1}=C- z{~gxj>BEBmp>NB|kBOX5F{!p95@1LMu-IifJMd%f+ZZY%7c~;kt^_2t27-}Wpu}~V zh7&Kr9#HA&xV4`I%H^M?x)dYc9=PYWR>w$qRYZL<1ooa!)}?gWy%Q{Y9HdPacM@Ea zvJf(Rsd6GzMyb$HZg-uA1~O}8okJ|@oQs^avWDU*+=`Fr1RO!?Q_<$SI{QIXA#XYM3#wZ5K{p z=r10d5};5x+dw16uvUFc8mfk)q7RFQ&TT4&7W%u;{12=IUpD#oZHFnOk=hf0Iyf=? z10FIvNiICl7M&u)kiwd(=)&2bRO(MPCY9IOF*FBll;QcKqr~qL-w04O1}_`e;>UT$ zpYCkDZjjhDwTS}%6_3RSop*m>(&-F)lLS2Yt#Z5tg89o=2jx#UfYN%Zw*vQWqk4IW zYiaP-NEGpmH~QWY1fg#I8d<7^bky;H!~~VzCQDQuSQa2g zJ1mGy7JJw}*F4pNe{toysI9Fx_DnNq2yUwbRCu@;W`f+w-z)k^NMsvX_%xov3q|j^ zcR#5mmL zu&ch$$NxOznbC$E#F}UhYU{lSghdP2M?JR&tRHvzI;b#hx|$PSc-XJ;pBmwXs)b3A zGUrlSD_4r9m)i#5^87{aX(Z>f2`B`Dk5MyEl!VBWFI_Hi8X|8d(>ysSvF{&|Oea zK77@YrlKB|Hbo~;~`Q;Oe17+9LV3ul=bj?6{aFZqFh~@ z&cK=h6NX8{+pu7EOI=_*WbE<4~Y52D-_aYq;)ds$7QclJR6$1p`IYE zk$sbe!Ci$1jFqQc3aB5T=s8b;RT&%B2G7URghRz6;6+=!$gYBMvD-vYr!uOWNQG|{ z)tBXzx5t3Bw0c($WkNP+AicJiwE*YEFBYboJCKE+3FYVw_Y5;)FZ?f|m;U6j63Rs~ ziBYpL*VzHn8kznOCPNWN(FGB!h8<}E_9XT56?bz^j)0h)(5SXxO2Lj;$m%+yIHu?5BXL?)N;Q3x zzTU*+gCG#5a_*f`IXWN)!)0lFp*5!K0D0XBhFIejlM1wt2{|%;Wv;M!@@2Pqumg3mM?H*BD)x=ZyTrxLvGvJ5$6t|{)Fl7S_LLOAkKANIi7&3C?e zjYv+}QIx+uMqL7WPZXJOUfPV8N|I!9ZwBfFHv>)H^!d^rr=!kmC6mi6H#HzZzsb+T zJxXHf*h*$idHMB)t3_Zg+>hXv@MHv?Gab*_02MK+GR|%Hh59Q!BqpeW2bUrHZnqF` zb-)dIaDNxTQ!y^8a2(6xpc1{vG4%Zif}bkZdtjM$47 zd|SX(Yltm3c)Sxv$KJC(j#v1mvVi$F_psp_)DNb+n{JoKN5o88ZC7mLl0K$EGe*f@ zD{sKP@f)vF#@H>Qrv3|imA@Rw+n!wmL+dIoCx63fGtftZ^4a-E^(WsIVytL8Q_5Cp z9p*T?vH$KE4@1(5?}8fPnZ*qN24&tZ3z8h*dOwv?p$dA`>$mxcZJzalYin_ctG>&& z8cn^re;|&J^#4*hC3LLEp+}mK*-JwG(?UW_^~z;`EG?P0e8k>ONVnlYL0Vf`Zl<_b zZ@h|dy1#RXa0ZkhHQ{<%aIU49+_+8|mq9gM$!tqm%9jEgz!UBDq&|&h?Bi!U zeP6Pru6bW(TiUp-L+a#xiGAN?~JK?Frtln?Kw~eQz}zwo%MYQ#>ArxE8>Px2t1jxaAKk zF7;YCyS98rA3et!e^VMwjh-@s2K;A>`TwI;`UeD+66mv7FUH75wQbyaHIxL9;Ira7 z27@Z`;_U#FUTSl(<|d8|`57|n)pt;s`5)KD=PxO}fAEE1z!tP(2nHD$Dx*2)#Y0g^ zlj(>_Ew~4XpGmK9hW6b=>_S$ws`v9awA6W~R%;As6}qcJ7;lG}np#f0QS2E=2BZl) zL9tf`c)K&$Fa>#fSvX`x_eijMfwL9O!SDymSp?4)l7#m2S+e0EmJEna4ARAZ%bcgB zZ&!!#fn08POGVDk#M*(gw)p574k;R})TQt}@aTQg01KorSC;ZZPo^u$ZMRm#{5n6D z(^DaS87}C>TgOrW|4}^$1JCwFl8=afqj(HCw%qeRtG=m!jM8l4_NT(uB}|vD-$At^frB$$hf)k(MD-VJI77 zFJ6tDdGnc^DjbKh5ABH>yP9fu^3507E3FBN8RN#Nrw%?YhF-`1jN+9jV<>@wY0?tO zSH8Ek!3<_^C)N>YH$}UQ#A6m(>i*xS!(OcrLcPw58$E)KMOEFM?)(B2FpWNmzb;fkQgMOEh3gPr4_l zRnmU7J9unq!IY`v^dh5B(S4_^gpvOTxS+dh<&_5pAcdN`mr8w~Ozhn#aIpMIb?)tp zcF;{Ko4Qb&_ruc$V(y->f?*N{s?^ads6(VJ_!3#lJXb*f^|rlAFvPiV^lj>Xpxb2} zBCt~zW4WPyMaeg)dEETbtKD4!b8q0O&`a`@R&NO!Ohj#KnMq;wfJF;@}8Uf#m1o5ea^Q zcIj#K-a-zTYEn)##!N#<@*oQle)JS6US%G|Ne3}^v$Kjm$sRD>GaS3Hco4E;pl=St z|2NbE5NjFK%`^^R3ISyvml^QGj8~aKJAx`f?I_IvgQ=Zk!w3$HKdV1`fZBEJ4F3rUrwX~Kz7P02tpqs=M|#^WCC2Vmjp z`co~dTKd^~-7cmEJRoomIDTu?jvJ#oM~1qwov{KwZgKJ4$nir-xkFq|^-h|v%8W#m zb|>mPpdqWZ@f84$ue1#ks1^01m``vvj=#Wc`vwr4MlT(U9q=s`&)_F$93qJQlkNin zNUfD5&Y>Q9&>;EwQEp3tof|Vopvc8he)eX_K$Gm^sSq|Js0kP3%in(=O+5S-wuO}E zNv-Au<4jE32QmrSn&n)e{f=?!^&2jW!s@t2!V^1pM@Iv0b7Yyk#_V4dPcCOdq%KA& zCmP~Jlzp~0JN}gP?&-lzmXLl=Df(}Nnm+F?bmwu~<2F4jP61D%pmhz37I%Z%iOI*PXKPP{&TpnzzPCf{WRh!$3mdkzFhUvbvM}mde=#U7 zKNc~t%Vz@yMzNMb?>X$hnKvjDN;GOk1W#oFC28Ejzk=T20g69D%Gk=4@q^*2->p3@8w)a?4u_K?JB>vZdlpJ2 z61dtbizR^ogOWb8&{f)8LkP(^&mX{A;G(w2c))m*1f02ZWdSK5#Rbs851R2%Wv?s@ zqJL&nJSKJziCy_FO^>60Kfg7<+uo*xeF=u`gKw}P%tt`Ms(K*QGDFAD>GEO1b07^33h)0&VM1$05MD8o$ zOxi^}y_N)@I3F)d2Z=Cp`QOyHS9%Nla5*SdT1~x$7NhghemXKa|a

}oYuhDs?$w~zjcPkXVmYb-p9nSY!>!`>dNPN=hxYJUKECh z0d0v^ex|l`BMWLj@&0z0hL;KKtYuAHP*0s*vu$=4i>pqZ+7 zoF>SDFFOwW>}0s^e#Dpd!^Xd-wkJFF)t_jtblE~XEifvO5CnMu*<_DK>(YcNhjRzF zG4D;Muc!DHzH%Dv!~{h1)fW`XCnJ!k;{!rH4ze|djep~#v#y}u^?#R(xp`%knawf$ zHAz2xvc-zR^_I4o-DM{|4IVb~I*(FcV!kDEW3K0!_X~H-<%>I6f}LAy?i;G41tSFg zO2%4Yx@+Byj7vB(c4x`Rd}RE7l*C)`0WIv8guK#ypR>Z7x`O{o>@b|)qGJ>YqLfA< zy3dEpJsm$TzK2w9sI8-`cdhKsr3&$MF!Q)#)mhOL3@FB$ zSu3Ca58oG$_wA?ILEsXR8?r~}d*kR|SdVl7n9u7A0y^@Ruq1dItqvMF`{|_Bh&%MT zo!iki`UXs6phckz@37Ov0phn1<8Oeaw&46vc&M<1Jn%1RGJi`!d6~I}5s&c)5(ui{ z!~+ZDB|;n=?g#AM4;UJ!N{ZsIW}|INzKM3evo=F(eFYxHtuL+yF9{?S%~{%7*Eb^G z50hs8;EB2Mc^JEN=M*6p$u+nBk5=?!H(vyDWEQGYT}A4V<9j76^$n$aTduH)D!*fh zH;O6$H$;cQI$QUza~BL31%YQkvurB-on8R3NG3S`Y)jP-HH*DiPzFMWo%m)n=X#Zp zrQ#FV$xorWHfO@pT}%W9e1;8^8Ik{Wt^%=A#AK&e@pWAl3Yc#f_Pepagc6qrQ2L7^ z^wqPADD>E_zf3AagQT$hs=!U~TKv!@sVBetAlqV;B(_&V=vndUfC{qJ7y3;--|rYm$49JprH7UWMs z(oorS0JUZNqc?gsL`V3ZQoF2ogvPiX$j{UXXo zTR-u7Z-ETU(XYozWtvBeisPpgxqr$a!Mzt-pWD(H!YD5dhTF|&jbstf8OV=@qCIiM zyxS|9CjN}J5mpnPU(4Uzm;3BkT3p9m(&rAkLI=o8Cl}O3pI{9n0=d0F^UtWrt5=V< ziK^)>FJ_WBiWq7R0d&(3c+SDD!0l}qWgBH^J8?&6^C&!Q<7*xIMsO9(fkSUO_;-(iRDc4)!8_d*?3g`TIqI3v6_r4zms`c177 zk%~)I=M2O$Iecd-c!y3T2~xYQWYdqMfsi8lctF3mv;PRIC?KMaPcgu(WU#_>Cs@e7 z79QJFe>)4#Ud5CkLuKM^RIzS&ubIc~hUn?4ORM(Qi^@AFLTcV9XUyl=6qDPz4S@f< zj6w>$kbvZshOal~!Eq&>NrIz;_?)6~*Pa)f&Ns_*pb=Ll&KN=vP>W%k625MPuRhG6 zm0kK+C_>C}J;pZ9P-fF|nKxli+R53hcvLAk&$}wZy`t?eZUYu`JMA&!VO3NdNUC@z zTVTk}3?1+VLEo=Rcrxk^-p}IOEYL8zebAXkZ>RtU8zMvd-6}m&Ucc^`%2nw9a+}_? zrQ7YN>ufNkR8m(0MspSS&;^9yd3m@e0DU@DZXTH_pOcO;d&!BWSqi7A7aq3jjX9BkV5WNwIAS>Ixl?5Dn367} zgN3Q0D>H#0xYS(c8+HbZihP_fG1N|bn!UoGk6YaT{Edr@*dgU@|EfU?u^&XD?{pUcz9lT&dUlav5vea~-{leyOW7+k&@nEM-rt+d23v7|5Y#*7!Fi zElB$+uB;CaQ~0}8sjKoDaWqAr<}kdHZ`YB{6kbAwq2u`S$`10l*`wp86$;=IUNf4t zqBQ{iChwCm+-XtkKE#I=JAr(;7PPI{tyRuLBLprsE^=4ZpzZ!ZHg>TNxpU-@$iy~< z7|8(2#6I55wgI%~5B^SRgpr(h6FUJDslCHmRH+*P${V;MB8^k1UBCSm=h6K$xz@tW z2{w|l?fnkp>iNg}VC{*6kMTK_h6xyyVwFfPw%Xc|dCOP+XVR3#h(Q)zu>XF=od7~W zy}u*WiJmWRuxIU~2>1dbo^`EGIWJlvmQseTD=d`e*j%Faj88F}G9+wrpN!|AoF)7c z<@~#2g+QU=@)hp&!97sP{>i9U+K zL86?t8@hT*a$kj`qS6%94#R;og|ih)q++`vW!AC%kuc+Ql866r6Q)s56O2>Fx-WzL z=qH}@fwMkyRbL=KVUS`iVs0K@o#NyydbGDUOQV*|>a5!}mGptTCnuCxExw)SV#45O z-ctxtmw-^C4pj5ukLq=*KR^_h=v8QrWNXs#k@jN$Q{(XE^ikW&f{rN3ca}w*-Nw{y z?&E{XD(SF@){HOATq#X#7%>kLoW(AbvDpZhhy4B`a7|PV9v>@>ltyar`CEum%R7dWdzxUw6ov*m?p~aBQPtJH?~%!{(;R?O!!PLeq`Mi59%@0$LYn*j=$PBB*`+CT<@F z`y~Z0jtLd-S>QG|ykrOD6CSqk ziyBq30yAb3{jn^LnMt~IMDBX;Fbx`_1oeet8vlnUl6DdT61{dq^A-nf;7!ocHD9C_ z21u&cq2~>pWr0{7botI=C378c9UxfqqjT1Ll$#fkm0Asdu6I2=_z^y;i%9}ga=dP^ z6RcBJcjqT2A4OxsD!!J$)wtu{SLQd-QH7OQ=tpv}h7xjjYwi z*C*-O)&5dcCe$T__EJ|JjfF*I93kAzHkGs=5}Knn6Nj7J739cYY=f@3GfSxug(#J+ zbMGZ?zN-^5>a)-=4V<$pHb_5&rqydppM_E&;`r#Ssf%-x-)a1~if?@QX^eEHumS-b zVeTfM+>5*j^ctti@~fSol#&pe^+?Nax|3z3Nuv32|6yO{^hLPnJP_G(W2|+w>?fq4 z&4yV&mSIP5%RlDg>nN7Eui>=E94{s?)y%pxc-+nG=72@yDZr;3-^xi>7ubK$+E~X! zEZp7xy5;afT|1ggyX|wb_7I|BqKP-VWmUAWrb8?c`J?Cul0`6SFr7RRlJl1NY7^O$ z#F~C?>W7RvuKNj>i(2Ar?bw%7XTjvM%_mux`scCY(`=M+>vVEkL@HbRGEu2PKMOVE z=)q%zIM&3LLvn>5Tus{XDT|EotSQW3)Cxtwww&kWc_DNf7C{rBVzIE5k5N$tMBFdg zl?k@MOc#q_tTN;m`WoOe941$@DF7OTAv7H@N1?q3n|#{ZaJ`yXTtdwxY2D~|9W3BV zU%)urL$wa6%ix2-xKW(w)ruZGT=r3LcKHU4*<~Ij>4-6O_(PRC)OjWn5{#_hR@(7c zg^f32ReXKst|akA!UwE{5uxADm!}L!FmVk5UiO9mKKasKegMgVti=2`3mS(ks7&~GauoK+_~08g^k0^#ah=l|$W z=QJsfNhS^wBtoyzjuOky7jGefwUf&Ddr{QYtAu!46bXG7eN91BVzyVKV|B zqeVO>%SVATd{OW4!_n>c1sC-_u!Q>DbUato@7|E7=3QihPi}8_1X^@dKz$<-3`31D z-h(vNqkh`YbsC9^SgQ`Dm?yqGx-NA56i0aLWA<%hnv>WK;UNR<3bTaPC#oh1bE{Ya z+ZS^1;PU7=k~xMb3z%Qi2$a6ynYIFdJ)?jii`V(B7AXI|B4qSc#iO+7ZcmF!((`E= z<%x1f8tO@tTE5?5BcjaY!6i$F39UQz+^F`~`P!KP1})-DmaC#g^MM?nN} zP$tw9ZG>a)7LFRQe5!#TXf~@X&a%00wa=KGVTMc}YF(c*`YVxG)5&j(nvBz)wSXms zx6VSPKRN2{hM@8xE^syGiPmTpUWRAJCjR`+l_-D(4_OugA~Z>FSAl2*H)dS9=&Lri zUc>!W{BcK9d|iYG>c4{F-Ce1S^{Df96b3Jnf@vxyjt@M9`AxFu(uQ|Bg%mgSAgLN| zqP5J)MMT3c8P~1X#tDPa?(0*LLl4x1xidQHiilaD^BG$(qy1rekD%yyD|m9z^Ig)$ ze~FW5-BG8T@I6x#um483X8(FQN{H$&p-Kc<7GCM>2-*F~pvZb6oyK;A zYo~Xol3&=ALbc{wr^0;Z_%Q+^1U_FjEa?V4gUn3*TMY)zV_X}kgiTT4Ec(-{4W7$c z!Lri08saj3)g*RJw9kH57av6JctD=nw$zNaK^UO!&w1_R0opP#)$&I}Kl$`-Mi8e&zZvQj;Xp~P!rJB_=Z zmy3frtP1yswR)E+F^o%n>hG4&cQWIruXEyI9r~go2IksRSk732HUdeJiE?!4RBMI#wvS>oOo2T9GK1B*fasiHQ1ADe#48ayf)Tnmb(S(|-8) z+WYEL-A%P9V@0_Z0#dkgN=b7mSUY1~6^_&}gB%sKGYPsB!d5Zj=ee8Pv$A~vzMw8! zmr+~PMtX`r`JhC8z+#f(GxDy5zdfWX=n=0VOc$t8V-G~F=o5Y4msrwRvm~OovV-`g zQ#t*W{LMY9V5~=t(xP&fi#A=J%31yfJECBqhX=@^8cc?9Kydg9czDjj1QMKH}+?0DezsV z6^*-@X*|Fm6_!bM)M%HF8u3qzrk-O?3E`F!(4!uk3DIF|UN! z_<(R7aXLS(zWH*o*J2(9(BJcB`U*tDF_|19mN;2QZ3RyQBz4KRR`DEUrbIk^!snjM zZK-V3Daau0Q;5&dJNOOTXP#knE)7aO8Ai8VJ2~y&Bp_riA9k>5>Oey@H1iGI;|ew6;SCPOZH( zXPCihKbn^OpBro=J+!5vFHL!pEt~QAsSGeA5d$|QM#lek^bj3-*cjy+p~jZa5zZiz}L?w;o#ajPEwCJDN3Dl9jUC3|tk;DofcPwD z<_WsC>ne)%BKJ11Yo)iXt(vr4pBD+bE1H>uDI;z0D62Vcf%@94Mlg`dFyrqQwT-0E z2_h2uO(Z~1ofLhEqL;`}W;fNn+AYZtLqvPr5Cng&;_l{*8Z_&U7gR}G+-n!DPM2f$ z8A&ACcwKX%7!TLXCGO9|k)q8XPue_zRMoiFe|)YuNX0K9gVz?QiuuA zZK!Tq%y{e+l7Fu6ysFJ==vVdv=>lT0E?ew++9b;<_ zSx>{Nu1WO@^alfTvcxOnwEHfPiMfA;h(jKv9qyu^@^{8;=R`^!$>*`QkApa|U zD;C-8FewSHROj1O?Ku!z>PY#tUWkjd9{MR}0Yhr|uYX~Qjx;los)zh#B8pPZ;R=eo zaehWJ3=6#wx_29?eLb4D=Toc+V@~dQ6zz)>U*Y(Bu}9pQX5XUdBKVnWAi9MRj@jB1 z0bg8`t6Q`!CIgtiHgNrA7`Z;sPzI_&!TxZ#bLJrG)` zOAfGl_elkl3Op5j8BjdUW~cC%v{FWn4IbD{3n5dw{LEE? z!b4u_VgKtQK>wL5NT1_F1^Wr}P7A`!VVle+V0fH4#8Z%-8?4Buc?5P@UH?(#9`Ve% zvjG*ro{;C{MVqMzquVciLskc#NRXO}O!l{<=tyrltMXZBZ?y$8d+8yPZZ>J8ka}U(kor&qb%K^csj@JELK}8~%m2>U84fkP}Lk~pyj6jzac{4IlTX**OhemS^285AR-map-np7rzRK1vszY z0%1x9(27}12`oj~$7lSX9^jF!-^r|7M07>YB341bFfMXZPPyZF5l;&<7iM@>fo`xt zNy}0iaLYuqoVEo^qPppZ5MP7+Ggvo-9B~Hrpla=zX_$jAB6FvGS)m|HpkRY~8SFx6 z?l#?!lc{Akpu$vK4CbN{H$sRS7<~ev$-+v~0EAsXuntn&{IQ<%9W*>@+WE#{*u=sh zGXWoFRU;7i+{BJKjf7DLcLMZ;TKiwpcP^a*(L|_r1WeglS8)Ul+Ky*>FdUmj{%y;r zzi?XbKV6~1>GlGr5YarcsMIg>QO&B{=BA}z41V4AYK4kbJXj*kj(J|^k(PbxLNJ`k zsyNnsb(^Zdvqj2cCxZH54|y%MooXRW{2vMM=<>tU=xS*vqMItmji9 z(f|mNI!s)4hm(z&I8F#2aMBv9Cg-T&WE4fa21R7f2V;UjxD|ST6Ee{y#N%|2daJz< z*7zQMx8mixN>>~~FGh&&p6B-i{W@bUBdy#gjBdEA#CDEu&bTPSq8>1Aodhpv^r~%m zP3Z;Z|NLG_ah`_w>yxEq8I2$NJ7XLjf=?L!;V8+EW&Dk~+r(d!$z=4gG>F2@S7DHf z2bA0a-}H5{_4<`qWf4L);3pT8)VvoBrcg$XVl+Uz|5RYf0k}-ZqnFBq0;6Ba?b$ZI zxlI>hI8sv~GQm*dp*zKcsQcK|U&7Bh1clVGw7t&iTRCO}XyYyCI-Ns@9J@a|$M9yy{h+&%vN7dIv z-GdC{?=N+O#QE1VcCz?cp;ee!kQLD<4}#}PaHanTYV9qT_7OyC6m2db;C8Q+swIKM z;RtD#rP7M>?oGURo{@MfTOWP98z+i>bwYCgPKjAbybhk?T><%u>a|O0xXz2|W7IR_ zT6?&C`_y!4o@PGEMU1RHxg1*Hmg{aR2O;sMyS4uU(zmXO)0`5fP9WNtMI_4M`Y_~x#s5T<`Svr2 zB>oWI9qRD1j^}Ucq*U!aF3yP-%e~WvHZ6FzEw3aF=d>ayvbDJ|i}J<@QM|Rvr=fNQ z@fioY1_k+ct7rCz!eCZ3t3#0RAQUmVct+zBIF49-TzbkQEIR5MLqv^#uOHV=bExix zn>~Ow78RaT;i8GF&h);lxlqGw-vK+q=k)iq*g_^dSA7l(^iebGP&r5!IA!lDhTVhd=RU9Ve>xAbm{C?W*9 z=3_|vg{=Q$TQ%6lbtwUrN=|+!d@^3)*$EnJb}yY5T8IK2nxm*ZtbzNaCKYT0jlvhdaX`Rcx|OJ2h`-Q8ofY47ebAG$bcfCdFkCqcT^TaNh$HDl;?`jIf*%S} zZgj*q3yFo^Ye;#VzLrOLb(C3OJu`(8r%59zqWFQ<$(CVu+EIo#qDgMK_UfyXLWlZsH->tEA7dN zVS!f+NZCm5YdCxsuZAWQB@H)1zVAf)a&@1ld?>3F&yW%HWi3C@(Nfm)L$q=rE!}LF0Gme=u!?tvfzk_LY{la4WrL z^FXjIw3>klWIQ56J>O)*8@YFT;jR$v&U<_fU;b`S2c0lbQxdq1X7fVSN0rKvp37Jb zo6EwG@lIvj`z!&qFH{*5)YH~`;o&;84tFbi(Z^UHM>C{QT%@a6?N?wcVk&^GYaRz~ z8cieOyAA>Z&!p6(dJuY?@;G~&nYqqzk71)Ep7gP>+EGZs-@W>(12W(WlF(qcd=i$NZ-NBOwtxIvlbDAnq{q1bQwj$ISlj6wYD|(igDe6WD9}U&W+m z@GoYKs}k`N=^aY; z&5u#=84vai=R<59k6a}-Md+*S{jNYH3XX4Rtkz_W&?mhJ#Q%LUY=5v&Ur>x{=9o+mvUep%2uhb*uBuN(#Q&n<{{~G_4{B@)Oi);EUPR zZg=Uy2FAlr|r9yw&f|DgyQ3}$;1a@jgQq%oO<_?_m z<&BOk!N}o$EWHF=CdiPo7Qix|99WxtD;;P<7#OCdDe`(0m8Z(`%?Iu0t}E~FfYmD2 z@e?jh1MOJGbx=mYP7qw+LGF_$LA7>%U7u2s5E%`-OkVYr0#5I}SEi;{%_C>9`g>6V zZh0VsrY-a)b0XzJ%sv>EKxgxL(msp#$YyRG(K`!5(Fvm5E*?_^8eIqdx@K34c!AZ9e2;S^ zwI>XANoS_beX@u~8w^E6-sVhQ&PLGbdVN92F%Ard<@LYq>tKE@hMG-s5uOuqv6sfG9 zMsZ_MuMtn+E}73{Ad{uxmt5=PpYNY2NyR!D@=odkfjlquecn|p@-h$W_!8iEW-C=L z22eo@5EPfYt2uk;Inb$inuN-Wx=I?arhe6jh8|}J2crRUUST%PkD^kk8j|>v^e>+H zOEi6Rrd%*~lqD3wOJ$bbSi9?GP+SdnZ8B=V9AHi%JGW&4H!skWa@^%EiHV->W5rO2u$v5oekb320d)XR0-{Wc{=2yYLIrM6LZzs_p@wzFmWC} z7{KGIj4EH7<*@YN#8KdUBHv(R{Hk@7j+AnR$KSk!MUV|_7jFvMi>Y6|Nq0gfErzx+ z120=h8)sNpVhprand!jFLHO!AA) zWjbRRbL=~DRArYXlp8@b~*KZ=r9m`rh*3EfM~GW2s4L+CfU zUx;&*fr0)wt9{_p5Yl&fph5D5q~=kPq?r89u$i-ZZl_MzAc4u zqf}7G>|EkKF|&KP0Y*udtJeE=#j|t!sT$-5>1`G)f=FKN@%JgMNOJ7T~+G1)PyG6+VtK9kh&Y@{Hz zVwHYz!y!%xv1W7cf=D{u2|BgD3qe>94{qzf{n)smBB-j1K5i=C8KQyugB}3ZrZp~2 z-q-|@hz7|Z5mNjLoQD?Z0RIh%aGCCL1JGS#tIwF^MebS+W*-f=yUyHLsfL;2_cfJa zr~H|aKg z@O^8kk;KBwA>l&f{8gHS9#AZJFTmT*!o*Qagg5PnNi6LagOot3 zMcG^D4p6_XaJ;8(UB_K;dM?juSY^Mo#^+p8?1oVQD@`(c-J=43Ny)?xn4*{sfs_jK zal+5NHgHq`ng?wG#R4-{%@GK(LPaU$#fZA=ZXuUNguU`72|$@D*ttaYCn*xNFPl~W zUg+HKzqKc+y#(F4z8wYI-PP3zGoFh;G%~04vGyrZN@AIR!039b%$URrYINr>RixEh zt8XEV&Q=>ZO&b+C$cX!^G!R>%n!wtc$sR#B0;lW4vPo5Og3CMHZGQpDzY{_Q#0`K3 zQN0OKQwrLAbrl$H@GD;B$jzQN<3lh(jt#7iR0UUE&<@tK3ncEaCX!`(r-3_!`n$Q` z3;bb4ymfT@LX`h~aP~-dY3@yey_y1&b|Q!fhPC2zIh+CzA z>HFmU1YU-Y!89jU@cMuj0ohl+ZIIzrx3%xh%%$sEc=q`KVlv7;#Chddo zXi7j8Qx1N&V3LtB-h=v3L(l_k5nq&@D4o(};6@Sxy#Xt0{}*ncVT!k9bhX};8OXNN zxW#uj`F~BJp1764Y^gaJE*}&;0!LX6M>d6-K=2Rv{EKk7fckz(?*P|)$MdwIE8}y* z^F_f?1;`^&D5KonheHq!^bN8C@2jg9*{;9+W7PbzY ziubuwPJ$%|2D@Du)_l%i`Lq)Adn9WDQ1db)GG$B_Gr-M#Able`({S{<$8Nv9H8$p_ zHq{XshFW{a28*6<{dhN;T8u^lsftb{UwYf@oY~)fdx((INu$iFDrV`SBz}WnS)9caxfvl0M{bM&W41v)PEIxF6xQh@kn;+~>-P|!c*g`n10^Qo*HJg3) zfizd6jdJrji1cttG3C<5UL@35u$`74d2z?S9|{8+iMpbEC$xQM#9&BI>;^3?xh&vC z=fqx8BTypdQS;91!sKX#;0x0vX+Oae2M6FS?hmlmM)HWIO6iGT$K%7E-Td-(9Q{Pf z;@|eNS6@l`SQ(go7d~(6R0^}vlNx6UnlJ6WgfeMj0*z$MN^e1k-)^wSWh z(7Bwvw^%`vE|O+7NFOb#4rlCM61}MHHu;hFB9a$%Jh>qRMeH0}Pr!{&&Zy%gl7avI z&owANL6ll^>l7Ox0%wlWUYA&M4ub90zq|x%k)(r5Wh9}0w`{f(u@&wdiVQ`)&<>%)I5#9$JU)?6xGL{pIse6}=|G9L6#gXQ}m13Un z*dks`eK^W%+qbJHRMzy^i99cYnf+t$Ug86D=?H#9N#wd_c>I)i&P!6?GC&@_C%{ke zH^HYwhRqd%dIJ~_HNwbkGBtOT6qvtb!d4Nd+^@4AKZ2okbHO1qxh@_(oa6)9kuuON z78Enh%=}QBrIP!9urT2Zg(cncsOYt!ZJBWSkQ+T+mWUMClJz@DNWlMXWG=a#ENn^U zhDX?g_Y@8s7@5D(@=qco_x8SByXNbQn%)>;R}7ebh(#(Ino^xQE+X>StA<{ zI?lE2K=Nd-3V&RnhJJeVlM^QuVs}MM#2b~1N|#fH;jrgA zVQ*w@AbLyTEUX)jVr9|hXb&~zKHFBe7x6CET~V{*LBPAmAb8+ zPXH|t_#oI|w>wn?25-C(+3wkKHZQD2Vh|+87eCxfZqX?_NPLz%H4wtvML7yJkpN61 zR6N>P*&J-)A@bCD_YVDZ5pr&k#CROg@6}S~lI7yAKr7esjVA&AU4M)~J2pSBU*Mv` z@qqr(Z#fZIkY2b!tcr?f8Awr3*;3O%FDI_nt-%JFIgOp&V9|p8d>2PGAize| zwoJGQH%F*2pq*8U-3NWV(S(svJTfGkLx|oNxqE@H`Qvzs!&L$a@2BER#gRvOW60`G)=|D>;&Pn zcPsxQsxNt!0=Nuc5y2f7C`x3c9DWgZ=vRXD7^G#O3M2b_=2S4}x6GZk8AEPV?lb$T zerCI>@;QS5vjCv(Gt=<9UA*NjQ?tb-*n`9s#=oH_7+1r9#STBM!*?H=63&P6^h3>2 zRUzf?AMh|_e~NU+T7z+k2kDea?LgLIYY1=DtW%MgvL;(Alr=+Uv6qIaU{4B!+{1A zXgeptR|8s1NADjIx=LFzSA>;uXR9*yroXVWcQ1;7JnRqgJK#TD{LOK+ouLRGeL&z{ zy=P-p-uG)|h6eTisya}*sc;_FKcCWvd2yOnt}YnH4q=~+r*+F(;)^315LVWUO%8C) ziyFYDYAA*G2bE$&O&i~>BBb+T;R^N}$&NtrXRq&JwJHcjWt*f?2=b!xEKVlID*l6} z(e&2O@$XS!Vr~3Exi;>P8lyhdOPRskG;b?+U~HhNUj5<6Pt@*X=4upE{6*~r>eonD z%V*85w0TH+W=^xLHF6cgg~=%CuT?R{xs|v~?$-f)8+hG}ZCSDS^j)ya3oZmJsG_jE zi7JIA46>4+{q{>e6v}B!WWC~DpDD0U72DB@ZD!TEp%gwtv$s+NXn++gKJ%O99@oC! zO06!yOmY5wHiS7iVKCeuP^R?^J)7meC_Km_2BQdJ9$R}pRJ?r&#>j?Uy`GvNp6JBk z$LOL`*C_qL7{i4>q&;$x<9q>$YZsAMtL`%Et$1nWaUm2TE7x7DYBYZv=J*t7ccEs< z!hJ|GI54mXB%F14X-^JF>!A#Hxu%`4;xOZhf^f+#=?!yA_z1VvExTYKvgz<<+sZj& z2o;tdnoL#1?n%;V6VxXio!<(2I$oZ$1bA6Yy0>uZqLX{|~pK-`-oEk#tpiO+$qYIp%x3*K<_#8fvZRy&l*yz3w|NR%lv=>1@7hBDr(vl zb2E!n+w(AVbx^&pdIo$V$+m4(YnjbBAzq~p;C7CG5pl1m^Ouq3LU7i9He%Z;Y^J-Myl=cy_E<#0mPLQRpXbVpdO8%%VK*#QiguKE}`)9 zBP4okv-j9=-h=IHUzf|d0SwFgfUB$T$sfz&J zU3b{@3+J2CBXc`$trQF=g3%;Qvwfh@EtO)D$IS9vy{TWnVL;fY-4Eba2X%a*{HWFl z6bkd<#%MT$MWt2ND=}?3+%uX?%9z9^7=}YB9)a~R6NxDMAkeCTVS8`UBTN%Kt9-3mtsf6iyu@*KNtM*3hj@BR)Nf_ec~~m}pZ#GELk-l#@Epoh^{04CyTttC zrgu;H*gC6^cSY)srSkuZUdIgfUh2)iVgr0dVEb5{%;rYFcRKnv!>&{wa{O!(0zzCS zf+ofF%TCb5M!5dTj?66%a+&oHD7ws1AwSFr3#9xh0xwi;(E9rbVN?SwT2g$|$Gl@i z2x4=g1nPs2-~*x!r%%6ge1S>@er>n?hE z7W0r3QtBs9?ZSE8KKchhdHfb|YcG%?C3#YN!TTuGI&bViLDt|0DS1c=j!2vmD`fv_ zUY&!5a0OjQqKxt$z;0AxvS+-^VPm1Lu-92vId>*(l_omm7I2{+=vH|A+#q{?zd4M? z=KMm?rq_V`pC-}y9)KQDF@i7yldN&#pq3oIbuaayH9NHO_W$#-rcKH`@hdJRXfW}* zYYG-xxZjOK&AzE7-moUiNT4;P^>9Et%J3Jm3ysNYhsX4tX;Fo2wb2C_0RBxD^|{(! z&|v*z#`7Xtq)I_UAM}RA>jWpaxuNTT8@7;W)jv|?4b?~*-O9MdrCfOPq%gSsjqq0Q z&d+@Ka65T)CvHRKo`?S`$e+DOg39#^$VDD!fpml}5l2jCk`#xK%-FF26(I44G1 zgu2t)b>ABk%M%|BAof7&xoVvpotoKnI7E>|xvtbIG+2en7_xeE(9j3dYGEf6P}YoN zlfAp3U9nxgt=v_#{Emok;8HD;iZ{?6f&H?0PFTSWu@Hgz;7y`^rR6oF=-J)MEP$J3 zV!!=QVx=3XIY039eTKM?SQ<9M4j=y{hPa-u=8Kmyg#WXnq%7p4Cl5;)OAPvlhl01nM17zTQHP?g#?zTh`_t@(19sNNL8a@Jmg zr5VHyu(YMZw4joN7wa-Nx2XKB6?O>63bVU30}Z8QL|q)00=4%WkE@YI*wi&}MkJun zpeVznY?Z-_Ow;5mbWq$@t{&7?Od4KP?xQWea}wRI7NmVF6sS)PAq323veQ?(TWPS+ z5>K78N0myf2rJpirw5cMISwik9fYEXoOZGpl(fp0%2GD7Kra-CZ z`1%fFNGwbXHobRKMLe&7i3;qF?XuiUZTd`Z|MQjUK(aPoTPEF*jzvr-W?|}m1pTj# zX7FJCLeq*g<*+C7CPDgehf7r50Wzu9O9ryP=aXA$`OQf z*YKpAWH>97y0=Z+l+fiwf!;dedQ_AU`+=A|!=vN1MfWYFYZQa|bYKah84(K}2+_<1 zI6OqQ9>blL!+=v^B;hJ}hSD7#k8iO7oYr;qTzsU6IbZlVVkL&@X>;6;GIG2Fq^BRW868ybT?s}a1tC^ zY9=yN(_fiuSCpL=TT|`Q2;fx8JhH`PN<t!MCu)V~+lS)b)`EfO98wUn)o3bL)wOMy z8Ovx>FTZqB^3=2)|C;~O^nVdE^7k_?=c2F6!H7kf(-z#O4SV%>A*$}_4xXiYxRw9L z{R-%*L$Yob72oCIj}~E)_K{xx22i!v;5tW6b<+r{=VH{pBHWRWP>s#B`o~@AbKeqe zKb~2ws*WnM%fCt*85G#wPP$D5+*)ZZ&C*l+pKkIhd5M6EcgH3~ zYk^d>W{1TmymoVT*^34??MGklEsN+NANQFqXob#m2mbN79nVrFHT|E+@oGcb?^3L{ zl{{V1#uengueg%g%)5rbX~a>p=9Wvg$CVTXHGg>WN8Jjq`d}uZX}otu1ash_xoR+F zgF_{NAyU!5zY7zB;DwXVzZKdKZ5-U#KknenE**t)<4Ps+PdRn=tasfTP^n@Z&v zn6YLzXJkwi1C3l^-*@8R(`0Px`90`zRv|yWR^Fe02WB0;DM+s7pHmj`?L*v=6Nye6u}kBr3M8X9FOv9|f--(4uye9%3WIdm+Jk zp%m-CSh;E`y$2KOdbJV^qZT$G)n9lV*w zZG86JMJ~`F&sz6?w>m z)=-#zcdGRZRjrqJzmc;cq%JL zge&^ov8cq`#7VDC0A#2`wq-_;S3aF6&J&ykl3FOhRv7=xJbUzp-3h^qCHg=={Bv*I zf*G>@ITPZv(U|MX$Ll??2M$dpCq>m8O~v=(zUGw)Av_Lup%uTi(Bd?56w@a2C{I4> zP&)_E$Hz`tL!Z)6?jQm^#vsH8O2ytdzR$RZU7C(~$NLr*Rv2cVg z@p#U&-Oi;6J@1NcNJ%cJX_2@~2sA6Hh#nCi-S>&{x+d-`6XT!R_Oko3AT$}X^+|?Y z@p=JbLv2Sj_~EQGuzTgsj`up^8p_GUwz4s8=kIuAX2~M#0O}scpVtFfMd1Swf+2z}w#(PpB5$L40`>vRE z8`E^74u;>v<ewE;rAy-rR-B&c1p6w_W0Yb7Kr3{HUItN> z(Mj4N_LYZF=_FY0&npBer%*=P{$p8Gj4=Uuu3z9ySBNOf=E?^Wy3Sede84_iyEVR& zk38Ebz^RQe4v#G!3PIy4F!Lmf-Z@`6@M3iT%&G8oir(7X;J<$wQfk4l5jp4*_}v2N-B`Z~l3rStUR)-^ zui#H6OC=6E%vx|^35S!#ooGm3bO6ROp?zS0>GA>NCT$h2NL!BD4GS7W@doi2dz+au zAIbnsNb{N4+CvRf$ivrud}4T5KnfW+Fyq@P5e;?mu{89uHqUV$@s_4y7Exx~&>F+oKnNS+6R;dn}vfrmDjR z0o-|nTyZO|R9S3L9)tv^gR z;fRS__D9wouq6J$0G8ri-8Ojh!W1^fbW2Wn26xB%fk!hZDj;*YDbDWy~Q9K+n!AN`s|(2(?H`{`?7 zLSPi{7qdrnMql_ex`Rd67!WzDdD^hWC0?<5pDm(jdUrc(JoU5;n%16LCh6Zck6*yj z-6z@tb?c)!ycplmnu0*9mzxZOH1>ywXqCTWq$RDkv^`nQWr_gO`TB)&A zcNuA-7IaZ@aV$3NP6upXPm;$`WZhXA^@Hn2D3nfLH@EKBQ}joHJ2s0F(S6-432^|P zKaE(PzFhn%+c~MKGk2F%_0D)hG?;+l{H@eOP*}S!Qh(S!#0l~2Qb3=$s(PZqT%!z{ zqs3jB^>tL#jNxdArWK&bvHz&(E@f}qj>Ne<2C|*P6yq|?|0qu7h$ykgEvRVlAERA4G4)Ve*K-@(hkJq~?XdU%{Tsl~#BLDfg_2Eo^kbtyJUbHpHa#ch#Rx za;B4ml5&3;>iRk0*U|R1F8DTpn11gHL`|dxIm>}n$3<}X#4)ML{e~qrxawZ_;!i+U>yN|kBWN${%556)zs?U!F@5iV%-*m=qXCc>Qxr6+hxTnB`N(#f*aFA#J&wJg< zEw0{g;V#?K8Ee<_(eu`ZPK;!PG~G$d)7%_)P6E`ePwD0%J4Fcp!H<%YtuMMV=ef#~zeYqGdunnn@P>R57CEUIt}KBzQkZ zQkKTTq>kQD3Ip{P62Z922fw#6lOw`v?A)B`04Q0=uXxfL!rCUTs+$%QpV>-%4S z9D_+i@L#LP;@PA!o7tXk$r`d*1nrRb9NI3>Rpn@0lIT!|Q~!v$b>jN07gK$zuIPaeTCa;>ENtqK6*@LUrH0^h2@FUlkNGp z3j))@#uCnu3G|~NWT{)h2DHt%AWmsDcRxtf1#G$UkY@#&uSfKYLg(B5Ha75ka}VF3 zaIojVL^tixtXH>xkfu6S(3vB#Wzx-Q<^#%2v_A%5Tl9T8P_3tcX26AA`zT!eab*AC z+G&Mu+tW7Q&z4@8C>(sTjawFHn^lbrZa zG1t}cAJ21DG8 zRXBCW24RXivuKMaG)hOTdUm38D1HUuGt`dNBtz%Xj*2+D%LcOE&jY7y%G4#C;%3VY zt@RORjhGftDP>DFZ{oyF)J_`>h>$F}Gwa*e+{iAdBBM^tD#!9?Q=j9bH1Y-6b?ll? z(e1jVAOMA9d**hjtxnxnIdj4Nd)~lTJ4@;$_J68$@Fs101#ur^ug5R2Xr)wX`RT~Z z6)-YYH@^6n0mp2Ah1Mi-Vi(dDQcnIVc?t4Mi&4;i6w0}N%YR_*Yk z3v}@@>#SY1Rsk5$AGu9(E7Sh2f%WHt;-4YTY5E#Rta<(qVPlMX__gKH!_ z#>X?*2T_@HqwcQUlk!iPA`nUrBK6?P_n8xMV*p2X`B%qiu8IZ%mE%^QsXNiMy@6`Y zFFkmWJF+&Jv*~ZkFPPvzx*D`}r9235bU+Bisd-~fn}M^xi0NQA#YqhXy&*YaOwPsX z<6g`5Uh=?GI{=Dg!1S%CxsN|KqQh(wX=X-vCSl_130| zNZG|SxS_y2RHDLrbtEq&4-fV^pIa9lj;;DdKqA+ot9avUB{B++DZwJbg<%JUP^R>f z%Nx3eO(wqp{2cVEQH*a@AT@$Rx0pIPi$0$HET6V^)xUacnbeRHb&ihxegq%Sby{ZT&}H*a7>J9xe z3EkH3S3B?ZGrPQH1)tYfojhQmWY)WY&h@iR(LHDJu2v#FoKQT?iH?JVh9bq4C-IXS zt$&uUKk=_gR3Gw`MIAq-UV5KW36sA$OEB z)<^F;nP`?;cgmq+;uJxZ$a2&r&GzvkmSrRtC0bXAFa20`5X1cEG}?h)17}=mT+=6J z+Q;ZeQ#)_ zg?t)t7zvo+)}kCm;EtkB6aVw@6MxZ&mK|yK?RJUb`;S7Jj_2gikwOA`vljd%E(+$t zVgMX2hY?v3CN?=OUreqoBZ2|>I5`fY>>{+oxR~iZyp*beO)CqS;hi@Ur@Z)`6A`BL zy}M+-IXtQ)+mFO54XK4}CxaY_C59+CQPDx%ccQy(@|R8mtKSA;+hNC10f~X4G)-eg z@jzL_jfj0$&7U|)Zm(@t0n3A{f1n6cm!6O3oXMJ=^WCE*c_~|4(Xd%L2I$NAn6h*Q zdXTROa#DN!+c>WM8O#90@xRf{VPobg2G@Z4M+(r)jJc#JsvcSy<0|ePn&z=dVT+9E zr>D88k|8`N5gmnl>isKpa=X>`<$T4~Z^}B#T@WAg?5*&aI`l>8wE?TxPtCxx76h(= z9p``h@_*dYdl8lQnelbi)s!|gz3BhOBQg<^H51sBaCJ5o3hOXeNLx*qKE|a%{$~Fq zx}f$%=Ha=JHYgAjwwDPDu%C+C^pV)^#B9o0Y9Egnb|kDAJPyowH|B2uaR+xkt<0dHbkrH+wX4ONLd=mJ~^xWpE-S5Thzob-Ar3m>9WvU6f@^vL}~wK}7M~ ztf@ozo`g;UW>(7%aKx!hjw9AWM-D*#F&}UKu;C%zT09SdnlFW@LYvjlq~~D&57ZM9 zwVoG4d#srp0Q~stq&}>a&{nbBvIKrjo%CZ{2m(0>+-_(Df9T{t{5_5`S2f#kVnFtG zwG+)#p;g?LI4Qp7*EctfPXxfCqJ#{JQvi>54+L#PW%~xT^JI4)z`8px{2e8FKD2+S zm`*PSVB`o})-(RJxx*3lR`7nuO18-N30f_I?`^cslcaZH6>JyMTY7F1ypMiJzoNWF z|Nm)%P6u$+f0gEhVECN^foB$`8lPg6&EpX$8UqtKVH-kD=-Hgez6aVH=%Wc0o7WS;dQ)mOeaX> zmI-73GzsNiwyTWK2R_~z6!>5c=$W8$W7p#G6QXu& zPE*N~vgwAA6EvNw3iaO@*l^z<9pf;t<&st+yyAuqWjiv>T*SI zh0(T=QWJL*Zb=}`muP|PBSreLGaoiCkBj##@Gq^HOvsgnAMCT1*aNdeh2G}=qY!M^S-~eQ2Wqik-Uf?13jH9 z?>Za}wA%C zzzfygpmz)}w$GVd@?dP!n*5eI%1&rfdFOg@vpv*GT+Vqa^vXJefu8`;`!oNN4V=|z zyYgX8jbbQPTz~2GME!$D@Rp(y20g(gEoqWY>d=J@$_dx|p6ij4U^-8HkRH5Hc&sZ%*@L%eL-riRRk zac=4NfsbB?AVVu7O=^YaAS&z~<9H|+t5ATRF|N)U#NVFl&bhEXKv4N5bce%zPH`)L z`kfi;pYvkei-Lu1qL}8?h|h@5tuKD5gOdbr-mRpQi{Y`m@80?Pi>Me340e0cA^X@v z4QG1MWu`21@#wIi(ME+LDN+UzCinjyA6%Du4-3=4S&`SX2^x;Zrm?#Tn;9_v#yG6+ zc@98F*W0qWQ$+h-vTZMXNAI*(XFFb=!z8-$k4;ZgnS$<4p!JSdZyI)sC>VC|gQOvU zWq+WE0U{2Bb~xvBcMWaJF=htvsJr2kHrp1D9o0O7bk{I`ODjL zP6+H4j33ta8M|C7et$FjsVcWvN4M!EEPX!mC`s9u;wdFzr@~5{=LP&i4dLfP^pM7Eh>lzYa8U7eG zH~?Lks!8K0HowQcJ`w{FA;r(tTap$wGDGeaFQbFoL}RMiL4x$J~Q|aJvyP|iuan+XV$&)36iGw zDgR5&1rO^xEC6}(qgnS_Q*GL!fdTrXuxv-;q|Vq-%;*PT?-ZC1IvUkrLb3fP)TRiH z8j_4yoH&>8MxaJOksT$^r##LK^Fza$G*$I2%8D$}rf_yLrUVp75?nfe`!b1-kBaGF zt~ux3UrzC0;UC&7=9|S@?!&xwLx8zddWxUfkuq@|EXqdczv-W8;3LaS&y6FbM2w+z z2`xE$D!%Cibt=^GSJpfI<+FHiGyi)Fw+7m+@`v68?edYTq(0-h;M!T}wayQuU0OD~ z(+B0D#X6t>JL0=5wEs}d2f}IYSB8heQpesMw$Y_|)S)Qs| znB9uI)8C^QykK{h1i*igUy8t{1>r<{p(^;6^gH>MfH6m<$UMvT!wlSxbiu6s9^3i* zc&_JOyeldH(mrS_^+~I61Q3O(p!GmVERGdm*Ogj_;#8^YtQH*=4C01$tI-nonLBe zgDx=}g8QB)>3sdlGh7wiotlA!kF-wn%1}<} zi3%K>sri=a*mE`f$GJruq-ouuBK(qlTfV5wFKK6d^HB)}uJgZ_ohK9Hfku`PYn*AS zcyq_Gr&4p**4$rat{h~GeiKnp8rSqo6&QxrL>pSfn`d-)%}L4)y$F)ANT)(Lds1d< zvCASnmsDPPF=$}xV=0__C1nmfM0iJI6fk{vGTF+=W{7S;hO+A8pT= zyvqr2(G#CE@k~o3ZW8QHr0xEM)%t1AaQ89X6ax&L13{3tNIvnumug(7bH_X51!M=z z^BK^4B0R!OrFG7LG1*~iY!Mxh&yb!0MUsv&NE=#`>s+tJluhE>^NgIK^!O?=1Wq%( z%z}RiVuH4}Tet=Pq){k)m44L|{Usl`)q5LVmfKYM7-2+>iTxs?OMQiehSpD&X*fBQ z_lrz#5$UH-RV)|?^6`pxYfIF+9`4}&OFw0lekF@_8CF!qGb3wING8)xWe?kI(JU0W z!J|U(yu8(GS$%Q{$5$v0XnlgeH_LtzhZf@(pcEAgw)ef6!D_daLjaHTk59*84t>%q z->bhH>*kU2INh0dnji|c#lRT+4+|$HgZ45#cS_f~!;sGw?ze%i(T>TT3LG>}xgrH% zSOaxu&1(bju?a|}*EREDIF&ud>Rn4>=#-7|HvBQk4R}BwGgT<~?q6jK=wg zm5!t&JTBuhqe7@!#sPW4>ena3Y!? z@T_D3O^AiA(Q>D)?Rth@zB!j$my1HPuw$B8sbNBqpA@5N^;_293iEt7`J#aPXLht= zcQ>6plX*lN+eD9QoL-|0UH8=uN&~sWVC5=J>LE*chDKp9MsM6%RSfQqyj(yT-w(pu!`- zpdN@=p79`7Bt!|VFb3Kfo+t3#-+3DT=q%6$)6q>#=6CFkRoan@Yb-Eo4?%&wXPOS$x z!i3c;A*ES>(BE9h2E=^9lDkH(JJ3H4QHyGO{i2-b1uh6ZIqGE-aMkLH2VI`2^5= z#cp^h{N}shC|Yn0x6zJ%S#fGL^h_1^*E03#L(L~*68Tg+g>#d@FW`q_YP-dUc^`F;(Z-3c< zJ2f5oqI1Arqg{V1DHiSdoU~ZEOnvl+spXhx3>6iVONFs;`;3r8(?q{xf}9mL!k0|w z@%$Biu9;|>u$&*GNbNMs*0P@0F=p!!Bkp5s7BBFLepqCZG;C8(4AHda4MO!2+si3! zVRC%)*DsL>1vbZ}LZI^(mKYxEdM+tq(HwhBV~{fDF?2s$W7i>-G*DBf%WP)VB9d2n zE9rti&usg!rnff-tmCq!q>iN#Mt$t81>OIKMfjL}9B;O%t{V}QNi#(%UgOFm+8rfm zvB}JwF4Mv>5=vAua>HzH?eXW%WS(VL*mG-ks>14mrD8*6tY5Pj_!F4wjw52|8XY|P z9;fQQ`qNK3SK9osG=I**Q_zEkGhlc?fzbjEF;o=X zcL~eUw<9BY=m0aOz`3?VtwA@+mon_Z6EDTaLplCLB4)%@2{AFL@iSwgD)@zEq*9|y zE>d2R4ey_AJ|J=U~Rj&w+%gU_0 zOX*%aXFK$_H-wsnzUiFX3`X+ttHFg=@$yVy{WlfAU};`BNW&6*<#ySBGZ{jJV-X)7 z8$V0bO7y&ud*T3BR^8?haA z3(|@C^qkoM{~%z<&k-6ctgO6uGGjc>LDl2VMxAS;l)eZ-g29Y*q53WYH$uqmBzrS)bd;h?1}${23+kf554Vbmvix7H^%*{6dC za+dJ;syg&ANm#8J17S)IMbi`bgfOKYby<{xgB0k1AnQ1>8-!d$A~lY2dMG~)Bv;8q zB73_f{CsnH;|mWW3G9qrX#BQ}3sj%#XhN$EZaueABtBFlQr=%jHaT0DrP1pZdujar0{o{Ofzc;q=qn6Xk=)mbqhN897GoK+Jx@n zmXSU9@mic9@p|~wsadc$#6Rp^0BsDGOmyvTlsO2oOnYACN+Ltu@HB8YO-y1ahhK4b zs&?n8)CQL=K-{M~205fxSnMHlHaZU$GDc1C6hU6Xe_@AJcS z=0h&wWcjqh)|gLn>WHjjlt)KLMIhtl@zxGZ(T-n?@2)#DgIuJ}uWVm8OcSBOcORzAzr_ntj zoe&|P|2waZdJvC2L}LDEpZPwZ;RCB)#d zC)d~-NI+1i4#BBpW?EL-zbAQf3&U{G7SF`(&4>Xi&3cd%w9^?1*>)b_OXL=|zkO(= zstf#mhXW&$R}M1Oa=9YBo4?pr)Kcq^0}R3=(UyhCI&3^ODvj_j?0+Ej3Pk(1U}S#s zJ1RtuLeYA4IV4kH9xrH1b_^J8uLSW=m$1rr+cj>4m{CM?OcIjs^2`Kd!!sy7z1ic? zpLQsD0iihM6HrC$YsCH8QTafWWGmX>JZu`sLB_=Vxx%&jGPHouAip*G&8!eDar3*M zPfe6^nyG$Hx>yaB5b;tyG1WX8M+R9x^ruQIrKf&EO|TMNBC0LTLjuX#xcKI)7gjE(aEy4ejj`j`wz7vDEMO^IK{}#w@S|;; zs^_bETu(C%?AM&Xvg%ts!i8d0XO^wgnoU^I>ZjM9%7^M&IkJ!OHBhUNraa)7T@etI zqA^niGJ8jK1cB}O>8r2VKDvbel}QPZgl9f4l(5SuuxSYg(j%Rh)M8s1DBF@Adbq;z z6Ip{2>$DZ|+}^+HQgfCO{gY@bX9S5Q96916RpC#?^7}`gDPY8t|jB1)0@&^ zg3e%(J?+^F&6?!PgtF56S*#FcC}!Qb&?rbV#!equah+`5n_cCd`DbvZJXXoxZ`Bqe zL&(5rbxQv{>CBjo;7roY}8y#0skpK9#RrbV!pu8Cn?LsE1#pCgYO{;zjp*> z(K{ivi*U$8`3I(w#F&xNrI%dZxQh)sG<-Q$PNCH-r$vdSiLsT1VaRgmOgLK()qr90 zAZBLu&oFbkcRA=SUXCJeY;0C6bz-S34M4Lp8QyDb^X(_)>I{QutimCucyLD)k~Em) z+wkzRv;6pc5v6iz+Max;K~b?awSwQA)cquD z1G)w{-X%J7Y$PcvMJIlxOIBL&giVDgY<_HYao?Rrt1_2g52|4g!^1>W^gP0(z5kZg z8>Mt~p&#j9))@>^@_jh#&NlAWI)bmQZoHY7{J84AL=oo{uA_cDiXcvfIyJs4_tC&y z4Hw?mju9>MJE&M+fWs0sLS#CTpjBnrK!9(FEE7;8DY)>hvhd1f*fD&P<&LU)+E|p; zswx28D@Ne#nG}bNW&fo<03l?SSVlq2GF_WR`O;&(5q$YY<$MEg7m=DytMF5v4pvyh zJdGo*+OX0F$vYc%MfOD7w%G+U;jY&Xo3FEw8#{PXUo_$_6hRgLzzC+VE-*-`Jy|z> z62?odK}AL{{Z~P*1dY-toQZlC^~@f=J1H#;@B*+d*bXMtYsA@Bv|bk(?V-|ICLqUL ziVy(=>*d5TD<{~D=MX1Vax+r}x8)xQjjPv!X-j(XfBNYeG>xtyrxQoy2EKTb zKYlyv6JSLhyV@#(s{+CEA|XDYt!4@>Lz$4y(ZRC7a7b27aCtw%a1cK``knZkZA_y> zocQU*-K;+gY3-w*VWXqMr-!7Atp>-Pr2EaEj@0eq+y|&JVF>rYw4_E zntoIhGQN?izSJ0Ps@*088PN%Y$ z!2XLL!#mfw-I0T(H~e&==ah@Py8&Yok+a7QWqQ~{+_b8*_ic}mlBB1Cm2Eip{p!S~ zT2faY$MsJhWDM4xNng`%b^ffE%|wi+Epz|>wu=2{(x!Jt2@$SMH^7G+7AG)rKa4Iv ztPe=Zqs|3!rDv}nZ&TUSpH}O5+8_jgEQ*J4hxybf|JxS(c_DC7_3)cQ z=!Iz#Ojk zbEa6)CAQ~H@A|fl(2zd!Y7lG;u1<3xuzrGLgItFlf6Yvy$uCArd~cw?v6 z+1LH2$lO^@*Ctr%Qtnel(6xqv8g!8iouBqIK@Qr0T@=!2^aiq3wRp^JTv>zdx&#lR zCSdy;!Qm8B#r(`Qt|iqi`qC53H4f5r^HmDIa#P#{l`Tsd3Ec4=clOVe!m%`P0w{hv zYgXa!f77}uCd#TbH8HFFb<&y90Eu31qpVk8=882hY=u_PvBF4c_PD=L{=n=xd=q*^ z_--U?FNjiD_Xt@0T=7l=O;a-5DShO*IPfolpZ;EfTG$W_2&7zNr)sAM+0KL8&yWQ? z;O7nA(>Wn8iX*{bauw=5mox(1jyeT=4RZc$lBzx(Icp+L8Atu12p)$#>qZGbL=w;W z21l@P*%gJrlAR^oj(AmgKYYGv3#s1#o6fC-IG|AXNYLsFm2q!Ib|-o=ukkB~2!M~T z)dIxSG#v6{^f}mGoRQ-i1VIJs96h#S*RY6Bszv#(=$Kf_x624T;98^p%Zpn3&ensn zhSG7>8WYj=`{ulq!8qtMlmA?%IIDpIpY^<1JpXnIz`m#+Hx%r^c8vxBL9hRwX8F-( zFVXFiJ~VBVIiM%T+c4Yg+CDXW@y_|o3rp2IFB$HfTDhg8?d!}a%q>oJ_cB=O@!FZG4>m!#QN_rJn~S!`L5;I42ZPtfmd%w z2?Fma*1@PE6i!8eTX5b80pB?JF5h~fgkYYyLHS3Hlo(};i$0eRrbUG~PrC;^G;Qy! z@Td$_9j15~sK8w+$!#S&y!pDXs=F2mf0*t^>S8Q031?6+;kh;tG+gQl5Z&+zDtIBIH4= z$r)b2#$b{voRl~SL$$g;adSK9@W5MAoVFA5CJ^H^F0uuCNS{!%+8nhmwZ|C@pNoErJeIo4d-zd^ZG$)dsNyx`fVI9G z4e`6_@uonvACw7ek5>Svf0TN#UEPCyXH+v9TWWe{0sEv5`I176q5ct9X{EhQTrcf# z#TivQyKKs%NTs<#Dql$rX`oP78=)g+tq_q|rgnKnS!c0ktrv+p7t9nJ2RAn>oI}o% zOZQSqDjEBav$J@hE4Qkb!jvd5e+!TL34cvl23q*n>uHwtj#Ou+EuY5YnSIQV%18-CD`*9&MVZaD$UEV$n;Xgjd%x3L!mI@i zv-+qN7Ixt&YL%RWA_D{=pAUY>T7Xg3puJk(R}u>ah#?*HqCF#qgAk~D);DSMc;>cQ zBUrApgzTpo_beGsVknThltApj-OQEl5WiA#F7_Ma6y3MVh5Y)R*IgYQIi$0eOM`iUw&%L zsgv2d-O7{hYEItV2Ok6Nw`w~rV}G6N9yLyTmTy4qPG>g4zBhhr(!WmRt--6)0#p&( zV$2<`t}zB=yjYSV*Ia4fjJj?Iop*;z^{G9Ug!-m&IvGp$XF@WJ!-ZUOU3`F%J%MlU z6#P1|6=GeP)l@j+@Pu+Zrh9L!dFWIzvcIG}e?N?!?vO2OS1)L_56`>!L<`>Ev1<`8 ztR8(=+~ofA_ymtptecD)zag$>JqT|{>%X$b{-{DU?jqzt)~l`o&c9*_cV--DL|^a~ z`B4X@wiT9ekdzxi=>2aZ%f!rM4k)p#6uM$Nx}^W5vK9;$6i|0B_%#wRxs>fh7=x(3 z1t}d}%~CcomPQ+l*A6iXy{2Iek0HogCh;gAM%FVd+sKO+GBAORK}nywcg0ILcII1Vw$;ods`4w#{rLW3INI5sFT#8HJsoQq*Q0jx!DihTQmx#Khrn39 zUk6>!z-YGR1Y@ZGiVW=d)ojrV5zL>aB9nkDz1>=KOJWzS3y+2^ZDsAssNji2%nFlx zdCA%v()P=-*=(V|QEO=dG=`pw`DJNR-!y&NJO2)vyH==gF{#{kk)F2GO5h7Eo3<)= zVzr#7wmr`g8TdbCzg|kZ??gh0VlRX>j$=;1+SXiA`e|%M_PQ%CEiIz|&w7)^_N$Ef zIO#arflFFcfm9=W%Rf421aYu^>nSgum}n)PuJx~m5VL;A!S~40zQ=MW%cbfuO4(a4 zR{U4R#Q$7xAJO(%Xt$CXf-IKeZ&Fbl^5zDTW4H>6U&!LT0L}0X;p^+A>pCGdbknz( z3JniOD<()J=SDCYvV9uTG!`%Q_tTS+wOdR)@(o zKw9(<5KNu)t-ndeGK8FmLR6%?Yb+{1U4=M0tQt;fb8(`*y+Xa%JFsf+{Qnn^L3#}Q zqL_Lxg&)ARGnYkAhWBVE=Qut9NF8a19Kr;Tknw&YhkH`whPnc= zj*4+P_kcV5YKzCctuzxGdRnB|1Wh%rI{j(CV-1yZ%IAs^07MLG$k*zkg6xAO1Z3`; zea^V*cfbDP`G#w;>Ll*#nZ0<_%zMrn``z*{4*Eu=X7A!C6IVXFNIXiaRnZAE9Z~42 z(57J8TAzOXT(y1>Kuhg!eea&cP=P%G$LZ{$KMDF|fPR3S@Gy*cAqSPbv@T-Ikl0ND zI|bfe)O>7n{fE~nnj(N+Zo1xIu8CQqJ(>EY-Ji2??7yOqflPNw8FZHu|IC8vtJry* zQr6=xoT&Re#LQGDIlprXXe!K^n%*M61TO~Ud`B)4EvLU+4j;|ihA&3Tsc#c$tlM8? zam5|LKI6q>tm3f|u$1Ifk?8D7CU}OubWwIKiYPC&Ic&7>yk?a=Cp1;O;LQ7ec5-!8 zYQZZrm8hRd+FxRpi;0Dl>JJcL9qaE>mv z8+U7rr2(L8r|WK$buXnp_CzI4uuswLh7$wju0;W?F1{O~n-0rSHpcH6@Md;Ln)U;P zNgw~|*yl&0Z3(J?mgI2F5Ibd1z|s}|yTn+5CaW(X4l%wTq3)*;ZF+{pgBKHqc9TK} zxyAG#(u1q~Pc*6)W+GHH-88<_>UXzkq`D$fbdKp`<5@MXL{RAJ4mmx0td7lh&wRwZ z??H>Un~Icw0@i$d>Sk^G9K!#-`tJl|dOD%HjzmTLT#StGMcV$LkLQqVJj7fjsEt7( zAU`av?Zr{{oKbk_t&ne(K2f__)DSR*Wiv~A(xiD*2oD<8FKXs93#SovO9z_7@=L%)lIKD9%0v4O_(Vg%T<&nc~Q<;0JG~cH%@?=BkB@n zy*Q*PwNChIA^HrymC`W0Gi6bw{d{m)d&yg;buxH22EzDKiqWWn5*o|$eNj?B89MRx z7e*fvC#a%Vh~T)WrX1gcRT1c9MK}`kDClUS?_Hir1l9#=$E7;61Yu2H{2`QJq^UN& z@_rF&swjMv#!&BXi=EbdLRQf{ahDL3n=2TMq&p73X@ z@vN~G8l4Vvtz>w+5Gn%66YW1X?}Oz8EVSPblzS2%)Q4r6yG>;)U5j{Ui2Rw{jfyvU zJ4+1OCaZ{mnd<*Z@RMb(9r31v_42blQVMq^>48#Nv{B3PB;i->#(?hu+kJ8~<6eXA zLcT4F$ELjHg^;Th2dL)8ijf92p!|h&V__Me$5y>&o8EqlzFv{1=#&ksBZtXmxXer3 z1FRzVN`d&Ew>eylS!i<#wRr|*UUOT+c&Z~_s5~JY;z~LTcMj?e8tmBI^Mce(X~$8Z z(1LC(VQ{uy@YFh-R^620H(lxLmh^?E*Dp)#O>@;U z2|MWK%S#m-9Mrc^P&a>W`n4+k>gI!dDe?ffU!TOePqL(qy zJ%GTsDaGJ~Xh;2Ip)+$f`_gR5XhZt_i|z{!II8y9LOU^c_{o_MAF7}h4RaBpLf$*( z{N>^_vRj4QBYSBKRTG@H(jL8J5FZ@Oy2+7lTaHf#SkMZcs!-?LvBa8DLnU^#PO+Tg z8R8_;n}oIghJnTqI4%*Bn9b$e&4{v|uGGs!!f$HPRltTb4)abGUPw~aBp#wFMHQ!* zIywO-0`k;m0v4V!SUUV?LHYuLbhhJzLftRS*DJEcr1uRe5+TQO4PK=5WjPG)ZKH)b zLP$7D0^B@C_}1nv6}@Uv@#d6IWBlAv1Wsp<2VZlniOxnw=QgOEBq<-PW()M4U&nii zS`BLv&9mAx4kiW$YnN3@lhX)D3sc~pH1?FxS?2J+I0z#3h@=fBKzKgcqOl7@NvxVJ zgxnw5DC>uazq}nLLRB}%ir2@^7_FaOUVr`O=z*S^hj`?%6jC26BebU(A9=*P6Jxqy zNSsSg>YSVaPSgRF_x1A)ZgoT$5on6fSD{Y~y$_%qMy_t{?`3Rjg}z4aEVxijO~QS| zvp{T6w+LM_FaMbN*RHk>5mE1g2K`${Jn~e>ZBnz~NV~?0DrB(18YI%p@}4rk6}}tu zXaFmC=y_?!MSOM^NyusxXJ~GT{iGeFhS?ov+4C=CU}n(O8mu0wf|nJ~*|9UfwzIyV z)fcNqcrgKrt(*ikIen-Y*1TsIHfoICXM6ruG>jO9SFC>$7&uMqtnY?cymlwn2X>g+ zM=VY^ILv=7`&Fmrx$I%ouKA@)p&*0^(d~@PgS>Lsg;OI{t!_9@*go`U$FwHM$)3kU zjet=tj3S8jkXKQGsc!%o8}>hu7a7u&ev)5i=iMzjot~Dy`A4@lY|QkAcvBaVGWHZ= zCq3lSz!pkH%1bkYT8es@s>g++9v?hH^eK8FsaTV?CBfdrN0~yv0)t{!V2D^+ILGRa z=)6OvZJ*((-BT!9z>VP%Okh@Wz+_PJDnx46#5_@|;6Uo#iqrc?A}oINUDzW(YMjnb z=yCJb`}_?~KUS+yfij(aq5HPCc=lq+Mu&SiPzCp>Y|3>PPxM;uL%$8BEsea(RZDmi z$E3)|{`|5#zK<1uH8J1|NeuhP()R5^c?DIAhP1mSdynV(dbQ!MuMj|T?BG*t@r^Y3 zY0dPt?lt$P?rQ&v4WT;Sv60$VhyNMUK63}p`|{Arxgy^OFJ|U@6_;!9EY0d1M-Chi zZI^y~`k_6O4Z*FA3yiV84)BfloHS(IY$=y@l(HC#Vg z_A=M;d8QP{?qXV<63`$Uj9Z%ri;gB_p?u3p+0l?*&WCZAk~;77u^GQxos=MFfZT9U zGd8!ow#^h706m$J&jcdeE1SN}fx~oQe=l_NaNsli*;w0~(NZ=e@W<;wmWheg2{L^G z%RM`GO*&`EdYShW@R_cWfr>eqT}ja3++=9#ikLl_X4#rkWZGx@YQ959o4f+;rRKJ* zn=X15@y1oR0KcL8o^by+gN+Ml4AR12l%(m4t^qUdy00^{sj$x9bG&F7N)en%(?ztD z1bCa^;gxh96EYrQ4?(ojBYP&pmle(FY9sC?x2Y^NyE`$4Qb%6j*?$Xe@jX-dulGjZ zp0WvqogvAZJ*xwc#6q{2#RFx%;EgjZJ{tv|eXXG1PxQxe3H^c#!zJhD8Bf|muAI+u< zvL>9w0nWGErDx~NF~Y3fg~M=H0}FhK$}}(s(dDp=d#;o{8dhpCJ6Rm6x`)Nov!voz z7QoB+7~A!Ek!rDt3T28l7l7U87qOaL61y4PYkic+&L|b6{$3cN2S_j=-{G|4^xdS= ziQ;6Oj0LfM76yl(o>{XRrXu|~HBO)2@EdGkko!j{U)Sgl;SUlaEv0#*(MnTaB{{R5 zw{1nxm(CyLFb^K{LW891JX}6+U|{Rm{7*B4RJA*#_a4_hzn!zfJnzzaGV9=Et~W5e z5K-Kyh^9bf#htV2)ds1BqzT&yiXCbdTh^im;d(+BWR5=^V$5y^bg0|peZy8w(i zkfvm>qY2aV|3tSjGlLRFEyzkg-IDAlTg(ss(aKi6-tt5OGRgkaW>h#o zFWB_$yyZ<@#h7bK%~pclH)hXC8hJ&Q4CM*U9lz{&`Cc42$gB2qqO>y1TqVlT%i$usmK4(a`pPh! zE$Xd4TrPkZpA58ESz7iihg6lWP*4-ejtU13j7%?=AMcAJ*VknkOF7WYJVteTh=f<# zj<;O59^}}Kd-oM;XQGm#XsL&LVm`bNHcdX^3BOWoeVThM8FdwgYS?JB-GlH^YnM(B zKS;d8OQ0c)0=34wA^+ ziwK5R9*HqRYyo~4u*EG9fU=NnumfQArgE%PDk0A6wv<@QPX#w;w3F@bj2=tVR=c=` z_}5R|IqxhgAE#feMrL3MX$m`i;GWV`g|}!lhyK#AJv@Fo`*|%w zN>8oja$OqSg@7$oXyCBc{Lq$nM!$>Kh z?Y7-H2bd-8!llbpBjhyU?dksaW0KC>Td{K&jY??D0%p@LrrT%ELqI8<9Zfl zGbtIx#^Qy-BxdAZSG7=UV7uxxOad1+{(H6ZNNU8gTI- z@M~)3iurik>kFUe{sqhHu4Jya=w#uwCNp z(lRYzkI^Ri041QJ<97+=8v2_C4)*|$H2RLJNOL4vs-1XC{xAG$Agd|+QY`Lt3HhI@ z#8$CQ3Tq`&#aK_*}{y5-xx5z*x`8AoI1t*kG6akA0**Ay6GtD53U zg5wH}A=UG<_O=SKv5v^?q#8_kT5cU2ZQ0cnb;@Gzko0h&o@Rg-MK3GOqkp6R z-AcVZ1L*9raw%HzjZKHzm97`QDG>gU&FGgr_Hw6F%+7MO7Nddu`Iwk=i?MrjG$m1ClUo zSkXCcyX{-q26j`9URYVES_ULFF&hZ%SnK2aV_{wP zw|1<^TL6ioas%qy^ueX5twj1J6C=e4sGHQ8V6(fAo6@V8#37f>qylH;lIFYPEre)^ z<<>r|lTcJ~S7)X1wF}n02#5zAR`=yWOLO<EHki3U+y?Dcih~PD zkXvwR1a>anY_E zPWeDF>5K&VRotKgh#6n^1S;cUTojkOENVoq1KHh|ta|zmYGlJ`IDz0tT&0;u0c5IB zs%ic>=u)vzLkuS@2%}vcye^V*j=W){|I-TCZIHJY$-yMaVdYpF>fY_f95O@pXCHKD z3#{=-dIv*6DKGhepJUp@uUyvvQILO(HI&_l#$V~b)~t`2ka?nCz95l1)A-iYddR0C z=YPjgK^n@e2@Lnu9K>Vf1;1?`SuyL%83h^zpaNjlKblA4l94rfw8y}xS1^#gT5~4X1=`{I|DQjP{76Uf=o8Y0X22d0L zoBOanB>Ut7hhTZ_n@wz})BaNd3*G-J%e0&imQ5=c2Db&)Ya4z3f#P&MM;e2s2mcbp zyt{QZj}P3+B5c}#_$qw}^s$@OF7RY;=vgBfOa!0+%HbHL?@O{2L|Ffe2;BJVBU`gQG zX!1nI$61bCWw^Dfi!dN6fo5-yVDRllX9|65jusj*dSZ>VwuER(2h=qaPpEp{!7m`N zM3s*1vCO)wRso2pPlsDdOM~YQeo%!Z%7#sXoLIJ*s%yy3@q=qPk9%e|NIHO8N&k~F#Y?v6Xb6;w?D~BrrW&Mx34e+ASsbIs70ng&MqEM=%F06)AcpK=+xVjCEE9$v zf|lb^OI|hy;b!RFp+JUOE~O=%{^BI%QdtmjkRABPMY*j1h@FyCzWmZ3&BsE&qf02* zD7dy>7%h%{Sp!xsO}Z@t@23;X;+g+VD2#)uU^j^KEkeZS_~{L($rP4sO-N1ul3Ghw zhmY7_(fKL+t+iaD$fGJFkh%1zMKWaC9bL`uYu0NQk*)|4=_i^fBs8)V9kQK|!gH)U z-$3_?KzjwL9Az^Bj*nGu&jd!wGZ+)$09C48E3~HM6afr8l>F4 z@qJisF6KzktY;(70AlZ?^;b*3u`s+Y&j)vj%$i(gH2JT_T(R$IWfeO*2xX03)6y+b z^xNl6jAtZt)4YrI&#VjSS{*xxF!~heO6e{ZAIXXitu)VBs=~fY7wJ?bnAX6Vj&1E{ zO|`@a)BQ}0dN%RF`>&wq13FNKw8THxqU7&)Iv5kxrw3%{TaAh+EEMR=*CFJFtgg2D z1YKcuJ43)Rw;*9DS)~DD_Z4}ElhiH2X~NbNkPH1p3GmR8|K}~ZXoPzbv%z=*Nc^Rf|x7a_^h4TU2ypo7qj-8k@R}gvFo@m_b zFb#k%EjnS@jPMs}4jcXOR4CZS8W16e;MDf+lq}FQ<=^*}jLQNoN#s7r6yOGcu!s%1 zxZdZG;Rx{18B+g*hl4kZ@<4GG?lw1WKF-0r>%T0QsWI2AAi?UGV) zodW=-upO*hLj7;bW!n39-?qx)Oay%(BW~$fX(5}on5eM!EY-!u$|tY?<*4dJ*SM2t zg**M>a}bm5=69+i$94KvdnSYB2O&7m|5Pdj}^{n7tAV7%x0uSDhhQ6q6@He+ZniOZ_IeH;|4An<&h z_YW@p6yPItrhX|Fv-(nq-X50p7Dc|%KKu1DV4p1DwhUI;Wy^p_DtOD!aDED5E@fW@ zynV}3xl_Nmsk0wZ!^7#Kpk%7$=z&B`dHRFaFmfSYoE}&aTuLwESDn}$ehW$KWKa9( z3*y<-RZ%uDPr|AXN7Xxcz{ieQ-Un_Gz3?A!gjuC|LgpR;*fyZx zP+i#-Xw1l;6zRag)h&th9*Av*52$tb%P=W?%qKt{q4!iTXBwoF5wvsQDig#9o1BW* z<2QYMLhR&KUgPrpT)y9iTN_)FlA=sLBA>V627`n859+>Jh+R^LP$A1VF;=ahGN;b7 z4?rAdgtW{Dow`%81yt1Eg4+_7{C8E&BWEpgO`?$rgpZ7yy6kyFZABVQ>K=F{K)VLy z6ro5j7$|a~%+Pzub12Ot)MArYu{v)OSAux%Zs* z6fSabXa?)J`_vdxG?t`N_Ic0RI%_ zIIz-zo&c?pUjLg-CHPa~h%ew(T?z}0LvDEZ(J79Geb7^N& z&$~jhfPnbOkrHA_D9sYGF6@GAYy|Mleczdo5pr*`02PigNX=UyQM!w$$By37J9jVb_+XeNw!|u13ZoV^76-#AmR~|Rz>SoTip{;l)o0kfPN_&0pzN2 zD#jJLYdjT4V+JW`sfFkpl_O~tn)Jj-O_NFCyv`AFSF*y3e^cH*87s99Db&GR3>4A5 zTkg$*9&u!H7}q@F!~AHNu&pqONERstt5bl(Y_6Ratw4f^jrn;Rk&-X`K(~k_&5jrR zI3JFV^}jv42ghdJTVci$WR^b^6$+=cXRfIDchZos@HH=Lii4zul0kOD2A7NnXEPp% z=X@QnP4Lqq#Y>=|U=MJVWFyr$r}l&TO!`TBD1FJ){KYeO#p^UiX6Q2wm{jY0!&IZ_ z>pg+4Q-q35(2xqq%MJu}`W?n|*e3E`9}?@pgMA(eGzL4J4E^yhPRMCx!kqU%Y_A=u z-jyORpKM>YP`0d=>gLs+6rUx$<_WCioLA-i@{mlZtyu{H77s!*vc72>W^A9M7|k2_ z93*xOBTd#bevyB(CGT?qkvZ}nR^xjQ@|UYL2&9O$aREU?=R4G0g){5$xw$e%xQ~q- z7P{fp*CCV~^!V&3a3)zMH)mQN6obuj!Z|H#AkxsPTIpIn;|*=7jITQ}tta#yz_ZRu zd>F4(EwLl^i2d%#^nU*ZhGP@hL@iD`_{ z1K^5cnJdT&{CwDt2_hT>z%D*anC$p&UhcD+NkQeKY$_qQ=&I|cnOgseXno}#&~=+5 zg&ete*O_*)a-}hD7sM+KaD>Gf_u=>G$!73V$^o}YOg|pCO@T5?>mHr4ZFeoABy)i22x{)h~hmK9fA&i2*_$leRjg=(m$aan>hs1SQ%Zd$Ox+4073 zz0`}f<_aD3{}!i#??mCs84YrF86hDF!y*MXlt8BrVE-|CXv}k$TPRGfwyt|FK;uz4 zsjr_@G!IG<(%F(d#_)*));jnwGWwxgY{b$C_XA!cLPG{ITZ1gx#bkH=AWv*weM495 zM`vdfteyRkHKs?7cE5y!k&?cpWVP11KqBH70Q;O@>YAPJw6Jn8$`4M4n`Z5fIawj8>>|eahtPtiM_p?k!HHVmb@+fCnB>7u6KsC zqMzH2MoUUHKl7l|B0asKJJXPHd20sk=Vf4`*^%~4cS1`;iR_W+NwFOb?qgD6g+uvk zAimoRoy|-f_WD7J9>5?tY7&FtfyY$NFiS1MQku7UCDo#234JrQbl3;_aJ&f^mgTPd z)hMj$(N&wQ7%%PcYBY`dCD+QqBJ{&42#-nGZ3j}b0 z>6$=VRRYE+tqcDXHsjw(?h$GVeF4e)L9}5C!wWTW@f&y~&dZIG4^GS1C4&R4hj-_R z8OgY0GIFiV!tx{p`X7D@8eEZ?!Q;a1R-xqI#O8nz_Vbj$y{nd8nPRy?C0>iqe`STa zNeY$d%0`1FsxTm-;@0pM!HdVV1SF3x0TMvMYjQ?h8N~yeG3Pt>w^7Ttcu&Y^KKqL_4Hk__IkBajj3gK4-(!X zVfW5Mx&iSjZ%vQSwMGBe^eFG@)*^44@f}sEAq#jgl{sxD;b567dU|&8F>RX&^Nb72 zMm)(?yJO(FBH%lTv}x7;!3?NwvM&Hm9c%l*BGQB0R=1c`nAi}I2qzWyeD|c*dyeV( zcbGhp*@eanr%BnW7G@Ts;o0?i1`dLt}!j>wdWa?68)vbAQcTWY04Yvn#Wb z(S@N#$8Jd#BkG%R%(0G?6k-TW3WF=vYGK`CKWK`Z{rCj<-bh}KaE{etb^S{0(G8m=)m}Bjf%LvWa>O92P!*8 zL3Z<0=HI5yFYHzf|8!GtsF1EG`b-2i%I(K(p^mtpID^2w9TqRdXyDG9VCO29nc3P( zueK!ne`o>39~bZp4Ces+D8>)f@g-bHOqLd3<$#QCvBr7!0rU%lK`viK$S5gdu_RC!ZQ0JNGxqA8c%rtB8W|3C_5-aOXr{13{fV+tA83C_h; za%uY=^xPlO@pa@QqpTba9jTk)-^6$H3$P=A_*nbkG+t#ST{oTGXZZ?0y^O6k;Mr-Q zA6J@OP${e7y?ZOvW)l6c=69#&AoH8cz*wZ4MeMRt;~}tPh0W!ynUCN;F-H|zfl~K- zWvb6SOEpx9JSjl}2))KHyjJ|{m%0w5wW}xeU8f;?P$>JQQ+c6z688I(%sto3Pvkay zTsebPsd2s1b)UV!)ecEL43hxH&Y7gCPT`3C8yzUtpBK9sRWQo#;~=iY!&dhq9LhfF zIx6pd=zw(vWPTM#u5|EoiO#Q}EbX$O$3ct^*dOy&&d@bUiB_!v+TvjADSmuvIC`mT zA{5{(q*j0_zay_g$U+$W#cUBo4ZPUTobXanZg8>C8@pI7q8woPK_OnZao=UR>b_Fm zvPmOk_zh%RLu$5VpTL^lPxq-4sc9!TC4c3hxcnLmjhRY)1hn|MWqiq1n0N_MH^vcr z?2@HhcoU>@iHR?4s{W4SB@DZ80om;hnT|N^r$xy5^pjE!Ge@@pu?!A0O75SMXOv3N zFt%FeQL`L%4*Ph}qi%SW1qNlQ1Mm6%$8dg@oMz#w-H+4N#ZR)5Q1&vrA~3_SseuYe zD#a$IaicngdnO@efQpsjC8LdIy}>AKt4QO9L_3)q4xGXOAN&JcaF44zj$)v$Rq z0Ko#N!vXVhH|SKT{>ln9$V9pPPR2vmjp@Hm7X7Cr+M=oe0=&|@R0|q4?CkSY();gc zWaP+xXvVKwSF!!ySUR+CT!-x*qAgwZ2+34&9}BSuj?R=Anm zw*z*mz=fO7tj23O=5z~B%#%a0SJISO@ij?X3hVH1O6{g!JnClaEHBZXwUB?gwWX4R zZvRLd=v%9H`V5D&L|moEL&=FYEK_h-_f2BI-5DFozF7-=9-wr5s*~RZF4mb-XA9^^ zlG)QXw3Kjh(v^{v&~4K2dcqz`4-0t_vV(Oo6Yj!#zyQexH1?hFV6-O#N|;Q&xbc7v zv>7BK>Er?P7kKOekuVg%%U~Y2vrQ4y_))&13Px}N%~XKlXQ5t&j5UB;3rjjs_WwSf+Az? z8#_7B{WSRSaW{&@kW(LR%G@wzp*)szf}aN=yEZVUV z_#)qzf5E75!lCv|?fxxKfYnb-x$cg=%!Yw_vZej~r(5azkTLMP8 zV8*ZF*W`Y7EFQs3JYGH92Jx9;tGNA8f3Upa#88sG`jLSUQRAn*_*qef%+=##&E20hsD z%kA2mt5}lw@GCTGOM_BuE#bR1T*CTXKt0=zT2oxpqOze$NhmiV|8Q4w)IhnT=2?0h zl*mYVJyV&pl#mz1T^uAw)al(D^Z#t-$Dpz+?Z7N4)(hMsEKY=Ilarp=ZGt&UzFZ~d zf#9i%>ccs&RBtOHG*ep=&4u$1N;WwSEz#oBvC9a8O0;fQ-!~=f|Cf3p#$bMnNAI|KaF?4{U4tvuOZwyt`tL22Eps5l14WCt+<}W{=;-b( zb_rsd*T3BxB=-;;oMo%edN#pv<2?4qZu8=p{yr;Lx5({rXKX?kIBFj)iIJG~x<<4Q zsMhr!l}7~6l|53Rd0jaRK24^7xK_E5b;?*jUz8*0{BPzYmWO2Dy++9a|oNgH+2Sx zvAyd*UIh|>F+o1Ul;7iinf6s;R=~_KmCqFtxui`EP^8TULF?$0tcqeWpe!qTgGmkc zX+uF+E7+vISQNo}LhaP}gseJqwY*5+wL4=chtNpjs!DT+k z>f%kJee)qc?8rb7*NgD~f=;iP=X!xL$>8B;hB!$2;im8)BDid*P1&mN{}i?QS^uLX zm&jhY1;f>}*0%~wrM>A0rT(ANqxvMXO_kYE?B{j%F=+e}ukoi61;eIM=A_ZacKk{3 zZ>l2+^w|U*=aBd`+cYnmG%O z==E^l=X6vIAc5K=q`_u0U<%brF;>mwOq3bQ2iyoBr`C5$uys^yrX7NVq`6voQCo@_ z`uYDA{ESWjK_pxX?6{|9^ak2uxSPSmDDJB6F$78ziaiOy1;1Ix zH&iw|1y2L_j7S!Uq73wJ^b&WS-fprOi;VAcfrB^0z`Q<4UGwnO=QhWVnuPqqumDqp zOJ?nQ1XOS~AZ`a1!I+jh&aI}~?-`Y6KZJs@Fy9le{1p{+0pUO;$35OELcV(4BMe@5 zMYoTo^WvC?<|CN^C~+rCu~qT$7xe z+FQFFNild+8z24E8P(d+NaPgd6^=JBycahm(L@CA72!4}4q%^)A;2MaFVV*VQn;BiMyON!!#UJO+X|72&u@54 z(%lhsJu-ovK`;6;DoFo06Vu;w*VbEbn^Z8S+zLtb&yTUIQ_xe8RRX_}snb1`Yb*8! zGP+iwY51!}Kq{Ns3jHjJXwQkctWnt&9wqE;Q_!*p9T)2l z4$^X~&zZ_jf}7&;uf|xj035djBkv*>qruPA8`!3@b^{~8M;8eR=i0#Ots$S-I}27I zaghW$qMLLJ+L9B>u#x1meCE@w?r^+KsB%C&wRAcMAg83k$)qjGSE0Cc z7l*O$?BSbcWbvmoP^vI>+Ia-+_S=1y9Y@bu;<%rqw^hLrC}_T?dWfD}(yi!>`@yQ; z7OTcO{)e#Lq6X6GjN56c7ZPSm?V;=7NQD$^e`VfvASh`RFJ9C_C6kBZ8M!K88WvTxy)Q-)tP+ERV z1WdjZ=3MW}aEv-GtY+buECJR=;%7M2vYl~v&60sS#)%)*^0iBvYOpO+hM@0fTdXxi z?C2V9R9HIx6co+11`GV+p6Sa!&1}ywf_skY3Sd)*x6f8@oiG|?fbDh|yopx#~> z+go&J*Os4Q4Y^K@k#Y&-T6XVuaE76j)_2`D8d(Sg-`-9g^uqjx^rbAY1{sw06`HNU z#HU9(W{nzy^D~1!1Y+iKWIXCE9TV@`?omjZ7okrAHMq zF=bqg*x_BQt0C_V`(N52+8*%j`!ZurA~%IDdrG)t8P5UvghZyTWR}WH70z1b{=$#2 z>oj}wpt;tmh=JQSiDfXqyL1!|iVR^NTD+9v=a6YJ6DYq;dpu;yDy3miU zhR=bBgnB*F@e;j30%-SN9v+N6gY!W8M!)qnHmZdVUDNefsumt9Ypt1|!aMk!CXGCa z@qX{2Nrc7tkI~47^*LY0_&wQ0P=w~GwaUq*a%Fa`{muG4ph9qJV8YMvKBJo@9-!6? zCJY008_dX!OuXhO9!#Xk9k`=H9Cu%=dY?4zlH1MCO8FdRyr(4LX+jOu>Bns)Zw>fB(=; z3_G)-QW#I`8z`69&mH>a&8wYEaMj=!-a$Wog!M6kE7J9UD1 zBA!^Yga?ju^sVbo%a-_>$;Q&3p=x0)nBWAulXk!jbiX*~2t_)09u|_$afU9zZGOhc zykg>{3m|U3J#8ic^c>D_#To|npQ(ATSPMFE^(e3?h{-X~;6kQ&San#eQvnFyjH^V@ zB@4#=X?MpU?Zfh5>JcxForK^+uHBqHf`#E+hW8#r<<{wc$e1XcGFEg|T!s)|3_*vN zY)K~d^QsL$fUHl#d%$@qQgC3@z|z#8ac|vL!8BCr9VAG8w-cAX%k_j8?%EhoSJWLz zkziyX^Di#x2)A=+v5&qaaM@t)yAzcsWZ7bU#g}i+F4v&a_E8@}|D%)l)3zs)kAkTJe^@N7cl6KWw zRaXfAm4e@l0uv==v4#VhJgx|h7U~X<@+QyR&R|6Vr7FhYV z?dO;1a(Z!Li(FY5o{MnVdX~f)Y^lUkkQsw)020Tq*~}Pk-wb1K5n4$B`5s0P8_qrd z-BZ7$(<2zCSVlsDNTAQ`z=1#T&?37iJpPz|<{fNq_My?~_hMrwLmeS;T3J1NKYieR zBtcc>rQmgolzoPMrUnBs2mh} zGi?kP##xKe{RRvA9BrXm;Nsm4xuaqhTPQE1#q@uY1@x~c;v}vt4 z=J{-dV`n|iOle*T^(tf}XMp;dwM$;|1O-jq0KG#q09 zOf-|SR5y^gE4VGe4Z?Ev*3+rN?Ff|&N`)gcALNVoxyJ`dDR0Iil&fu3XJn~J-lgzP z8W|$^#h(R6S@Ofwr-1Yp7HU57N&8{#z5&q|QMMc|fk01nA4N4Z2NAl~P8ufCD8l@k z`Vi?(iy$h3nC;%2UH8zPyid@0@|(tWYiod(^BgK6+CX?DxecOMYAI>N;0aB{M3;_U z#L3d4&yi~nu%NT7tg~~r*k=U`rv_p{g<(>eur3!1U57LGGpZpJMz5Lc)Z^@qLHr9vyU(z$H*CVyMb$z91b>R!J#0)e!CecGl5iBK_Pm=G5e( zO95U@Hqaze_bLi~-EV8+)rv}|$=0FzhA?^tZDL#&#ztz^FUpgtoFF3g^wToW>9Hv^ zKD4&>zmUpxWcA2bwo3XMU?I;C!vAeTruQ#5AyH;Tze5Yk;_)(A_cT%|FUJ>hKE}KS*Cyc^_EoF`<0_wVCsY5}TB@gh z%Ro5w09$VT9Y+x>YtY)IV(n%b{I%xk3fZw+ad?d#Yg(@DqSWHb!E@Gty$-NxwX(Ue zlufO?M#a?6gYlsUJFZ+@NH+w8WW%zZUxOB}Vz0ioM+b6_mR*Gsdux)a*tvu~h)kSqfb2`&A~rXAqZ@et=z7t%hBpbrB~NNHUDTX&Px<2M(=$_HO1-5 z?eg2=uFF^sq4jOpvpaBANut69t~;f+qq%K^VbE^YP6i?j*UfXHwiAa)n7Htqq60b_ z&a@6VX`e;fSyyJksmz0lZt*1^&Xt);7B2wg<^r-3jNh&`dFt+;ME3*2JVQUbdILPX zY}Kc~B~I25bEGXTVApk!h$8m;vgevM@D}uW!tm!e>_DuJCpFTt_MP+ll-A&J)(p~e zug9&-cV^Tvx&00^{*_64A)J{LL_ynfvedP(gkp?)*|Lf^4@7K{8Ob5`>5zTc|0x&Q z4ZH|#O$gctt&RFB4WKEb-LT96gi5e1DSrS{-Vv?vPo;>j(l4O|;G~9mdeDs6s?OLF z`ysbW^ww_e&u}nIu(=(|?#D4%demiJj>k|%xjIVQO>8a=o>TK#@<_;Oj23Zxe~K&{ z@4G7aH1}_CKq`zNmC3d-?_J&lkvmz^cJfuY-$tIqUth4BNF`5r=QtdESrdCf_=4t4 zSn9n{#u8fk66NM74)i?$;or(?C^51arxq;~ zKj1nkTQ~7)?=AIyus|C3A;7}sAhtvRxtjz!>`#r9t*Iv0SpqPfABp#UeiDCY5DUED z*K@5^H1kFEpO|97k~=pi@e+_-nyYrBZ}ZX~=*1N<978RpY`8wF_5HmCM5iQU6fTy? z;9fG%O)w0dZxT({+!5YM2q~qTCNWX~?MTr45b-c-j?-Ze)oltQa`-4}NOo8W4FLW0 zf>KsIx2joYo2HwBW58u+0_^0rbP<g$plue5UaZgxy=c;@sTz6 z{HDs{e2lR7!tCELfG0jC8(%LCUiLI>r?!$DW!qNuU7d*pWWNneT-2)>^63fIu2Yer zsry7a9Vfm;Xw@;T2ZFMLu`{PcEmImCF;&(`kg9~b+w3p0z zz{L|mn!-+6Qrq5N&pbIr_-jCw0&hxeH@+G(x5EgRmJyO$1!oEh= zG=)kltifhg2FW6xuQLT;utjiKBexvFOZM`Iw7E^eYce71nm75GDLEPFW{Sf+W^|3er_Ez2{!#;3*iqJdS>CYt{FIWKHPJoho zHz=TRlQ#GFXtC?;UhcV1+hMu=-!0>x#7Uj{Qldxg^iJAz1F9`tRT>3$}+wjE9W_n!}1Y&DyRQ&)44aK-?CI8_AcO{3P; zkPI|tuRkq0IHnFK`2DzRz&s3xDo_b6^A4YnRO z&I(_l39ZHIo#taVn%XpcxM|@WB+hv23g&)uKVK zBCW=hrUan4i}4R+tBoxIsQp;44!QuVSI_^!jk5;`sF<7VlcoW+A>Oe%@fTOe`VHQ2 z00#$Y?lo^ZV_biY-yDvNcp=IlirnKnqV}FoF-+D3U^$m|)Uw!%1H{eaf{20(=X8=s z1}etqU4)9swkkCsr*_BQ8y*4N7S^LaB>H&Pw_lGe^C$8-me1bk#eq<>eKQkvti|Yz z0%Rb;r41>@iquyWQ8Mz7PuW7Ae>zYPL-)JfoBGP)%c}p7K!LYzPk_a5;X&gTkBXv> zg?{4T26p!5fq=Sxd-lF0(;1J=?Mp3FkLhtPGsWxW=b7PUsc~l;J=0P|@GKm+*G`J( z+4g}T?|J@kpSGtAj3JGPzv1gyl03{(^9;O2t{|iMs9OhfR+z`!+g12^{el^+m_si$ ze(;7~I$x{eJxgfL+X^LB0RzUH z2#`@*Af)_v*cENSei>N9>jzk_tV;5(U#w-Z`FsJl#Evna2oGr&{2}07hBwZ)$5y~% ziUOMSt6_wCq-VW0i9HgIu$7w$ACr$;thARlwg`plBE*N})>14LG?ah$XVkKmo{EJw zmjjXS#K1pS()k(?gZUMTAgBX-_X{!_WrdB`%xqjJV>y{uZb)`@9RUV;Eyr1z`z{T_3qTbzCXoVpEL@L*JZYdEcE<2I#&{L{Br=ZRb(*f@Z|5FSO`rA=PVe)DtE_`z5w4_% zRCo3b1;6}N*taI2D4PlS-r}(yY&OIA=G@DOGzytm}#=;fpTd2tei`&Fg);C3xmR)5ARL!mk`8j~uA;FPBjS+eO7B}@;A9lHJa znj@@Nz8GuuVlialekAzOxu>~~uv)wJsTz@NBc}50?(0WCTq-SAMF&Z53yrnQITXVd|7dt!X{~N1&a$A(1 zJo57DTgN`iLuYk!?PNjd7`9Zx=Fu_+Zs~NhL)tzi1HNgqqxG?`V9V6?j&;%qr+6s=FJ=*UVYd;G=$~@lZ4q~z}QKA zbW5&;0uS>jEc%q1}J9Q9;4K7S#obgpm^ zPA^5c4KhQmwQFxH%TU&a+JY?3hOOYqYyreWQdQMgDRuw$AE^?dLqOyy$e0ZcI zc^a?Vkv5nvN0HYSrHCy_wuaZHJk)Wo{G>w;Oog`~CSKT+PItgh^M3Nd0r@PEb3wr- z@6(!h@C%;8O4yC6tR;YpFnzXEJ&9+;yEEp_rncSm`)!}R=v1a2@JJ|LTo`oaY zZ0nxu)vh|DfFovyumfL5m5I!_^j5h&Bwoa2C@sM!TF1tPiu9JLk4Brr@5FNGZR`V! zW7q_7bN9u=x;P?9u?~McW(mfWG_$6M6U|Ucn|wpP9CH|scNGiN37pRjB$1d?aFkw# zUYK{91Gi(pYQpe@h&!fC<+}pckimD=_hkt{ES!>KY(*uT4oN(@NUA{F$s-*g==y$-{Gx8>#D*=4V#@}Sjc%jlu-uWugJJ*O2+!3ff* zPc*?m#OJhh0=ea&;}o0PKms{nVq~@yVc*)X<~I~ngJ4b72f(Ck!nV+5jG=ukVukJ6 zsk+Q(=fN-7YY9$Ngc`maif8zVnXR`nZfTzDp$#UZrj88QGF7Hk4BiwoGAKCP%myMk z{qjUD1QVY^v03>~wHwr|+!X$6tGN^!=!^H;Qv2=~qY>x18^$n49+jEA++zlF#^R^%xo|F6TBzF;iby2>1?S|X z9Qs8A1OG}d)^~NkzH(o1&Kv4pDcf=HDU;o(1UIJ5=x16U@5}X}gVFat=GcS^~ve^4pm=t>>*&rG_hOoQbBvqmp zXRSH4q=o{PL$>ZVUbhU|l~P}F+fCiU!JT6_zDB%Bb-EzArRa+FpeB4XLFa!BxdNI{ zoCB@?H|KjuBx!06*UBpmgREt?hfK`6awq3?6+G~MrFXqPrht{M^@T!!LydoVqUc6}PET%|08j|y8_~qXtMM-59s^8P&Qz;j1cyz&2PyXBj3Rh+;Blt3WBVmd ze3ug-l6Qau8d=+gTU5VG@u*UArl%(wtQ=E`S;~osrVHYaE!yim`#=x~V_H3@?uz(p z>OnvM=1PChV+AGCEgKX4x-_rviSHf&P6J5UwKa>mrkj+L2j5~P^~rw(k71%3ZHx*$ zL6Qw6iuIs7<@I#|VMvomfdo~jq1j6OU{ec`uMCKhN3`bH!m$y8oFM)m8vq{sw6Wso zOLbXAqQV;$05{mVBOE!YH?2O*`^}U-DV&cdF0D)J44@TZ0)xuK@x6_h>WPNNSSI+` za}xz;ZhnkEki0|m)RVmcFs(mjApZO3?wbzpswnJq)y+R8B}Y3s&rxpRdj zk|?zrM^fP-lnsqmc$d6*i@NmT2a`}VDY7n^4VUxd>fxPZTzV4{%0ipYb|a&ZkdH*x znAiFen)xIN6At#&N+7L-rm;dZ-Cf_homYYWAH{b9r0q42r#-*@LowsDTOJE}9F`R_ z0?pH?NF}IgeD1SD>EsAB6!{&WB^A{Gf^;miC6M zms)_&+IC)^iR6@`9pSV=HGm{i4q*kc6F2deY4Kin_vSC_SH(>3$tTRp=AOo=wH?7; zFjdx$N4^xX6PC|UdwU3CD+$vl4wrI=eAqv;3eOy5h)}TZsSJnImH;nf+dqb zx-F@YpBhl{{h%}X64v8scVa`1Ax)P7N@u4I)N$dXpi32n7x?-N_m@9P>jyb3ER;*HXx z3jJglks!$Y--MZSQ0Xj>?1=tYJY8?K=()p$r^%o-S@~G&xRck6I&>lhCwtoQs-6^T z3Bsli-gW1g5MC{zDQ?BC^Qu&9aQx0Q1&^Dy+*#4GVnMFI=aJWNhGhd9*Im|R?i<}F z(Byi8;Y9Upv@_dAx?=-0HZh%PXIw7Mo%RGACdrXZ6z^92uktR7SnGLwu!;%`0^$2; zpbngcynOt@G*qMs&@se z@988Fkn1hvh$~=3Hg2a1%>Kef%I>C&YRL0E=!`wWcZ3W$sG2z_3#M~eNYN(fqJ$g# zgE_-e*+;wS;{MODJzWq=i??4s8T2R0Opls(oUp$M;S~Wh?}}6 zv=KO4Ds4(Li2FSzk2+Teyxx(rO04T(CPAH~szDKTDdn}aLa=s&Ap zLF~k~K==r-0jy)cG}+J=ZK6V;KI)G*1*qA`d&=Dg#Lq6qN`xpiF5&1h_4G+V>FFss z(V3d!_i1E{zW6V77mwc+>B$HoimD7&t3hTjp%nXWE5zHJS=B3fkR#M)ht^{lCjsCJ zfxK1}_(?I1cnxnrXdg1~NBQVfCd;Qt=D)$rbsVObe3Wu# zd2qz!jZj2LTRrYdGT!d=IXEl~lg-bg#30QDkpR*Ew1am`mr4 zVVEmMAO@6Na~*EPr(Qyphh;>}Tv6i-iarGuLaJ+EHpj|OgZLwFVI6Z-fvZ{|gXe>3 zp;`VJj2R2077J+?JC$Bhvq|KsOWw6rIvfi0@QZno3AJ^4Xpa9SJt6rQ;4K3vILZ6?&GzuJTX3P8RnW*fDkRk6>|F*QYWUjT9P$rerR5D{?9LTO`P zWZE3!Dyp9Z$a45xonJmG|3-gVM>GZ=hy|m-pC6cs8!U*GLl>35|a>U?f99DT< zC5qvtQpQ*KBuYf3#vT@=|D64TKba|dl)KxcD}KAuI&FbSwq*!Q&@w$Mi(>UF`nWkG zwcp4ON3p(qNtMMn{cv*6TT*i>8}7Ld!PryZcYo!?d*{w zN?1cbd=ZVDH$8|dDi?zq-+x%uo_;zYa1hNqCTaZVutMtUOfuz8x%ZghTl3=N0QKl> z*ro2K^Hqk`PzBmWQ1!SH(lA+xhmMJHiY0c$we@&2b5QLIs0QNiFlOB%g|zRr?l zCRF_*44Y*oJzO$Ni#vbqxm>(S+n=WyW%7=65PiNK8dKY2g)f|4)#b->8Jn;2Di(Iqd6O(?dIGf) zLoQza)w?syD$_bP=v*H1NV|9TmrWe9u={!Pc zfr4cd(d-Ky$9eif=>Q8h6jQM?QL#aN|9#0j2?EidK>4EFad>g83$;Oca?CfdRv*h~ zm-u};phmZ{UP%vrk*X*(rp*o$HFy@Bi7j#>R7u@nYoHy0jeX-I{gBIQg8s{22=9AL-z2)zpZFD^GLDdfe#aehtPo_wQnYoWV!txzbb#saDsW7#F1DSU_a^ zHmquCJlZu0ZZEH#e3y>x*RNaF)TaqALWv8`kNF!Mfo3S?yNMY(V$cUxm}2Xex7{FT zh0zm)MP<}ftH~|999&6QlW1({(ndZlDTxLJpfzpoD4$=liGRYZ7?~>cMYxVCmSfhA z)+aq1TG@?dEb^FOEHNHA!4N`uCa1(Wnr_>;&)GqaCYH>jzK3(A|Wgdy~u`66lvUfciKkYu?v=u`z zag`o+)A}k@^vXvBm2s37GaJ;)Fz;12Y{-o}!hztGaaz87a!0ktLtADIDU_)n@dw(> zm#~#L80d-1O|zUz0%?U^qV;elUK=Wgool2*&f~0%Fz5AH`~?wOuH3>n))W765}kos zkgr(h4MIej1B8_7Hsn3RE}G>Fb;?m(ut$)UKQnBM(yz ze4c-^nNVzvZbiumV;`Ymlwbu>!xAIkabC^nSM#C0S#inzX(Y5yTxK4i+7X5$7<82S z&ao6HiMsfV(3?hZ-AT^h7Me>l!mQb{goDLj>p-$|Y%gpbrf~GhU7VV)3|&3)h+of6#nB2;GiXI!6?W zOt9wzdZh>CpVaJ**k}gKT9Y0{C@uUZN|SR5f0rhaim*)dWPJ-vwD8e&@+<=O-kNM8 zkv+7!s}LwMo&gA&4OvKxpm3YSJmlYE*H5Bjh`lH__O7%-)}6=l1TT5UR;fK2$=8t|5oT_7O8 z?bp4pR5=PICza?v(K)}Izncy2s?$%+FMMJ|z1v|?$eWcTg>Z;l1a|XVnce9Yd6f@&h~5{~#=qTpDRJ=v_Vg&$&OW$!sVw*R4(3tL z@RH3`TJBV0#Sw3=Dfj6Z-hBa$t+-+^EfhW!^DWvH%&&ww+8w6h-DZ&vMmF;h4DZQ=D?w9~6>|Bh%Yfh)%aU%CN!XiP8K4AoWJ?Npp( z{62b>qWiqm=|Mm~F#cJl2c~VY0X=!TM>(}RCl=eRXGxEBNeoP(T&k~^LpzlQ>E)=J z{ZZ&9FQ5!g!B*dYv=he^P2OgRljw@Xq{mozuUFhKQt|XCe=Civ@3d-)BJR4rEF<*0 z?L??znAfXJgU-}|&PZUk^JT|P4Bvv2q8L|-;BhZrKYECSI7Phhy1UNJTzLejhcGE=bfHn+ zN9kUpUlE5~6o&$iv?R$@Hl>Dm*4F>E(BG#8z8(xzrxap|Rl3|D7}T+s=uqc*+R(ho z1UlOqZ18#!vX2S^@Fwt)hdJ2879as(K!c;v!5k>5iMrd?Cc^9?>)&LxEg zVZp>2J@An!HdqlWVz?_Z?OtcSy&Cntbu9a|z#m09puJp{?i?Mg)b-3IRQ220P9viI z<~@npuWhL}N<8&fjb~;HF~#C!j8OvhwZ;eVFQm$64cR2Ff{AN}_yRW2UYqreuA_yp z%a11f^BRi2y!T6O6!G3M$pJsrukVK|ELXa0?10RS4^A?Ge1Oa}8DTcZwR@U+)1mI#iq@ zb5(9JMrP~N6cYBLm~6#LJI!%sXx~6-rok<1%7SmTD!)udU9Id7|2Y@IEi!l-psfDo zLXB_ok0v!^jj@JXOSo*eK^|r*%#wW5WfnvoaVu0j&oqvv!)j=JDh-4nJ{Oe!we0_a zVa8?AgU5c3>IMBKFoW1haeXqgKv(a_P&>ik!#y-1jVFR`|><*+<&tq&4f&ej+(bVrC&KM38`vzc3SM7kL`-R)bD(59DY2E zxE9g})D7~FMrWNn@y!U}#{*QxwGS`vWl z`K!!^V7I)t?!8{Mz>}RYD4(*T)Vp3~#Z(GSQ>*X59<{xig7~PBI2zPOBykxtgBr^8 zT4Sl0{&}$KO|u0^VP6p}?~O(d)YC^-BsJlrf-F>gJE=+n=AYNKeWAyuvFM>Wmqvj& z))4aK1eeKlYbfxF)GA{%uqA{Pe!3~kQV#8>SUOj)-2G#JKA}P{_2p(le%yxcy^)u7 z(NE1|FT%Wz&WI#tU2nQVmT+rdx=q_A%FvUjb8eB#te#j-jat@FWVkE|+WO%7Y1iwz zUdJT%)>mBAz4+;8FXMNHmzDcjAD!CP^s*poTsiK!WNB^KnB;~ z+c0ffGwU2^>{9Q0daeA-ok`iM;N7~f@m#o&xBNv`{m}xG9ZSD@JsD1J;pRzjSmkD6 zQ(~aE1sP~1MbK4tL5A8KZctuoV_f;5J|;*0IGq0TQjs&V^V0OW&6?QUHKVc9017Kh zTqb1@l%B4>U#;yiV4h(c%&kz9U5YWT@um*oD@A=)h;pT6SJ2z{9@fM%AXExy#RD7* zH2rgx_t44#8OECwiE}wAk24372^yS$rb>fOC(8bh8 zE0!Q}vfo#;`UF~Nd113fXoMb(_@)=yn)@IXt5U|?Y7cQT(%>M9I5t@BI3TLQuMkE? z6b1+kpL(O$BqRqdKhY96y?B?yHmLz_6(szqTu+y}w`2(*v~YUzJ0O{CMDT zF!^gV38&4tP|YzAgcI!XyDx%6)yOQcydPNU=~CU({5G1>UbD+!^Ymp!Bwcw_7imFo zhenXPsctYuB3_ydUw&x@_111gF=%uwTrxuL4xXh)kO*|M8l_>L6A7vE#1AGXAj3rX znNoo8!_5!+kL}*CD8P@j=Sg}QcpJ~O? zIyJjA-@-2!4eci5Z_C12Z&<6yaOUbO`8oCDM7I@`ekZRw(&@*9_Lq4$D7p8GSD?_z zy>FumOSjJ{t_i5dKLM`$#D4*ASu#m~lX&km`D$~K)UxoH`gc^{jDpJ}ZUsmFQ3rH~ zZA6?e%(6JX1=fVZ1*%l;1w36^gI_aECJ&7IlEk?5=IC6d6!-&c3$Evt1bT~Rz#B&m zi3EpE(DYYV7+qtpk3ML9XJRMxM%W**^T}rf}&D()CH`)C8$w^Fo1JeQX(@z zD37sgye$c6#j=6)df5W6wP3XYh@N1aNm|&;7oQ-C^PO%Y&dY&@loCfx_HV-_)?$W> z+7A8w8h__@PYIz*zUXW*r7*}%VgSWyO-+EoyfoyzVYxmbR^U4>sFrYOOK@)VZJs<+JAMhN!Ff~8`ox0rPrHNmKyX?JGNRR6^V*Em)GmKS-U zljYFW7WPM}L;{ZH0Nz{&WFUT2;QRLYEz9(Khj6Bd5uG6U&9S!TQv=^cVw2g?^HJ4& zsiqeF%<;R>{U#wWBxhVDuwsKd4-x{%^S|=z2*&oie6Mbvxi9xbdl@c-JR%b@pbY$u z)t;Z#HK88S*(q7pbt*8sM({rhmIuTT{@<^OTlBqd4Lh6=3})`$#Y2q^`;~sesDsIi z;-_bUe!BqO|IyKae-PRpiPv{CXvrn=?B-07nee@ZlpP#hyrHMUM>pezIf0Ps_xnU; zvwiA)DYUj>*qkc%X|chhAkl*`jLH+Oh19-7%kT_IU855FcPQh)#qCJq*hkM1`%`L7 zdLd~riZN9h6n0T{+aBytKAzXT;b$F^YIahDnWVL_iaf}_d?90$jQJ3N(W`>#6$ZH| z;*&*#p~~P1O63}KRZV%xk-%F1tP+J9l2aZBKKR-bU;~c@=>^2YnO|d)=Y+1vWN;h$ zBVYEKlZLUBuL^}^7Yc>TVollO%6L((tzgei{RPj7MKU}n?~NFWY`eJPX(?JA3k$_e zuT5H-^^I&1s^{p9d(P6Sc@6-$+iC-Mf%I9RHe}EZ9j)2#TO`&;ak@S8^oJc9_Ls{) z(%>Q_$VlT=c%B`rtRV3@M1SkdqgXZ8N46nTLok3W%-36#Tj>=Dp2B)|3iDdh zhyBRQzhZ6xKm7{464ojwyz&H1EW~fG7p=~~K@!G()D;ZlpK@r!ke!`3seYoa+8S4` zkB7Lz%hAVjw+nYYpMJueiS#-6Wmzp&XYGH$;B2gl?rW!AbWOKn+0<)PBXh(IHsyG) zu7?-DWjY!mncRcLLgUe9zh+?jpJ@RTC}241*jr_Km#69_giG*_wGzZB`Q`*6R?}e0 zi>JF`eJ(X>RW7Vnr?DhgLoWB=31tZsILG9u%#YE! zABh;JWkViwhZuFaO_DPP1vRJSw-x(LLZkLK%n1(Gi?-QmY1^2MbjmL}0dR3_qi0XU zNZVCju?QX425n46l5SsYsUNNs&;f6i_*Q>kjLBVCNwtW<{w|%yxR`w^88j5yx z*l=S#{pNKZpz*sdOVct{1lLdJ@<%ZBK2T>xb+Vw2W3vNTEBMS8B>%7=zDCK_&D$5L zo&}48^%lDDA)3B*!(RQZ_)K@8GLkR#IPnCd$Zy$2KHzpOeg065^w?jQAI4G5g}~F7 zIZniD6%5^6?-BaOmO&Kh=?7q~2c;cgoB}f#pI0Pmcq%nm3(E^)ZKeKp@Ny)-$gAGC zAnq&Jz$MR}g2Cia*gN;dxKp?#v}kT~9P%_S8CMzHLwAZXD4;ug>&YhhGZ6JB6piZ1 z>F5=J`b=aqLp5WSswRLf3n^4zLu1y4pMb$=CM{NQa7?a;{ucPsI$fNRaYez~3^7kR z-VlmR_|zi}Vxj~ASMx03x2)4Hu)J_$9`vq&&Eh%Wc;pemDJ7p5{{%rjFY5&AY1ObOX-r zp4uy?nfnT;-R*y(gYjSJ)aCI1_TCR$&V^hPqqN}A9>APgYAe`pWg{rjOH^b3Ji<|) zl0W*}D^4@acIBMu6P*FJ=K|Clzb(ShxPZ&Am!&nsWl62p!CL~SpjJxPpj*BZLU}h6 zsvmBeIPy{PATIL&t>|N)?#^goV%K;$t5lC5zeE2W zd?iy#@A)FtTATS>ASRe22Ajt`J@}VI2EW&}$OF9Dxgl;nnUuB+vs!^-_w*Y@E-a6` z%jP7#mB=n8)MFNw=~$i0izB_MvASnfXIE`QJw&iUlEnrBw4T%E54=_e13bD6s;YS~6IrieQ%_-%|u3sXW*qmvH zRsX;;l7Sr4PjL&Cr|P!``vvqnmU+`2p2zE#D1=b_ruYigH7``Tl>E2G8OD6d${sU5 znx7K}n4}X>Iu*HunbR*u3wSGXQ`eI7BCZVec;ayMN^n_?%!g17e3Nae`+uTXHV`XX zl?-%3;sS*)eyR*uJb0Eyb9TIO75-TI>GSV>fcjMxw=Ix@1z}rs;U%z!c-kFHyu^(~ z_`7Q199?L~*WVy5^#AG~)9*L?r{^*SctmRee1j3pqMbK8ysP%OYwSi7A8(Q9wMtlTpAIoGpv4Hgo~8t zyEBABQZW|>1Qzz8<-}s>%y`rVY?UI5cAhQygR5OYK|l$0Md|0-A_sk-P*dN+Wtv&NcMJ$Ak+BvNrvfC117th#4SMG3 zI|z!U+QrmzM(6A5hjUZ&dO(n?aACf|^Ay*<4p==ojL{$~2xY{#)zP8WB)V)0#_dUK z7LD1?P!pfR%nb>(+GUU<0j88KU@vcM+L!cW>a%5$!ZXjCH(;nmyGJeE5+(PFehGgT zslH_dHkJ%S@|l}37T`=;;pD?kntRERHfi^?ga_oabnl3V!@5ppt&ixLZ=wfR)$G3I z7K-=lT{l3+Xs5BF{*1(hf|P(eeCSsj_jy+8AK~6>goi6B!1|s z@`p*yo6anPc%kc)B5p%Cp`k>cGKYJu731vMd zUSkC(>sChcyIf*QwHnLc*ma|JFZ|79ynCjxGXIRrKqjtudQ(KAA6z~;kQRbh(nM~f zN4fEeN9iiWJ0L{u?=kt#FHt%_zjuiCox9*g&**__ZK3Hb=33FiPRW1mX>*JZnTKoH zqrd7y)b-%A?Z2wfE!kk;gy{x*s>$%2&Ilin3Xnh#XvC@bwd%EcFD4*QQZ4qt8t~)^ zsT7X;-R=C5pnx}z~msPHVp zqG=ObH0kCFRs@hgZf`~MT~UzX&QXeW?b}$4To-1gKKub_qX4c-L+vKoM@Vjv`kq3^ zF0;qcp;!GiPxP_x3-0pz3=+U9W?@Jql0eE;)de%$E;P8r<#3yJh_2W?h2+1G zz#B{`XJJ*JtwkYigK2(>+TXF(wNgJ+U*`ErnnO9V zURVH((x&P=gCuBoRdIP!o;dI!Ue3W3cEh${4Q0dZFGfQME({?pXn;^0G;hKwj>b!yNN5MTbm288bszEI(GT_j;CCa4=JO02*&iul;U=jX#-6* z?P_wzdkQc49l-#`&1F%$l?3^%bEkHLYGkY0$k7}Ip9KceTt&k~3gLNr24tSlyjhYO zu3){%2!^-aXbu90&U_48=+U|G`tJ)4|9UMz1_dH@!4-j6w6XwLlc|RF<4y5MU<(rb z)gb?gX|Z;KbURE(iJcRYm|Vs&hC*LvT@bhJ;M%V*eKE%?0BHA;w_YNgbaH%%)zIRt zYB&Qg^nBaOH1cMGdA0a~t%IPqI!9VtnhHfKeA}I$F&@5KSIxCRThy_Ltw9Pf`8V^( zgB`cE+M=l*wq6R-!_?);*UK1JMWfvL+Kw@s_mK{A&wr%$`y)m!m=TV{XF*DvgVMG* zsBHQW->OjY9yFR^&kG85!S;2oofc07)|1yxf8+(}VC2tgx zzlyG2n!3QYsd7d*n~Q6A0By%O+?Jp$!t8QOSJZw*7&+}0NUfizxyQi)t@744UeG4{ zvLj&O9`F!I_w)N#hXuM4%enF=_kV)HFekWV#fyirB)0dvWBYcTjaE6u513KqJ)>wB!swFdZ$5|YV~~WRrazYjYm%g5 zv`O9~3gh;xVV5-@6AC-0+jNLvF58JQ6c8!1q}%xYx*>$QcSFq4nCehL7veH#Npze+ zLeZY5O&57et%^BqT^feB+)Vi_agZj}N`|Zw>TQ^N$vt`BO?I{PaR`me^mYnr5)3ur zfK#%>ptLfQe%@M2d)|W|011D}i#^eOD(GepFMH{@j30-b*b$NeFFVZ?fazToIgu>+3>};5BU2()iZ~fF7e1#4lB+*<7WOx zyDQzm6K>MM*c(SC8*vzvGco~K+r67nZh)bbbv5=)@*3h_Ir`Y`NyHE`}kX=N*$W1N0d! zy>@><5ZyF5UtB!2_*JZWc*}3=hk@1r`8S06hvvL z#p<_5Rj7cy0R6reS3-KB|F_D&A=5lbvkxE9aS1q+&R2bGFfaz7s=8h@igwv$5vxpd z{qvS=RzLTGT#tW#qBNJU^Wv*%Ihs8$Ioh5zmU{ z@;Q3bK&>@_>8nSjdhb2ODACA_!R7j9f4c|%v9KDWC?hM~o)*W$#f(=PZLIuSdqc?(qTRJpPNPBX4@?AfGA)wcL{J_ESB zKax9AsPoD;L}K;_!#_>MCe$+Fn(+YuCz2Rm`;3lyybckVoTVHfHU$3EH7!F*Lo(Jg zuL>0CR@mp|E-dZ zg^dEBNa{eG;4W&hm{H(jG2T}AzSn|zaD!Z!lc7IP|E>GJJCd*}WJ{e31Y?vGdli~@ z06gC)N)AQ|NAd#2zeD5{RUkoF+wS0XI&aWsi!7Wog=&(h>Nd+;Z?`msSumX#DSSFx zX{C+$@FQqjzdNKJ5B0>#pIENP&B9r7Rn}eexkP{)2p=2D`-4Nl=Im3mlDib=Ej^{P z=1O&ikVKn!rif$vmdJaW@3y)Q+VB`hy@#vvI7qE~aBTY{X;b&5zno?Hj>hxlJTd~( z5i9A{akfur+RcFIq|)|@C(QXWkj{Rrda>FSb!Kf%XYF2i>an<}#V_vmrAPP&3MeSBwFokilpJ{ohpxaT$~>-!o%_ zP>99SQw&I-^3PGr*?)t%0cuy1WLAusw~}pQTC}ZI^G>sJUzph|ATYoIfpI3z*q1k6 z^b9vsJ4yB@X0pnYT|NN*Vlk8=K8mmN+%}PZ0Ku`pC^OoW@f9k;RS}7*P)4B-cHwi* z=uM2Mqq=N#CSKHZ-*&U!wNz>s|6{@ZJRh82)xpLnzcBYCPnkQ=^Z1Y?mYS2&o!}l7+l=tNvH)i#Dkf zUe%hRTAK4KQ)1}Rag^e5lI(ivMjkXm02uo_sf%kj674vR*z}$xHm(TaxT!_%wNuzA zNg6%D>ng+@tqw)&T>1#=6tCOS*8H3u%UE;44;W58swaPcCl2}Zxe&GaKW2{0?(Xzu z|D%3IPC*o7-Pu7X9ih+2xf8jSzP#!5l=x|fyKP`1C8bD|j*;9KgV|b-M+s`iG1h5` zN$us>uZxZh-td6jeR25l^ye|O>obU_Wfim6gGH1G|G))iwi$k3Klr~?2PF0@35CQq2(&AaJkmkef4pppsTnW7gQ?&DjMRaG=N`%PD@HIOK@z8QK0#! zrULeX+YRO!>RM~KI+cf%-J zco>e~H1(aMS&eZsFnp32e2tVhZ?8qIDv(j0#V$A{P^#;Lm|d`ckHha!43i8^gSnHP16%@+g3|y-+TzArZv@OlF~&S$2N;#Zg0?1v{ds~0I*OTv+LEj z&Rc6Eea&&?SBMpo_3RBY*nnKw*7Xt@skI|8Fv#p-XXUYS$9uo@xkQ8E8t%Z(@O;yF zzxhI^6|C=yprgRpt(N8RpvLQvd-T4M=6A{Os!!_@rm;#a3K%#8)1oAEyln-+i0Uuk zfX+A&!*1m&rkV$KOEOyv^A=s6E^VXgD7t)bMTLIP#W}l*Z-IXLf41j9{a@uFfQl<< z_=B&f0rrFUKzyi6(ow2RyU(J;W(b0hxQvlemR;hY!XOb;LHYv71%uD}iPvLf^o!eY z0qEMKKcPa(Rde%vj5_o!46OcqM~m$b;1=w=!romGtCf&C&G&E|lv=7cN^-K`kW)*pi4%g+880lc`{i+mtqn9cn>D zk!-3Nvi|FRWLu(}2#3<4AIo<;7}U$_!P~I98@aL(O~-cja6sp|H5}6S(yu%-A&^Ra zB)L`)giwg{aUy5h4sY32H(sLGF+y~>x22JPvv8a(@%lg!NdZ?c8+>=t7ew?&bKU0W z&yv8EM;Qsr62lSB?W=7f;7%aifchpKAq+py1bfO12VXjsPI`6w6oI6ZOs^xgygoH~ z2hzcB=B#YZ27+(DbA*o1F*;gxW{R1`F)pTxlVpJq(P!Vz$daz#{d$d;9NI;-HVS>W zPfKg8zZZ>&T2XEF|Y|BLol2E6fTkbR^21-RH9B*LS`X7SAGD@Yp z-w8Wh>%eLbouNFRsw?g68&;uLCoD;)|zhZtAlhN&aN`v{;!K~{C@+b>zYY-*rua{zhkCW9pVG#%Z3JzqZ!-qR z1HS2{Ip?mAiomQ$=4D*0p_}L=2M7Fuh?|XcWGwpUl;ZoQy)k?FDW=PadH?k2dPr;A zhbFz1x#F@HmZBj_k|!An<^QRa??$F{D`bR#T zM2dn`{AjI}SF6qqb1{z?cR#~9rk$VR_37uZpDZ9d(bl%5ZIwMBj=?{^bm=mB2lLz7-dw%HgQfPcb^^Q%?V zU$oTp7ZhC$_x;txlXKTp1rUxcbOZxEu#NjQ=@#5c#5rQ59h>~dA`URW-ebYi7KwKk zYMZ_tJTnzf6H#l#{fi0uLaAxhm!VzA``v}Sd+hiBnLqI77m~V0@6B1depnh2i(uK~ zKJe}p0-0rFp62vcDb%@?`MtWnK?)hdHU99&wv$wzboD8Jg_4!P0O=75--|T7AkTEo zkMe9r1pK`Be3i*{bV?NUs{oK4tECmexS-0ftj98viRPOZk3YenuhOMW$>a@!5iW*h zD7|m0ffw{a@MCq6_-Z$`{NTj}3QK9gz-mig@QABvwoj#?l2&s17-I35Z|^34BLWur zT__BknvL5C!~a?69@caD8Wo!Xv&pi4r`dj|-L4Kqi~P;*4UoHOPEGG*JSvHblmy5Dt8GrD%id3jkGElc6n}r>QR2+a3kPzk0 zW2=eK(T)#KI&RDd!F*cV)XuCpCa2`Sjo2uV{S^%eK?vBjnky1Am=G7)Dmk5w%$!Eda4~P zKKvO*x$SjjVXE7{F%zle3WwC=e&@!a=Qp4A#gf4aB|62RR9okG~% zqycw|)4cEMF#LU9L$gV&){}+)`_U0+FKZYUmK0MK=?7F^IwGrL7|@f=MF{y>Y~a!) zQq&N~{xO&ybey)D3wor2b7U4tuN6s^w$u6*mw)i?KmY5PsixBrOar2+>uG$qyvs+; zRvtt_A3;E8Wwg1GPxM>bW(omZ=&7Q)W#iV4av*;n*>k)Qux%1(vdBKkSv5)fqqk;> zgJPNr0UB4*f{ zho_rRRVt9($ zMlo5?k;4-wqd*;sSc|OF6`_9>y|tLh+;KL!R_im;uW-zkm$UQ& zefhrOUAln|qJVY8tk&Nj?17q@usqT%R%!v*po;X&3%?i9A%f67yX@2sOrsTvpPmI5 zSqrQDIIci}!%06-$2YD@gj9x=yU8aM-g~Lb!B?e<_m9^9)BnX%LvYILuA>)K$z{`n zKrn#n^z5g|$>T?si7zDsQ6^gsq?4vXYB0=&QZuXgvX`^On|K|&A9F1!(=t;sgOpDO zsDVl$pQI;hR$jSW(pZq!RyNc59cWe2p*Oiwteprp?D0ErtI?5rHTn;lKXm5SPeHFM zuD&jmyw~B`-A0p%(SaStnLfH&yV|7!bYbk^UPhDfnS-J}AlK0mm)kEHuAq2RJcDAX zrz+%xp<^=#Fp)U?i4eZ6&+ceLg*BJK4ooyKWYW2KXH`{Qb_pYQMC8`kMm#NrAX7al zN?iM>sE9BbI@DwR^1Oo!m#ssy!R8JqnR^$ke?iuT9B4Qzvn*N8&Mn8o-3#S9lrev0 z3z{#uGSvogr7%RP$mebanF58DhDdw3#5Lv4%0zxsB5J3wlB3)_dUf%Mrw4?{7w<4G zN6FFYemfXEDu_Y`$kA2++FP<8-RpR2ZBpdJP~ghOI-wJEoI9?Yfua=(La6lul$c5u zCnmC(;Fat~>*l%DG1jBU5aSw5?~iW?la)A1{d)b-ZSDN|*R_7s89~>U$)G^+g9%`m z3fYn{i&G5{xvDeL6Cc`YrRZOM*bI+h)Hu1RO=y2|r%KU`qYo2I$X$zV?n%_Ov%ZuC zB~%99de+zSgOx~b=+B9IE9e1MCJH#pPu#*Q!7{&lyq!A+`|7+rvr;HMqswna7;l28*}AaGtAyKehJrbee|60Wh%;i z@(<`uc;x|Ip#A>5ZFj@4Jwdy|u=}591>z$s+j4PDBbe?WA5SNC9f)VV#Q}y`oITl4 zmL9lRbT!%{V)_^kEWB4QJgPpGOmB`Uj6ZsGjSuq7Sgu?2bk^OZ69aZW5>;AF9Q2E` zw}$eP*TD4+n~S5WhnM089SIV6ET%3J;`=g-c#XA-r)049@ieinI85~EJa1MCoZf^< zq*JSi7Cz~QhTQ6i`M3!8j=H~URL|Wgw8UxWd8Ta9h`bexpOao23ED#r<$|cJ88Q=X zzlXoQd?p#)P;$QDYvJ}R8xgLI^7Vzh>(*LI@w`#kNG*)G7o}mz$klYtgJ)BBiN3_OWx#?$bg-m_~=0DB}RlG_&I11mCyw=`2&`w&hc$p zlN@=nzQ#Ur4lzxN27V=_ImT<;NFjZV4u^)7_#2Yr+L$~#qmOdt^_833z(hrKI{JQb3#rSz z(5v#tdo-L6@xPL2`Xs=z^0U&JHWDoFo3n%$7w?OR5c8UPVn<=_Ake#yYx;{n{lhlh z(0$5uH$lQOnfH}K>S-ZHu)7W4L`KnOrvnyH(cR;RN}Oqvn16|}p^jmM5}CW_Ns)NL;G}Fc|})clC}++daM2Ngct=MS^OhF9m^a;lnO&?IL2# zBWBTO?m>#Fb{dW7mG8#^*}afOqp|jSv9A(_6i(H@lT)6w85~jpD`h(7Utw1D8R;wL z|9V29FTS{fbfvm7;Fck`-sA!>WQmG5H^>rW2j}970~wl^%4%TxBR8#D95C`yIriCG z{$7fJR8Cu%=z4RB3d5}B{GR-|){7Inn4NO=p8J+W2@M)L>`LxlN%43Eo&6eY9@Y5j zr_&IwER6>m{Q?<5_6AYwS(FnGGt*=sAX z5{>BZ%JLEEE8N2F}O0~`r`tw*&%rQgp+n< zvUgIgvCNFo(@#tX{JH=Lv>pDwm3PgzP9`Z{gy@BK?W(2 z-4nY|yN-yC8(z$Cy&4F{qx?Yy|kk+dY!@BQ`l1^2F^>jiK{{Zdcwc#~hWjiW$^e3%GjvsNq+ zlqyPfxVX3~mM9Gztm}VH4E6F6Sva|if zY&W3l+=DXrUzdP+J!V#M|AY3G8ycuW0=oTfni>b+E4G>;`_8lMgy8|K2{W@GIRo4X zjPgH=jDqOpMHlsT=sch;Kr5rWW?5M^VYG=TidW)&ZJ<ItA^i<^Dk^d#;yiHy8^=`D?vRu&D#T7t-M8f%?>PF3tv^v+`|r;YTmCi z=UX=Tsr9uL(v?hQ{a%`r(>6g5cEc!0Seoh^KvPaqXIm5_#SeyU-mn2putl)km@oay zqvo!1?kpDjRhP8@hRot;XD5C6UD}t{w4fH5Im&ojsBC`=k>*F0H3hJ#L&iM=N6(N- zyLu2$YAfF03Yr~jB@*WZ)03_6FzWWid$}#$p~Z7t-wYnca_nvgMoIGb$iQ6NxnHQqiufb5U{*cFgHz&3BO>mIi~8Hf`xnD> zruT9nisSktO5t#nVDB#k+7<27>j0kfrZ}U1{2siBB6hjXpShwL_cwB*GIvS&IToi) zr;J~937>E*xaSkP<8{afGrr@3e$VjAYJI>Rs9~X^&`SCV(SE2anRVk*IP@ezW?Ogi z8x>gSBY3wdm439MUM0M6*^Sav%T2G3&)=kW-GZUT;`I)vpXmJYv}X+~$i&+>3qUS6 z$~9N1bsi=g8yQcp6h-bXg!35rsqv2Jg`nf8kPc$y7X`KJ=`)xrTb+b`@@}PO5*@H3 zQ*jcHXWtyods&t|A_ZWsgUyYWfx%{4+AU}sb=~jO;``z9u#N!UIiJo(b6Bx(-PyEV zSau)~>yD@8wD6dtZ-4?o@AcF~7}^>vTCzkitdkp$P+WSV9@9kX-D!1R;cxMbd>?TQY~Bcr+q#!m_huv}P@ z)sb&w>o?Z`tK`mMzf=WY+yv8HPS6-Kw#qzC6k%RRwkUQoEyk?|43(VUff_t*R$HTT zdq=ldbyR@!o1|%C*k48GB4h3JDq@jJxveHndw}#eA7R?o^SxRsJc0^= z)6(@nNE>vZic+^F8A^=x4IN$w&O`Y6V`0%xV=^Qma8-2Ot$qMCK+3;t*Ha}79NlFU z8v>{S|A6mA%8uXP6NCrzeWKY73Ln@XY~q*rgA&-*2?vo-j3r*STjt$G*6pa`xSb#rfR!72K+s?! zh}waJYsWf~0#Lv>PK$S-K#qZ2j^4}5^ZW9{nF~!IKe8`@@a(h^%VKqC>cDtEVfJa_ z3@+2KT_fi4@7_M8Vi$4K)Bd3;>Q!@K}V#H>zBtpLNe;3YDDU zIY5ZVLNgRPa**~>ar8Wb$)^CW`uo*0EH0PvR^z z(U{6-6BUfiv6<#o?X0u;b_CF@gwPvWBGN&xbgQV?{xeXlRU_iy2E!mM5fH1tP2^6- z9?M~(oW6%``P(!_bM`Y>~rkTbnB2T}$0oju_m&p%K_ zT_@`Iv3|9HCha%iAa^IY`N5~o^imV!o}clFbX?@B@+^X-(z7;Sxk z2X3)@X+VtcpxrU|oWd&M1sa&x@5MvXFyyR?%ihham4k?~P*5CJ{IN6g;;XI|7PZZ)(5m#cFW8G5an$xPrL5i%& znO<*ou`W0DLp@sO0`n4R8t*#m3zwf646TM(7tmOt)wTZPwgX zIDMqN&2k~8rul{#HR8W&{?tqIds@0z-f($`9bLQ=bU!WL^Qh-~1i|5}I_4#2il!=( zb_Q5X6AO-A5$eUi;keJCE=FDAfdCiNn6DBxb1KlBf|j(#@M5dBHX$WOr&YZdEq#&- zarpK#g2(|~;E_&xewTsq8Ac-2yGV}L%gd)IE(fu+8# zF6weaOk5=Lk}RVUe6Th$FxW;kf$NX3MK^nr!~g?{AFc)4Vd+iWA!WsZp38)wf5`6)?>J!taGlkEFEw?AYQ!JUl^(Y$&64W+IYsxSd_ig zS-;;4)5YH&n5r*c10Z7n69&1lxBe<(&Xo|fA3d1-hi_V_+yKS?)toX_P<6h^r86)` zPZ$Lt;3$KyYxMzXJVnC=xLY*FtU&ewl@~Sps<$D@e;8SgbnZ6V{Co7%JD!kqhOliD znTay8ujAa6B@R;1Z3xP|>ZsRekQGC9QL#s@^~qNsdYosCLgf}TGCHekyz)&70rVN7 zn|QJJo*0p)`SQPCKTC*NIw@U+R@ms%iA14I_vg}`r#BzjHc4K(Q zvA`3F%x2u|x)BXB{rK6WkWAr1M6HkrfMh1ltn4kpTiJZlD8!Bd%h5tQxFHA5h;J)`n(;Ao|w^qWkMR5kl1AM}_cc(W&r zQ8=I=MQ!(dSQr+=DBIf8U(6hE4ERi)bh>?~%X7lsbOGzjUq`<*a^mgyT3xMYoz|$W z=#K=H!^p*lkpbOH&EJhuZ=HLBD56O}S( za^Q{Bd|7=g1TcTVp&?_;!xyV~#pnNZl!XM+AP&mCScdo%BO5szOjm0K2jiZ7hkNLV zG%$2Lluj|R#7z6s6Fyn;#yQl{zDMFXFPNCxW1D~n&XN2zE8q@v^<@YR7dtVC^#)#z z&y(6kemc8ak}nF?n(d7yaq8v~zr+W|Lcr&=_pdGo+Z7yok`(<<1)7EaWu4}_e*Bq&ex-!QH35(Z%Is-{|cVsCq+%@;E{#At}p}O?8O) zS0}tZXpi48i#KHsg%K$bcnrt01drZ&xRigTBPMe?>WeEFJ{fZ#r%45^p9DeCDl&P+ zXE`{??!stLbCM_FL84d(GslW3o!arC1FHT$M?}MX#Y%!PB;Te^P-hI%cLUfH-KN>o zIscCOZhaa_Z`PJ2GmU|*==-Qy63s+PWN_WcCwH|7alvR11gD0i;(G#{{I@JpEZ5k2 zwN309Kr~;J6ePMY?&Rk#`ynLK*F}7a&@MuPxVNwR|B6ltJOo@W zd+AEU8yorsR>Jrz3^T@qKhTv84aiCDHq84al)o^h(t~2pr?X?229dyC7=xBh?6PCr?4~vt#hCpiq5p;gf{GpOfk0B-W$sVE&(6+UumNz9 zWxTvOINRa*&T0+>wo*T3()uJLp?_?sS>vITLY?4ashMm1we;7ei3>!RW7l?q5%+vn z;_CUg9A`_p%j^4#Jfg{k;*1z-NETLiq}n zD|RySt9x6fdD+fh0$KP9NsRXzuiBdxRfA#EM5FcMPot#Ro__m?7i(&1T*Nkf(p#tT zsS>es3{z}AWvxun+HQ!}ix(cGU@NjSezv0(2?wWo|2Z&!WM!HMn~Xt9A%PZx$LIvj z`4`ZP%i;OM0bSs;ZY5*u?C+@j;p^qbfU1PW3pwy7l93;DvcqGEid(Ww3G(nxS{Y-( zF)S?k3-41TFXeUMYklGs=~&ftiIMGANmFZ%n3K#f6a@g}KzmX>R>!;M2qoxM}+!*#qNFPsLb-UKQqwMX2 zLtN)3eV^AgCNtR+fGjVB0vGtWaNKEbFhcQ zD0=45ibtha8lSYnLedvjL49Ti2$yrJ57S+^e7`rLKsVgEeE8-BpUqw2qki*<`CE>@ zSNki8qm`@S4C8ZL)u!WHYhw1Do(egkGUO0{vY2G{*hA${{!bp#CTS>ATmqs#r4`(- z2_P<*3m#(s&Dl+xXs+hAYVk)V^Yz5(!IX5AK7sqzvT=Tg{;%9hre_04>bK{m{a^l3 z)u9gY-WxRKfjKkgD4>U}8^PchnqtdA9sb=skd(jWp49ez@vEf~ySqd7f8(EGc+K@{ z0rw<8?2&a_=N!@kNwC-70MJ=?YPMC^we9}S1@G=x zkmeFb1!lZ;82pcXlvt(%VKH<=MNadu|NH26=MAke)sSyq7Xk@sk_cb!JeP56Gn>Q& zTG=OKUk#<~#syy+6JyGbiLH&cn1ft``Ee^2%T^Y%xkeoT3r911vi;TIqKy1sq_8OO6_6)URM zC$!U;+*Om0EWaKqF5mp?3F#WDz^(FWBbx$aP8+^IgK$>FqS(XT%5;G-Lndy0FdWh{ z8A49|Sz_ilNEFk0xA%tOu*fjYro>5QlkBZ07Q-A#@7XLUmb8*?G-JAcH%*_e$ejru zdNkY1Nb<%U#9Va52~)b^3v{;eW%nxABI?Fci4(LNC5g&8lAKhZj-tixc<=wt@T_@= zO=90j2{qtP6G%JS|4iAJOWQQR%k)s>S`WA7I2W{O1h6d~3eZ{rPR_(-Wf6$U8_&*G z)Ri(tajl7<;|V|E7brX_*HXE!NGJBaJz@B$=W&twOoOlF|DH~c!}4*E|3I;(={r#K z2>BWA40J9e18Kc$@`(4K33x7-JP_@jt6@aOXZfcMg!W84=`Ne7m+4NEG|>eo5n+L- zY!Tx}Nmk1Ac;^I^4q-fEZEnyv5`!|v0#2#2erQ#MqGu`W=w;I(s2Ok@{%!7>h4f=* zMdQN-CiBSt21E_qtSk?-Ys@4?Ak4bBw6Qyz9WkW^AOqV}Gda0M^xpDf*_=LiJm3!b zBVR#c!j0ZWbkFjA!lG@^ZQ#h>38+B*TYR(SA0gWCY$055aMJb}6L^L1-bvu2CRWV?A}7HE8xm5GiH7 z7bGAYck|OD2PG5oVa;GC%h(qn?6RM-+I9|7df2X=-z--1ICU&Kwb*PBko#@oOS!__ zhF%gFadyq<3zXUEpp3UmefEYW(GZ<&DtFm}-0Rrf_{9FMe!iu9F(vOE7ef#sM)BIT z;2Wxm20?=8Thb0Hvp_hATf=0Z5WmEhz{L{Z+9h|^4tVlSmPf5ew|1``)<|mtH7BU` z;>|`A{Z<0$4oj>9tY;gX%|tE8^aEBqc`lpQDQ%eg8IL4Q^M`q!$hG zs)zj)y3Ru1bVAp9cfbdpy`>HYk5lyxJ<@|`!CuzQ&Pf9IXo8EtL=GOluZ~)N1vf0?R{fd7R2N{4r}OTh0Qq_Q6n~j)>zBBJ)tJILC#&e*KYIDplXN2Ze#7P zme9a<58-!zm!eje>)ONg*;27;k3@APABzfBPGl1i6s)D>8lYuIXMk|1t6i4jB4qX% z{03fDC{QRdD0YZ~89cdVBxo{79a|(X3;CjuhmXls-NOJA1B$ov z*U0H_Y+0S2&v^*_3SjvV?|#B6<^8^xLPF5zcjAghp7UN_ju<2#$A$1tCMWB`C(un+ z*$kDH)KHED{G7Y+CWUw}=Z#ZqjS4X{{y5u&41oy?YQTn{eJ><%}ldE9;Ld$IR8Z}RACT1`CLn_u=M=#E6 z-x*4ns01U^;JX97&$0mH2~Su2ZMssu>fq8fX*Id=pGykCTg5E|lG5|6oa;K~Hkg0T z?OmimB8f-)SO4uQ7utvKAM?K20#6^kQY78XrghVSsm=sJ^H>v>d)cB;$AJbheCZbonJixC{B=}|5a174=M-?gQq0o zaY99@3Xry!3Y}_|#NmWj_6=d`78kp@saDEcj}~H@!+bRoI5}|~ol3#_UDq{{^6eO* z-1&#H?&h}{FcgK6gp#f1u4m}kf#kKssZDibFx|?U%8lgtj(`80%8u2zmV~Z)cf6vV zX#u#oQ;V%oH+PvfS#D)`(Lzt;jFCgKTn*StT7YNQ-u#Dj`&b8X z?){JCUEb<#IT6M@&JHLcF$IO2wmN!q9s%Bp2&NWym{X?+id}Bq5a}MstoX>!nz#-U zajT}jy>=~oQoB4_3v6tAT@lD%3k576B~l7AnC{tI&Dp*1*NHEmy;!mWxeTj2(l?Ki z=i8fjCbdeHZG8me)BC!JkYXIj65-IOiB5;Gp*|c5usgHfjULJJ$J}YhG0_#(56r|9 z_!;j1({;<0CcfN`;i>8#8?j6iM=Ur`7)+2$JkZlpI8;iiXBix|7*>nYa}+|X)HL9( zcD$KBo|)9z-YbytkJVl=Ni)65jilu3TW@~HYV;6x81XWUPD3sL#sfN$cUGcb9$z8*%}!j zLxEuOx^FC5G_xM}{Ug3%A8}G>3#L@?(^j*@rXu3(z`3&W>a1uaDkStbyLUB8ZnxAD%FdD5>tavDf1HRE(gpIx=IF5mW2prpTJ^#-_gV; z%kw*J1e|8jBPzGrI%8%IiP~v4+ky+hI|+OKd43FT2}R7XaAuWKgIx-7K&*#XBZkrO z7tm^A^5%!0TX@7Q+!HNq;P|sn%%Lfq_gcNI_5tc4mW~jwGy0XRzG*4{S0}4sTmGS~ z?O1jm#sRH?h30xR-^E6TP<96F^g?l&4j@=B87UdhrtCiY9{NdFDc+xQJyJT-jiUCr z5Mn)BNPfyKT5bqWU-+Z4@))Qk$w7#$qEcWiej%9VMle`k&uxe^M>oqouod)_Xjuwh zii!1^U_2D)0FXL!))|+Z+7JV#F#-iJww-9c-ZEyb?{{DFLcwbg9%dSa5|oG>WFpO$2KjV zLFPH@+C0=K1Up8ah-bTWbb%d!P`_6T`A?{884#xAltE&1JvUe_kXZJhAe%k|dKSn| zPE{p10ueze)hSckUd7Z#@!l|8sfN1V3O@LQ-hlh(ugg|!T|*EJnkjRm{_xW{AK8;r zBLAjW#D-_<+;wNEEiYmw48QOrfuqv**5hk`>qBiY&gr7+o3$t79*uD>7(TZfld60K z03h;yp|p(waJyVd$DTUrEqc2x2({0{LArrcxrd0HqQjvYG4vp)5pxgA5S-GfNO6TS z+q6{h39ao{Ft~Hg>uUv!Wu)j}HAC-glgw%u_cXh3|AF&z$`uBC0$_HrcM%kE@N2>` z{hz|y!Zu<7^HgRdT{;@17;tv8Mz?t|*Lwhd@7pNXb9hn1yT4||i;o{L1q_KTK1{98 zm}oM$@5EhTv;Hv;b1)>I*(gF010Yksse`_pnM2M+n^m)XitQq%5xhQBLr79MN9zXme!QFb*KVcC^Tcyz(Tjw>#-ZZmgRB zu4tE4y{Ymym#G1NT=X&{W3tx8oqd9z`L)J__4DbyJ8{V6eW%C@qyI$i6OOh??aS$V>H zAW+<8h9Bw|!||SQS0myKWRT){i^KI7RO+bk*X3Rj2|+0tDLDpjO>03KdfO<-ADJqG zH5yEKNlabm#gk9Hz{G#~0+rEDV5J!|#wSq{xvSruaQ2m@K?q>$wHgXuAZWzcML?5= z+IE8Hi@!q+(<1M-U|(jSI56pDGM5KFW=?-zqy3lWYBA?1m%>@%PtCB9{?nON3r{dZAalT!tG)aR ziIkXjrHlc|NPD3aA#~fmQc1wxqmf;D4-&+K6mxVWY@760u0h$*M0#WA_9#hqzIW0V z-zV41KcjrSiI`Da`6l{M)ePp6tc9u0+5mD$hn{m;?ta7%-+j?g%O&bJsM-W z7uEk)Qv!0Y%@bmTdPG+)>cPOo#O&sQFE4DgoXb###tbd;t7sK@#}x#^Sn%gbG#X9D zwJgFU6;+B#KUE+=EB!4&gCQrC3M>BjV&NF8arB**A4<}B7&bJ=hSo+*U+7+dk84>C z5Esy>1C(f~HpZ5^ueeF}uxe5K({@}>&5(3p3?nAux9y_%7yObSmcP@n+>^8aJ%w^5 zb={uI0OjCytj?B!oSdz6K`RRLL))DQ^6M>F`Av$NBv{HcsfJQ6AlUxc$Gd((J~5{U=%u%|vWe$qifQ*=nY zEYQ~YAqxPZ1@;jq0InOUUsn|H2)5LzR|xwef8l_F+|L<2+6ZoVpBzWZi$opIL-SSz zLoGkJ5&RzfspMytxV8drtY&x^S^VKW)nC9 z>TFh<_y{4CvQhj;6j5)7!GRg;h#8$R#|JQXf54RX9I&#Z2##^ww362#JDv1%mL3if zVu5S3;r|*%ZC%%t!ByYF-%{o~Go0qs!?@PV`~b?n&#Yr>DhB9i$pS|MrZ(*;WXcX; z@2sT1eX~onk(zSB4tFmiGZt(i1BB2D*z?+KdywQmpe3FE!t)=~{>H1b(V9WRlHZHs zDszhA5ce1wxponwm^QD;9{|R&{eFVMNhh=zY!@EUJXP|fk6wWcx@yt7#ZjwaEuKVc zG|Ka>VNM8x6uEm7WknPi3$KYkaElQX%SGG>v!)WvX+6!45ruS1^wwvgWmhFBX1X=@3%@?Ki2F%KST~5wqt1KM z^uQ}nymG|J2W#eJ$vy5|pnVMm+e(5oUqbSs&bghPD(Den-I-pL3e-tUm#m& zi`sp|At77nYFY>bub86+&O%`r3uM@yix^~?#we+%J>;B@x9gwkH*qHC_M<=qud?tC zSfQvP?isYHM{fqR^z37h1|-f{)~ENh*Fb@`;%(VD7GCL*J8Po|fxvR3UBD>VS`pJE zX9gHTl;e;o)SwHBR(i78N0HIRFVxSb1GBfcyW1MeGEmVy0U7}T7FzWNW{<5S4->(3(yX^1scM6vrX^#Y&xofD*#tyq}$|6AKFP4Y$}sGR?PU5sArCr1LiN> zkS5u>E5v6lZ_KQqIquEVsv1cDnAa@z3H}SKF>c03$(6Zp|00q_GmF14B~yvWY;JUy z4|3CNdX05FP274x)rm&RR|KV}{q<1CpvKFA=|6LXL_)(&yCXX@qb?Uvqq%?QP0^yM zBfw+$zwYO?)eMJmlk_?gE(eJzMtSWsC!ogLDCBH+L*M>0fI_%a&mHUfFP|RCQAwLm zjk*L>3zM<%d!|--Mf>rsAgSlvWEsR9UMEJ$r9t(v42q<5-<6!yWD^s!m(C9cg%8tA zg6E%bQxK%^?lYm~$~igAhKs$zLB-s{=y>u?yMw2c$X7iJS>flk<72S=?%notlWwtl z3D6=`q^1yNDg*WrKcF+)A{rHn=E#@Zd**b_Mz1Nsqqo+dR=~&Q%jbaLtXy7<>3v``o3SBWDM*lb#JHU=u3$Y-mMZ zVGUck-xa}q&Hzw^GY_;_sMZBdISKWuNslX6D{U3cSpFtbcr%6h%>iC*aK($~){QD; z(Z-9n2DL!d)YSa_-keAGqbyoKz+8YRSUqrUen01ljay~a?hU)kNbytU{FZXA{?{#a zIhCc1@ZcTl3fb__uU#TMJSpt={<74b1@697l_Zq5cy1}S*UU3Rw*-;|T&ghCT<#Tr z5;g$TZxDgH4Z*TFP2%b~jdrjhJ{F7buS~VrdU++78>DMZD~d^>N45-TDOmdxfM!X& zT2Jn?m;J!U{wgZ;&Ttz$+nQC1W*wO@V$q%#Oi&WFqxM#`-Uf{%g#VSw0pCQ&y!5g` zUE{eogsJljPx1l#SD4XO1i(xLeB~6AO&8rVq$0hFx1zh$;v-yvKiCy)tVIeoxIn9Y z@Bjjq9l=~KW~BC&4*v&#GLp7Rx!z>D+U(<}c@ZmV;JiG-GAl8sZg7p2T%(EbsoNsD zgW%72CJN!xWbe0Nx#r$trgb^XZDiVAB_sI$Dh=R*sWyFht+WL+Dmp|DVMJiU-ukh7 ze+qCdiWO|s)naJ~R>8{83#t3vU~BitZvqp|&lg*08)52fz@&DbuP&J^LSI0);rk|^ zHP)#5Kpb`;6MH#1M+3f+MU?|37vKzOXWQs6rMVH(K^j*L%mz}~Lj{-omVV6cuOEL?Up+f)Nf)a>tNYMEIm#oG zh?t2{%Pq2(uSE2>%AG?xTO|j?G{IG+R)>Wt@%-Y6qb&35_n963nUjl8^|0w%?x1s^J)@}C#davun7T4}*-%rv zzRCe3@1GdqL{|t*NH2?%=47gezx{fjiP|xD=BGK9I+AM|m7PNeeBMO+y%%If&<;9Z zFFi9&`b6TjmTt%gV5)9Y5=?JmT#vjNJTUQmwcx@Z+nHJtqj+?*9^6dZrc1p7e`N|# zsX`#{0n=*Azl6SPBe9K{eL3{6J5GA*mG4o#=eHY#)B&J#IWSM?Rsq8E7PK7C1H8=rYb`|2t3q57w zHA;E`S0g?O43x0sI;L5DLB_AkR#ig#TS3b1~U3_8q+&)?!9JvCEe;$L%2kFgYtW3=|To;Zo-Qxt? zTZm(4$SHyv0w7Or|KO9~xpHBW=grb1xD;hlV)U2ZcTR|?%GXzTD(uT<3E_(@X5h+ zb7&q`wUR`v@QzN;vTS+}=AdCad=8<*lE@T6owq|caLZsUIlhXPEAjDd@G{fadT%4f zA^A|#am~@J#TD6|;G_VlfyE>>5I2g<{(Rt3n z&P^KX(xO>7P@X(Lcqu~hWT{Sn*B#Ff`4%#FzLg5S4B-PrKS$j&p^evpKDyXVuxDAn zz6qs2?a}~LfACR+0Hro{RPvfcBnU=_F_LoJpfg5^k^GE-841quQ+biNtBJBhuy88x z%j)lF_h;?xTfBF`<32E(nC$zw!Hb_o@iNtR17FHzj%t|XYmdqkm#uamj8XLv4im*3 z=~>HzGrbPS=e^8qAqit|x;h>CiICR8`AKEi+ zP@KhL+}PW;@4PV{gkFi5fB4Df0&)~S(GQit8KOR%6Qy^a&u^&Rq6oVuWQ0ak3pCK?=u++*J_j!3cL4hDpPuR3nYK zSz^4}TVwg^!o%>XpcTlpTgf^YkZIO3Ekkg>-uY>^38`t~4x{cY<`AfuX@i%Y;7=q% zs?z$B=c>R=8oK+{s6hw}&sW8ZHK)G!>RDl+W8ySx$+>mWx3sP_ zk#DS_=;lsyu41cR-2SfFA?ndI0G!vI7Zn_D%@xq5TqH?14tw}`(3WaIzRkj}1(>s{hSEh3eI9uNK`_*s zoab4cp6U05N$~L~|7w1xU-_nW3y$!(SW>GTuO&%|kd-OOL51kxH81wY6;Q#9(*=oq z;mK{GN$=W8d8Sh<1({f67h(TpB`M_r6rK1 zEiw9yB#kcU%K`yvYkJt|x7ooLim~Lg0<}7adIwK*Imye=YSS|zSE!@+JKKnQHG@+- zA4ivz2ig}i-stKiWoPqQ?F-(N*q%`aJEg#wRUP;0`OllJ#^A53Ln(hHVJo}F z3u5v*8&w!$CgjhZNL*|0w|TqzMD3Ce>ch#xx78Clg5~}KC;n$YKF0Nes^n{d8NVB7+o@U zu*E9YwHdFi^pljyC-w@&Sy%|h#wml-^pc&unOHbMN4`A|G>jFIf|y|r_#p{9XlOb> zn|60sR$*#(sYu3!su)2ZV?A6 zuL{iIEkWa$5jd_{CHGbX3;4vgJxvv}^*RA&o}@#-j4768@FjXQKtkKHTb}|txgqK| z-1|n&_Q-~VsbY7tU@62gFV+|KGk&6@Q1rCU4nTCMBW`5S&IQFD^i%pOl=JNbT zJw<4K_tC&Wq0My(6CQx#!Db&DfI26a6f)IioT36sEJx46Yt~GGqpXtHAL)EyOgK8v zdJanm;a2M=Y97IpAg>0jxR*xMw{owrGGXAB7q6lPC6xZF06o!-qsRy+DTtY&EAun5 z4nhvCq(337yHKO|m+Y4Ph5-OHN;i$Z48i3ZYqF8$z38-uJ=}~t^h_`Qkl1*&Q2~u8 z>LGW?mSNQqQ&^WuCJ5wt+pTBBG?73sEO^>XL2o?7Svsu7B}S1dCY7gO-L!;|;kcIE zM%C<75VqBCGj_$g18DynbmW$1%erX~bPCRB) z!RnzjDV3C_i6xztC9TZN)Sxk;=FLlXJYUr%B_LG~39k*;VMHppV1^LWQo4rTY!u&~ zc|-Quy;xu87L`~U&2w6@`{OHU(O&wBY#ARALEpvUsDJjo`g<8JjxF^vbvP0>85RI{Ip7-&;a%nh~a(UB}<2jTf4vZ zlcS_?KQi=z=j@-69|Bn(hj$5u{`tE9KT@EdXl@|Z{~W||z#My}&S0IgA`);G>uLC%L>|zX|osm_0b}iC;PGo1x zojG@#a$pY>?J0+gE_I=|#J2bgG-D-?WRV~M>-W7=rH?@ri<*;)*xSH6O&M1PB7osa z&6-K`UH3Z95ysJxUpYflA#SUMt?`Slh_iw8jokF?&yXoPqs|gN$}Sg#T^}MVdLW0) zN3uX&{jQ%I>sOT=za|3Kq=WeIwYvu?A(r;a>Qw{p_01~N4_=tr;eili7SPaqwiyGCaFv#|hr9biS!lV?E$@!{^x-6CJRQ7e~KMwEKNX5Yy80~Vn2e-hw> zoNqOlPS-IEqrG*7(AO>~9YaR3ZnsL0IrtI}>i=VQ0T~MXQp9rVvbQ|$-2^}#WG(i@ z#k@@0wf-LIC>vr)POT}QZJdA{v7370ZJa?p*(&^& z5oYgqmc98vrVZd>w%oi^9ga}jSqkfBElpq3smKJfVVGBwHVPM03|ssqVSPu{wB1BQ zQuIs~HD{|5_j9CLGRDMehH+JvvJ0iCeYKUI{7Sa}d$M-zjw*sE7VsJ_vWY5WN{goH zx4W8paZsvmR+4aYCfstK#kfm4bCS+I9_Di^%zMAF_NG1T-y+$6hPhXC z?cy-GdkmctEwN)arJOeNcI-=oewfyG&5!$U({o@j;ZkLihv|C~)pfc(E89Mx3L2Ju{+aEBYF)Qs5e}0HXUyjjEq`&rQs21{30A6EU)!BOuJ|^bdOCj zCL`w-qedE|lF%mT64BBtI1kLw82juM_$3oKoh%#uxa3*3;BbB;rd1JcTNwP{s}-WE zN))ia(n*@+SVmkkAHf%Bg`!A~T3>YakLps%zbjSnh{UwBM51Fv+Wmn-bhlq@mtHGT zK~b9ub*dSc7=;`J$DE{dQV5&^z_m*?o2_wq4tIDqckL_YUMb$m)R9n?ovd{a@S+1Du zS>yyR2lPY_IXbHe`Trnda)Y(t7O4D)ZtcW3>Pfx``xIX_iaIRtv<@^gY1GAwyn=SD!q+~LfjiThGNWDafqTgBnOx6pao7(Q7^zSyE`B;zguv%-5 ziKgg>=`H(6TV?mSz*cIQOo!*L>*bfeWu1-+*3n_3eN$g~oBLAA(Rehbh>#96|E~^5 z`R7I#>zjm*fnlO^&Yyy#j3!OQA4#DhK)%RmFOh=_i#xkEG_SbBD7@v8O*}FrN{_8x)4ZPIlJ(P`IfmuXwgVE(}N5p#gUE_(HB% z9zIIywjCJj;52o}jBPB-kVFmZ=rwgeihw^&JGWcOaDc#$M08dIjBkuJ4dEg&U5HAD@uG5x*Gv8P6u7!kCDp0LzBS)|9N0mR{VUu z7O&6vpqF&02=APuhRJ6s1KSF#JXqY4dhfUdw_b58;ZwRT7O8lN%C)(m(ro+vRM+cr zHGa;S5RfVXxJBdU#%BpQGO`TwrSt4uJD9^4Fo>454?i(D+UGc_f5NnPm#IfIVFMay zN8d_agRU-QX*$v)z@N?#{ZD)qvl;hij0+69_{uJrNdFD4=sb|!xDj(LwJ#C$Ab*b3 z0{-|ut^=nPZ3JZyVq>=XWE4litrZ!Ne%@Fwoi|^M79vy*(54-h>YHkzkOR{^D5q_wU zWIR)_B*ltyD#in00sA?3L;ViNFZSDE6U46iantAf=>UA4}X)L?XURNbf zd%z$k?w>R_R)GoxqBR0NiJd{N?6~ZWXflT5-;4BdJEP4RqFA#1a@?pu$XUruel?lk z_31^muz-&y(dW_4X95qfM1XHp?F2DV0JhCkwuENALQZBF7>`|VFSlsy4jzv^nZ>^Y zQE4+g1L0pD&PWHi@m5smr2fiFX?1!0KhM$e%YLl{Ad%w2)`J+TgHDdIT{9Xo21Z+i zckcOb@;o%s#aquObtL8sDb@;m!HV^GHnQny%Kn)cLzM$C{5BVW_9`rj8bqIw>b#(R zP(h1#u^2-(Ldgme&Z>>y7740k$5YWOGfuv6u(O(jHaqPgi4q-+z5CD>7Jv#b5>mGY z6KFSR0Ymo&?oYGF!2?|zr_!CdVq&KzGJ~>Np77pksv~ywQ!mO|(`Gq_K;uq4oEwOP zV58PSgo?If{Y@RFPqz)xjK}`)EbW<>bLwSAV@ftnGXPNuWP>WjQi|krtSHk3SBaQ3;LuPQ5iejI%Y6?&3Z0YWnd&Q3#oiBIbcjhgkB@fqQxC?`T|ITBaY zTcZb6)A5mG*RLRy(-qnK@0KzdWtAC6y;>8uixfTA0hov~;9F|l9Nx9tzaL>rkJn-I zfH?NCVMxAyd58fudF4f0rD@;pIhs2T^yT{Kw}3xE=y=t}Ps$R9D0^T#Z9Mc;i5pM7 zkdA*@;xsvCZXn&^?D3k_6!u~D5rAfUynBdUX%T*3ESk|TNo$3piA6T6fxVbCp&Hm*gD_r_(!srm>65^J63QEkQMVqrSawv!n?9$j|-afV8 zBCxBC+j!1z9qn15Pa;=9iJ;jS_dlU&F>M>9LT*A?A+Kz+Y(E42TCMLmmbeq2n(o9c z1KM%Q?-ONLrV7fJ{V#!X1%L$vI8nYob#0Q%{BJe`+aquva$A9`mXp2pv4v|AFs9>Jj{4h< z9^0(vR=^<{@+J}UkSx8{LCAkxNgj=D^4lbb9~c@NXf22IXid{Gi>kr<8p^`{&O-@?CAuTzk!ROZO&ScLF$hBp{!}zO*Xkk6l5bCa!@Mj$&?Jq`yz=gC~>S-68_+MD^?agi`0EMKtgv=#4#7(fgtTh8l8=6<8U zpAE6WZ={)2!L>=Q^vut{!>Zxffy>p#Ej!`}1@kiA3;|)1DRXsyMiqRwus`iUqw_Aw z;94q1JTNr<%*l0T4D8nbuUtMj5M!nJYyoH2__d@_62=}gNS*%<449YiUoM;a(-X-G zKzG{&X=Tl3;d+Z?-T>D%%3VDkyiCs?0Tti%Bla*dHHOHD0b>oerUaC{I=KotFJ($d zzhyF?X6i7<3A)5}lantF|Ijsnws7O-s7e0k_oI4dxu0S(4%P|yksBv8F}<{3CX-*~ zo(B@OcGP@eRv23s!Tv4fWOq)vHGI{8bC zmtT1-Wj^^AWhB+z!T}Q!X1!(=@4Gz!?zvt+;!yG8ejcAeCk+Nmqyj;aDNrX@HJuC)?V>;t5f#O$cUlbo zMbnR)w1ldsICL68XWTpaPgX^`Yy=IPVoU$jQPg>I$L26j%o?^eM<o()> z5hf&W;?CP0k_x+^>lf_n4(?E=A^i9nD-Bsn+~tC8QKz{>-S{aXEb^yel|^-YC+y6D zA=k}Yq%i|8D#Por+!ej}M+=EddD@`^u|w zoj8>X@-s5ciVy<@VPei2f{fCam$KqIIiuFo+tEwnY2+Q-bGe^q&tQyWcTfC(3kElU zO5L|En+V0-DUiWKf&0@0Ex$Zi_Kkch+Df|iB7iZ7wO5Ls01Yx4_)bDzBus%>#*BR2 z)uapCe`r$iSp!g)sycYgS|3yg)p{DS&$#?~m3~j6*uI>@n8fJpWUXsY4%JxC+$;sd z7I|uB)IoEjE_J{R2qJH4kL-xmt(zSC5S|M4$^usQiwq!3Ax6Kn7bsa7dE&TTx+~1g zbf(zIt&tS*Fm17;*nA3fG56NkRW`2qw})LpfKIc|qaxBWO;rH3~^Z*!rbqH)z~}`F?v+ z9eTx*u3)L8G=Bsspp?v&<}YC|L4A)w-QDx{SF$JHgCriCK$Ee|Sg*3ncj*6uljP_W zKX2{K@<6dB0z{0;! z*|K1SfbhM_cS)ywGUET*76&!RZIaf?coqCfI)T0XUTyALs}*OXO`D71T( zuK4<2<~J3&n!?VY`0Wm|x~r>QsYA{ObNOg=RTEdVdXZJ2e8vHNlHB|m%Z?dsUa$<2 zeT=|DU`nKI`?sd|Ew3%N*OnsP5Sm0rnt2$fpcl%M2PSIY zthg_vf7o;fFCNY+o_O|_I#lO=CkZiD7Nn>|(m>mSW+jE{zock|nEPFOM`i|AxWGe( zsZ`rX*`+OpVpJ3e{Yh3ZF;sc59zux)$z8#Z0Po?Llu-w3o8C@-)>kltXt^oFlbTCu z#$)X)iV3$yu|y{uSaD;3Ybqb3{m{b5ZK_)my6LoI%2Ght%;x2sLW9NMMlLRE9udo7 ztnc?8HE+!>jQ|pv!rI^f@sCO`Gcb)lYQh`wEcr^c;v}VXDS&{5b9zrhx0iX#9vZoa7Wg_Byi%CH-RMDTMcIPg`*Ac^Jfzmj^Koc$>dGmVM+?0wF$2|D9vcjyUB|LK~#& zm492lGev9aRvO}3i@pa1pG_gjKw1G$j#}3xu#s<7(uaT5m8JN+W3LG6_WZG5FM#*s zvx~b&aqsX8ZsnM*0_Db8gCPL$02rY0d~bsu4&iQzVHu@Gqgw&clGg{}v!b5G_ z=3rkhzVuOm{n#`fL_zWS;?V6Pp{*{nJBJ-Zj#s^04$D0JX@NBCHs&X6(_+DPXMkUoaBATa$R+cb&7yHa{CkpYRGJJabl_1v%s$&#B75U5y z4XA>b)6)K9e4M^Dc^47xCnbb+ioi%9bNN!q$v@9ct6#@_s*F3%_t=aYuo0zuhLnA} zUK(J6MU*fH3e;a4+-9gTSOXYw+VN22=kZCjb#vh;!d8^cdGvi? zS@=+mGKkFdP3&t79*!k8ZCI6A4mG5My%u8%ycQfu<>_uOkucs5vhD4qC-6!?xsKq8 z1DME1SF?^|l*cn4g|EgdZqD7pp8c#_;F)jw$cjx{?BvSxYud%Sl=sdj&myEi9xPlH zb2{Emh>zSC!aGn`1?H0Djj4;Un%IEK+UX@8YY+YmW5VxiTpRxoZ&p2KDNE{JBp=@% zu?X4h+6|pg-0HpCDUwV>S@iWacNDM?;Y;G_V^#Nzqsctb5X4xYWzv>wNz`AeIyI6^ zK>;~p>f8r5b?SZVM7@cJTl<{zW+m~o3)gJMLm$L~$N5a-acj38)a0N6or&P55DTg7`BZ>E{UV&GY*3Nk{6L{WGPy}1G=-*2eS2@ok-WRM9EEj z$0RKpJz5OxKmgb|c+LBFI3`*()4f_5sCjO&{m4PQ}wv`mIi6N(?Y zfPuKE|9d*Y>=1r=O>?D-tx`(&o1p+6DZ<>J3%zyzguJpZsZC(b^}Z$ajvWz+16wDVW}YVj!t zE-F(#So?)4q|DaolNhb1?4Dp}=>F0E^7pvsjaVJM9|IFYA7}snMDKzYQ)o6^yIUU$ z_T0)~?_n;O*S^HX26jm>jgM%7fmBn<LrU;FnJeEZr=9N`=Z2tG_wHUfdd>J*%`tH-yHXhszXPpDGNSL{hb|bz~U-SWhE+qi8$UkKhdvV-B}@5Ko<~G)BzM z*lRB}jd+jNy%!y+!DH-fn06Q{IuW|Wuz+Lgmp7d!pgNv!ds;OX-KTOfcb2hDtD7)i z?;U+c!uu;dlOeBp74E%d6-QBY)Cu=njXI4_MdMBYj=Z}oUyc8*6svxmITfcCv{pWY zJ?#)PB^c!ECGWc+z~9-y1s~=wn5H8(TuNv}Zu@FMf=0xlvj3sJLw1#z`Z0^wgfZUz zAO0I2{9E7FIexei?M?Fk`P{^QjIj5B|J89#VYl(jk1_0KPU7*B_B-nG^bN zTudP32>(ft8W8FY4Ph?|7>uPPI3scmmeLTPJ2D1ELW@oop1IBE@-+kc#58)SIo~6An1#)vS&&wt;JaM?di*_NPd#eOTGkGmFk8o8USac zApvXGOOre1hHFZyyet&5JH3kepJ~mRn3>QKxuT!T($eQR#OBM=X>{jQ4{sKOmZI=i zHm#Qo&>I(>^IyF?%;dBLMH#utz~U9wsEzS-76Y~-H%y&jA*qIruF?I}Z1^&qyadMC z?5J38Vja~obU~3`9?eT~slhs#*Y7YISRyFzawwq8+B389uQ^JWSX}3I-qV^u7aQcm zhAVg22F%(#UCw6QzakyM#jL$xR-Y7K1&L|Kk+wd}*dHz%T%W@|t0l{k(n7JVf2er7 z5YeKb_`&=wP6nJG(blvptzcMP;d)sEPI4dY%6ow{h+GLU!+AQXBg=p$*(n-`?FQj+ z>h=l&YEzKs-D-1T+5w7AcU8)gV;lO5o9mp=!Lwc6MAyn3P2!cildEsYZLRz> znB9XB6t($)WRK7J%%pVwq#75X_6_03n4XqbYZjIRQFHMY)_#p+P?4TeB28RN> zmG5W~6yP|(>4!t<@eZmG0067@M`{KidY*-Uv7gNdG6^QNG%-M7S9*%;i}9K1Uer$9 z@^YGqLOo15+ItTp_9`JMK`!!)f@;Cie=aW|C7t>`N`vs2i2BQc0@g{kiPgc0mViM} zVIY=qZq&O0u%LpBwlf%YfM8W_esye9LJk9Pg%N4{IWK;Mh@k z6y-JAvSlM)=>4gfKp?ZxYy@&fF&sMms}L1FMNQzCj1QGc;O2uzCBuSf*dXV}7&T$+@3>JPDYF_Z;tK`Vg>dn%} z9c(`PZq^`u@4SU6a#N*5`AKxa54;a<9_io_XJ@9J^bsEk!1(WNx`tOaxHY3!yHX3> z4f(I+cyOYc&hJz_Ze<-jva~R>FW}3&M)fW!hxtOdx$&R=eDke#Y&FeX;yqnj7$TL( zfR`nJWCKnPT<4>#-c;uLu8f4o47v7yqI1QMzsu8U(wKcjLcu84H}|bspWq&Vq6$28 z0s+q3_$)(d!Exep3hAF%9$!;bz|3ILg0@}d!>#RyI77X&b(+`6N`Oq9V(5&rsxwx zY&>Cn81Pj%ycXoAtB71}Up61gs@Owt%FTTwRA3dZ)|77O%E~6SKQGJfzHGh1e(7IO z+QvR0Zd5uvJE2V0TIzteZE8%5zUzWpoI>wDWB&N};ny$;>{2B0f7F;McC){%n-c7p zK~e!gHMMw>n40~&?dsOb$x%3rwv~sW?A5IuY$_e3)p42=ZlG2}AR2evs^DutDA_RH zHF4`{E|K*@9wO8q93d~%RPs`l0%=mjo7Pa~)eCPMy)@xa4E?4j?oM-9wnrTwBD}n^ zxhp^md~wW#Jgw^1@dw;OX1r+hZ65Iba()NHmFyRY@ITvLibA$)q80Z z-%~a)*+;3iwzF+0<`;keRew#RDBXY1d{#6D%ZOr@1KL-hzL=NYLRp464sF?`@R5J0 zH;UKOPfe>j@ra`f%@);ptM*1~K4tagrusPAWlG!+XCzOEEIGr_GVh0^+03v9Vb4+diJyNFIwH3&<>2&&?` zrYZ16agi=1a%JOiHksm1ad)FVr2QqvnX#I@%0}Vc8}#*ImV^SFJC*4GAoogw0;gQt zY~DI3c3t)hvID55)YTByvJP?ys{p|@ufj#odC!Z9A|72!>4;A!x6^TQOQ$&9*}l!U zjvIAHLAK4W9`Nd}mGMGAIIvP~8h(vYDqi9mB`gl{>BQSoa4e7aSLA4ilx>wM_4xqSy?{tOMvp3P1OmDM?zi5EeFdIK(S6AVJRc*fWgt1% z4n>ukQdfR~t#HcndZC`%mL-yh40+Yc6tb5pHX!T3H54P53KN6xu5v)33DV@N`i<)* zg?=^BWhzQP_ZDAIm(D72wSOj7*`AdjUrGo?w5((Vw#9b)+}nG`JhALV3Y<7CjHT)l zxv2CLT&2jm$FH)W%6C$Eou@TGKk2RX8y6p@pV2*|fbqVxlonAS{FnfpEjmQSpme3i z3yk$%ncOwxD8$wsmUwT|2Enacv{Pm~TmSS>{#BQonxQ7p))M>Kl?@=)z2Tjcd@+ZE zUE@<~`?iHln){~awyJ~kv`_JnEBL2-)deqnasgSPLk)g<;~C8woUI&y7gbTBZ?noW zCB+++)1g{&x08yhWc8^%s!Tn7AXl4~xg1>WryX;~tN6n4N%`w2P>|e%WKJGy%{Py) z^KK*xE#Gr?2r;S*ztv*=2Z^^{)ON+~QPv=Zl+63vgd!6~=3qEHB=gJI)ZWqkMwj^# z=IM+e@WLh$G(b{oYyL70ljvNPGiv7tvzq%q(?--LxC_GIM8aoG|gY$g8-!C0Ubg#WdhH7+5V z83{j%tqi}|QBdjEggP|vXV}M4A14^;8`dVjG7tASr!p1C>}JdMrsKZkz~%l3e}5q# zYMGGsGToSh^6hxwNo%4-1Ax4y>u2NNdhH>CR>bY-4sD$ zL@WyiC}GDM3No~=XBeJ{B6$~Y&Uno&wrOIXC7BO|3-nQt6waBE>ShDEF`rBP_scdw zxIFM{Z;if;0_Y8`roqB4c2R~FRvrA&lhRGD{kUCU9w9&84k;0(Zlag}XR(k@iscPl z66YvmXyhHH!t=67q|MI(FvZLlv-BbKXQpX-xS-65(4F&D=>x7R)U6l+mY~NAky^AT zE1*BR)C!o|CeQjl88z@GUH~73+q`dVSgin16+8!G3?US^p%xe*>ij&>?}XV6d%wDfEa~LQmZpBydEYy+H^?U{I}fcyE+1IY6-13wB#uz1 zRSts7YhVc`pT=4rr#i4V+r|xn(L^rD+)@4%pjJ$^%{4s|#7GXRdSZ8vrsue`c1CU~ zc3vbw?I=kw`xFI#!cYgx~Pni74lewYwxMk$+E&|G3rv{2K)()>LR(?1Asj zuX289>}u}}S6eGv$t56dYEH_zZ!n=&pMGngBjv@JtQQgwE_SFaV%;QWEf{*N=#6|Y zDExgnh0TF!db*5EpwuSzVh)fv!rUk}FPvME0L<$?;0d%{8BJMWk?hm;O@#DWa&kU> zVy-%mST60=Qa+z!#P5mnok+@zE7HA+`+a!cNL$>Y4J=jte_8d|2cLUbP|_%l2$27D zJwa-q3UP8=+l_C)u)WPBzX?{3qF8H@XhT!l`z=DTTb!hI51C{mV-a+FhmpH$pN%+W^l3cJXd@Q5e)$Sjg~YS zfr>DpxUG{&eP2)dAm9Ku6$b$pDeaimmHsnW@0$-9pXFUHv*0Rq3fGY-@($ zU4LD78yl}v1UH?m0~0q6+S?@xo&60aU5>#kvXr0Z%F6fN$=m+u`@jXyI1~g{%eLyP zN6-cPFofc2r7g!SGnK*o5+@r~xDm@zcUnC$$i$@V#bbK&Cr#mkK$LA9{15Dcu;7Ia zev8K|$4AG<8?#k~ECcpN@-`fVMUH>{D8OlfL>IDgmEttD=R>{DzAJ|HAhqKJy`P8oxBAeMxaJ zCK=zMY9P`?3NcM?DpeBscj+#;Ow?L*J(&DZRg z(<<_ZWok9M{pyt?@v_B6@pcISv2?t6 zQepIvC>+M~=GLB0GwTySFG&!tg8Goa=tKA0c{t%o#;i>11Ag;$4eoRAnt$cp#bTs* z@R3JFv{-3C0NAH>6s9kJiOX9j{!Jo%1@4r&Yw9+P{R7YSX-m>&4=E`9NM*UYKXUz5 zse+{I6UyP3Uk?DV5Uxfuyf>fhjNHb)-gN-(_nJ5KZ!khX&dB$LaTgAyM(~vWEb{o! zTnfvCs@4U(C!<*u<(cm1po!T&L5BIGXcnwoQX5ASC>?26V)Yyk>^VHW?&3j%_|#om zB>Ko%0NNAH0(b8|6oLG14#j%54q2Hji&qyTxJISM&jkyhU{gW>@pM}liL_?*5rl>^ zD_pdg0PM(_%W0b+Hy?TvfMWIst>KKH6E{vJ{z15slgnOrY^U%V+5`whzw(^-b}{?F zp^a0?cgqA$g}h!Rda7tyR_x|P=T+!#P>wDFv^>E=l6lVRAhML=)}3W3ZEReouJ^s8 zbmK>;fgclA9%Zvw^TOV`i{zdLL3HqC+HwAjZ1IoB9>vcSpr+q-7Kc0Yg zmEXs#ctjEhm=a4_soZ)P36`#XBf1**_Bnz%KRA|+f{OW0WuoZ=z(Sf7hXOdgM2NZ` z3Xi7N9rRUdNpavy`w0c&=akycw*J-VHK3~Tx)RuBTX1ZX0OvjDhy(Yx-02T{o4do0j0 z8(Z+sWH4TeWD?+Ixx`|vWEXw8v&Qg=P!sldfl^zcGlr$}Sw4o_l7b!{a+dVkI3Od)udTm>U zVrq7RJ&zk;RIB*gTV^Od`SzLMkKzMw%@eDb^*r6Fw}~=kOw6QM`S%(@s&^5bN|j8h zKUgbMvjSYvKg&eETRRfCh=eYOIESWam2D#Z!ROk5SQdUTHX&+1To*3)w?+DCfCzCqIQ+t)-vy zwS`r|+x9O~{3^d=l^G0GvZGBq{tv^(E-V-7STt}*>kfAQ`%h;2K& zwP;e?Qgn2I+J+$%j^dnyJwBuenkJd@2w6g_#*DY2Q-18|3aw-c3yWV<3`WU{d&P6j zK4pd)`zz)`yD?vZwdG{?#5yIC?m3SzJ>B=g5{})G9}QXaL(RQVTXIj7g_g5ahirAh z3@sC-b9gI>t-9hL^b+;_fn&|aL<45);3~-9P*3&r+WV7fd#cn11@>DBeRew639%ZW z*$kYLX=?iVdm0CJGPfNS?-zP{q6nw09FTty6|ZcFdU+2C9GYByi3&BcF*7I>k)$7K z$30U_y3rA%RtK_@yDRYXIB_A^{WA@Nec8oDcU7N6DgRaDv%;Qml~&e!j3>fz@6R#k zRt|==%TOyrAmS%_WFXKb&4_r(pC>4x^I|2!YcnV7F|%dgBBj;(8Nd-E`G!k3G~&^> z@D8Lyp~U)dT!`a!lp)AalqI|}G934w*GuB-@UfKL^*KX&1ybtb7Eg!FV1Id13ZR$sr+`#gwm@OZU~E7f4oW_xGt=nDx$0)Mur0>P<4qe*g* zyq4ujaHsbes%OOJn4`1vlQ;XKYz@_6K5OG1=Az#&w6W=-{{|n2 zWMFHdyKO)g7y`S*i9sUck7eElwSRsxS!0JwQhM@y;_~b}G>vH+*W$$x1RjS_7-Q1O z>M_5(4W+jI1gIWz=XUe05xYty8nSW@qHF%S6H6>sR5=$6myH%?3{_#w}6FC)E5S#mFS>mj53^KDCT^W*EMG!PMcZ{ z47bX4P>k!2K;s^X?qVuHpEYYb{I<_}8QIp2B*lQ);%zN)!G~|5e0MeLFLZ^5rq@a4 z*SJFP0WbPHA4w)#NC?W7ihyB*W1%n8nV1gF`Z+ErTE#I;qTAu?4dxMt4H%mqx)*8z zfK<@p$C;;1A727^VdO-bP8Jy0V;~_gCXlSk_ReaQ(926N$p%i=M_$STAI7R?1y7#{Ub$Etlr60odE=IDti&VT`N+A!Ixw{*nO7KJ=&CYB-7tj z2h*5)?12GRMW)vRj|pJ?sNSOou1oV^lqMZCNii?vxO%6Lo`wQ>?r9Mg)=jI% z_r@8BN$m`pn+% z1zdL2+xl}5VC5fc>lHqjPpWCP4%fLmGiad;Olw4$fYPl)sk%auUWMD2vY^k%s`%4v z^RBYqpLx@Lk*QCE%)1(0s9z&y;HcyE42;23Gr<=(b+<)G8m_Z_al2B!u_nD>lzkgJ zs=7@hA!?mD9ajfhh=jKc`-cKw96E{7ll-FMQ>%6{WP7Ii3ZEGhEoNDqDmh%aT9zwE zL#GA`sk?|8ff6si_S$2;Wp^=weSQkKoK+#^yKiQ&2|jXDx2q<(SO;(bfL_(aO*)oEwoIfVePeQs#? z-!`G$Uv*F#CsQn-zHRG?L(KWkAWbnKzOL17jWSH1t-j50R)?Ermz%jJ`3QGdHbT2BSVTs zR7p|1#pMMg%j%(~es*2bmHap(4|!%fcH^~9=h8JjoQg`j-Jx$b9@=Q@ zry-oaL62p|OnrG_V=>%xcz=GbO>h9ljLlyRqzM|)Bmi8)@j~54XFRsL;+!~Nu;x5% zJF@5u=GHYJE@N&m&)z^w*Owbn4&rEZjqa^vMk%#-6lo7T@HRL@+^u@npT+)81(oj2c3FZXrWS^_62_@sA8FbX%(x1+J7 z;5invfq*9!N3Z^>*`B{Fa-4x$ZXS0gMn7?fRfef8`UF9luumINIlVp}jS??JAv0OiUaQ_i32&Lq21ZW!U` z@6lff>(!8i$FESMj~!kq$LUs!d+no!0$F8+k)Ni97^t@`v@r=Vk0)onEK`_vvA}i? zc?ZOvCNnmwfBXe09HW}>^=jSM@bij9Ci=(&@6U$%O zmyk1$3GN&r&DdP8A85_TH*d~^;Tzir3`~jY_!BHN8bmn(W6OP1IjoPWES4AuIKG*l zH`f$RZD(6rXoCxdguJskljP@y{FvhTuU}iMty5j*Pq7vuBoNaDe&Bl&XtB`!mB#=6$W837j$j5<{1$FBK^pI3dS7c-L=te#VAHy@V9} zF82!$W24W1kqn`rvwr2jfVDer7k6KQebsj{tgJj-5?7!G0|j6TP$(3Abm}D&wV$P&1hqU*))iP1f_ibUr-=^aw~`}` zsNQY;>UiOQ>eYdTphm-ML_4aF6VC<0^s{wlZVlFzt%?uhs=U3pY}f43eZspuTou8o z^(65mgEO5U$VyygMX2d9gD*MJ$VWA5&qrfral5e06CHt~N()W7jai--?FA980m!=@O;TQ*uH!%E}?8r(K^>*-`uVqz2=KvR0%TSYqY#@9U)2QP6cmHWxsrmMA8zkA z6gtTu6J}r2a5<7t@6#?hP@864j95PQaBLJFb7o7_C4^ zCj1tM)9{ACafbdgPL+ae)p01Pmn1l}qrYlzi4-HTp?uq@nV()=+ZDzMA6};K{axeK zZuX8VE@B6*$eUdEF$O*B=`K#t*U+$PNLV1_H!YedXfUT5&XeAh0B_C33=d4SaS23k zUOEwl%`&`uI~+jIX$XYaEN(){(lXP?5m=edPeJTqNV&-GlYO3cxE=9c`S2%ZvxoRR zwyWP`!<5VgZ91;-&({ZBt}|f&n&Y(wORRx^y$O=Ti^dby!II-HctYUA$@S3Ee03l~ zdd63|+Y|z=q9=x1*C!=Aea>JfHw3|jyNWb-6~$E@=`ke$)!o}X#>D?*=73A~o&+`6 zie`xYdIa?+)uADTf$WQZQI=kp9ByoN)ZiVjpR7;P#rQgpF*Ez6)S%Zsp5ed}i7FKl zwD1+T2ZKVA(7*ln2?`h+{qK+KxB=0hxIZtxd;K)g)9D%uDB$spQToR48TlIYLWyz* zm<7TU9+~*wXs~yY)GYTf~z3#)Zk4#nSPN=wA zRU)364op7Kn?VWPTSqx$@04ql&eA!%3}Z?3%=hfr`4!0}{_ZXnlv6XtC#-*JOSX>N zXKE?H0#G1 zVZR)xEyhC2h;`cRmj65Rl@@p`mH`8tcg0yjshauWDOi@gEx72xF6OV&OmnlOzv8&D zH|8-j!P&ezDLqe{WZH9(sbWt_(ubjf!o`DJNcrohX7QE)_c~A*txewSZgv**W=gAO z?~n#TqM2xEml^Bc)9mDG3+(P0UO!Ty-#x@D)j8tXPC%P03KkRx zwA+q5&c(mZjqV7d>8_d0wqmfa4gSh*1SRuiro~(wffHEFpG#tbfs<-0x1M~K-j-pP z2s=sXb(3>fQcBO1>y=%79~}e1xH1Ck)%*+pF}XsS@;v~6os`QZ`f^``VFG;QcNylX zRNGLipe$R@E;RI)86u=AumWaOJ7RNJRXlCYD36K&RPb7^wQw@ILYqqSSU(zk?zOk< z!-cP(^01un#~0(|t;I}IdD5Pjk*+=7<2)O_A3u?-N5K=RPwPm_@Q7sB5vfGniXzU7 zg}w|%gj%~u*=TTYqZ;O|JHtZ>9R8pLszQA?Xd<#g=@?{fn0C~1>HK?gLcd^sI**gz zGD&U00XO9G=$4jdaAdkrD;SV_8O=)iO;@{^-5_s+!CHUhL1(A)ZS<}kr+)F*3W|e6 zMJa0$Mx&FrW*jTe0tvFl(STKUEWR=^tXSV9ICH;NtndEDB*1EGP+}h2OSY~fu9PfJ z)i8KsoBr9;CvbG5L8)*_OMs_ZyQ!r|^wV=$#ARa$D~!1Ahko%nLN*3u=z0)l}D zI#}fkL2gghXRKRx!ipS1zq`@pys%rL1RZv|-Fa$^O>VZUo_SE`vw((ptTd#Ir zK4inSXCs>N^R3Cr3@i09Z~;!=)p65d#}%|5g)Y(PPGyXK9vWlDw0oi`zNo{)E}ZdG z=Vj6=f_k;yRLJXnA{CrZoU-{LW+Nmkt`ahBZSLcZ4Q>o;-como5I?rpFI(M=BK~g+ z9Nw!4%l5)mH9+C^r9$O3Sm8Sp3^@m*l}?)iz4kYYX+t)4WHm#CQSa-FqO)70W77EU z&fW0M=p?M^6sjG82o8!6(|MVr$}fIa<3+(W|Nq;zITktCu!OzkP(42V=%S+a!<#WR zrt=%UkU0`y(6l^>ZxsPIkT-!teqm0Nq!w#_5Ybfgl>vsAh}rzqAu`E}nZ~nM)wy37 zX4kUS9B&Yi-LEaGAaVw0E%>D}jSr|=&b+@+l6pwWa1{j;7)nNz(lDM;NYaBflaEAa znmec_8p5uLZnebHcJIuM8YxWk@mg%1maBqt#~X)4spuGZh2fP7#@*umcPfw#;f<789C|pB3#(4K>{81m*?)|tX zQ3yKW*2Q*yj2awqhV%d>l7d2y)viuo`>D^d{&$2mC}a=+iDQgw0#9KLT6lMO{Astjr0pL}~?) z3Jv}L>2?{p+Kfq$oKO#7utW*+@g<{zD~WwNz8m7q7M9uXN|Fp+vayR*E(DQqCoi?-q1v=W&7&vQl$y#oYQ6wNrwf zGqQ_yC9t5XCg+>g%)s>MzD$fo3Ga9|atllt+zRuXZB19de0}3}N4=sAT{qjT?GuE4 zX>5CZ!WORzoX{-X$Q{FxZw<7l%UHE}Ab%x)`KgB!3OSFx^#}*~RyoL8ZPO*Bss-#V z?`i$P7#%jEglA`xz!m2>bx;~4e`DyHXwR2$d23E z(Yik6^k738uOKg6dLqI?I5(j|nXqeHWc9pX2Odc~xdWbTpPtZl^HqeVnS`DOqB2B* z4)Bv4(J^>$#739TWR~wUGags8=#8;;P-z%X*irJ$HR+(QsDnUO)GZfiL0L0995Y7F zg1~-Gb_q`mj=yw8f8nuFU1{tgq)+(yj&?JKxRO%FL1!sF{==&Qj)9yto#af+{L=Qo z02EhP0GZ?{7<+Gh4P)AB;XeiZrD^JIH_H9e_r-baTd3lBd5A?NoJB|Vf!!5{7pVGO z8xI9acB{yt+J+uP1^*MuyH4k|QZY+6+_>oQOYFzyb;$wnYCVMm&@*_g#9xIG~Y!I+WRH}URl>0c>1K#LzX{cb18%DM4j+#8-v zPCbO?mk?Tr8B6{&Vbrf*HVGvoChbtyR+G;_tg}kPqFtE2iv~9#3-RebDU9sdixy`? znmtG2s&PY>x-GMT|4Bz?N+F;n4npiOuD5}&l=lx;v^eyE*PVf-5&hFfviC^m)f z*}$I^U?RQpHtS2bsutntJvR`K-5d4!QzQm|W(RA0-wN8?hRruQN>tB&Xtp_?nm2G{ zTTT!aMU(u8geP1iH!A8jgFPZ}^`_tN8#}%yKNY7C%Ob;^60FMD=lE)3hOvlO!8T>4 zf6jK|0Sfp3(c=||CJ$7Dh+C<1p<&8)cse%gh{DTaNmyS>hxK}pFGs)Q#H8d^eIW&e zG_1f+3g=l5HqSJg{CA1+b3(WY#Bl}C#>b!>f^@H z#}+CjBIcXbxhqE*1>}Q>CNAq+>cT+P)U}%7Z;LG2?HnEmfKfC1aW;9(G&v|{Qp8H8 zhkhO)ECOQQNZkbrfzZ{NAmsjpKCaa4izeY=9H`&V7O#35%ApNX-Kay}(zCDtoh^to zy-9m&B*Q4B7PIDJgJ13i2&aBUtq}1D5ffw3UxjQ<)w@ItDNhi0$U>lHLU^aonVD>* z7Hyoxa?0`71}!ri2kVP|{8#XDRJE?mX4)Ohw81*0*fQ?AYgm!~#3M0Zeq`>nClHZ9 zx>tVOi-aT^C*qs+pA-*1Bh!^drS}{A4;rq>16-I#`T_ovV%@YpRtDXbHn_Fk4lUv? z=#`au9vYV0Y4C;6yR4J_yZ@&V86mAx8jqHV`b zK(vI%b$nGIhW%WYBbYS=H>HRf0#EW=)9v3uXE>~;j}LoUX9YPa7?Q3p+30vemi|7~ z{9pj`AnQRKW%|ZBQj`ak*g!h%mbdz$Zr}7?W~vXI=$>?V6j7(GLq#Z=aU;83vTh55dhTroL4D8vnY!A?bi{+u4uFsWT;lg^}^p0LCj--jzM zGZL$}%M48I2Kj1Wm_a$*0o7OX&|0Ye&8$~d9Ehof2TlNZ&)%y1tfPHg2J$K&fXG{$ zTQdhhm9}LV8f0<3-7^#M;wgV{^yDJE4a+mRD44d%9sk^nbm=ZirYU9;wm>!dh|jK{ z^l0CKD9Qkt@r$=ym~u7}u#6n;XxuoS!n-)b(o1cK+#mv|-n7m8481r;^KF293H$&; z3)=Q!mqXS3!=Li%Rfc_j?2LVDdZrITSxRF)-v1CE{Ws9{{h{ncfoGv#6x#b9hZc6^ z94!SlGUY>BBX`}H|jwjDt zBVW!o647E9xdeGA(9?2I3VcAzGGdM7jnf?HFT3h$XIFt)lO4{Uxb&|RptaPlLz4L0 z@YPS6tG=Do0DQ5J<1O-?2G1~mVYi{oTla*m8v+SX8#j@zuxg+8j-2&v0>p$W*#1t)&h?k=^P^vYQW(g;y{_lKaBoS=FB6!fS_PD9-1m1Y#lFkJ}{Hb#q9dLKBrP6e7VZp`5fkQ+!k-S;V3~1TMPOy$g7b!KHfph zNK!{y0ftKhstIS1qF3~jlI;+|F&__%!VPWX$34er57GMwH%(UF7KBU{5*-U9$4n+n zwF@Xu!J|0&yDJ0BNnPNhmh)ha`=qoszwsM)OVX4@-UX%9`~?d=UsWKqY(wpsPXOw+ zb#|kY`t1WGTAY%XNXsf`0_-PT07F2$zbsp!l%&{FD<-ug`z_>{43II`n?2h8rrddh zT_*PMmz2dz;UlYK{A0B&I}ctyx-s-l{5ya3SiDR}`ExSeyu!Ml8Q zJI89iID<(l9XFE$_B+I7w zDT&L{-_`mtA$Sq=KpMOc#$zUL{2_SYuQr(Mi}e;xve1OV-=~=04k)od&y-tBzhp9g zdhbB;)qJ1L4fIbpX&uBnNYja59=kmYb>7Wh9zetLT*gBvg9d296(YJl#0G&}_yb*Y ztvG$($CPCxF8tkBsqSj5V*_@bU#C;Xw(9#C)iOk?W^%bqduVhcbg{uW-PrKLQ zrJK7jUujQz;7y0_Kd~nD6x?P;+c&#t4M$ExS*;AME$fKAS{*|O?}LdKl_0tb91$De&)jwphpXt{~nd- za7wyr4#QFU+(*Fle&??;Z5k>IM8pgs^xpgPgzWKi^RB^Q-to55ue$M9cqQ26QDS^^;B0Fs_T?v3o)!S z0eAzE(_SJldj^wlR)4ytgSIV7?P4W~Nn|70vZe`CPJ7+V_fQJFssD5QJ>J@;EDVPU zbHWEx*=R~ua$u;WAkF0NEX=-_-M7KauU&#H^pw?u$mde@(v8lsSd&Dt z&22aOA-jA$x!d#(1^lWltC&5=hhgbl;73f9-XFG=Y@sLZXK#t}y1HL1L3-ZBNJXM1 zk>qRfgHD@<`d&;Cy)QRUEhKC4peL|m}dTKR@n_6cP@@U=ThyL9j zFS&2UrE_r;s2qlxl>(NA+sl+mme=516ULeRT}(;Z&>6Ry zK$A*UU~O&x0wp+Ddt3%gw09m0hUx20Q$G|=KZqJStlGnh?qv~lGsz@$Tlx3aTw1|nfPE? zT)of{Eg67Arm$3zhH|w0V)mt?2p$FJFLDH1mZMnTzXe|bXPj)n^TG3fI;x@%5fa#|1L#%j^AvOKnky>I-g4)%sbGCTKt#r3olHcP;Uh*2 zat3z$eoPe5=GW(R@;N)}4+rhry5tL>{m%LKcwAxrG;M7v3*38zDAImfxf zX-Fqu=Tu;14TZJ(ld0XnavHYq(Aq6}y*u)h5JbJikDpVlt1+!^enq;*KbN_FxVoOA zUpj|HOzSXsvl`Qv1Adj9`xs5-=cGZ4puyxc2j~}pj-k4!!9X?;M38`zbl4CxAXaVS zc5lQvY7FGVP@$&0vATVTX9->=jZ{d|BfEcE1VLUi>B2hk?aW~f=k0*XB3Ps25 z*Y{f=cc(da0GM@4Kdq^z5Oa?m9&k8nmJ@$4)w8-y|=a};GF%BMi*d>A!20o(QpiHE`VD6mqG#_(rp z3E;w0SpeX5l6IBrw)Vh_CDkVL@eL7n%&dGv2I&mNp=es8hS9Qg7oEY!IVh?ic&qmO z5E{hXB1g8B1$VD&u`ul0RV;_W#vgaZGU0p4fSOQ&O0Pl8i2E#U?hSHXPSBJ>03BsWrxYW!6`~1f`<&tRQIc0TOEVyd-ByH^ITeC4xEI>ZiXs z*A#zxz53@@MW6?c{{{OIZiT7by9^b1DpS@9M0|U~&TY5gV}#RB21J=NJm&l$9vh)? z6Lc3oY(e-t5y)WQcY^CECb{%rs$EpgDo%z&3dtI0u{b>|uee$<W98|~ z91AgIQ$SS?su#|WJACVPLjNZ7(GlXq2{Vwqp7QaXKCl=qPy>KB1+z-HhuO~9U1=m9 z&e_O=8dKG)H^RE3f7VvqZjT4YlyyTbw)^HneC?c0rZKml1-^19aX8Y7^Y(RcY=!!H znln3Wf=MCjT3nYhVQ zgpkIqiW|6&ug>uhjW#bRb<-f+1yGh}Jw)=;8*M|VGYm731s0i5h)L7rYN(XPlCp-k zBF))KJNhWdl{v#fAby}dDSL31(-0x-*rgA@RyTmJ!W~>!y8k%DYpEW((i`l{^1!cKWV>Uh|O;ar;Sn}LObprb)_qHL=Mnpo_O3r>$y*1GlGOA01|IcKRdmc)d@zqb z2_&0#4&3!c9az6p9zd{A6A2G9`I`MiHU4g0Fvauw4o}uY5I?bRG4tr@#X?k73;j5i z(psRBmm=nJ&=o(6*;3LwPIG?}x)Z()2g}tZ1#y=_)MgAGtbBt^5Fv?hHc=s7)nhRZ zs$m2OYGwx+b5+Oap(!T1AZN!`CpBBYb|DkUinR~sb=3&4I0eX{#OWNSoM|M8+s#g0 zM0EfO#ZI1Gb>~rwnSdgy)aa^>BCjYYf=3;I;Fu#e3Rz{a6bU`-$aK{4_tVv9t|JW~ zl}VEBvX9ZNV*nXP6)5CQ`NYHKV8w6a=Gg%&9)31g#PR!0~m-1Rzx^-?!J}z z>Rif@RX@$*a>0)(%=Mz#Wp;H5y>x4Z9wlqz&)o{WUe%mDtP>bO_l<7Ht*;K;o8?#7 zvPz1Y+~@h)#mj)1R2N$7(qUJx2RQWQ&NNEGu#dy1+SocS$vH>7r-zU)V}Q)MDduaF zUi%kExLMtK4&85#kz;F;r1=j6ap<%aF;%);0pk^ejmt)jjKE zjl3xWD?{RSvJFN zq8T=xcgk3%r23^uFH`i<(t{QKAfoT2yILPTk)^jP^MG$#HML&%@N^)){ekW5^w?e^ zV(r`!=$au21^qyt7Hv}dMFE)y;9w!VW_u%hkg#V5u^jxX@;9*;OsrYX>JtfHh|uNS zh?P~}XA4NeAK`W~=|f{}Q4flRnCZ-=+gm^A%DXWuIA)80P;nZtCQWM@!B+A>@4#=U z7fbE>1tKs;;Ha_h7*a-1!h>Tg&;BcWh&uqzkc5E?BhjqAmQlBll3KT4s};w4pJHUrliPcr zdF$O}gPVP?mgq%V}I8w zwQP}!@wISagx}X4P~Y@=*KwfP%PckM^|aOeS9btse5B|&g9Nq#w%!&KG}>=OpSc1S zN)YPvs7e zfA){g6cGurETc|XcOhE0%H6es;rNumBomTiH^UBSE};gupYCi|xEZCDl`zV> z2_v2m2Jg%I{J9+y8A?*2$)RMZ+-{yK<*MH!e&q`=ed0Fy^<&fy4!*!9jIN)d$K z6#w#gn+-{#&n;t;x|7@Ii>W;=jX`*Rpgc+~!`HJQy+pup-@3f=!Bb?CWC$=)gb({| zk}xlAqK}4B5S8{%x3%*q0?YG3o{OyLLMS3rRRgSO`2u6EWYp#q(^mx-3xR1g?z@1U zr{cd(3})m{9hZLNXPQw6I6WV z$~;aWPi5K+RrmDx@EUfadcWXH4oHaxD*X%$V0z2Q;o-nGB7( zCK-q&M6OutYaE~LI`$cy*O&r%99tJV?V2eEmitZG0#YzpqS3h-#F6GfNELJJN3hX% zy~uVl6P|1sC|%w`F3eZ$IaRDHk+h%vD8`C^GgL+}IZHQo7(vuUyNIBIq1RCHKM3JU zV+;FS8dXlhMO2DUr6n8VYzuwGNx6@NM=Zp0p(;d0LvRYvoMa3lzx0RdmJZ5G zRXVEIKuy0V=?0-u2%djR=A2CWf^f>oMd!??rT46I0k6`UPfOKvg9~Dl#rD~qVPV*N9}TlFZKaIW5xqD6r!sc4_~z>G~Tx$V)pBFrf@>=8mt;) zSD;HvTPCdt_d8-PF6vG<`kDvd=bG^9Gf_+Jkx3t*q~yp2a)+is=E4En+L57urGf-Z*X50qI;?)9Hc)~=bzV80W#>jszxFrkPcNR@ocjtYLn$D# ztQ9wcRf_9ij-u*%7G!Ep{CzoAil-ESSpQ51F7ODsfmEey-aNB}rPA|Y3Lw^+KrBgZ zJZUW(n~!(C%*0W@{}jA$3p%`YR@d?**$TD|=EMGdsW79U7a!%A#bf{3sNH!?eUK|t zJbTAxVJ?0c_r^@6joB##Mlun&!T{BDn|W48KQvr&2_|CFDIhK{&X(BCycn+$g@GhY zW?Gq(S4Y2OPH8XS64QG23)klS0%sa^0i%QXED{9&1E{x@ctx?%ubDGxGp&=NIqvl) z7TB_QN|F&;aTKE2yGap$ji8tArb{hO>6kXOTnlF*IbzGj3*FBTaLLyq#LWe5Q^5lA zJShBjB|&a!_@AmAHbcv@b6ROKs*c*V6OQ)?Fcttr1nQ&p%@{#PBGk1Vy?sNc{58>& z_-hv{dEH)a)hHzIkJ}&(jaqB^nt@sa-CC&Pq%%sQb`@+aDSo33_@IgWA+OuQ1fYj6 z^@lZ+G>iKKd`@;GI7cmez-x_vwF;pPw7NCFy}8O;1s1qnOP;JWl+y+vC*dbn@Oi4k zUyjH2_$pc7Q+E7MqlVnR{utOm!Ws*M+wpWtso3lDwCAx&sa3<~P%l%3gkam5*cEtP#G#^|> zMH@z=B3MJ{Qs~T+C7fEWcQf)HAtlb_r6HQQmz_XH@O0}K>sp>AtpT8T5Cw;}W_y5w zeNu)EU2-Uqv2mpzjGeiLzmf6iYznZxaKBNAxCCs_7b((+XUYCUun$1wpF}?02NLxO z0XW8*uGfxvbWlQj^3S;NVXY`P@eY#>zomG&;jvWg{0whdlc^?sOs)5~Ny!C8`c6p+ zIL4qGdfk9tY(CHW_-gFDfT;E6q$?Aow2QA%Ge_^12;7JT7jgipma0pf?rJfw%ly+nkkaPs!>m1H zMYTzS3@NO`xcQTcEvu0`yeRg0lz^Cv@!ae=kv}DR!O4P{vANLDyO=^PBu%nyzZ6ub z$qCj}7-K*t5B8mZrk+%uYoA=VAHACPsCvAJrlplYrKV<eutV6fbXD}rITG?(Q#O{(4=!XWz~+{+QP_$1WNsVnzeSC@z%J14kB zOKfd>ate6=zW?fy37Etl>aDzmhcMT)^8HFmZL_V!`gmx`H|C8F^u9}iXW4~qsCRY0!@US@kc1XC4qKW&$8@GsBe@=e+NSIiyEMS2igVHL zJ&PQGzKwpuY}L#E|6?8+nT)zVH7lx_;|lFBM*OP<%Fc3o-VC;D9!sZjX9cNdTqU1f zEmz#B@w2h-3xp20y{((KnRDkmB7Mx7(C?C8CRsHI=hJDwd3`AruK@>qS`j6{f5Gs~ z;gbql_Zfn}&FfajI&S`{5tLE_T4|fJtG&%In2l&*=1yD=5e=BNGOyuv5|y*^}^=SXnizd^?*3IfyFJj z;>3Oy9N6QapULN@^DAm65Vl4sqbQJ9K-$Mr#ttO8SYI1!w7M%7U|@k|)!ZBdGH@2p zAyk?Qu(>=OqK;v@?O!L)pmoL+7fnfDh2$dbO7fSO#12(;(8$z#lGSvr%%=xd31Us( z^~77nV)*99#YK7PoP!LW9GaVy3Td`;$}AfBWj7-Hz3DOpR!8=cKi@Eriv>|ck<%tC z2$8|Ow_k(l)B*UFrmxg3-2f`eVE~s*CO3bjTvajH&Ea1@k|2O1Xxw61kfPfcfEgW0 z0Pb3<-K?Qcs(Sn$won7_9(nE&Giq-n;KIxj(Dg;=ED`A{rs31h1h*Vf!#DrM92wTq zSI=6JDBzR(^Azn}wo?`;C6>kZDt9yy;I>FBTEnIu+;u5_TNR9(OhSuPLA;?2&a=;l~w1UbxBVn ziJhL7e4z1p!Lz08ubd+pzzhQ&}E ztH0iPF1t9)3`*joGYZ|`ev>g0F7)?!s5f3g4|KZaKz>hO?$pDORA5DrgGv{N_HEPq zYJV5LXW_`2)+S4-SgybqUlGlm&U*Pj(Ph6gs34e%7|DUi_eg{W-eRl!I-Anh@Afs( zqIu>)-(v|S7|U^Tyqy6K#Oe|f!kNde_gmnMHj3QXQv}?-5RCt37Pdfj5X#yH@2ep+ zGhlX5P(TnFs+ zpu(j`F|HgNrZa9IMhNspVYWL9@n~!9Eth(NxOSs|@bzwh@Gs9pvapK>|8SVdNmrxW z)-Y%*NU8N#l+s$jSr;kfYkYyPr@zAbbcFl~Fw^Ma(b&(|;^n9_r%*dvpcKlb)eN^t z#8k?EZW{}t8br%FQLi|yPIJUOpZQNHQV%`Q1)$FCLPwF?#WC+ElFfz>HoXHaoq%!X%qq}pZsvV9 zj=A2*8$45?W%v4M5M;+NX*i6fb73H93ge*flf-!D*wS+M^Ngz-;Q4E~&;0|onpdzL z>|gjC9jnU%mo3&7idKSCl)U06`=skLU0q1UW9#(u;=7oPr;hS;y?Lbic(i&@>mYrL zvoYv*Pa`Qu#X{TQ-^Xl*VQG|g@-SFgR6p`D<=!Q4c@pxP9<%%c-?}_>+ZEHxnYh>< zM}47+*-}*E;+FcRmExYG9z)jLVQ@d<+`9DOJgh`K0JxylC1-A|_XLtoL>uz|yvs#A z+S!A}`23Q)PbeG7cz_q3!L{%ZrnxDV%kV(2A3De0xakQYoGK(Z9IfrC$z2LHgTr$W ze#+cS<6j{rU8Bo6Nbo+jza%DnguN2z_8SL49LY3EK5QgIgXALF+YN@lakG6h{q2R6 zw}0!j7PVaqZW0g6IeMc$TZhD5n400&M8ZsjYoax$^hA2x{=b$Y#iZr1N|Bna915Ju zE%LbKf|$d@((5S)4#hEsY?xvuX$APqq$MG2({JN}lSRAZFD|4$h~ZiD0mJCtq>bb6 zgkAqiIECvEfc-nM^jTi}K|QusGDS~57Z=st2GcD{)OfRpFATBY%?SHqaFc~EUAmej=o`v~vaI|v9!;{Mp#I078Y}ItNYlOWp+ky? z+^_CHaXGvYo>Kt+ogaH;BLuzYDp9$Gr+AU!&&vqJkb=&;C^e7aY{sfG&zz@@>=u+$ zInSR%&E9iV@nOYojOC``_b~Yg`3&94iPg>3t`(ANIB_67t>|)nhA!t}oSHvwv^m%% zZV1`E56deKm08P-{vkl|N-L7X_LctT0TT7m>1Ofeh?)i7-kUrgwsC}KkFhyY>CgL^ zW+fFr__5@)Sx6FFKE@ox11Si_`$E#Km;Sd-t*$M?1&zYz85b~;ahdp~$-KGPG%*%w zTorvg**lW(5{urZs&S?b$b#qS6cw>+HFP~(gX#vk%<=?3xU0x`0N6LiD8Q22%-?M8 zpgbXfaaR3TO5JB$D*Ph_ZVkgV0|p79~#2Hd`=%(MH~` zYsY5C`QiO?Vul+;Va}8pnpk|O&J`QKBC)JBG>UwA#Q&{_pEja)olq)mI-v>AmfHLw zfuXnboehB~aN~V9t)g6BR4z7vtv6j!ZcVMk0*$whmeN34ychy95%%`o?r1xd#*xcF zY;Qmx?`u>qJzNE)>~IxO^yK)RPV>psdl{E(`JR(eL|#?Gc-jD+d{>j_@7yB;cnyB^ z<@8@<>0)vDi_;jtfoc4dX_~_}K5qeT(s?udQg`}ujdCu}D+KVcq;>xhHit_WN7?TgL!503LW4j=S;%!e z!Pn>cm{?c93?a-enT9z^{u4sy4+DcdwV)jVSrr!Mu8irkJX`|M;Cyke%!3{?O96p_ zue|)36fOz%s_2Tkgw)K*PJiE>sVw8QF6IIcGI2{t*S}MaKv{{YF|O zCps+r?qQXitvntgfBeA#sv0C-)npHae zg9H^Jv9S&wIE%ihu2%ykO@isJefK3Ma;+P!teNxdOAsCfWPUuXn}XFZZ5W(RCHwqE;1ftG`rt$gP~x&(64 z6ES;OnHIZ9@^+NC4Gh$Cd}dg{ERkvbGO-PJx$EVTLt3|ToS8vlXBcuDt#xh1Tb*ib zqLr38$Vu=j=I9%=|F8#1KLL&Z!b5mQSNxt8yvzrn$9jeAtJ>uv!>|jldcnWjp-}a0 zlJ7{<=Dse2`YT$PYaRzHg>p8sYxm_Y5qj~yt=M4Gg9$X40m>h1q>>ejrL7}Z1M;be z!=UC`@EV@Y{TX^Cm1DTiFhbpew=y56ITQ`mDet;D;@hdRDsQD260IK&vM;cBQx~<| zbA_xw#ys%H>`Ob=KyO2=RzvgR%4dy;5z2)T(pJMBA|kBLT=Eepw&bUV9V(=hKU2O` zrg@%cX3QNeoRHU>x>nlWwqFf*ogE$7rgF##F%-Y7HFvNSGK`*dO4H zezCp6P%ZDsAlO)$Gd|*0U0WRaA;+~~hlVHq?jB!_y1^_7f>wiz7H6I{xgc-BzOAG( zLZz2Q1P|r3U;GQE{2S!8c$Bd+VkNpG#7&o_MW55dd{S3*%7`dj6ED3MXW*qK2;+tF zq9`A)Pd`s2icu059|#jS$v=0i#_`qR@4(r^!0$4bU0jE z@ut^QKMuMn3=rO@v1)k{(V)9xZ14(WxUXS#>j9uob7Bwc*msU=wh1X{Vu3ntu%;3| zG~a*%$=`4q>h36{h1h}#;@R!vhw&IAvJN1DsIVvyj!G@P4gOl27H{G!7P_;({uHW8 zY6`srr6Z(|n5kK#0`b0X3jaHFo~j`N7@P2;HzN{mOLg&vlA5{#?&f=YEdWF6aSkVp zfTyq)I$xlyAM!W`>K@tg<_SCe_tI2FYi}`#m_ZZ8@ixVts1WMZ`yiawQ zGgy=o@Y)df?z2%%>izBLlld>Nwnbf~6yQ0WDIgb^epHaV#Mbhe$~6!XRjP^ES9h9s z;It}rZ>sE`GuYTmdNM)LxqsDdmu1mQu!3r~E;A@WJf@fLZ_DQs9NeGQ<)t|xFWC{- zh#L%oI~n9A%r*4i+^~I@(v$4EBpEW@{I_VV^T1q?%o$!mMu4EAv%e)Wwh3Tfh#j&6 za4-Y)FuFl0=nQ)Sl7GcnS_e0>wJ)arpbR}{HbiqQ9SZ$L;2+B59q&NT%II*15zfeI z5&}GZfTC|L;-}bB=aJ|ALVgpwLXp!0gJ`1E?hj;($J9S79O4hT>f8_*S=NIvw0sr^ zNjbC1DA|&GwHTwmv_1bneh>YlO&S33lPF14!uTc5koiA?Rh9n@l)pRzE4srY20JWS zRX$zgv3otRNh&#j42?yRTvNa_gFf(6pe6KRgh!9Zk~bV+=3S@07W0T-NfKrg$a}-J zu-Hg#-*-G+CU*kLMd4RX@8;a#r)#^b0<3so4PkvK>kiq61`c5H`j z6|{$ku7IW?I-GEG8U<@|E^079!R7~(s#Q}_{e%4?sKvYTmwl|8*nFpqf<*G7-QD;- zP7LGJ$2C4B;J;vhl2l{`(^8|<+&V#BXput0xZ$$HuFXOH7jA^gZ%pR z$oQ?)`-xmO(x8u0BA~SP=McZ0J#=kRD^KUrfP?;V1i@b^Zf1!x4?Z_d@A8JOF(6^8 zheJ412|~ID$^u;bp&32U0lq1+t)msq{bOd5Wup z%8mG-8vcOGl_R&oa$8a+AJsO2V~dpY;nCy`;M6njHcdTKX<3 zIM{B|R}?3BsccJv(>jiOLzW)>H#}V0&9{{;Vpg3uTbD+HbQ)8R=6eBuM*IH0%%SH) z)-3RsRt8ElabQYQyt`qte~hRFUw9M+({YGt6l9g3WrQRo_M(3|%htmxI|6jn-`h8i zqlsuC_5c_4yP%+dVr|^Y*LUN0@4iT@WJ(946Qyn=Eko^2-Z^xRNE@JOs9c)8jCU7= zEpHtAW~oRVLC>@Q`v3n5-7do7_b!EgK}mU`emGo0CIIP`8H*d}C%SYGg=oKX4g6Xy z?7ZA4ssad(3Wc#@OWT{HG}}+A$(__MqHd>w%8>G;hlLYvy7(>Le!!6-Ep04~I|V4& zDqE-d*VUzz(uQAh!HC+PO{234X=wEgDBDU)jf;XWZqYVQ10g3-VzFj` zaKrTcFC<)uiH*s$9ZNLSUTv|a8-^x$g`?GxgI~+elpfUrOl$;@nNCl)kX>Q6)!GQ8 z+eIMvTZnu6K?`=WjH%%vts@nx5AKfpmXa=r&FvCUuP>2L0b|!+ft)9GT~EiOQ+EgY z09uMawZ+a2-TbSqVT~U7*6D)wX$r4(xG4L(&a7Qdzej%OL4)MEu#6aBgBdWR!Dl6( zU}EAQ69*sGsNxNi1(OA3=`x^* zWluqO8!1(at0S}q!fC8NDq;w3hNf>@!We9q)6PuAQch8U(@dUK1sAG%31MOtFI@3|4p%8q} zPD$O!=9PBp8_LQ+tq~%a4AK z)B-F3jT8hOw$v(vg9 z1B$>jsRV&yI(+%KHSR{r*dSdM$i$jSaBe!!D7~OKNd>S!nM?XhEvm`dY|$l9b;$x$ zxhMnz#`E-)j<|ay#U5C&a;n#R3!M|uxmE=IU0Qp~gduRza$KIw9J0WfQBTMWelb-QBY$6O6Rac5v4ki6rb=f?A-*rZu$bbhCd zUt*1722qe@|7Tz7Qad1|k#oI${#XXmNz^LDv_#~2i@*uRFcJ|^t0K=(c`L*j`5?&r zmyaHdM5Ie`E0ecxrNq=f7Y`o$DEbQt7vj^NR@9jo-fhZnl~1*>vGzUW2MVS=tz3X7 z^crmnav};Rm4NsMW$0v&24!4`f8-vo=9!H#`&>7kR zI%_UyrrGxXk6)nD`-nKgh^dDUAuh)i;q>e6q&XbCXwB%VTX*^FudhVgt385L{#fE@ zB{(t2_%Bl4gK+{x7b>kr`YKhYh0SbD{J)c!A%KtJB+Fl#vxGFr<#d}_F#1ekx40vH zdXBAP-)49ELPV&hv!4{L;cylRRaTE?X|583*S$gS^}OJYsZUtWb9?c6C7t*cWX+@} z_nkYtoOJ_cr|wA({@3@n;&Bbl;0*K3w~}&;9}z;9)rcBcaHv%bmxkFiD)_8B*cY4FcoKq61q%sFg76F%kO5K{lUT9vbjOIzTHv z&WH)q;0MkNUdJ&+tRUXTm$xIg@6VZUiYYKzS$iP{O7Jj?puW`6Bi#K(>i`0l(%bx8 zPF*n`u=@oWWj$D13}^}#X<#|4v@W?nA6;6*XGNxDHl6OYwJST_S-1{0>_9E<7FAcp zEWFXtuElta)W2G*)d54!>^Tl%cXh|6Ip+&lR^~rd=+j?60M`zDWlyWLc6xA?Lg44x zafokWN(u10KH!EI4^r6vk4}5^oN$djj$rUXONoxUHO?J-flTRY>BK6D>nbW2#tI79 z6K3`aPigP3ZSP$m#4V>q;;I=T8QJHws+b9M~~v*KBaGx--Kv#DH7 z;(_}9KXGV(_Ax)HcdEWWo1*Zs;&I2FLOSHfvrV?(pBow_PRm5ytFuavJ}V+h)FB{s zpNI|6@<81EuBTIx0O2Z63fuK^47Fxb9f;ZX9&83qzp5}0Fk@jN8xW@z=gd#iV|U|y zAS^`zkGl7-jwFM!83%gfF@|COp_l-f)Ae!o!4kzP_=~}X239|~ zOCtOGRAkgv|JWq=Xh0J$N$S`Fijtr}C%S5$nJl+auFKL8Au5WtM{GKRDa81F8MI(K z8LJ@_RX%0IHaG5w+CU)Sf_8kCh^=_z^lR#q&}2Jgvq^^3L|oVJ%R@9tr{_Lx2WH{; zz??6lMRosxgVKCP z)09Xy28}aI;#A4=kDtA_lY^E^WlTrmFI8=$p3{gZ($=o$^APK_Jn;UC64SA?M{bZN z=3G#zXQEmu`?Z#m-}j*3d*VGOSzIc}0*&LYYYdaGB?Wyft?sr|ub@7_cuYynYUIC%FYKXvAR((&iwi(O{2&VQ zCEj;iqgGr}XAwGRALXO9gmr}rd(}ACFedgXtNBC5x`T7W<|loF#P{8}z@G#KF3eg*RN3nBbY=G5rLj1=vRi4lKd}c=#_T&~1OU)^XZ#Wc)XX1fX$A)JWX0Hnl z0=3Fnb0!O=NI%HG^VrL!_k>)j=R0oed zv#;dHU!=E#RGb^bPHoM!qp@A=0U%{Ku#th7`xjPbuWuK*>h1+#c6c&Q&a&(;rEeV&=I9Arn^eDIIv5XG5+Y&1>(t55Yq;#a#+SMm?@U0$v zM%#Hq_`{5|s-UiGPK_2r;XkN3tuFVod~hBINkMhJFb4 z!u@{BWxpl}e+pe??t`V;NgBu9n8CneCzGL#|4NxA<~SKNJJ<3*zvdadUPmG3U6G`B zsCQ)jT}?##qCha;B8==yptuJlz`n+TfW|q*#OTrD4j7F4q$0%NQ$T_7Y0m0<0F!~l z{i6W~`W||?iEwu-EE#MkXs|2C((Y5*Sn*P%qe#9yI)3ckgQrrmC4C#c{M_2WLMM*w z7pjnW3{o7@^Py*%wLb=u1K`Cy@Gz~Q@FB&CxOEJaH*7NBU?ZU>ho};C#dj7esF}R& ze$iyt-k3{;095n;Fh53cEVEmO@E87Z1{7EcyL2;q8(f&ivnQPhRl5-N5wR z36F*#vU!LG+g=PFhT}FV+_d)k#Cm_hI|d&;fk+Irknx@i1#FQmz-rXg3OVhTUSB)k zXorlRNYZofk3fWUwCd@_()=q8|n7HuE_=xXWy(Aa4bz8?TYaoZMIq}X>WgKHbgycVSEcJ_28W!VK$O{&j1ImyTI_Y} zd$oE&{Y}^m?02QGBXeY8-*kSgd_Tn8H_{A-y>DNUS#~VLPLKDv;s?G0KW;p~bKz3+ zIP^OW$x3H|D+Iw^T3G9pH-PrO54AxFE7~HAnot;rqe2voSDyHZ@9ageX&0n%gfc$eaf{4@VD`?Y3*Jl*BFmcA_0vG{ zK?7zp9At+E4i!+!HjNpC?3HggRrBQ^ku^sqtOAyG9{FoeXg{; z3g#BM>7euKONp?}tL3#7beh7IFMzYWQILDnUh-M2(i~3B2?ie-R%c;SS$lf{bPX@> zA7<<{gtX>=9LEbm$iq3}55Z?O@}mPo-unu}p!l((=r6FH+-sHUQ3Kz2`%%~RzI2FW z&9X|0TsL0nmFf2jgZ;%|=zgf1JRvxPhGBgIxcLLl#;ENU&;ahK3BIGPA7ZMp=y^>A z2pnO{O@ymbVTKz_Q=Yq)p<2w^?1D?s`^uu?Y*W6oxg&ulwwJ1=z|ybUgUg@#B{kyr zuAD{*tbQmECV&u4!!TU@53uzM*RP?2U(ChRH=h4x`Ddd{f_J5{x>Fl z({hw+qAPam_n|V@&u`_j?6n>kMMbY>nk=`->nOLbTZH^v<=&P%_vQm^GO7--nk}#? zrt~qcb=H^g6l6Rn=iIhlGt;SQw#i);nef4iLc#?aC(I!?1K%YFiLxr!vTO^#QHj@L z5Zj0{TS-+m5uM0{S@Mq`xR7XSyw*pkB8?DJlOZ`3_E1%3Y<}^dz|KjOdG@9d@AF2p zh%rNz)%IjGep>TnioiH9rQbq#^38(M`#Y?gwTvqgfVj&_Kph$#)LCyudiBI7 zs4Qb@UAi`14%n)LJgG_AbNBeGlw9}nO*%L^D@brBQr%N{ZXG%+m}QGa5sZAjULSD6 z8s}YHvId~#YVg05Muf@Ne(=cDinzbFd6s&346y(wlqZK|^*moZWDE@;3Zw)jzXkGQ zy^D0BpgI|VpZ#{%xs773BYrqy(t_hn>y`&ae%Ev%AEuEr(22oJZj?<`emFWfw=`jk z@sV7*eMVb?T@55YkH=I9bHEUQVjFF~++WlPGEQcMhN(-38krAy0o`~_cZm5U32?}XX>_5IbH2#nJ{FQPX!Ch#wBiN~IA2J1e4EGja*Tap+2h zee_vbB-v0XWBcyzd9Fh8e89PFTID_qVf}p zwpNA=L{s+xnMcVv*?#C;8YrVptfZLasVAm7N!fAxzztG|s!hMp zJ&81x=$9*yg2;s28uB5{0di7b1qrQ%nJT5Y&o0RH1vSlrenNwAXKtYLL7XxYg=;IAPsm$%5$1;LMC%uj;Q;pZLobQcH@^z zprd&z{p^iLr;Oa5IA5C?J%-&T+9l{gwR_#6RQFY3js|hzY(^U%sTLt0@(h!fmM4?5Xr@;9B$ZfQ8sbnYx-29@NY$!Is1DP$k2gz@{fZW-=0QA5lx>I zT^><7fZ!qsWB(}=i?yIe@S2nDjpx)!<#w;|9xOMOB=A>eqZxO9^6b&;v~Nr9Ylm(K zp`>l;`(d4V_q0JV4QxQ5yPH@!z5~z(VkRC0M|b-(w%!h2vdnkDp zg|6?z_+dzH7O41Lu`P67wD2O`AD5wX!8{ESCV(2=6ucE5p}bKkY`dMbgw2-&XeL#W zBpPXgD7d~brpR3_-44flTEVWB@dR4nBq4$Jy(0$s z!Rl)>vH{cR7Ga{S8iB6|&N(+v~6pXH!58uRuqAhQ*!My=!B6S&?CneGli)f3tC z6bbXoppx|lgx6nx?ja2nFSfhsA$nQ zq+$EUA-{39n2*nC zsWTsYJ1=@0gE91OgXXc8O&nXPC%AL!fcACn*uk86m&Lnh9aw00=tdW~q`57JHcH%e z+M$PlMD%?hJcZOIKlu-QSS>(bZqt|OD#wpu%og;a3yGskFak*u>xNaTtwJa#6O4n+ zm!#sB&CCbR5PjkG0AxWc+Q|m62>2Ey2Nn@MXSdx!iFd0<&opl-j*L>>8-8D?-wrIi z_tL-vNY@_fiG1UGpT>n5!*J#Nz#!HB09>an<^Qeo58}n}t$6%Jd6>Jdzs{H1f(s<9u;{%_IusPoRWMjTR~f%yIbuH0R)3{s>$%z1YXPw63mrpxY` zEkNLN@I7`RQMY}}$;N71EA*{tj2|hdd6wcbzt+Ou3%hYMSjNtq;&E|Roe?L}CIpAMWZaN2&P9^o zCZitx>O0*aN0uJAs)xpq|12Jj&Wt15R0fGF<*!A`x(l?ljCNGgLX%czNDRCUVxi`d zfOdvAWgJ|Tg)XAr<^VIHB{y-u#o7j4^8l^fR*$=`cAoY3X4Yk$<-0*;oa@#qlvk1% zq#41%cNKj#xX_RLp5Zc`H+Uooo-k`CAuXMSdji+V3QVBJpA4TiLQjyu>l&|cPP^T~ zq)F4JQQB{Cw0uM|YNeuj6;nF2`16s+KhImxx^R)$YD!1)9{%N`N6N-PDV#l zFPhQAx6>$h*kJ0xt`nYML^>GFoBIJv_=d-KJ0rNZ$=9Vqov z(>R`(P9{^^wEnP)A9wr}D>;vx2GU}`C=>I{FqAOlmic8t)bmT+Ms%v_`GCbu`i$%t z{p$ zr{*AGH~1}txHKz8iorSghawtce&tsJi~Q6+JsR?dSZatu2?w1z)BkIctI zeFXW3B{xLg)-Wr|s`VhD)V&Gf32gOwZbxp#UDkw9(%9DkSr7<#T47sCKk4;Xbu!H^wkYIqN{l!p4=79k8whHR}Uk3#ne%gNlP+*kI@OVW8sQDtx z^)$rnnQefc$|q5F&+`T0RzAFCm6B$V{O!5-ZVK3uTMTAf(9>&ZbU%9Vu9w@$^}qBk z%L=&b4GeQg`^BY|$K2hc`(DomqG_1dxlbn?L0Cs8;Z zgU`MX4nvF?4gcOs4Xlof>p1Tj6MGf=a1p76T(3~rlNzm){iFtMw+k`0E|*-7>hXZD z_2p34*q5rH)9;?yom^Exy@Af!k2ajsvt5rG6VU_5=tli}1c8|V9_k{Ez{uDZVT!vb z$Yfi`pRD}?j&`8?$BX&JJiV_D<6kF%&8yz}ZM6&-#@=rpI#!W&cl*Wy^Z`(KQiCmp zR~6P*wi^lw)29ZLekiZ`hre`^xb!gSCCX=RnlJ!}6wMi9wJJ>MjVeirS9(YPwKWiKk3f1=fBm%YNmUQkV3na5oPB88rJf{Bv9(JU;}wI&7tIr0`9w}0INjF?VB{bLp0;pclX=C-K^ZjL6+Oy zGw_PSpZdI>D?A`I3kLC#5VBg&!|QbVnCxRYSW4U}HKC)|5~?C2%ZhH#X}F(swg& zkA}`l`OYf!g7fpK!}CDaZOr5{`%z>Zit;#TS?7lcj;{2~srd0Q`~Qt7%4hWuul@Cm z{5FCGFYRFSUH2isK}K!rT}odmOd#&~!E8)|-ykx(nu5h_y!AmGGWxgp%|M@qrF+B~ zuQy-rpf}`@*7Getp+R9gKU5s*CNV4!#~IIZP#mZ5Nf$ihsf7R4RUf!5;2NX_v`y)X zp0l>|>8CfZPT6j+4PimJ_KUX6BZoOeqN#m?w^K37aP9kD4wUaH%Hn=-ob z12hCF&I$T>5xCJ2{`##Vc_M6S7nbgrT9s-x0@F2s7Jk$eck9oGfveN}w-|l7mE_ZS z09~`Ny){r)c_D>v41Vcv_!dP;@&q)pp<@4EYiUdVxHKUQdOS>Y=v!421Z3DED|E5p z>^A&fm0gG#=^?544M7g5QuO-Mbc22&+XNY%afGx4TEya~6+@32sJ)~+U$%p>)~tXF zL$ns6W?Dv?99!FVL;~)%q~togP=@>gzdk?H#1n64T1^w{Mr&D49R!OHfKy|Pz%wSeF z41$y;G^MGLNBG24NnV^2w!t>($#5)CrC79U+AaE;0weeT6AwWn?7?(*;)m^~ICu-0 zxDhvQNvP2{vL7=)2CI*c# z7m!eyC-DQ9-YwueYw41jgkv`PmUtpzkeA7v>KzK>iqOi*27%t-=E3*BiVwap{>^jMz$yZ~JV zhswAfCx_SGE<9)~7Nr(p$Y;D*ml$D-An)X||MRXwPl zLKMyEPR;3SW^7uW-?;x8gZ5#nKkh@_L3NLq*FS+KrUE^eBJpauO?S!%m&!Yy zdTbTVDx$b!VxE|P&Y^U3bIa#frU52G%g{tYAB!$t%noT6W9S%(bvsaxbZxf**1{j7 z{CUYCq}6Ucc+shIsKSVV?p`WY=VY#LzQ~$$#|xA+`^<~3>iZmL&!M#)idXb3Z4Gm4+9td35-7R7-(&Zhv~1e_mVH z1iGrJE`HxNO@rytov-H&&YD2$gbZMCb3{eB)Bh2%qC|1QtV9APUyP-z{q+dMs)uTr zFaeUREbu@<(P2R{3+ey+ANCBnFuHkuv;sQIeaV8&G40Z_{sFk~E*2H;Ma@&H^g{*V ztCJ!mB?*6Fvx;x$H#|nU~vVz*QSC0_NO=2$Lngn|!UFN>pNUo`0 zh6t^C%VWBEBIW)PU+L(?L~)=cqUZ|Nf%RI@Ahgm#FP^u1tv?uU9_N^Sf!ph-u0*>K zD1iw5{YaH@IVU-L|Mffozk0y#?LU!bbvFgQp{j3(KIc3v>3q~|JX~oaQ3~J-K1J!D1Yk zxlNZR(a|(5i#|fHnXRG0%l0l7FlHyzM^yO^_mDWmzd&jnlAa#0Mvw z;8xE2uTFcN)e(zqaa9UyK%WI@4)C?Za$4WV+>_sH+<14KuMd5a|GgbivrPSPwm!vg zsqz~_X9k$D?brzll1yyjBa}LRFf}TY`_P+s&Q-hh!J%4oH1pZTd2fQ!;By_WF{oUlUf;^ibU0Y)AE{z-11s{Soj)Hq1HJz}bIVE~T(vZp zD!fbRCCbxu7D@a`t<)=v^BFSQ?ZtsrlUueAc-m$*JP+0IYF`S%oVC7Jsrxjad;!8R zhclX@m9$%?)Qq|309#6!h$5}1uv}S%f_5st z&rqW2B=M7CWYrf#a8akSjSR-Z>?FhrwiCgGMvy|C!a7_C1Q0m{y5EB}Yuo`9)KA?w z66^SJOqw*!Fo|9xHm=BV!SM1vql|_KT~2aamPB>bH0%>|Q-1HdNIboByqM`#8olv5 zbSLO3i@njmBhD+YKUAoVxz?Lj%a!nF0YGN>{-o)${ed7 zOgAnkmHW;5=GAk{h0Fo4E=Oc{fxw$8h|vmNzHe-@IsN|<3a7u65*2~B{ZJ{X%7KNk zzMP~?8+R#N_UhR@Lss7>j^1_oGN|gyQ)96;3BI73I7&wzW)Rc1H zO<;xC@j^VycsnIf0x@$ZE|OD13n-a7_(AG2lxpl&QY&+djVLnvu+}r(x#+(X^V0N# zz*hC8eYK%_QIvCx7J-TXvvskU%45#m@y3Y?LdvBXz2SKJj-D%{Jw26GAe`wEgF}fh z+BOv{ahaebBF9s{lgpChK-tmj>h~uL?KK>Z4#D3-gfwqaHl6>Z#lAZU*XJM@A4T}c zxto(96En*Zsb7@EUl_K#S(|)AZ%?}5<)KR2v`*-l@i#JTGnuApE&D^J8tLq3d*xTr z;D$1^olL4(1r3gd8Ksp?JuT8~{ObhHQKfUJ@#f#|Jshcsku`8F=oeS>Ew;j zuaBifSu-!8`z^5P?pIFj#S?CiWb{R=)89X)UKX&z4I=$uP29}V;q<{^r&16W8T^eT z9`AgB@ZQtYIa=qLH{8lq&DiZAMhQZ6j`Th>Uu&936RP|If9A*0l8R2*{=JPj+LM>{ z({3Xq0<&gNZ(#x|yBFhJ%J80L8%fCd5{HNJ8-Z`rVqz(l$uGwwCs} z`S83X0JpemqQt^XAb)$eCtgYIpR|S~tsko15DQSb^`Zu2q+ZdLAAo5kyi;7i zX2smqD~H{YCz##&@{@jD9fffBw=3L*%7Np$bgGQY#*p7X{RrJ5Zr`%;!0~@-|0BVL zEL~>g<~8~{^CuT$xPbhnxOF{gcj9%TL&hj3a2+Rp7*2mr767ZZ0T6)ElgS(C{R1;j@b5Ca#;G+#{0k09`}PNSJQUQr#yLp?zC0 z-x8qFEG7;4JswibdH%b(-=OYGS3YJ)8)-AU9YH%($xso)4OCtXWiYd-JJO*IO^M`N zP%yQyRQsz*2eS%pUF_c=(}PiE_7=%~o;08L923}ZPDo-DX&L_-Wyp4pIXMMN6A%X- z1$F~w$z_+(SBhFbGDWpVTxG+~k;+i)D1M?o3oe)oycf2i zKGgXuL>T#`hob;x2aCzr#U~ns)&V92{-lYbTFU0d=C0Ci3d;Niv4;S zoPcN$nQ7W!)@>Sqgky>0q&Dl>LFS7$45O^x8E+i%&;{<$d_S0~$G+;eCHW&tH2GT= z|GrAl4H=z0w~dXuDNXnM3P)h+(?vCiH)+sP9$q?#l2_9z{IJo!+{J8Qrgj9@YzL}c zJp=C9ot|T)!_3X#A8Po;=g4AsA(`{bKL@v(AY}_x5Lk0x(gjs)M!qZfh|}IYPr%T5 zfG7o9K3V1DJ*8@1Pnb|6^xk+y3S*r%w06}ugr&H9i8N2=ue%Fji%L{*y+f(UxN-Sx ziSqAK`XX74D=i$-3S0Zi?_~uhg;@clpuVaFN=-rc_@-snxI))rcv7i#Sz=FpD_Ncy zHrJYpaH53ba}D**kHq(B>JA075;>@4fUTX>bpP%2Sux+9U98C6+VV)BXLF|3r8WHs zxh~lOO@uR-0adj9WMSp;L{QZuF7N-k4|)pWU17Err0xfo3HGul>)q+D9b%c(Fp7a6 zW)o{tbWJoUc|0@YkJitJaQhVkBA{b^NtQQ>?9ya0vSFemKL1g70(Z!pfXAS;(9}$& zG#uqCo9dtt`ZEZ@Kgy9lFxk!Ykn#fvU*X>3^!Xr>hM6HDK)Xk$C~DHg38BHKK?;nb z7br=(y4H0wd_pFl;Hu4Xxu|(dS#o8C7K{@3AFK3!l{Mll!PGt(OL~>ASHfq3_gN%| zTPjWA{Pkxx=oz+oo1JeM9ylVYMFMz#UxXnuF5$HKDAbign7^y%tSa>@IO79QJ<>q( zjqAiWg{+s9f7(I2PjKsXXlGY&mpW$^p$meed0Zd`eq zyhoj#NjXJEM*7QppFPrf?jC#Aih9{sM-d#V>Xv@e)R{%*@Rm-?U%2f!!dt2ELRHhs zDJ_|&M{KSC;aspZ5Z!eMbs;;9neg@GS)ztn42cK_9D@x*EUJ!96|jPxM3V#LSLwKl zZG5xKrm+j&fwP%h<33vvswnKj$Uq%S$EGjW`RdW>IbbziCW%dSlC?84kJXo!*kA() z$ih0f2qvX%UA7Lt^B>44oV{T5bE(E>3H&Z4bEu7e0&65_U1kg?zk3_{ z{3{Lxn&Wy*Zm;TbGMf-~PwTwlkms$izo8PDe`=?;ZO4q%ASJ$wtE|l%i8M$gFVHvT zcwk6Gh0649QR(d^m=zC6U23GqCr=_I1oD+nTq!134T^{Atj55vyRH6VEBUx06P8q zttKJJ2?w#5MLjDSM2{! zOB|736GFqhXk;2uy5KC<(sC?rGT6K$YJIhrWMF4plB1j{xQT~wanQ@;snq9}F zbaIbA?NoQUAb=8}XUJi1%FBgiUAC-l9qr9bm9;B_;@Ji`e&MJfp93Lqy+0&;wWuvs z)!uN2V03z3+-&-25H+$tC6&IXJER%{|!ZTB+~>_1s299=<7JR?;#&Ov$C|t8FLvzVK)OO#aPBj# z`{Wod4`oR7wv`W2uCJtf)k+7)vPSW??d1_nOva3nwVyBEj}$1oCA({!%B3aFRunxA zrY~OKc4v1fep4a4&K3kY(x#;2;(Mu{IZ}4h5o9A!u&-&$F{scKJYPQW?`-G`@~xOn zPA)(o=q_l&R$=<7@6u+e88Tu0j#9*>F)&i1r3l8d-YPLt0+lIOKlI!cbw|x`(o;Ff#bz3xk6hH0%@jm{)FWZY7UE-S9l$ow7W7DvA_`%RA0`xMkkP9VRX=n6_g3z;%;rc? zOrU_tk}VD^<IZudsX&f@Cwu{tToc}9SSKs&#wNTOxd@P7GcOjKt zDoFKd#E9VlS{mAs%KWms5B2U{Y`%dWU0r@wR?=EQOE59=M^f`s6b*u!F-XOA7WHZe zJ#y7rYXg}=5Jg*HYZG=O_!F9(GeFd~4+U8{8F9^Q4f?O~AM8XZ`rH6n&iw?0o;lb% z3O|?6SXz!9th^Y_5R#fhe|v5F`C}{2%C6=9wt{I&24`@-WfLO2NQcB65nl=3gR1Pv8{YqkUx@zd;^P*Bn?3gHx~%2x!66rGG%M0lo>dA!fK;2d4q=!8PqDLw(!OtJ7S;=ziz9q)5WnomBJ{ z?~+%XeO>ALlFF+dV)2c?YVc&9&@n3y3nywP>rwI?0Ev_JbI0ueiNCP%%vC6uL~3I? zls)ns`?MdrS5awj95OxkgK>BV z61vTsE8Cy;M1Pdog42whQyxz2iONXV?!KQccOT*(&`<`{>ekw#H!@RfxYrNXhS@ZR5M*WTw_eJqPNZsioMl666ZRUKs`vmm?IdN zoWB8LO`i;0-%k+2OI|E6cT6gNuUXVAlnRSmV2XY?b32R-2lc`OxQmb)9f`Y|*%T~f zQzZ1`f934z^E<7B36^a3RBp137T=~b&=S{YT;4ZZx*8H}-e(SRr18i|2dF49MNpdl)(b}hW}9hVHSY#U+sR~MH=SM(kL{xf z9b@l0+pQyC`Ya)GcKnV#Vl@HW4}YauhstHc#Hmg}k2GWYaHo)*Nc@#^*Rr%r-V{sQ zMevj#Jb6@UG?h2N;WPwb6ausR6T`;6P=cEFqR_LiimwXxD zY@%r`QVh=U_!2vPm`@;JSon!&&u4=%N%wD!CJl62{>DJv1N`ptu)(u{j4k-fbaTT6 zQ?6gHIT*k+bl#+8#asTIQ>&RhX}Mjrg~ZF+3#0hw+5ItYBF;bf(fVb<9^!7eS654mby9QS$ME z@+415mWp)swzXOVWaEF){vO=p|c!&S54EChMgtG+YJFdA9sOV6U6#-m^s2U8BO1WIJdpI;Vtd_YLS+mgu_8E1^Xt zt9+h66N0MBRGuv=G@Zc%bXwa%*pj}M#-?a&yfy1Tq6}*vIFAJ`i1724%F&JOp0n-7 z5Jbz*{9oFxngo5MkRdh$w=K+R5usqHJ<0`wtTGvz4Gg627-atZX}El9E}KI|;~-j7 zP9)cpE;{Z4zLX6~L@8kKSV`?pCHF_@Gx9P9-KU#*Z|w#~0qCJb9i+O`lSv0d+{$ch z#nyxDqc?z&d$^Mvg)aTMc4Bp=YCjq7M$uc4(qG>N;LX} zC8f$x$Kw!!*P{Mv$1sT%z%D&XErI5qkgU2-fo*Tg;8q?JKUR9H{b(ibN*Uve6eTp2 zxABGwAMr;Zag{q1OL2PO zcd__!P{tpwCAB%+hzbKpr~4sXsGFeHLeo$mUJLE;vj`SR)I`MSCbcuskZ>6-ueF!Dy)fz zf_unrB2P8JkWPWgV}ruu1kyVpoit+zp8mtp#nm{};dl zLuOaqkdw8fbh*Ex&=&U~5Q(vJAn@1)`n!{)qS;T87h~k9N_Nmnv?WCz&giKZ6$x+s zC3G8cNE2{<&E~#^ibK&JB`lzDz`8jM0}Wvbj0M6praj-IzkCsnIuyg3-EjPlh{oV`cJF zbfO+|QIwfgT(U69L?q`leB)!bNv@u7P;XTbR|{&ZES1H z(Av1%tS&oKy}??6zUT(vVBgS=V28~Gc6h=7UJi0TmXZ#v32|P365%;Ay7}kh7vUGo zxm*5#{jL%^OB2(WH5wN|L8Edm;dFH(se^OUV8uWm7czrsUi?s>6+3m33}8kp3A<>d zO;7&M0L5OgVcrc^kMSd#pu;RZ69}C>F4T`41F&8zm3bzK_Cu8`!dH+sryq=^%=u=Q zh7v6JLhD(dM-^zdbo&;UKnG{LRNcSo2p+&)AkBsOQk$L87QCOT&PbyTEHd+ENn`&U z>mCXB5@O9>#DqsmiljG9&G|N`O3k$;FSx)k{|F*POVh1BVAUVOQ5QIyUUk{WH8_O? zrMJ;odTKM*NE0QhQEm60rR>eZ%+tXsQTPLP{&#n06kOCX*H(wZ^La_TESlYbIR_DS zd8L`I-r;r*WfxpE)-hrpd424=o-o1#DA1^TTSq`KLuXX&KU(GKRkkeRWcIzaP<`FS z=JjzqL9CHQlIEgrU+l+fH1uC)n6Vfl$!;lBVp2P=7_f7Ru{~Q({YA3{2H_b%Wv}u7 z0C>7ov4)dQK1|UMr7YlVJYYNcufp+02mT&C2MIg2{kRd7RX0KcC47MC@7MDo_%a7% zj<|9Ob2R&TvKot)fy?51pV?a=rZM2Wt%-f5NPOK%h&i_M`ZE- zMoi?hmxSL9C0V~HO2`?=Sy94KcYVI`&P0`htUls zvGDzD{djwnl0AjuyuKMcENG5}n)|~Gv_*6L=Z{{Yj4d(q+jh z!86px3T{v$oYik|!XI-`Lyosx`2;j~Fet?G|5P0k_oL|e3|URNrEeJ1^Yq&EJLxw@ zmU7spnY%5AjFkBVoZ8#ck%iEj`{&L@r<97ji+skWF+z+QP?(!*=5Lt>`b2e**+sIV zX~?-a5OkKnJ^~ND6ge#4Fo12lY%S_q!$_Jc#bZ;Aa7q$cpol2*MIrrkgPZf|cRCYl zk6+^gB6Ij(8FdnsZ+ZC&Y+s`xbPcs+j^Q4xHI?`2XobAkE1ZdmR6crr;15JP3vY#M z4i6wd$KZ19$cO>g(iU)T`VMcq8$at_VQrIquAZKI8Q3IPA>_aoGfx3POOrdq0Kj`o zE>+-F_;^t7{La?{u{N`WU{7kv1L8GcHaFgoEf;Xey;(NM^~ zseupN_OUgLSb>7JV>p~%G{f^Fch&n$X=*v6brb<1^`GrgDIG7C!WoJOJ z0Ww|3e3oJo8(hPubmeEfJf;?nCwe8Gb)Z#^g#q@QK7);mpTP3d%F4WB@m@0Ee{JNS zo$kHorZ#WWF^k_g0AAidCM>24@XJE)6c6xMe1qBxPcM+L=_xT))s03BzkVTMtMF+A z93!}OgAij_HOU^kP_4r+7^7X#h*CIy%5v`{tn#LP+fA}d|G&_7Ha&e+-l zwL7V`;zb4c8{^GW63SHFSpy((aoPMlY4q@}v|ipo4mfr8L5pSfo-Wr}Hy!yaUJ}#P zrkqA$mVc#WVSU?-fLIP_bw>TXu#B6n+D={>!d90K&VqsuOsPSTUa&*9Hxm&g9&2j3 zt_Y1vzV_mn5!EZG&@f*>&*LNX<7F1NZO8YF&J-T`OHaD)rPc$}?Q zWjg%T%*UkQ-5o_m4wj15i4vp@WoD?QB<9MD^P)`yY}`D+qa|TZxC$pkKDQX~eemY+*baQMGC5AN?H$7U)gi!^H!M`eI&pfNRS`aM)sy?f=J~ z1=N!^`9f)JIjRcnE2B$OB^9N_t_i^im%PurI}A>N`8@57_{+;~bZ{$tuH>6+B@`4g z``lcTp0dFYFx!9;OYxD#f=*H@rgzd49fVf8w8J0sd@ZolwOzZiGbV;+ONmkNQr_e-WPg22Y*KK&yRRkd)F$+Scob^r{C zv^3kpo6>Im9My&{{5Nwttj2f@{eKeM$*6@*59mN{5{?hL7cNFYATPmw$iG^)wbB)9 zA?}|+RJWS?f?flsVNKRh9M$`7&WSU4#1W;&PAGZ`pRc>)Yl03q)-gXo|4C@Cr3D*L zL{thi{P?!cUOq?zqr`D@Gw2 zANn^B8Py9G=GN|jHWU_yS8a%i*X$^RKE0O3hNSW!sVxUOY8E^O4+2gF#`vG}^)@{Q zCL#8Bgv_{c+1urtUf-`32zRY?2q%rMQw;V^+<-Bs83QJY;im#n1O>lmJK$HIsH3~g!QZ`#^jZ2`;BgQGizW!m5-3M&jWv6*rJ>tU+D70x zn?4K$v%?y#IZQ6S+2;wIz-S@r@@^U1$7N^&$!w+#c-X-0#KI= z^l=gQ*)UwEu0GsLL3nhZA)VvRFD60krZmMllP8*952%mxP4MG!y5sx8>%y2zmh&~^ zk?>lM$zK*9I%^rkuZW^%Y`RM`LJkIEv`J~mX`w|53JE;e1@>7(Y$;;Jbo&m3fAOJ! zhrkpWPHwqnvz&5y2zEV{ZuD+dJTFV&qf{*07vOy#67w4kVRz@(uv#(UhY06E>HOKF zh^}Nh8H@F*N9*`+&F8D%e}%#b2GG%Z_m~Qx(YR}R-w!29?9Gh3wnwJ&rsQA-2y|v( z*Q#^J7$6-Bv8#R*&AnozQ-VQ(1MzQhZ#$Jwa}d9qq)GAHp*k;Krq1}bNpHYYy^Uvf z@3}kOt@fxEM@STdiuby$!ZzF03>>JZbXx!b38i=@=6fgt&O>}QzBcO5@FJS4(Zgsr z!(g@FOuy7l^GxIab@PC1azDzwgzT#}p#*wvlnGRIs8bOHW)~>72R=eg2_h~9DM$r~ zdGG9V)o{BOelnM=<&-8lf9J&WKqZl3+7sDe_iekcAm}LsQDSi;bqUMf!E+0YWf2|) z#~;3t)P0z^`fPSx4I0z+W@|`t^?U4^oOX`}ZV?A*6knluck)lq7r~qEdF4;bs>X=cB0L@6_MS1HNRo_K3 z^_fWzE75IihC7SQP1zUHYFhmRn;fhfXK*40s;R@#wU#m|?>kb_&WWcVH8@GBYYw^U zPt4hZ3Pf-bR+>3V$xzU!v}Xgte2QyQ=mtG3*??K4oMWRmI}=Q=hdVgKpND*^!u?AT zv~Ev$Q~TTe55O#0NU063^5U)n4$kh*gKa>EFn%RQ|Cl5s$kXGcPCAk?sxoMqi0a0E zj7s)Mf3oGcR>%S5VdbGw`%e3zwz|MdGi>;cj);I5qKPjQt6JyF@2V#Nb8}a=} zSYfV_!-zN}o+Cj63HrFcZQ*S=g>Dg(bnX-CLpCjmN;!U8zDl}F zNB<*A0em0X`tADU+ilnUydY&u@wQ|9cOib|GQ(xsebl6$C~|X3+ndV^mcoceS6qdx z1vB`TWXW-IEpI6tRcFKaqEKKl7uh}RmX9AjnY_596bs$z8#hEfmG=pyUN`glZ&VDa zC5DY`lMWTp$(?Is(9MmH+vS2^KC!Y4Mb4SKI~_j&kH)g>@!|n=UYlVe-$5wQ_GUwX<;O(M2Fg(F-fnRrB;-%20S_a@MQ3Kw~e0;>&*?^dId77bhtT?jU; z%-8osjgs*ePBfDmnV5VKYyBHrGUYoZfT|I#%hQulebA=u7z11~|7(J*o%VrnCa+ga zmo%cXfJzu)a(&(A9wC)mhJ#$gDF0xd#exoWyiA^gcufdIr+#e6WE0{#q)7D;Px~~8 zaQOvoVGs_2Zm!kFr1-dK9p4En_RZZjb+z@GX@>V%xGzJ)GesUn)I+KShU1GtO@%4R zFvT3nB)0#-B*Kc2{thF3V!ZkL!R8JGe%)YIIL>5&tVm$6O5A>emJ6Rb`ms31tReVbb8;Rv-WoTC5d67umedhz(ze$ zF|`aTyFIL*6N&hBGJ4JdwuT{;O$uKnq|@O2HzMyZfv|;?2)5ScMt0gFZ+utv|!U> zc=ZJBm+_o+%-Q)F`UdMAjsBjSG_RfVN~HA z0sO^~=`?N^V_fGfAa^rz)G?l}5gFU6$)>*qpWI-DHPL?uyQC^_a_i642hGip3(o|; zmRY$7|4 zVwrW`dGdE>?wr@9&E&QxPb^pkii3U)%JI*U3RZV2VtL6fP`WSljV|_T60Xuh_Y(2Cf^a`gBJKv4Y%# z>Gx@?Ej}EEu)YY18-E+blwz)0RmL5C5m`c!fvSmo?)krdnD7D)CQ039t*|PzsObgE z>ptcwMqWKySqRISVL54}E{DZmfXTtDwWZ0babl4z zas3@rn{W4lt6&p>KkhX_aPRakh;xE*Q}WuRqGiu2Ff9g)C5=SX)fH*rCmw^$n*u}P ztY>i|k9;UAZX3=#gZ&6v{whE#5eatGat!?9GEz9L+LZ~u}yc`oiKO`GAZSh*_rK5O682+*=qRwqZH!0!b z|6z)G0V1GgbuC4c3+|i^Ft*Z40-* zow670J1FyhLMhOLfUd_k&kqof1}~7 zHvcvud#zL`!uJv{K~ismMqJ?+0SLaju9}rQ716t5eDtBTrTy2E=RAQ+G?KIP6ht)< znH&&(DdCqi>#(gD@i0H>5m2eH87rX6v+3PM=*gvUk=PtylhXC{CT0F^$sVC@KLH%B zeJYAbDd2h;ogRLX@7aofc9Vrq!z3ByjUkMMU+kE8WgUtOod&G21$T)FYaptf_d*u~ zpgvkQPT@27A}r!css#zUjGe!}Yp7^hV zP7vrbpm}Y~<%i!L^HecP#2tqEQ&gHJ9d2`^mIos7nhLCyt&`;oNf@nu2vFLV^%{CV zzueEVC$AcThmuMrmi4}2O%=$gkyqZ-hWHXgi0iI;R5ZSsFjcYUy^e{RL5( zEG?mmeILs@y)>i{069R$zahuU_CeL-)?RkKd%N5Vmm+%9JOWgHa0;}E@LHnW{t278 zx{B0JM6jEWNcI)3bHuD>r8u1JTNKMW0zLA(69idGTdr>M(_iJ2g=LZ#6dk?nWgxpX z_!?;pcp^E+8gav`aHain(MTA0H7C@K8@J4HSpz>F+S(%%R=ae^UjRBT;I?zGvcdzw@8@z*oP*z`Wp>;W z@&#ZKqFVci$AW&-9|iZ++@eAvUjf4z2>>_c)C+DTjv&9*F8ixRBg)Zs*V5>dTI=^8 z*8kpv#5xNJka^1?vO^r)6W=;6d57dZmu?HhE53T2V9#K{f}pTREJ^z7PZ!L+Z(3%7 zf49F6pUWSO1gdGUDAIm^WJlMa>n*h!<6JUfc|%kFhGf>_q~ou!hoxu2H4pRUkwpNN zI6D0sRhkFm29NCEyRUl^54L6J@{Oc_o9kcVRgU{ttR)R2GyXc`9r;&V>7_sVP=Lbq z>Vb^o$Wm$piQSjO_73Yq+Aq+BC_63=pu>y25UMeggq~2myR_IUOgq2ja}kDh6swVi zNCTng-O>Wvx`=coy1)?3#_6-$JO-{iV3oT`uMHvyGzWIuS}IAMUc46`Liw% z=8*-#Ag9p$)o(GQIOh(Fj5|+)q#B>z4ir@;hzCjqQF-bsh=V@pxQDMkE`e z?`P0Ful%gS)u`^K6(Y$$RIEBJJ;H+IqLDsOYraJL)9sjjEB1xltzXX}lXaHrCuXz8T%Q z{|F4dfT<)C1;j+0_QcAZoT+{hAa34QVM;zCC_`!iVACoo=(4$0+zE#-BS&&`)8uh} zfQdIMfMkZ86(fv?Y=D(=kt@_zQ6C!>g*sz~8H(iXcggS;0h=A`u^hKS4k!Uxq>qPH zB-MTx#Hn?(AlG+3_+}PJ?ApyT=|8j#33G==44?)}G0@&7>=DSj`1AUC`@Z zGS6Y6&HCziT0W}NN*DR?5`txGsT&OFb``Nay3fL;^epo8OFl)^kCtT1#5i72H6ct% z;B%>v(9y1Dkv6U8_>QV^ft?CTk$?zBj$Y~=>{a)SJy}{NN zjiI*PUlk9+SWrwnyhIGCrN=>8%A1E*tj&FTwJrzy4odz+(&TPc9sbp4?a3qk8>R~` z62nIZJk;%$z+-fU0I5FOciy2+;)bEVeoG~cb-?QK(`n~Pirf$%-&in- zaO%4`P;cMRc9`X7ZvIaFZB?`4rVG}`X=?PyQaT_0hWRWHBlHoM3y??b{D9MDF=6Nc zR%j9Ly7IM)W!fhzsX#2lTN}oSwu^P!E$J6sTG1}^LUi&19jM?K^He5Ax9;Toug$NK z;*PO3do1@$GD~AjL!4Vd1&ST9OdQb))e^8;!F5~EFZ_Rk*%Ds-lt64FM%{5li6L+_ zy-RR?k}SsM`nyrkjHa29NHwpVmrcYtHvD)SAO!`jNO^RZNqaZ+)6Bxv*c?1xu~WTb zIcIjt>F~JII7P~H4?=Ic4k_=gPiHt?RPo)W`$R3?+Idb0tL@3uxHp95p-L?Tf(pJl z9WDE0-U{!Ac*`Qgg1)zO=Sj>I;2U4dsEp0D3djX<>E1d{OXbJLc5m9u%vPAfcd@(P z#(=&1QQ9hDv;8vE(57w$Tf6rKk`kV_jm~TDE83a;>9+wq&~p{`PnOwgfn_Z)9*NPp z;EXNyBRuE@j=A2}D;;L&ORFEL#!fA%S5QZ#^SBDfur!10lnwPTU>$%TU%(lch+`P2 zk(1vy{r`4`n=JtOZbLKOYh~X)iQ2D2IY0bWy3UyX;l+;>(;A5ZF;%uEg4T)TJ&-%Z zfL^XYXtxcmMy{|Tx;Yo=>dn#d?}+SLDXj`A>AEDVknPGu5Tz{sV5g3YVb!|>3s@VqjtUkEbGD;ls;P0?R-zanb2(Oq&f{WP~x6$)K_*0m>6&Q$)c;Ry4pv_a>bdyV4mBsn*fFL!9 zyjiqrGmQDphAL(aSXeqy`0n1)q|DG-o@e^KU#PT~trF3z} z2Y$~*nD%PLC{Mphn{)0`3UX@&QPG^M9^E~2+<=Os;4z{iKom^vkBxyf@dQBUUwH!@ z{I?|-7rwY-8=TmusfH8r;`}3Rk3`+X>*ppx6%D8Tu zsv6k<#AMbCHlnvPvCoj$g~`mZ1{*%}fsyW=^037efxMSNNyZnI(TMH1*K4vUxdMD9 z@O;J@JUS^KI(wFCq_2Q(??O!PEPmjxCA0CmI+1GSvfU#Jvn|u8v2ieqi?ISDAj@(} zl?W%)w1RN%|2gd{l3n2E+5Q6(5?N#YUeAe1I}bOZNI=x7HMY3VLj~oC-8MId)yWWx zH!;VEvCn_X0V~_KwcQ?4MX3;v{X!RW4{I5N#9@E|3)yKI7MJ}JK2nqHG=(f{$L>M= z2DA&-sMX@3*R`ZvYXT!lhX?6`4XxV0qyIaT3*_0e9_Ma;p{DrPBTlv<-=*%V+~#9b zGH|`o3Kbkj7Gv#Xmf&p+euzpJyJv~WlF2$_(g4joRH`N2m_4bV!#JvvsUcTWvAr*I zXd5%SAR~WU<9@CNn3t0HL*k;-yJZz}0aV^?_gFW~alTtuDunPD4s&yNRgGtlaP)iM zG@mj6Q3gc@GWZPZQ<$CuD_izPG467%?bZhJdt&~Gu)tuC|LVlFAK6fFm)Eb+?vd@e zzg`AI*LgSQu1Qx&m}9*ELPu77H$(wy)@(%J!pZ@EU2XPW+ z=USFePi&q8j4J8=OxhzjDTK_L?}7BUx8r8!)CcxFfP1mNmUtsP_6E7`ULY8%O>%?L zhlxc))wQ;6g~9W(QT`uHZrH0m`Pva_@NuWAX_o;;Hm6?5i$<-k~p0 z{5xNlD+;AWy|*-YvYB|(5DRE&+2LU|f#O2Tz zjRMz(oTBQ~LRe){A9hlc3m1Bqt1K#Cj=C^LiW;a!4?!C?f(BFb>`x1Uz5Oj8X(!FE z5-qEqMslwH1s+SPRtju|7OH;}Sg)8WMIIbcPgH`o6ANhFxuxo1P?<&nHLM~vcQuX; za<<$v)-J!nBbF`!Y9mm{y_40hsXj8&h^26ybmAd3PzRrgfGej?slasg@a^a=IZ?3Q zbOkMHkl_Jv{wI_>maq-!>Cinis^EJiL*;gtkUaq0r&5av)&#u?Hq4=v-VHu)>O)J0 zKacD>or!QP^yd4iDjz`8@Ou;D&s|jOW8;1(ZorU6Y*JQtcR5|wUJUT&4_m9$*iL`oYV+37#Dnf~nhI@|$J8?UJ~&>?(pyf3 z71^HN?lfTLczna~VTX;)Jrig?RNjWoud`QWS8FDjbev>x|=FZ-e z+GvK`32;`$)Te7)rNpg08NRLjb5G0(bp03$AdUG;HSwp2#CHFXK-v>hg5moNl{Iba z6ZA#hicueF)U1XA$z!DIaZqlVzz#+ z#oO3Kyd1h3f&0s%ACE>PK1WO4JoN2ZdT+ z8OAZbwtc--;bbnavUW4yw@_12FNB81;Teg_->*_wFY+Rva!h|(bK!h6_zp%8*H5vF z&yf~PpRSYIPiXvTp{qKFR9{k&b+3ao$IFN-=e?HsB9RFBLs% zWJ0kmv6{ImHXb2i!{mkY}rZ*O8hlC1ab*+3=b?Flv$B&&ra0L#jY#AVevrtQwxym)G)C85^7< z7gs6=Nxz<#7IrI8)X)^jMM2CKF9}Fqba(W&K6?gAT8bi#^#;V418VBHsnGgg~ckrREV^n zYQs|)X>s$SOtiYyisk0dLtXth{VD+Y4iAk2Sdw>~e)9!nWAE*Hkh@84u}7Om3U&m< zR6<`Cqo+=a;v0Y>r=|-c^Ln`ir+zU8s)ETjf~O4DAcfP3IE(lzJu-#13TLF?pj+At zQ@9&wooDX0px_ITrW_U3rv8L5(+=;KpRJ!VN|)sQr~I~Q(oZ4vK`#8gTGTeZ9!wyb z$qx|bLL3U+%2*K!skC6T59qJVtCr!Mab%}u3n5 zO;P9x%W9wg_6U3hT*lX~J=GFqZ4ApkLnD^?>3Qhr{YKNoYpx(piL z{Q>z~cS&juem37(BQJUsPz_n<72BtA&>!L4ZO4r^(t^&_$I-wFnEo8fhxTB$s1Z>9 z9sU$S(<`z-qDCz~jiG-jJ}@zsSJqZ2cIJJlv$9xM4c7!te<*P&IwK;T{>Pj-7|x7r z!Hf0UcGG-=`D~n$TMWq2PcS`qKSCcap(d{@98vkKq^(AF_|E=451leasyi6{I>d4rfU1btV$RCY zP36OsHLi67qGz_L(oTruZTebV$O36>oj(rJ9({lV1#Y)Vj`M8*2<)N`dKm4|&^nyR zUTt5rL$ooWdoE+fcSo6_u5aiDk`vBz)Mw~><8vIE;O1uIe0md|OM>ALe<@V8s^YA) zxveHsZic61QR60T_%p60Q0;4(-Ws>hy`(h9Aoou6t--F7*La^^T+Kf6KGSn2nqtX& zFw)jLUGjpgdB>fuF3fpzYb;hy8q*BqPvE zr`f1lPUrNYuYVN)nH50dZ_C3RC~^n5lRe8GNC;Hc#CoJJ-_W2la~}W(z!Aq*W0BQq zdhI+lEoey?w>y_z7b0>gy#g(+x$*lS>J_HHFamFD6>AWh0_urGq>Y^)fpMYLl-ED+ z{TaxU(5Y%?^x!##yr(Q$;`Ot1rDSix&}b^)`4xgdAcDe#Y_&lvDyJ)AHs7~44W6mU zjGhHIr!KZ&cU#p7Wl-aEuTg_qGvu30;9I=$If@j*ZHZo@c@%T`v-!^V(-rdQQDV5T zbpAY&0!fU=u0XbSfbT{q)|Z>3f}wPzFJ>BE$U?8H@uKq13e)g$Z2e~Q?2l$iQj~dU z(eOVNfdw=wZu_r%nW{E(80{#*sFM=-k1da_ImrtfJBSALj-EfQM(0?g^y8*M0y7!Qu0i}^`j=dXkKjWzHj9~_ zTDB}JBID7Fe8RnwBuZIixOX@}q9nVxuW0AlO48rd`9TTMyKsuB~9N3?tBv_^oQ9X^Hq7yTL_3@!OEGmY(Orm4ZX*MK#53q z7*Owk*l07)Csf@Cd*>kT9J;Pyw-@UQH1AWDN#r;dLyLRAXcVV4q9)iO7s`m;_?|Cy z69w}yyI9;&2F{RNdAeDRc|Hg#z>t#FjtqwXxcPE`fuh=_o|h4>2pbfb3}s8Qiw*vc z)P6GK`^0Y$E$p2y909#wyZRo%)B!WYCSJn0bK}%Uvj0Kh?ltM~KT;uu1uss^p8k+z zT)HZA6VjFHsx)@@#UZv<30JVEd5YrfgjPc*Y7$FD{5SO^E&ScUi(QeUZ==cDK zV!0J+9pj?m3=`+05;Ta#@_7lM*fr4mH2Yn~^bB7;M!>#qOKo;Zp{Nu0dfY;%A#X~P zj24?oTQ5eM_9jcZn8Ws}@1?gVm3C*C+E0~-q{P;50g#QY|Ge$M;jV(6xHW z?>1~HLH()qz)K=vGfa;V^5lDG1S9UaH*%AlJcVp8&tT5y9W92=q|%=Zj41aVt7|786M%Zy*xU(X3q=mo?k8_ z-5gG15t&>zmGbolO0qee@|L70yh=bK6K^>0KuHC8BKy&y;w)Ajkn2^ZLZ3@eKU+sy zLk52!IK({|9qMY8wE2mEO8nPOhE2;(KsZ#Ru?$BbaYNSumgQnt27f^IDYGu19v!+K zN5?QB{Zd63oC{sGUAWMv^Ro!*7FJ+5? z?X4xQO+KlB@hurh)`|lXSC7M$L9??Em7yLCm`L^OoE4dyMrN?BS_K7wWaLnP0hBB! zaZDSHElTLM9oicl^}Md@`@!6QZPp~ajTxP=q z#h1HYIGf`*Y~N8vPbWnU$ttFVaOC<2y!v`JbY1)s*BUA7*# zsh0MrML}p2Q*}(^+}!3ZVVUlhr%XyK0ingq5XID+DRRCG~?0GAp zzShtaP@66Kq8mER(0xtR32wicp(^U{c|w0cG7^N&X-+}>x_jK++o$O$S5P z>+Ucwc@VuEj9e_vq4yChK@2|ZXOPR>4O_K}4b_^^zy zB;d%B>6_BA7bYBxNDEY(+|59c8-`tjpbiK@dL$_}gMj!B+qG{D39EEy z6Bo$vhjA|;&vCY>)Ey4!+x@2X_|-1fGUmcej`y2;>F&@e%uuYx0Q{^3idZ8; zQLgPkB65qymGbpGq{0=#hh0d6_y(?;aCJ0NDCKjwcduU-*2^8Gwki`WP3$+!z(=~Q zOV4Yp9In@!WvwUUyYJp1B>-&~y&&139GNAx*}Ai=gpMZA)52!lp?x$|wH_|rKwnlJ zc4Vm7AM{*Qnp%Kmc2KVSu=4EO3}6K}Z6s3;R9PjD;r4xU12$SxPji5~yqvptvB^P}FHrYluK8!q#2>L5412?BLB+WJ-N|$oCv+u|Xc&nyhsWAuZe`5V`4XV-{ zXzHOr0pH7M&W54%B@B4)M{83tZ;(?Y+zIhMBsGLQ%Qd@O!&X4ap>o4MQpw6jqqj-S zb_xW=Wr#-z^-XCoqjBaCZ%Y8}zaNxr%bk{Q#vv|My= ztVjAUBFDjN+9)tNuQ`5&BnH7%`1gSq2v$sove(X$he!W`8Ppb3?;;!Mm%Zk={JN-l zt%o=Kib(Mtt^pp88zF6@2&S(7U(U$yUK={9zqy-qG!LT7@V7Cd7Y=(5gr_C;%o;V2 z)U2u6?JKVPCi7>6$z9CP#qEK&UT>+zhHN}97 zt=a&1PRVv3pz!ooGG>RjFH+v&u%g@d4{RYckbXA0E{}?*`pHEO2v=l2bM;IF6wH`53UQ?A%i2Dy>Mz`8MR8y@M~h3-9mZz!S!|`DwVM4 zrPL7(6wvSrItHWjHF9OC5((U3G=mIcapc{#bUH3~^dhD$j(|s0B|oYbzF)8JLss&xM3kbK{?VbSBMnXpcF2pn_08W(WEe^ktlVLsXWuD#anq zvdE8c2+ub#irAi%=yqVu4tg}w#tg&YVNpxkyt_8~5Xa^B$PdmB;BF=JWf~p4j!``R zS&FPCYXj`tixWxCG2IBSKkUW(_ zYd$W}W4ey1D&Qfm#DPUdrDSVmf4536bupuk{nbJ?m{3KpdQ+$fnNotM?ckGiqToOv zC*Vv^lL;@Dv5}~pNToU%boo*AsO2`7y!b+NU>GDeHO%$8_IA>PvZh&h$NPtzuLT&v z3#3@l5QOxo{$AVesFG;e=284WXUvY+TwPFDoYByJVmHiv2bTBIU;y{=7Kyartq%SW z$RybwM*Vp_CYs4(;za~Czd*$g_hur< z!M|r5Yr?y|$7rXN{r>VPV64fxf2E|MITb;W2%~$B)?^{Mv%tVvywue;*u?xNIoDl6 z9yVu2dFbn8I-b}D-#wQqL8LP#4|##Rqkme0CWSa7Id#E$ehj)hSk+g_#veIj!JKTT zcL9tC*7K?k57ui}mdZ+aEUkdx?=-2QEOdsg5&kcZX0ag|prv?{bl(+&XmU9x8l~MU zO5V2Uhd)__?h50dnURHlhm$Ec{Li3{M;dQ8*Luy!l=2mIoXCqiYf;d|scP7a#{ZdX z)xY-kKIr!d4@RQMFX$tl`FeB=n523a&p&LIAt3@YX{L;M&qG%Imi^}WwgZ=jp?PB5 z0V|;7X~;KgjpNhNJjV3w=|Kg8u05(*14 zf)7XSzAmycR;tBH`HR1&@6Ow5 zF_hI_{7t@$IHv$aC}KK4LK3BX%NiDuzTp)Q2m^9;6-WvgQ?Xa2=ed`oF>>*y0Ouux z5ayP~{%g={GUM_KO7#>>Agr`?o_d`{&E|GB)}t?z|Dhg7*VVwmo^qPLdAVo269t8h zP-k#vSl|wQG(ICD3xNb*KTKZRI*jBRz}=vx z&vMdiC}Kj~3)nQW-b=xnPNlS~Bkoj7(B`wP zA4ApBA%Wq&C+Q0I&?>yMqbDP>aUQDg=uL=v7j&z)HVZBRU&-6e6L zba-)sn9XQ-tcaUX;0q%;KkAi$N^3g`k7^`+#IB zxN~qK7U~w11%fB*jGvXT1f`bymBhynCZ4e#1B1OfcdLd35V2nYR8l);FELr*xPdKa z9ZBNM42_tO_4^mG_EH7eJZGm#bZI9SjKF>-`^QH0i^-~Q4*ao)Q!=73C8q!rMvjL ze0Q6Wl7>ctA3_j1EXGcb=AvQ#aCT=hbqg~}lCPp+JSWfUw9x<%k_TO`H49G3lbEP_ZflDS)ln5Wbo5$fs1jSCj~7S=s5Wju z5knA8cCcEBz4Mf*3YzRwf0Z$na1|7v6odQR!LVDKj4eDFQPiq9KdK;Z7k`&1+k(X- z&2onxU4u~%9zclDd_e|7#5e}!pY+q-`g5y=;(cyhFd4gPkh|C~$P`%!lj+MEZ{9oO z{FvoqEE4QfZML#>OkqA{?{HBHSuh2sfYDc_EZ?3AgXoq=@&Ucg3#l1c78D@z5)4ua z$;7JD*V{l{@kOhR=h#L3Q_#{-!CAa&=X67bg_VYq4-z}*IUX6od&ayTSjh-3NzD|S zh=LBP!>KFULvHYil2T*}$2eo5PNSznq~!v4k&(RW5+nFu%Q9aPY=ubsc+{%S43R^N z;J!}!?w12dgnC6#O(Vz`I}I^+Hf6;rmJO)RZ%_rcx!*5vRF&V@S%5<9&gN((i43W` zb$?quGu|+@BnUQlRkC;4(fII~&HH*@168LctO-K!5k7^#K+4Dv!=;rIgDvUI1<}a~ zAK|7ytIp;3pH+Ie#O(0~gdbjrF4B1U6s^+^)E_&v@P+Jy3w^%?$V_S@{)}uGD_L>> z=%(1NS~2&DfhPI9q&@=6s2Fb?Fe9ocVLb~nK{SoaKOP^!bY%!Sh9X!0vHJR5w7LY? z%}`n6c@By?lIo9pfAw)#&}gdE;+Ionq4;>(9iP{5_<#orc9S@7u0BdQEsr9b2zgR zqh}gnBXW3w0+vwo#Jq-_M=%$^hvRDsGw62$3eD~nG;mOR$eUwJpK|nq5|G#)=Cvws z1bxJsJ~~M3e_mrnD)uwXmoQ*^`WU%o-KH#DJymeO7B~6G_TM;tiA14D^Uc&~CyENV z;E159V>PQn3YPphpf;1BpzL+AD8c{m=3SNp4{r}!PE~A5(sz1SGS)68_$S7iz+?ZI zQbsG#?@JxEvc<~r|E+)aAu0NMUv7vF-xp6=4Tpqd{*X_*4z5ARI!VNSVaSjg{ikm+ zo_??6j+|k)k?~=4TR4Bi6K#R+B4k~eOZot*pGCTJfXuSHZ9r4^QNM>`{LCE56t7xk#lb1E9As_4m;nvCkI%a* z)l5T_SdP5#X1Nvo7337?S0qE^>x|)7n$Zj$QO#CnPQ44w!clx`!ufSeDeuaxfOG)5 zFhf$pirsG1TMqHg1ioAzm$v!5WM^~SY)!Kwh(pK%`4_QsayC~Rw};GvAHz4ch`zq| zVSBEw11d|GX4|mSdBdLn^})*eV(WS2OZX)mD>^p%&eMSw1wl_1f#lz6Y@k529fz_X zMjGAFlOoRS9U;pB$IR6uoj^KQI83%!#U)Zz84%~4B!h1X^&d3{+tlt%KyC7xU7Hho z{wvSTw#>13H*0$MNlJ@GD$(x)ZJ~=XB{+KK(tAi^8PYNs%gX!VKcT{=G87o<1WKI01seJj(!zE@& z+M7=cE#b2}vO2g$tOv#P96&OQCQN9IyqZ#*?;ZmGljGROQZ5k<=j~A z6%s^&OA%LAol%Ox|5$WV$e*j{CkBe=TKR) zin+Q8k$i*c{8dpjkVYSkiIBDrBk&h(8)ufIk2JC54|zO`?MgNyiLRA9f!rk{!)XA`N%)Ozrk;zlP+D;^IXe!BQ4hW^bhm3_ntFm zW#Z&s0^0r2R**_raChK(kaR~wkki{r*mb8FW#$?X<~KJXXH8-n_F6*s2z`24Q8KB_ zPIO{ngO6SMKx0<7MW~^E&kd#CN(Y^r{1xCf(z@RCEWjn)_4i}*dd~*whgXxzWYBd` zWCYt{`O}aJee&8h7EPM=ANgBQ@+KvLp~{7W8XUY3d^Wu-)urV}Vm+II8!Y&OKM-6b zGR|RXksiXM2-x>6JOo7XHnmzv;(rD?5_c-V6n2=*ZmR;+zln?ZFvx7vPh3bMtVGj_ z1>f9~T=hG`9r_p;89Fh#{@UKL_*^3?5fUtORlBvoP+eD=xl&EPfvJ}ekGww%8pMhY z20w#8pb>k2Mre64Ik5R%?Lwsa*!qd7LCii$Pb`2_-o}40uLXXgptEdvICBv6Do9G= z^pVIR`(cBxm?&b?M5#4h!j0M*_-3cq^hQb!P;utpXRWXD2gBw|F9gXSRQ)xY;MTnS zY215QCJQ@GOJ0lQgxsL^3L@fxSnj+p*vUssgn$gMo98N1tzV0Kzm^dgq z0p!J%x1OPDCBD4e&--idTnAi)!U~b6+NwOeY|-PDMAsO>=DtFjOozf*f)yLzAyFL1 zGmfPtV7j9+A0Zyb2y&!hNX7ZXM8T;c>1qTgR`U5OB8ejNOJ}pypo+d~KyI46>enan zx7Cm4Q>|3B%?puIM@#^)S|sGt?ceeF=SuUML^}zaU+{*j9@`%}+4ODTB2mHRemSIS zv8OjcQ}=S64-0b2w(3VNGlRFThmp*Rf zYsO4~Zd*2R#?Mk}+~dhjh7XF(J+H~=!KWg>+h`WKlt)nhg(gp|)p1PICWUx|luUT; zAVmrg{uV{EH7Q5ul;#QD02Q7NpYWlG0`nA?U{$ZJZ~S&bI~2xn2SfI9Nr79nw?*0i zBUI9{FCZCOZ&6+|4LiYv3N#3e@s#SFAEQ}KJCC1wAFxS}Tf;tqwNeP0cvSBz$rXBZ@N%3|k)6+9-$lXZSrVna?6SdJjkq__rlor<_(FVi2; z0vAtbJ6)MV`zX31H6orT8UE!r@GfeCYB3RZCHqnYMiZ+owzJ+aVDK!ZQGbO}I0PJ5 z0e)mG<)Jnvi7?8qf*uasA)S>qfFjZXqV%1oT9UIG_ljnBw2$SggaYS8(so$3Es0+J zN@->wM8!p{gYUW!%D5Owc6*!3{@|OT^j-CqKV9}|uN`r$N(`2l8-AWs22b0L@_4=O z@RpGdg$GF6_r&)KX%pG5=mYfu^lTP%K((#s($wv|@b8oI=pZtbqt|Gv*KofgIjWao z?2!V}Ms?2mdireXeAtXJ3!vWNJio-Oe=go$lTGIWaaTH(K(Gr;1;%7o1SmI`YKFi* zm<)d`!DmG5OU+wTy)eKyijindO8V=2XOsG`*(^6iJ4HRn;Ca1Gez$SQm<99&j-n;k z3sr?+=X}Pk>Vze}HI@J??g8dW9;#w;W72tXt(StQ&>hPm$sA4{l&&ZFrT3RhCWyZ; z-v=ORyfAvo=DwQyJNd!S88+DD8@|=O+y9SIna`jL%f*xdYxkQO~HI%7XdZC&ILVN77nG;KpGG>{SoBV0Ij zpXC@P!ql|eaSUIVW|_M)EY?Rd$%RUDmOHJ*6qQF$JCKfZH z6@1{E@Ba?0Nc)xd7TKA`aKSLfSI*or8)o6|D|@&KR(7_-Um0kSXdN{HEYx!~F|ruSjRFtUdRw9@0?W z;a260rGc1wy+Iv@m>cp^8ilA~{uS#q91^0(3!&4y6)_??XVX3SaT8O>m>Haj`J4de zkW**DkAXx(xKA!|C6Edj+#e}`rz20m{)1R`3z&kcO~QJ!MVE8IIu+0&DQ(gb0&$S# zoYAxp?tShUDwsnE!X*B$h#WeX+#?{*L%uA^2g zMr%UM7GstISH>2b1OeQiV>>9IQ723ZyxPnVrm5F^$|5)00^_~Z9iOF?q~%0mrxOhK zQT@7bf0PvVS$4dUz#}P6*#b9M$U~ZUJ50wqbXsR7r`JorboJ6V+y_Cj>pBgZcD?jN zO0U2?vE%RW0B!edR;E%{b4QDA_;GYnVP%QPJ7|%W(dWTW7ZS-jD~E;VYBUGM>9hp3 zJgXb%%sA-r)M+~beJl)*Ctb3oV}2b2b;ol!Dp&sObeA44ZK53scA9d3)L}-)O;(&(THTl1o0iI zEkLZrc3P@jdBW9_fvHR!3>OoZ^B8^6!ZB4be4R-}OJ4JBulN);qf0iKKPC zpBBDU(U479nY%8DezM~Z?4mN*PU5$w{TOrqBuV8c>bGbFkc-AiM-3|Dtkp@{q6A3c{C}r~A7M%6-^O_KmSr!>o1X|VMu~KPNfxd~{yq8z+ z1WP8uAf^k^CG`F*55H(uG)n%4NdXL>t+ zg?U`rOi({an_0&|-AL0Cq^$G1#6L_HOv){^y3$N z`DmF)F^|h0M>9VK_SB8|>HG$J3JgvL@#HfOV&M>ri&86X%21f!A|uVCk=uss1G-mU zW&rZwgoT9|g|Z7&mL~V(K-ajH7l2|u)FyM^VQM&?&;zWiy&WCPFR^9$hj{4V?(h|F zV8|<2#QR#lBY`x&-XaN>ztfy70B1+XRhiUig!Hwf}X=NSe=fJ^2(d*{z~j4QSI}0p&?i(jPlZC-^g|`>4rbURL#W!OsQnmzOv*Cp|k{Q(5OE^2W;0d|5_(4msWX&cWh@UdxSwd-y(I` zSmE~JpD8V!TXzoc)sNr2MQ90&#E<7;&8@C-eaL@>1|NUd56K?6&vK?h+M0rNMMz^1 z38jQ_GJR*@#v2s+f{BLAC1U>rN4%oUv5`EW4iEAyQ4*L%BcbCGP`2Q77WyjA9w&oX z(zU4y7fmR|BJF_p7EZbs#2d_9dTae5T{K)!UK_ro-P_bRPNOWtmJ+k~BQE)(tC=6n z0{0e|hxlET)VIXfiG&5cWZ5FjN4UDQRWp-+500B|13?%**t5y1qGeIFF?efz`Ga>n1S8)u{_O3jcvY zHyseJCdY#q1*NK#0qz9l5r@QDXra*$Nb?UmkqG#PHwYan=aX)z(dkq)yh~Glyrnvp^t5@a)>Q~gq z(-7b1ybLL(CkNe0S9MqZrG||nw#fFC(QR;3*#t$phCS>E`0yEfy8fIkBw}sbI1ELR1mX zIkt0E<_1_DLUI*?I+F*082dxcr!>B!p>lT5wr)sm4%1e!k$V?HohANWb{R;QY7q&_tx<9XCI+4s4kq`g>vSZ$9QP zz>HB)K}Oo0n(M?xKv3lMyM*%kEf4s8=3F>ZR-D(iuWKPGwC2bNG7~$K`x(_SHY4Yg z_J6@(!ety-*4>OPQc}nQ{Rc}G)rs^wbE*vLkdH3w$3SlX$D%STJuL0<+A^^S54S#B zsogy@Z>RX`3B=)qi(GhsTQ_#jJL~b{?`Z%%K*GOjOS$1b9%6zt&3)iVAI`*GPUiOQ zmcIJ+i$XwJ<=+K-l2b`kS;P%bP0)wjhlrJq%xJue6P++D}b6wlscX5up`WeZk=(M;|bQ1O4 zZqVpz6%!z#LJB&o4_HUSSl`L6hvAh`F#eS;hT}*wJLD`!0ho?A4v(G+P~12hCZk30 zRmj);M9sfDmmzUFQ0bLZk>jXMcLNo1hD0SDF&O3>6^da5)H#`@As{rh=vxg9#h^jB z8gjo6`~NZ_t5xH@cVx~2krh;!N+lLq52(A}G%pfl3+!t&;aOk)|)2 z+1d={=IoBGK}D+3lsvEJ8Un=0vL@$cg;B*hQFdkxw-gQ?I8JZ_t866pQ9dbemx_E{ zpM#;!y0C7kI(Pl4vjXAxVHOifdR6Bn6d2-&g};EU@5y|)4vw==hD^$p5?ZixA~@z)^E_a@x1 z^jIP!6|QR=lmwrjNBKA1C?gY2WkJ;^mOJ{dY5gM5OEo}9006f!!B|w*R1xM(@2Q!E z+QqIwF}aoOIFVa{hXPqtX>F7;+b7R?lv1^}_;e^DP76S{;VA>eZ%KVIH-s&1$4>xu zOjwUx2-A~87eDdZapuN=&ic@bvISe!6Cy>Kxv(B(!DjO6hJ<2UWG2_WIHmYy-j-_Z z*PSFO7X=+@W|I1+>Ns2`%BF1yu@EcE-FW{Z1pN@CCnckLXjPk0IY+Fe4a4`Htbo8bqNC0%zwHlZk&;c*vO3Zkk_{-E{XWxOr zJimV9R5T##abx$znb?a35oIqkCU^Lk#Py&7bj!FVFNF@9`ppTq^Q3+WO_e{|EPXT> z@xxwLWo>%^>BLb0i0877dZ|8y@2O}=)`REg^kK0~N4THb3=4F-R#OdJ-|Yr>^M+W= zv8|%K;9n>VsB8Ywk9Fmiw&F!nm$O|xA&Rt8TUHb)%^ z_BkuYO!ncctpN?aI-US>NFiGCPuA)rt5P)f?P(&Lzo-Qvz@EeNvpydFBC++y8EPya zCJ>tt*Wu`6$>J|8eM|qq_eep_pC^Z&ZV09B<+A^KT+CvXs6;j!u+CW;PZh3vqY5W; zvBJ9F_|f@|CqA9y?2x)!haaI+_!MZp-&mjbV&7e5IZJa`o&mORevB7zvem)>6c<~R zDmaUZ7Kx!eaB%sxaV>_A0&LcPMgssv{keVpmD03$ZJ}Xsxfe@64cZ!s5fKRv(0Lh} z<^!4yj>te=%B4PrCW0^HP<@4c%Lz6II^HmMfD&fPnyOTKXTu4QK6;?Thb)OmtFq$_ zEd1E~*Ho@#8RFsYOlGBF9`OSNj{}Otv|mk}uK(Ey9DBXTmBd`EKkN-6?Jhw@Rnxv; z)eiUUPrBHf65T`=0};mFWbA+@Lq^6g&kJfxoF+;j5cIfTWXktq-u!virhx>hERZ`? zk&bgq(w$unXO4U>DD;BF-3A>gRIwI{=8?3x( zotc!-BBakU|0HR|ig=O__(F}^;+5#dK_~O7qb7f+z@BLaYuD#NK`Kc_4i?ruGy<>? zP+&h1Si!!wy`uLeNtj#?+yY4WZzzT-C>C!@$Rr<6bWnc5Tr{$#*EtwOBBDxSy@QR zVD-L!N*DolA`3~;>^YI^S`h(ZlwE`obLC`+&Dbl2Kks>W_EkZFICQyAU4CdlqKO0$ zT>#TGiJ%XO^2#&6?Sz5Y5svtq@BkYw<@)igM%r}3ZxKFJ2-o_Bo+d|k{QT`!Z4n^- z!kpR*GAOWOqRMkLK%zRwrRE%;QcG_Ekeo4IxCri{D_2`Vu|-O4(?Q0-z!R#`j0VYX zVwMVL6<~L7L(@LphaS%isWy>qC=ogc~&a0$Qc_rsWK zCiMH^Wn!~h ze)|GzXA4Gt9&-OZ00)crfSXaLcHBj(lqh}-k3#?7AXB7GV^oQFUxd}kb4m&@4t8EA zaK0lZkyG~<>llrLcNkX*MAjaPdh2jwHmxxco8UXw-lk!h-e?$!9rz-)>AAh}aYYww zD04QSy+L}<6cN&BuT>kq`WT?)u}nZH`{Xv3TaMJZUu~qbrOeJVI=zW?wtzredc^xi ziqvPO$w|Wy4Y2(P@jNwUcOPR1q;ok>@F$@I)KKQbLYsGD2oDO{RKHR!JHNEF0@ooW z08j_k@z`LDV)KvpvGpVoP5!JrJ+FgDSz0U?C5&KLH+>mpSj3N(0Rm-+3vM>MCp#>D zu|sbg-B;>azrfz${zGDzZHpj9{?U@{BJYOX_&#y9Bef;YkSKH(VgQgV<0%v5a>vJA zX;8TOA0idL6o*qgIn9=X6`32f(EpLeCM2d4b#(rHcm%|v1q!X{zNF4^vS$eXI0Nhg zm$Hp|IzYuHCrFbjpJSplh?Ti7#p3D~>+Dw4pA}bB4Le{rj+HU)1 z>WWW8cWAHmo>tN5gFC*0#gxd}q!-xv}IX95`9eCNh{9LYnI=D4OuMrt)gPUBdy`$TyI{ zp$So04zLpvZ=&li~8K^T=aZcb84C`E9h zxjX)=@{ffRT5CGi{vhb>>qnX*h>GhPxzA!V2vK_}Z|qK*4Jm3e4G#J!tp^;)5Hvqp z1)WU;WsH%qp8+NYK8Y9zhLEyE{J2r=bQ*!X_`1_cp0T=D_V%GTGr;ywVE?0UjL|Is z>^hxGpQML?d!l0X1MsHDZBtxscTsC!-{Kf(-+OwCor37_nRL3mAxL%yVpIwSqdZX9 zLe5}!M3iC&qNU!i)gB9Rd0wQ-{M?5naUQ;t2<)Rb{%B3fDpE~WCQ&8lO(ikekXg-H z+>!4cfh!zZNDEt&*kf~kv8GAHCjbyUPX!I=-b?BR16JMmjM5T;Fsekp(Nm`h)V->x zli{yq`ZKFIb1O(9qmMcAx`KFrv{M_Q@WzS97Q^N!fs~ z&{QAusC7%$CmE~=ilwWMo2avrQfCxCdD~eHTTv_gsnXxbA}cwS`_{l+^(ANB{3q2g zHVJh!!^`&dUgL^1D}U&rx+Oi;ZNzF+xCVRt-O3QK4+fwihjBeAun{e5Y{ZHJj1n_K zUrPL*ewnVzty)jChB=dVxZ;u|5b@AMP#wLGu2NLRMV4)2J6PNr;;pl(U+a@<-uclC zBPD*|rEbjW6G#kypOu5sKb%TG%bi?GQ1J^WP@I#@T5V&P3Z;45&DJt&RNJFySwCIru!VUf zN}Q8e8F2aLBZ}tS40C4NNRyWg%C0S6v-?Jllq67PY04dIcB43W2mO4YAw$nRWyT+I zR+B-l51m2n+eLU|P(#i<4y?9HeblMUl`gnaAJ zol^{ksXh|et`;VU9J-kAZ&CSI(XthVO!aMQB~b2j!~Uu(7|5gG52x(|EDMQKy+}gD zZwR<3hLhNjjH5w$MXuE#^lH%X=&wQ`Cp?7)82O3WGf^c3Yzx3*Jk{5})QxY=5ol}g> zb;llm{A+*-!aTn1P-IHt;;|OYjFAfSuuQoP3L=8H$Tl&_(DFZ%h;0&@fQd?$Ujk=r^h_QFFgsV_r7wQVzu1o)N=B>=Fb>oUGg3nLrEwz#JhrG&pnQ*<4>Luhn_b<&Dg^GF4gB_G@#fYVXR znSWUekUuNY{d9DnDR6oB59aON%rCy!__EOxS5-APGFAK5jITovu8ApjTva$W=g9rn zgYID0Ow|nL?x8`Cr^WjSrxesppBc>+vUi0mqiMD_u?9u|NEm@nq`&YvZp_SEtQf!_ z=HO1#f)5XL9Pwk9GQdfDtW+Bw1G}&fp_vP9!^_u?Y(yHt9&r+3R=7HND9OUZ-Dvrl zQc5WTeB>Rjk=AOOQg#j*G#cJ|+NOTiHX|9uxJu4c5#?h4{Xh9AQ>x}A4Askv7!26* zbg`jzwbm5dGRqJv%y33{O@z_*?`u4Q@e~2}FHuY@P)LvOLULC{RxIcJ3Fy3xA{c#y zY#3b0&0SEHSW^6f1nr8n_G!t!q=HukFMyy&Cz#UigEI>4H;j&L+7qlTe;N#czAi>9z)%Yy%rjA$qp)NEqZb#~0^d_K7=<-_Ic0L&yo zt}sZ#!hQO5UJp$cR}C#gfz_q`msXTd|ME)o`KkNxPpwq}vSinXy)Yf&)KQQe2FG5^ z`^n8VxG~sa@CsI|>l^77e~F-+E@bE-5;H$^eSIk|pQ+-sZH6ydmaLn}t>4G&&9yyE z+bwGmY@LJf#nHE;puNmh6)j+~tu)H~n@(qu0mVzU(3jGLl)&jscJE~*J1+cSUJ|=J zY`&2fL7jbF1w?G*pHd%;C6LtzHQf+sUcr~PIk(DC8A>sx`GvA@y3$-zgSD5G?S_X2 zLd!Y7m~zt?!TyRHs!PR1vF2FMd)Q&jN6mZAEAHJa=*J6{m~Mv4c1d_2Hd?zsTYcjE zO1B*r`1RrV2u2Y|(58YlFTya^)_%2Q>jwwgawS^g0Vze4cCppyAJ4bn3eCva^~7%7 zBnk_jr()x-A1NsvBADAgVdo>)j&+zo3)=r+g%Ar{r|IFGV*~K?78qs$VtIkeZ?bUp ztVX9h)3U>0!#?aj_RJH2A zmILic8eWUTGIFVY0+azRj~4f2DJ>~*sALn{$813>iz!^x{S=#4?>|FiRAmPx)$0DU z;&zc#Foc3;X!zRwo0NxxUWgr@#&pF|aG32YwbO|Yy@%(yy=poY`f{}@2X~!Yy@zQp|Rc<0Oat33TvFUO&1`S z+#|jVN@!Q4UVZ=ejNUN1^b#9tFtB~cNy8M`j@OwCh*@yf3FUaRdoFUyGZ!PFRsjqf zNEld6gU(Iy&z^5D3Vf=D5+4=?V_0WU%IJs*Rr>>ni6WyGFOT?fImCk2mFfw z=TfZe6f$avZb*wPp$pXqzNNLC;=c_1EaDT^A#GVz7(?+IV)rUW8Xi&PYO0CTyxo;F z^#H4_`kK<PJOH%#3sLI=dKY)QDR_4yD!$F+$PJKj!jH6@DI1N2P>r}~hm^K6)AVCr>b z;!n~RXGYEGe5Gr#wqnnyTYRJzshxc7M7z%Fc=s9SA|V?50rsxPdMxF_&SAS|1=7+u zRcct5=6UJozmg`kVkTZ2UIPYTv&tqj#^Nvvx=F1c)rov=9$;S3ygzUp0Fl3j2=RIs zcknH;->Zz)FY)8KNJB8w3Q}&;*a?M1l)%An6YSuE2$pFp6n771v9Z$)L0*Us0$vOu z^TDe7+5r21Nwv=?aS=GOQ(>d=>~MVk0=WEKGzf<({i2$KfJ+h8hHFV(2ab37c1S_xa$FrV!+r>S-NTSK&dsg^=TYp*TS|&-u|9VWITR# z^-b{dRlz3R@t8+6lrt^5YFxPQA2g}P?-$%9Qv`f{4jp3Kq17UNE&Qr1$SutNzf5}&NXM&*k?Y;ROjltOL&;(#rx@9PEEp>wO7Sh6)@r{ zUvI>T&(LnyB~2zvp|zG{))~nt&+P->p*543B);mJaG@tViN48MaU0lN@`2eAz0>}3 zhmHu;aokUKBoBq;82R%n6Ldo-@2-ZxsUY4yN~%f9EPm1HR|6ejDW;&PlW3QW7#gMT zN_c;FcaG4AAh7IqpIk0rFSF9$82~(5=H*%KfjnS$*k(k+Yu$tp2MVT^XK^(69kwnl zMeq*Br+iao6Z^4V$A7s&oJ9N4hy!U=LvL+2hwx_1H5FBd^afT=s7RD>pI#oJ8fvOE7q_CV$^5 z+~1+f449g^@oOZ?gCuo$d#2YI~ivP96=hk!zg$?!bM!P9G*XH*_QOsdo~C1aJDA-0tB zA$+-mmmV~9Ft{Tjt=t-xC?D0JYsPD=$Tq5|^Qv+uoF17b(rO5vLRz!Lba?C@kATPa znvA*4d$a}PHv!zDqZIQEY6C*jlhj$G4AnqXjB5_D=202^W82-0`jEEhuq>*|`Q2a; ziCd%-Nva$r(%D_FBoM$EhGVz! zM8%maFhWFLMIu{EvD%&ItqBm#^=U^p%|1@!K1rw_OMdi>&mEkg`m}* zoTt5HL1$Z(;Unc6FDX%B>XLcX0fTHgN7Jh}JHeMI^tt_zgfJdXzxvL<+ z6~_DEviXmmV5x`rR>}s%zGhs5;SNHcNviorW)fgEuYN^aO3aoDz45G$>xI3^=ZyYH zYA}2@E4Ku`P4p!E(?L1}VnC>Zfv(0JBbd~3Du>3UmwUidTN6c(rKo%UdP7%@hpl~m z!i**!0by#7H6v&Kft5{qVBTD{yJAw%68Cn{gS=0Z0{|_-!vhl+@mfd(Wi6htr(Yhb zax{7kl~P~6A7)gGRRgkKs&_T+M`2yz(to=LgrXoDvp^hYZRYX_9v%nOGKNa{*(Y3X zZcAul9sr%n`v3|SA!g>>Cd)XXRWSH*SQY~^c&=+kOc&+zvbISrGl%TLl&}pa7%toj3bcx8nfYW2f-9{y3Hb|w+mmOaujwOBvw`K$#o9; z8J4fW-NyUXD~N0Bo{ny>A*7Q!shpaf>m#;jOlS+?HjRQsId_fp#Cf}y*`xw-e1@$! z5beK|D062iMk+`%a3F5#?DS|9r9`fP*`$RR)8fh`kQx!&xf4wL312Pn5<}QdrX0Pe za8(>dwLl=-n|r9jU^@??v#OL`J@pa#xa;+}SPfbW*zFafgNiHRKyhHO=Gk;lB3a~= zZ?wQB#y?S! zIP-ve1v>05vK_8v9P4ixWjY1o@OroM8ED(?h$>!+VJ59dpIHrP4yE;yG14ZxyoRd? zZ&w3fYONx(DMhE2;HqaCEl;7kv%Ex8@q^VXPSjS7ssx0TN3kG7WX79`y|#-?QU`S( z4dBQKINu}}ZRaru`+W8Al z&k6J3aP~Ul;2WG)F(C|rnb0{V6HCf`wK=LXQ5ln%xLEpfQ}$(PRmAGTc2#`R4m{(} z^cpO1-j_buTBTV<#p77!94E$iftWT%ZdAjk7&UVZNVqfooixtM&~?(QlX{At4{>y! z`c_J>`VFx&_L4$Xo5h`fvPe~pX7PwP>-$6eVXUX}kE z+Kn)cNiFh$0@wnV-H(yHg%s^K2jO3ulg}WqhrhCi`^+~7#yKWy;KISDMrNJW69XF{ zh$*YDnHC05V9UI7Rcu%TfSmq<9a`i|*p?A8f`JBNib|;rKdN3B_GAeErRjG%HwEBS zl8y&0gi!`~IIt|5@s}CJv>vdwyV-~Crw!c4;D_&%e$&c*?#-2JnQG{W#+yit3N@8v z8cw0CmYn~}y{|`f^Ogk2Hi0A!ItFiQiQAnCd&|gbnN!Gn^fp&ypRN(q$=iwqE*u24 zf83vUAi?Ql>_`}m$c&j3>FZ_&LRO-;d`>DF1~zShQsj0iC+@QjJwm6!wXwiPNn#dY zYz`#gn^r{?U7`bFa6i-uE*MePn2=mSeFL^mSM64L*pc(Pjlz~?64rKHXn7jA3xc9( z-Am5Bm^s|nY2PEGdMKhk1uKx5j@Y5S2e)m9kS4H7?l>n_y_FsThZ(>5wLz&w+Bt+>`%!qw%GDDR^96AmC8Oj|bmvpS~3t((xGc-9YnM?9z z?z&Q)9wFu1{|!bfqF-y@%q4&qUS6 z=9K-fv81?WwQ@y)U20bk8LOv)3wFoLYcX&u)uLC3S8GmyDb1zrpZ$S0hB6~C;yyJj ztvO4SbGbm*`fmVAOE~e?G_5X^9lW$0Irv))OX&h6tj77~JcjNSk)?RQpXZePU{fW| z$yQb@J5dQ!k!-U~!dqx!*UwU8RdchsrVc6*+?HK=sz$H*BF;(kg$X~2d+BjI<)bOh(7-uVIkL7t9x)49$fy>nn4<%o zsBaYwA4Q#`TK*R1KkO5g-!Y^8q=@&*u7&DXcb+7KT?>_yV$mv-Mc8=$F z@@jyJvAFsEXGC0)hIb{@;!DwW^8RlQ%r?0>D#n&yKIrtAM+lI5_5VBem!v%TU1b*_ z>Ej)ME4IRt(X*!!OL~Iu%mwI8Um>1oN@mw{v(qa2if$0P9RbnSA)M0zX^i@vwN^3CNaHOr~Tg#sHQQAxcaJN|rJH+qb{F4Cl<&(6TH{T<~W& zcp^wdvTl>*Bg_m8I2aqGqBp^T2qpjdwxLN1XdQexz*iF;I^_%}i{-fhqZ=9=bJWcY ze9hAbnmu^`DAVkJcRVQdXq9-YAsd)quE1IeCm*b<_@M%At?F zx7p~PBuTr&jGvUpc~SFgjM{A4(!D`fLUfuww+W}E&*x(}wyU`8(bng$$c+EeZ_C+{ zbe~4Odd9=?9q=hqVI6sL)CQX`cE$#3?c-gw18BySdRiu?N$_CY=z;)TsAE=(P8@#R z%%jo`40)~@ER?}sYzg8ty|fR0_389HE_KMdnj+nMaI2%Airt5wQwI&y1b zUp+P(N{VB&QZX{p!O5!}w53wY39_Ir;YKFk>jD6F%q+^L2=}Cqm0P$lsK1 zr~=*be_eog^C32rKqjV$%Cd)><&xKX`fwy~2scfly`c??+|$(I?9Hz{#pKvo-Hsg? zUnwM`U4Qm{C+&(sMR6&Bg&)t8gn(TMr{sbtSbd(+-=TCZ6&P=op6N*vtm_S3I;gz4 z$r0pEfyP?B6A`2Fj+@JkzqrRT2wXMV$mjws{D4)E5^}CvqkDfgHU56p+O^k83QDF( z&|u(Ol#oe5H&`U+tjJZy_0ZiAp||3;E-myI`u^|k*M(CipK8A8=!e9OjWNlQX#T0VCpGJj3VoMz&@KH!0J`F66->LO1sy+p?AE@#+Zw3($Ityo1frI*D715b(z3Z zEZ*S%LI3Z)E}gea!4O<}_A&WHdg;8l9r4|pw+ctprr<`Oc6wftpCQ%JBs%|) zD6DvIvJNHoAh->iq}p|7TasW&oCL*w8p!d;FP#J`%v8SeoZNWpoOyuZ3Hz9|l*Q{f_Q&tJD@`(l>j5X06 zP!b`fz_wmK;9{X_B2d68?z~oe_clvIM+h|lU`6xi+GF-OKZyF&@#V44{XlxG`ufG} zSKN|7AyXpbph}~`}{Qr}1PrJ^3_{S#uhVppag^-LXuH5|k(|B>?vA~hfkfB5l z+44eLVqgjF6!WPFK{Njq9E-YD4e8&c{_n%FCGJY#1()CowallNJ~a&Dgz$FXQ;?(6 zhMp{{^C$-d?jdn>4PcKkSn%ZDu%S<9@YtMgMK_xq=l3b=JuIMq8_kQ82z;P;`<2z-GC3HqDiHHBg`2ga=x@!((kCG@ijk=DG2UJ5XF;FusrDzphsav&^ zBxYyk&}Y~{ET-pHX0O>NIpudJFDG!V>FST75MVk{Q&2lIf_gZK#TUFL6D`Z0J-3K} zxJfJ$A*bWhE91zXkZ|!i*E$uWk8|4ELq5fPfe03#+fUOhN_P<26R;m~EPUQ~-wEi2t@mN?nx*Ea@3ltlP>YWoqyB1?K%joArl=2CU zv&E^%Gj6UChWLivt80cY5{%_#Yu_@VR=!O|vo>4(6hAwQtlGeNbPID&AVP?Uc3q`q zuOzgpRxKfXGsc(fx%UuGg<;4r?J^7lV}#mU{K zpjc3su^}AH4f5>L^3ub!Z_mlrs_p&_oI z3+BpRKiV{s@b6Pd$KTUkuzD ziS0&Zu)oRk%I4n*JVguV=-Gs?P5X3#yTM$u@)g+gTb7e;*f&h{i^ZJ)ra7f3e8V#$ zfm3L@Yuhx;5bg1ogHAkeiuYhDs9|8>5u0&9p}%QZukcu}j(np}d|PV2?WG+3;c!Qz zFsRcbqCI5S>*b0}VtadJ+WmA$yQ*al+pV|#m<5%2ZztmFJomW>HqMLdJ=!98{qjs~ zf!;BQHXA;>gI{Q1lO0Tmv!r5kbXWoykfWa2QK>_~u?ARj0tY!56MA`zrIkHH);)Jp zxN9E&#zr6sQKD3eLv4#Xt-67X?;n}+fmJ4FkMDM`RZDn=NssV&T@2PO$b_y+%dGy0 zl3{D`!BWvEcnBqa=2n_-4=N9LeyFxGG|`%CW5)Cup5WT{S08M=EHGXGgTAxmlIouTSX5Mnx8~>B6ETy1vfBSV!*gLsm%ETnr;)7TpeW^n2jGU z`loAJP98YOdt`w)!H*8?9@rNJsE+JSvoyrA`h*=@NE1i_xXW?Pe5AzfxUG*RuhaHn zdMS4%YT)9zIeAk?&^UABmb)@uhr6a8%tn)Z^^(yjNbw;b^gH#{KSg)bo*z79etzLEkbcIvBs$zWtv z$e8If^1T6l7J>+@05u z6ZE3BGAb@8%VRH3bs<=QIwf^DsgoY1STdojqY=$(4pGs5ND5s7BANf%6wJQCS6-Z~ zkuJ;yj?`BZO9#cL!-uymuG}Dz%`I(_>ax*vz76{z@ zv!l}TkX|rjCxsH`R}B$;nQ;`WZZR_9iN#AU2h0Jq=Bv!T^L7)n-V3|b_;0OOTTU7J%rlOrJiM458cQ*YEjCF*74r1wQWtwNNtnM)(x8NP>Jv?AH@x> z&yL#yF;4i?cfYvlZXrOvjB=YgL)W4x!cRTLIQjcn)8k;3v1@rELX}VOp;Sxg*CTY_ zFf)Dv*aY*8$MCQkD?b6tkGN`w&w4Q?F|{QD ztlY(ZKB}Gj?#Kx+3}ak&tc!y!zOEm$u{7Uk;fgP`;O8NJq#1~2Fq6{jJ=Zk2Ik|Fl zS=iyry=mSL{7WWKp8EdcBg@kXds_@wEj`tM%A21X&c!iuRP*X#t-GfU&WL=NEjQw4 zkz94<2XWwG%!-09VjjR<^E}f9^z8yW%JmS)|pF=O54ue>Gy{owhu& zPLP~wo&DYu;5)PeJz%hNd77ODbn8KId;yAFO}jL!9?Jjb8{xZb95`OH4QT@=eB&pW zYH+{lQ%Q0{er7t{stb3++;Z=no5#H7i;ePgH@3hCA~t>8_3D#UrnQ=t#@do)15?XS zk%8=g?|2VW(L^aB3l$nR(giUw$r-YLeon5nEAL##Vv_OHM-255)P=$&$RtQ>P-BX8 z&SWv#*4=tZo87mM1M80uAty+ZhI9> z3yhsRAssNn@*caFU}v6yhm}go$Ny5-#~TVyvVVTj0{6+$9+7WGYMwLnkn7eTZWg+X zyDzRZfvD8ve6LOYb(_O}V2+VYH$G`hv?2!ep-&Wk4fPg=4<3gCX|_rI6%1<$S>`s5 zdji>0+{gF&=n;{*-S6@80EhnTTK?M(!=~dX5RPXu+0w@ZVDB-^AzYK$#*<4Ywm(r; z56C@}1B2>|LFJ|7*tJQ#opy`P69$2Dv6*nRGj?J|(%=SiGK*P-^i?RHLGhk2zAmU6v0Ahg4CRy8Rb?6 zn_Iz(+}sjs_*sba)?~>xfy!Pv9ocff3o=B$p$ zQKoK3U*-MBJcWUblR&+q9?35I1c6t=C@Rpt-V(yF#I{CU)^^SuQhPCpVWc_xR4Vb= z=29B()VJuhomXdVrSt&ZDk_2`X_nD{QbR3p!xu+nSmst>J3GN&_TL2)j5p)7ZGLe&AyOGvbT9oL^VKuQE=&t zG>Ijd*agxSx@@P8FdHhUVfn|21(ge0{E*Y3;%XzPHK=d@8%pQ=0g(FAh+wapkwecn z-f*SOcP^k{RS7@e>@t+tkmJiRrSYo`HJn>|y}iQnaExbmb_}&uOJH+RQYj^=*7|3S zE6n1i7L755Se>G0i$QE$yCCZB%E{JJKHoNHwMBk2E$Qm$(}hNOkc_$6zQfr>{$UXO zT!ZbVYdCsqmE#~E{;QZBHXQ7le7MoM+YUeJq{%QIj$wH3iF#adS#uX5O3yo^4fdEA zQ`)op;NgbCPa&DyilUV>0xWVUARWQ0S)G5L0Up=>@Kp^S`TQu=webG`4=nT2Ysl=} zH5By$s#)cGOvcP_5;N^dd?;2>AtjIYPI2{R$h`Wj&HAPQPB)-AfQn`n zk^5WC8^+^*7_%bdJ;=7}r5KfJ)f%)V&%p@8?W!2JFzr>+#BB96poH4Na(>go{1kj?J zW|2~-DSL2!14v}fholJd@|f*{L9lezY>7%?4r&vB8UEtINCpKAeATgKWT9DReutGW z3&{!)sZeJF%8Y*g{ZG-~ee0(t%+hF6aCwMOk=W^BInuHh(xptcFf>Jf3>LAFz9{SjDr|?p5 z;TgXJY+KD5KOB%y0=WHDm>5|=Xy^pj3wK1|fa*(qwio7MwBBE?J}eKq*==E3PQ!l?$0f>?FoUZL+4#@Bm4%ikxHI9W*m({RpjWz=H?Z?vEtBy z5E5V4><~FHSN)L0{x$FZA_%+GrS6W-AD54nl%QL9L5TRcfvIcmF;K+IF!#{8I5%# zP8lu0VFB$SI$sK)UDdhUd33so$L}E5XU**C1q>UnGh&wBC8-!cizKt=GopS@HCL=Z z>SzypFCIDAFRwJS`DCDtFd?7Bf30*h`k?$#l}Qy!v!VkLSR3nLRk6vda<$lBBrdHZ zcr)F(@7r;^snqIe=qE|VA?|g^h^ofH-nd9y(|M+u!#Un}x{k9<(3*Kc=N28c1I6sI zlTO}p3hBHa2@Iw7q$K(dVW~dyQ`6kOXAIMIImj~!7JEUMS9w7Q;TvvCp~n@9VobAp zf9RQhG`Iq{(K4gZwi~p3`*wQxX-t(c@{I_Z{bI-hl(Ud}2(XAPfFOm?(s>%5WT~Zm zj4S$p?1vUi)DCV=2I3SkI=JUV+uAEF&TdAo57VUPwPe^X&E%JbtZxpCNaU8?5?*Zq z0Nu5trC5Uc{jiv1*!G~2fauFCE;$Pk5*Cg1?14zd5{%msO^9CXghWzEdjT&ZFFuzw zU1(G&burmtU{D$P6wfCnEFj#%S`O3w`DjNwM_kbd-F2`JH9lir-{$fgd{! z&^MfXI4%i*B`9Mt3Pj_j{qz35@~v5E7;a{ogI_6&2o|id{+AhAiSwSA+3@LvZ}If> zmlMs^M2uhkTFPf-1!0MYBijcAqYB!;;T*} z1`g0FM?Ie8lz9cXT*S?_9rfkc^+$#k=Er7!0ol{@Zg`sG z9f*?h&OJ)Lfr)gAA0P*HHPc?ebn~It1(z_>7HTomWLD z?Zh$H&r%LPev>P8<>Wj(*M`y6iqKL{q?bbK<$rY=cgq<5L6~|q(?bYzW)z&Ct}d3V z4*IO07Cac7#M)CAOpT51S4&e>dpX{i>RY*s2)0K)HEp3XcW!tO%mw%5+p5no6eQJd ztoezT^_4at96OErhffsJw?dQN*tHyeC;M>rjLJ{Yw2QD;i)?&mrUJbS^bs%o15d>c z+T$kd0R9avBR+{}s+y=gX(?;jpvjV&o@4dmk>=7^T6scEyp#hRTM*)FYgBbamhc&h!%{QAfdo7eHeh0a>MvVEF?l>=kCpm?>Il)t5 z1UP~UOIA22!blWY6(sZ9gH%UO$51>ddrz^>+`}UXAUq%EcLdw#Bw$sJ>NiI5ZNYV7 zT9en!?|d}*l&n@;o@tKKrQBzaKFu0pU{9-^MXJE>OcShm6h}*@Y1-lA05w3$zjXJ* zv1%2GZsb(ZclG@WK-OnmLStRRv+}5Fua52ut^qBFtMl84W!vYEc3B|CekRu<*{qil zu9uS37g7W>thXv0)~2{T<#=bqEmLm?C`H42lgw9?7;?c8)){5nMyo~U++6`34CrA6 zLD;=@#LhJe=M~jcHlglVF$3TS{hNy8{gXc0v*&&3#fOrX=KA^E-i{Z$&z`2{jl8&{ zatMhbHEr**pQ-fU6~3N*dpb2Hl=X4w0rKZQ&9K4c>^UeYyk+(^fnx#!%L-j&9p|tj zu-1DhIAQYg*%J0${pHkXk}5m=W+U2|pM+fTJ{A1rxzSExk~ol#%G3^p>$3?t_c332 z?QIC5ceG&%!K->5Sx)wz?lAbnVgpR8IniWdIBAzG<1-sfz52uWkbb|%r`t{R2vS#I zGA~cjxW$@?SMhF4XIQMoUu6-fC>%)z1wf6rTG<30$+OLqiiJ4P`-Q@s&!CdoK9v?f;1+@F&X~w3mJT0b>Q0+U*gmT^To48_p2%{VjhN70~R3Fq^*{ z&l?}MirE=EByykGYT-a7mDMG-oh)LEH%+05;e__nH;q}k=T)OjF4~^A3MKOD80>!X z<8B>Vj7Nu`XIBxVd%vgat)t_f$i3(&qP*(Mm&ndqT8vA2fFm)yOx3pz#mp%8U(DR% zZ2y1iX;U4=R(yyU=jxgOki45L$-?nuVZ-eBW>s{q7RPP=P-6b8w1`*d-}C{d*_ibbfpq3`HWhDRVnZ zii%4}F}YvVBKZ$fw53H{YZ#%1vGodh2-R-`6XO2`%*26b)L>}Zlsm(PcoH8A_Tw&gZ0+tNpPvFlVYTtq$i`nh^04 zX{N#mNTS73Y(zJ75)-}r2Kv6g-tEVB((Sgb>3UF06=nM7H-g1w1W=Z}1L;JE)2GC? zrqf!niz$jYd1i-$c@deKm>Z0<+>6^MlCCp}!O601(FnDm5Y^_0`Gc@rUW09T(N-sg z$4Y0>^hSChRX&EL7r^uTKSR=_6P8p;c#;sL|FVm^1g zHK|o;Qz;?t2@5iy;Op}TZy8yqtYDKcOkzE^nTzj6tfTKyX$(2GiJOcuc3}V<}SVrT} zt~Rb0__SqTAvZM~WJ)f|)-E+Km(swE%-vY>FIl=hpSy|KJMwMg@kR+;~P*V+b+oU=Q-e)IfqFW*z~%cbAo zky{wJ6#XdVX0=CVliWXDQl8QRApijKw@M<&3coAkfNiuj*wg$g8l`g~%U<3JAxFQ?K)VEo(9Qb<3 z-E^d)cd$JA$;nkQ+qlIS46!$9iHy-XV1r~%4K)UxH~w`1c{5O|8eg`7mQAY2&GB@> z&dpiB3;zO)8Dfp}j>G_Ykh=wK7j|LUkRTyXw2$}VNF-2yr4P9??c~oTWwftN8(;sJM=0hpYMqL+N1uDO*{NL%l?Pq)ipn&?C*5^XR82W8oNf>{>3 zFr$Obu(1fS9&BB7GQm>`vWSxsTB4oz9?M1y7}5LYGBUUeJ-}EgfXa)-P6FVO zh4@~~xGi!fe&jqPy+U8F`hsiC6hY1GVFUd{ze*g^P*jve7I=< zg-q)F3#fHxsa(b0VfzvrYlSAmB5VkS{vyrcQQ0i93=F)p$enoTo!m2zYI}n|bzpgCTjH$4=X4CG2XsH7YV@SO z2sH{U$BY8MFq-@`FPazsAW7qm`o7^i7^lAuR^=^25BMLu(`&#`To?%fyu?jmHU>dTw-=*MjA>y9W;^eRp%2)-m>s>FiA|FoA zd^$4D@XBdQeO8_F#k^5Q{&}($bClRl)xEe;9ZM-9r?CR74XU{>yz5tH-DgH-Gl4`u zK04wxj$6aRn$RN`6Yog2_1+ct^9$*vt%-%t6!^6=O_rzSOk6M)!4zbY8UA2m^&Wrc z4;Gm@73k0d`v82eyC;ATWO{7P5;@LQQosG82`cT@aeGl_#Q|r>lA+-16FyD-K@!*1 zSZ1{DmHUu#?z|~=9+|LKb01~}Eb@lQN;>+A#xE!ldO$6Ag?ZKSkRGqTwPD;N&Qi-O zOC9+pluE1ILET}~+>@+uwX)_9G^&C7k*0{jr&u0*X>@Ovz$q6r3cI?eO!s#3i~;X6 z|LENe&>E^G%vR_%e${5?ZIiH_yvm?dhLka3s$wvRQUmendk z{=UYELHZ~X-*0SKA&0extPTy7IXU9TGzW+grryf2Nni!ALnRb@_&^!O9>w3&RZv!= zBr4~~q2L~fFr;pwzOBx?nlNYT;EalT&T+mNq%9q;RmaomU%o<}5>Wa$zk)pd17tDY z-40jZlzkB_$49PH1-+#gL<^&_W*kj&aAok9K&d#96Eat-5Vgpljaw+DjiLRT1P+|x z2Qx*tJgoq?bVvHwOpXnV9YQTXF$cSRZc6e=&Vp;gY>p8MuiWz%9X{Xno zy`xbL1ZsLAl4xMr5*snVk zgu@$Qh@6|#+&2k&87-e_l%YNozaInDKec6e1xNLl2ejj(9&JRR*|P0qSN+4cTUu#L z&Z_*f0Q)yeVOiih$abobI@Hl52ER`dxiO53NuG0{&;pL>@rRdVqYs1Cd26t4kcH|Y zRO2KwVhF)jFJ!@O>is7YXorjpi#y4iJz=u2;T8oPat zj*dN8+R^^z?pn+ZQ7V%ax?a$7?dNP>vl_dsFbXT!?3I_$aPu_5`ZV)gOOoCdPK0UhGW5J_eNLbT4t z?)QTJ=#Fq3WZm0Yy#4Z8fgByT=rE)zOU{z$uB9~aT_vaOLI?374w#wuYj(dwVk2)+``+I@th?m&?mpZT!i#r- zE~#%=F{BXepAzs77~i%`iGciV2Hr2NpVOv6OzXTm8dS^6aXxyIov9bF<|%sG@a0iu z?;-1~cv8tW0vO%n1~)bPe|S7Xd^%6(8>;~SHhKi6+FOB#QRR;8zhHg{xw*n%#emT7 z19MD#;6egl?{D|XfpHA3LrHF-$-~`hGe=_q(J)>d^7c3K2Y!%SHE8MKk0mA69@2FK zk-7x$uJeaFlvrX`T}z~wxJDv-?9sK>OAj34gG4m`&xG-2L?a<`ew?%DkLOoO8SNOb zL!4xKO}qX1vKHyslxGuf^eu$J`N0@c#xwKG7q9yiTT77x=VwPW4}dK$&^5G=n@$y4 zktv}|{9QNI>zPvPIh=!APuJ)x_ZhXjv~=e3-mY7rYMJ_SX$!u{o_8j4=CyRS)sVkl zTi0vJ7NBcCgFGb_($P%r87_k*KP8-FdPu>wSwf=+-6_NUP%Lh`eQ8_!Aw@HOtaE#{ z#&8X$M6kPy!@*APinT@NLi6%5i&wfE-l&48bO@)2i66->S{wFc>k$83KTxxgfO%pK z%o~!X4<6YkV4Ycn9Buh}Aw=aH`QOQJx7b|q&qIO(clPyPZ8s>`bf-1;lCymiDSfMH z=kdxG7$+}(exb3jyPsbi}?Uvv#@ka+gr1@N$88coI+$Dk*|mSNk+H};o_<=oNghB zHk3+XxvAx&Vq>y)PjshA)wwzx&>2McvgTXg&&!k}xuIQOMxV%Oit9J}FB6H4w7f;D zIyspNkU!Yb(|<95w^QeF+zAW&op_gT0}farlzGpDh86N81A?MO*7x(TAoIOAo7fI` zVZaQT6?HKSh3iAcjEt5VFTPhghOPhls_qE=m zd2$e_&^&(Ob`$?+rfx*T(uF2m-@WAyq{F+JIk+X)NGYg9qq^h~?CF@2p-O*5wvmMW~lZIgI=03nh;VOUUp`2;!zer&}QnsQSwx#upwQFd^>g6!8-&obqXjPNGUA?*9Mvd_G=C zR&8MsGG6odwjJoLX6lhsng9_aMWVj8{%@NBvBfA3%u6FErlX(S zW19Xit=;2nfby9|Z zXo*+sKNPu7PvjxFpE^0nyBXogITyL^FuKqf6rbHwR`%-mx^UnfXf1ZqAF|H?x6;K$ zMzu$)=DNc+xtJ zf$qeXH@3~YqWcXe8mlI*f~x?Ixt!%MY3K;E3(Csp9^t1Ir~=%rP!`GP(#TC$>hC^q z95*ow4;0rBHZg86QHK>b>ixvPcs3Z9L;^y55LoGforxw$v{;`Lb|Ug^ZxZ1dMGl_L zqNx13Hc>0w>$ODV^NAH(zmD5cCOHNm;N@<05CS`?CuZc`Iqnwn%y-MN73=u-K~+nZ#1TY;MEYR^m!CbIN1H?47$#NxjPZE9*%e!#}+MnPQhLb7BqH6QSYC zktLZYYG%QIjm<;Nmm4^zqW6#lPi6Qxt$}+3dKf+$BEHS_j}gf|Dzo9~H!&in^Zy{= zgPxt-8yIw}aW;Gf+))x{8uX>!n@~8mUoG`LGG#{zt~7AE8z&x6~r32ND$QT*Tpfyp61LW|3Tw4L$jXT|nJq?vt*+C=;c5pzjz4CpC znPHHpo=KzDP!0+?@%;TP&_9h1+@uE0b!Pc)163rMONE3NPjdtCA}RkJYRr~kQq=ef z(zif;C>R-sGTSx zY@CEgj0xY>`6SUue-|dz6;@@>2T)J$iWFzO8r}2pn(HDG# zI$Bu-0?!ziQLO8=YwxZ?s4d{YRe3X{xG@g(kmr|LDxVRXu0kj%IwCQJ0dNtL2nk!{ zMrQHgq&E-ES$q(vO?-)-nXrxc8!jfz0Px&Net{3SsRTTCT^cw%a!keDk7Na`Cduc% zupSg9Lty}*`OacbN9uVf`y^Y{oERaTdG$+%)=S(89o`phwm1Cd4VvuVC4j)g=NqxF zlRIfoA(qRo#klqMIT9wLMFkcv=k zb6<;WP92n0$SOa0>ulK+3d~Hx`X5D;&z22Udkxmqu$D2!Mv7z^^W#4}YG$j`iYf>`rnLg#XCuT8oYWRa+*)J}x3et;XkIxxtIcX~OH$S5~SZ+KFp ztnF0!Oc-h~t<>Q*uvtDg8Gj{w1DMNN8PALrcIu6}N14;Jk-{)ig#79yUBcm5OVtX% zV15dTyooZ9Azt1c=HLJwd8<(Zzbk+}Q~|NF(th9V#jld4SYM_~+4jy(R}eki4#T{v zo!`?WiY!{Pqnqk{Q;mtT28(3Vowb!68ne#2wjkY9)w&)75gEkc`DqKwYRhu8QAYhd z8F&a6X*_i_6q;P*GDm1S2~-6`!=;z$yR0pss2Yw-s52rcnWhv4n|zZfPc-zM8wF-lip$1VRguPJnEY7`u!f| zlLztX<-slhS2e_GcwgFn5ZVL%w?WuI&psbe-_5t*5BBBAIhzUB5B-k?QK1yGVR2hIT}lcsBB2<|j}n7pBB>$$kgHYLXS-C%aRR z2(l)uj5JJ%C^7_jM6dFmBAJM;WIaZ7TS0`#AC>_(HDJ}AK?fKVe%6&FaAb{zM^ENs zPp9M0B!+e59a)b*)?F+H=Qb3~Asu}miW~T~w)>>8^7P_fe%B3_#-k~z1C5mbZm2Tj za;h3MTv}JvpYg{r4xL$a(ZtmHH=$zo8S8qJOK}IVlb%7j59bOF5X`eLfmJg+nMyQ< zwjq0+&Vt+$uywMhYYcMQB*ckYwH4pBs4Cr6tVs39xMu;xz$ND7EL||D(j)ojzN3Bp6@BoQh)bzY77WVMm{?g_sl_h zhD6v1Dgd`dB|izs?>X18hq)vdK_%>)hokgWj@7Xj#yWSUkQHn@roM1OY?yOPaI>=mbs7?}| zTvwjq{+5=F?lUv+GYe4>di?&N`!4OFz$v?G`#6(~u^tmR#oFlm|Nf4IVxh04H27F2 zVLP0(`iP9l=CKq^!VDiIM&6hT>C{hYJmORp<42)kOTnLiT*F&F!I_fVBAE^@pBb6d z^pC$SSFtoB;%%nkInN0(5eFuUPxCEzDv~#1=7}Nej76YOtLJg!YrarET?>=>9j>2u zppJ<7VM=?v&vp9(5BFS;+XPibwao2#j|-8Un&^@~}32hke2B9(IY}A;Xpex!^l3 zg&`D1d-U3%Cn1}+m2hhf$y#6KLHe*;JGnLui86An0TN@~D+P$ruSGA-prF+ZM=*J= zDoy?nt%~FqrCm@K1t%A`G5G zT&_`3n_nb_R=vZ@23vPh12up4<1j`omIArFN>v_-?DKC7BKhHuNppDZl+^@xNb&l( z{WHx*F*3?X7{kH$4t`r`sx|*Vk2DTK`0m?i5kt*XCTKB_4CgLXmyU(WDJ=!rC8|^C zZEDpb&Uw=xNp{SmJTe>L1=2X1K_pP_XwD2tshdHrvNis&ewlC!tUeloPp;S!N@5{; zH2e^RvAP@AR6$8kA2Hn`z4A4}zfX@V&A+n7-nAaF7JmXf3~Ta1#Um-ryBuWE`Arzd z)P_@`k z2Wq_C@f(xPq38b;aX|@Z72ZDtoSxBtlZ~W0_AOx~hwX9Q=hy5u5VOnF{{i&&BIN>T zW68}W&A}Q%#gCn?Rxo#2dEj4hsylsP_=Oo_K$9}W2GmTj6%tsni5RWd2ns5QOvh#KG_*G2ick0O%?PwD2wnk zPX}$K>BJK=4_(w$swv(R&jXTOk`Z1OfCPgg!A)-X5ME8RNu>LCtK5kApbS)!b*vfB zq9C`K9Tb)e*jt6*(Lm}AgVD2L<)lJVcqjB2A>AstR?CunZ<2=(&s#nBcp#YQ6zU9) zHqNta^12z14v{Cqu;4EihO(=5`Dv>cF-E{0 zI+23JOH*Uo<+L@-N_qq#3HNM|T_G|%bBLm2$ zd#o9nRSbUAKa}b%g(?T(L%4y_nrKfa(bM)*$((px%kN6P70bKb$=%dRI>pL%2V@;w zR}%`C3_T^P0h54DnIO|h`%8?2K%?MC;^xrf3ExOsv3Tz|Yaf}EO2h8yB(_rgrp5EL_>$GJP6iyQ&e>uHh3@ZzvAs;B_`j#u zJS;}h+vjCXhWD~N@Ok8rSQ1Oectw69st#s6WP&-YWV#%g!M5@eK1Qa>PZS>!Gs!bemvz<5O&Ud!C7eIUJ6pU zn`txJFUFQVDb@z~F^FdT`oun=@oPGsY`OiL!SRU_tJ46d1LZ{bW=j!Enc zg7$pPWvp(JA-ZApZ01tdF`m314YTc)cVibhi`Rjrp*N%VEOj69-QKWms}pIxaQ)-4 zQW>U|u|$6X%lFh?FOP@TV+Wl+fo6TPmEfG~Lu@tNztpDrMdxgoNmdotf`$O{_dN2g zED}A8*MClBHkE#rAiTV9uS(a20Iv6}qQumB__nTiQuPnIa4Bu7$tY<2c0|KYT`EFx z!Jm1|yH|;h0};Te>SIyk{-OpO@GCTVCvL|etgSC{4T;Q7t>cFe0&GqAWOEs-(x(<^ zR?+=?AS9lz`QAyEd@#L)Yl?f1Gf?N0AmZE9*w8pLlVayzC@TI=9=^h?5ArL}OV0Db zb$Bj5HVY|MV6a1xjPVh~gfa_^mJt$!9dc{L^Lc;N#kEZ!tP|8NBYj!V)<->bxEZ+E zF#i8@dagWMdW=U5yQB$;SzXzzsk}>}Z74tOJnM$`k*#3U?bI%zbL)TmdsBX#zQ4QL z$_4R(O+_Ao{3a;P-i>NqAhj$H{PpAl_p{w*P)PQ^!I^LDz{7rnIWP3>Pktn2@8AN` zuXy;Kdj*)%g2b3<5@0cG5p?j>xy?@^N8DCALW)ceXEaIT8Y)PL%xP-JYP+!?4VvB*MekgBJt;{}wiOJNW zr|@yaVYNvGb>PcE2xv?OU|WHuun`cv|3k>OfaU5I>=k%Fse5IJ=s?kr?8Swx_zFJb zqmP?gD!#Am=HIe7T^9V;+R3^iw4y|wD?lHta0Z)A{_VxiWe%!-0Aae6iQY{JntYb8 z8oP~D)2}0P>vznbo>&QlafhrUA>_ej0=BJ1&PHzJ>e!$t1$${OFhSN!FhstsV=jfW zUlkTR*Ve?O*I-<*Zw;$Dg^2YMp_)sKl-jd?H`GVypqz_IC77>CoDBRiToa0;Zhcu1v0n3PVC< za}-#gA=Ia-pWPno@KF5(jTR-ip59m}{9E*R5rG63vEc^~v4%p`k+vD4P1vtD#oj_9kqT^1wgxmEc z1?i1g08oEp|W83#}Fd7MCm$sY|exob%ScIYI(x!kvk+{wND znh8yk5~cQKg+Hgv*5VWu0cNUb=T?;uj{q}+H(Xb=;X#d%H)eip!jr6~Q?n+4eggV6 ziI&Jp!LcI(hV0OX=Zax+CJ>dhlts>dYOVXX=@#L^c@Nc68G*wSxz2uOpRZ4{1dRk* z-8!eL+Nit`cDVCA6ng=!+bhBSa=6$ax--yiPFbqd_Rg0B<8A%hZ!s)e0 za$jQtAyU2R!IE&#OO|Z>cf=*tYFbI7j($ik(T&}64AMBiLJXVR z+($*U?*r8Y^b0B}LqVDpw>;qX6n#c=3luI9<)o@gHYvTy=U9`hi$uU19hfZM!dgcH zwl%zVGf-k?3bMX?ivP*ZiG&HW2kNNrTgQumgf7+dvJS$r)|HZ|!}P;|7B$vcewfAc zgT1do)T4@_4s=A|$RkwlC%`vHYeKE3x-oey97CYR_YFVFGtiyx_+FxU_I;_d!69(vOk%bjuviq&{%K1!KVl@{!A(PZ%`hk*M*ZmRvbmcr#Xf8IXra(9n>J;IXE zG*L$*3I~sFaHho1qF7ZD8+uPA9_`jE{4L@zZWqwG@^QpG;$)+Uuf;db{2s3&H#b7;kA3Ic^R3}t>T$x{34*aqDX@(-64L>ZL`pZKzP)5 z=zxd_9~6=;7m)!oowNQO2t{OADS?56o!{jCJBrK&5MELq>E+tJ5VuF&58t1bfI+&zsTXv#3{F>Oq?ohKhKQ7}3 zPuP!JdE&D1z!dy*Z>tE!GjRe8U_(IU9*a@?%C+a!PP;z%YJcaKuB~v@PE>q zkE2)uXan^S=b#C62l>IHdml{r5L6SB+*ESwm$pZL)!F?kj{hBa3CK%Y*ex>J&v>7tA13VX6mJgYZt82ovz*$}C!ls0Q zP;W!0WioOiH^jU*YS#p=NzM`Dx5NI(`ZWcfubzqIJd2EzuDYi&Pq(Ku;kE=npx0A4 zs{@?kQX?Z@-yoKx&9SqctY>EO$&u&j6p5i|f?>;DNgkk8kOZwRsY1+he05k!L3;r^+QBRVYrf!21u}ln+^NJ0P_Zzah;>|NADBTA* zH6Xd*+5NB6Em;%?bbWJUHxoK=o9WdsJ4NQ^m453O-7|Ls`SvyG%U1RP9kas(Zt-S7 zzhTLKl592U^q$E>z1mbjR>hC8MHQy5_CDQ`z400T#UoytCn4+N5NZVb&a6$)8!fFu z>F>L7g>a-CQ5epn`c`?P)Go9{y;@SX3co4q`UGI_7mnheRu5vv#u`VIi?EW z|2u5T{nZi6^^B39 z6%^$x=+Vt!Ol9x*V(Itf#+cj#4xp4xNB;Ww+=(9V6w;zDB2aaDxQ^lY3iY`N zL^U-}`85=d{6VPtyPLe!U@NwRR?QzMpPZ7}BMBGZoGtX0opKJm9jpW=dtycscAlY8 z72fr>k-QJaH?DDvB0jbG;zt*(ife(zOf+HDwJsa*TWQ=P%8uCsFaSo)tV**QJsCN8 zOF`M^qZ%|}*{&XM&zoP*l*6R7;L&-q(hWmsUzQRPM5K!mG=Zdxn}W_|gE4O)LBfez zy~x7+iDBVtNPH_)x?0x>cgr+tMcj4@Js%Gw^(T1Tk+Ze;n8RC^Wu8pzMN#Ik%aq>? zVze-xdLUqtf5EevFtAG%?o(``58aw zIAv%6-n2k3o*#~TrY3Tj?OMd@cqExm=&KzG4ruqT63~LaO6Si;yaTXgXT8M)N^sPQ8ywO{GB^R8)d7= z3#X?pt3lUV(G$#)U17=V5kBtMRpYS`vfLM3fZO2a^jmp*_G01L=S{b5jjEXR<`> z5dq>BHD839T)d#gok}EJ)UL+7A#t}$rZdG}u!vRI)Tx+>M@6$S8^kt1?kfZkM}kYU z8tJR~0+dJbpjC&l!PV2YfGX0&l+T@IA|P`sVvsh773ii&GI4G3*7z-GFon?>fpJCc zcT5>>vf8bO4BtuEqgrth$<1&fhP_iu8{9AFL}!-b&|P_5r^)ytFOt~+2jJZPK@DZ;B$buwoDv^#KLMOO zXGLb_rV4IdEJ0}szw51t+|a?je%j}HJ28Hhuu!4ytnR%6mcY*VOAKeuv=hhwpPDH8VB?IE0MKBVN036i6=6~j?sfTqr>Me`FshW~BCy)@up|kQ zNa4?CexKbuH^k-IugCvK2Rfna=DlcJPYPvA`*%x_Ys{o&Zblhl^six`d6(w*0I4d-#I@gQEVYDLuTX}03A zP3e~5OLMQJ9yCbw){mE4hgblr4@J$J z_0>Q}kTb=<(T|~>Y_O{OmjP_BvNu##qD&l_Q3g>xIznnQi?9?F%orN3XG=9Zo2gw~ z4mr|iib14-p^L2_Z(6|udoGMen{T#+K`$15$9YBG+({<`)*DMuYdMb=XAozyS;1|^ zJ~xtIMeK@}eJc8FUx0)YoTSJle(^*Nh2=gT& zFxEZZi3>SVsYBmK7VEy%VPN(Y$n)Rhox9a4x=5zQi`TRNzsi)`@1-5P>lQUu<3tn= zgsIVw{;tco8aWZ$w9#oI=4cmgj!|{o3~}ICHzd3W^-2b=1)9V?|6#L`do3QV2s$ls zTp^G9$S?|ehh+^?KWyUp;zs0KOK%R4K&t4+916Pb9@oeGr>8;Bn<;&3*~JX>vm7pj zV}$A~6x+O%&(fJH~0LOK`^6$2b1CTpF8nO*^z~4+%lEik09v>^Kvup({Sr>MXq?7Vj#8H3VPF zbVrYBvwf=v^~Q)fkfGHPrj{+J$&njRMlkVVW)rACqNMyEw3ogv7Wsxbqfnz5itSki|>6sKto+5R9Ngl8aeI_7l z^Q#;A>+mPNY2YW!uz-N5lvOOXYmZK}i%R#Yy8z9_rFVDkMdRspI6!3m<56(9NKb+r z&H0Qd3aPzL$LFLB5fOfm`C@xhd5IOo;+zZSN!qM;JUSc&YnbMQ+qgEP*hI95paNof zR!)&tV%Ypp_5kg8GMk;5awJV$bi3sN<_biJJt+e&ye(7cb2;iv?v1^3Lpi&E#YZ-r zMhsV^<`#NHY2o`Aeo0TKviB??c*LZ*VqP{Q0<;w0AH8Tr&##V-3MW+o1V#HYHvY_5 z8@b=nmPYq88m%>a(XtW)8gpS3vqRC2eY~De`x%-}SOy5)@;zkY<|I zQ=$68zA5L$VI&aJ0yjVurPV(|q|(>aqK`HT2shTIJOn zcmN6PR6w4smUe<&HV7_AV8CHwi_}68)sV;Z`-`Bk&C-pGWy3ST3y86KEO_FLrpSAt zPTW%9Lv9?3i-36WzxAuoHwp=bKddoa7$`9t6%|e|bl@Wd%)w$OfSO;Ns5>+==sb6y zHZveyK0Qr;iaY|a%@6z@w5st%DzGtqsca7~YxLbWS@cP{Q)XxT6Bu~q{OD&Dd;M+i zdgF4h@BKi_?P4eK&zEr(&+P1$>Y4KW_OL{fDBiFk2kk{2H-K#s`+d%wdVPxl7L?yH zabK%LX;j#EpLv=$BkD$c{D12H>C`s^2ky{L_39dIS_ot2`Ey1xcYppMX;>BU4LC?N z$K!GS1|8prOQw#SdPSa*lrB4Xv3nhc3mJ(?ch0GpoCkgJlvP8V`N z%o|`oT~^U`TK?qXA^d3TvIPt)<33-c3-m4IbSRcja?N&Bzhw>pOcrLnB{Niyr|R6D zhUd~EE^5y9C-EHMI~c04@jc)-pFewK*bo&7IUy=Xb(lEuOY}c^6ork_!y1m{zsk?= z&l96CtS`ds++zN`#J?GYkf$oODrQ)bi1$nfCJ^J;#Vc_Il)U)#y{?C(2M+Q?r-Vf?7?%c0J8MLj&dIv)4CS}G8l2VmmpR$VJvC) zMt`MurGrPs_sP)4FZhc@TAc@O-UGuwsqyK+J2~8c8_lLnug{o}wTi_O3C=yA;1_@n zY(lj^Kj+88jWj5#OyA9fOn@Qw?`!vBwZ^)rbl)ma7JvKNlLs+kPduIBTZiC4a*$=9d$| zI9m7_E<%KdYR;EyWbJpQU*5h^S1kDAzEVK!;axYYmPi6)M1c;`^JDmgNLjNItLqm& z1wvrCL0JtZtRP`J78=O7W6}JJ;+Ye`dL<{B;qPWuWp$~~C0Xswe4<$8`%{RuHiOT( zkYy%moB~eIdm#3GT;z=EDv=gADyqjF@DGXqF_mifnD4PmG1TqqYJg^4Bezj4cskh% zKWz01A2kCe;%Sg{wBoqOJ59wGm?*qSI}yjReW%z^os8a>pmV)Hx1A*y(1bsEy-1LWwBY` zh;lREBM*WYY)UsID1DvYE(*La_NpZ2_(%ZMogTInZ>E9JI8T|ERiNmKGWS#)Tz_-$ z8iP@QJSA&ciP8$(k4PG5LwB#TtYJ?s4}Aum@_t6;*b+dApy|^UU+s9!Qh{iI2l>$A zc{+BB-TGdYlTk6MyXf>Ta+F4IvB7_mp0$yz5H{0H4FZBF(Js+i0}sGCw?<;>wsfeZ zT$DOOf?dx>UE1;$8rrS9;R0P^HV=#AGU-!MlyWqSxm`!~4UnLT4Ug}?J#^^+gcbRr z2t^@Ti-`+xY7&hz*Qb!HQF-GJKcXTpYdj*ffUrG%97RA5^ncZHJ3t~Ce-oYvr@sTQ za_URVsGw|u87YRbIojsM#tpMF(DG%IJNvb?T_rnQ?xa8`*TVy4vB(wtrWHrGJH0EH zxYZ9A5|ji*&+;A$*~TYoNf;aoyHhX^834DMq>qPSm(fV-6coW4=;}?8#_uXt}recc079;G4H6}jR`Es4?pXimC#R?4BLnPdlBM=+dAj{WrjTA_XDvC znt|k`rji(a711#%+X31bo(AG_O$=q4K>`In9NrnYM0I2z2|C*l4Q6o_|+qSNF4_uXJ5 z&K$%QSZ7TJ*3dqOcI9CAJ~Zdmm4OP7{Jil->tm}kD$J1&(7M=i04NxFZul4xt(ju; zkol$bTVN?v9vl`*?A8}o2-|su{z8_?x$M>xTgUy?g>!pm;*%OE5@!Ga)X0(EMnrrf zIG(%M#+rADLD+pT?= z$;>;jl<}F${{LcfjFE!4Asiusa(e^lUOjR7WE(rASv1h2Wsw0Ef!NF=Dbjm^XQ99K z1Z2_dFVf_`GN$V-`PujqM#(yN4H-uBbgW&55)T!%n1E>~PNbfzlQG?whBFiHE~hYi zJ(5R~V0U~o-EgO02AyOCH1exdO)&fn-D>9$te!JTY?=1kb6`QYQe)YURYwse!~-d9 z^yoIhnNy_E(DDKZo7R;@csfGAoV>`g`vYYWzF^+F@B(KzKZFjn|CqBS$RC>t(Gv8fN8`;`>a z&J?3GusXVpBz|WFhG7oS5z}1*% zMAHPHB$$=szcVERdigFSCV(;HN@i#<8Dw+U1`lr3yPGXL1Pa^0HY*fWr=%R+OqgFY zLG>-wrY>P_FEvBlL=D*@_)?vyhY{i68c4c>I91J|X>Y9_y1Uq%)Z)E)&GW z5o=vwN08wCC=^2I`tU&i6Ysh;)nWs2>L@JTx`pj%9n}P`#!iz)7oFWI0`P}_0{C9x z@4u@Mo%0u;E{j%$nnaK6r67;|V=$~i{wi+k2CjfP?u1`=G#VE65`qhJ`;FL698}K< zSoUP*vvziAZI<~K%>>_BFVXxuL(B)IcC|C?G)1Z4`(T2`VTR{TmArMx=`5q$A^*`A z1(_q-BnIa>Xd@+we`Z5w101L|YA2fDjdlC0eKXyYW}<@^mHu*%#X#CD?8yVWjYt5A zhn;muarKHZ$Tx&g@|heVw||{YyGgQ`u^8agKDYB2SAOKQNVV~;?NUJ&5dC_mou<;$ z=o5%eCWi$QaspNkBD$rr000?IHG5YFx{{zpiXhQst3fvekiNPS11Ju5#bq~jJ^G`s zqo`};753p3Xpvj0g#S%=qXd)+44u*dZ5FdfXAYLcpbR;EKGdQjC5bdco=~+`xD2WD zU+Jf^snP>^8ORoT)b^Dq+~|Z5Gk7&K+<_rhMgE&iD5Qyyl$uM^rqZA%*79DUmbj!Q zj$9Jq3*|+3t1df2>Sqvd)gl%Am@Y0al4rUH0sJ%J^jHjnq{gOjUSQ*cbKvdpGP{qH zB^z3rz?Ym0WwfUZ4H2)y0y6MiEMFZzD;*Z!Upo>RT%ogaE}S3k2i(pul10(CY398* z{_~}x(+17{cNH>O^)j|0mk&gf6<=TK;Km;u!NLmddngF6RYKa2LDLoG{PJCsxiE z1m4;S1?wIcr>8eOd31A$54xdfH?}4r?7FYKU+IdvWEO+`7=7ngZ{JgKDA`WuBF5s) zZl9ezwZZ*K_&`K{>aF8#pLZk1u9mYO(yQ=;gJ0vo431FF}2L+6r%BWH;Z=>wREwDZZ@Am zYvh+Pj4Gd36<phF-b%FouaN5qy?x3GavSh0%R^r3(gto*5p0~2}a zmIS_5I(Y~X4A{wHsjN>7lWcXx%Ws;Ey2zsihMvC61M@-HAw}3n;>ID>{6-87brE$m zxg$Vs0>@}$Qu{3o%2Cps9Z~7$^a|Lk7W{wF;I7Y{o$*vD^@gW#z$Khv?h{LwVQFA4 zka5+eSAcyT=)leB@xRjRlxi>r1jLL9-GQF(D20@?bBZ&7x!&RjRMy9jyN=$|Tn(19 z&;}4(xr@;b8CQ{W4WMyzwGHAenkn-(6@XI^NDAd}K|Mb$(-9*?@HakT`s7gsKn`aL zEtngi!&>i?@t{=P^ zE+he{>i@@n%vy-fZWpHsizdRtiZ0&N_3bi7kyclM=tx7Z=6-LeY@9;FCTL?)K7AO& z)A^7I@hc=eT9q}AP)>(}_Y*{CKaoWE^@*m4cq2M6>+iEdJ*yg^f_OGz2>4;@W1S{% zCW^lInaLAQN&m=}yCj9$PC-MnrH&yWpH(;P6Gp6R(7s=h*RcX?gti|Z zzh*)7kH>w{wjz_DdA;ORMtgv*OQarXhB-lH785KsWqS?xSy~VNX0}RCR4Ih}KLTMm z$yd*?MH{a|!VA?ePRpe=oGGQCRkvUmVq`EnsWSS4jdCM))AHOe1bdfwRFJoVLoM6~ zs@Nf-CVfr}SM5G!YZ`{sP$ll|Kwo2}t1Ad4iWDy&Jii&`KNi??BxTW;;fpf0m6vwh zR<>=GYjmFOm|AYHhsp$b`8y~20B#BX+COl!6gmmH@{zVdJ&z*hp%F`OV7Vit*U+`C zW#<69e(er$SqR6ojv~f+7pxdOJ>XpwY^zwwu2gTmotZ>08a3=ALQqsf0;$56wgszg zk}uH;MU<&W{weaTFt697Zsuqo?8U`U>EjV;4#F(eCP4nQi{K$*k_~fYF0zTI0k(8E zWWTDTbzbbejW19vLF-A;`d1ae`!t{c<(hOk-LQGClTLNpXBfbM7jV$@2K+e9pCQnqHu!%?1VPbO9sjjhqpk?4y~R5_ z=Y|ltyJW_8%nIX`K7_`wRFKmAt zZ^Kc}a79={#Rx(?X2wx@-5CJm`2mG?$Ot3qJXARpjjHq6t7&l5uKPx z&`!LCR3#6ch<(bIuhG_{4*|;yyd}q`mUKgyMwo2!&VagdQsk~<*OM$1^(cjf3Y-WM z0E+n!>9uL*haso>?bJWo8N#H~$Y!0=S?UkIe&m#ptYXwpx zFvl3ACvUZF{M?f0f0a@nHqY(0;uwE>KExIUjp|gOr$iN)Eb#M;K)w{Jq@kM;jW8jJ zG#9LHNG^)w%^O2e#^mt8hBC(|Em-8G+{k8tC)`tUJO7waYJF8NKvPFY8Ot!e0#-Ce zI&t{Q=dlW7Xr#|}s-k?-YFa;PYwSEIksn=$d=vEv=a;8)E#UKZE4O!*iD}O$N=-hU zCb4Mb0|Ic&)3%>Q`iXWP_sSiG>Zi@_nW&z$u8G97xyz7V>FDxYxMiy9k{&BG>O;woE^CqVKe73z&Q=iNwb8>kQItabhk&88hb2zYE9G;!9Gt-8KcH%8k^msQpL{;Yj z{m^_t@mtw13nH3XRY`kW6WG$_ASeGRvdhK6#WWKGswV`@C|9MAS5iJbW5OB{m527~ z%OH|Nk;50@ouw(>lpcU7HBwZh_52Jx*;mKIr-6m_vrldOzc?BA1j{UrWeO+byT|vB ze9>C$n(Ohv6^1Yz%f&-G62KEwN}H;g*$5NMh%ek(t_WH{Y8F#MkpZi%sq3$5Ku@v; zDH>oGnbfYoHQhr4j$M?rd@S8>R-&Ln&#;RT}ha=VrFUd z)>PDjMhB?-)QCZ_CYh*;CkLeNDI=hcHwR!-UoHbF2frhB{B12SeJ!1SoO{IoiS@ly zBZub`uK=m9)ipPPVB6YFg&!CQIyG%q8wxN$KfDglL~Jm3GTP$iI!gt>|LqTIT$72~ z34F0Xj`l+V=`MTCtT|JR;YzDxVha&NGdf)$wzWCpf9X)gx-2k6Ey8rgvwCOK`J=ly zwpzw!1H6xyemv&9#>)np*WejZtu@ZhRb&eR=&f8(W%bqCzB(!r)iK^@obEV4*oBsP zd~HVj#SO@_8j-A7MU*A>NnF|IN2M`tih4wVPoR^1muS2WM@=Fk=Naj$n z;)LcsU@YIj%tLGSM&o?V*l>`h%y)J4@Dn>tR8-=K`PHkwxFRZixlYRbq^%arm9<1q zPOtMK9h-s^6PDt=!w=jpBr6s^o@sN+n%L||pMMioQKG?h9{}MBXh1;)kkQME za5t9L&8G|B4nt3jxL}uLrtV5$Fgj6vMDGwu%0 zt4?(}4oe%s3E}*&HTQpA9>&@un@)j+I%oq9^BDFOZ*myZF0V+6V(aD>OirTsSjL~1-gPqD% zrExi_fhA?}u25ZTij+n{Tehk_(D`}@6=wk>ZAyHDVP452$7%*qV?*H=+v=?AU z0BlQ@TazAT_$#7S#@+B#86lz1i30_bgjKH2 z0NgqQXz`|rfwYZu4cTM^q*~~{Rsa<7^a3fB=6sx7Ic!sDViBS5qJWwoMl5$%Xg(Zk za6tK|+Xkr&WCX{k;8)EGod?yAh`7I6Y5OZ*ZbbKuPNeYHP8}y__6WPO(oTg=x?tqm zMAzwmv=na*{hs8Y>w}IfQ^WakqD{aC>8;i`UigTBc-SLRJ2?;i&>a}LW%{B0$>r6} z^4_-kxaX@JXZjSDOdvSv32PoW@ktYXkBFpsUoPv+Tj?n^%pv0MpSsQ7N@+B5s#i(J z_t>u!@JBttnH50SbxXLcj2}j$&E$KJ*($~Y=X%N3kP1#`HOb%pY-ZhRp3CR}QxGO1 zWr>Mba9N!PmExAmDBDc%_gd-k^!{R>q9Q{ur!Bq5!CF+Q0i@K?7?*Ziy-`pqqu9bB z<8DTb1KAf8uDS@_$nv7Y?-os|$$~VM!@4)Lv=GbDG8w8G)n^`99Ea#yG?rqwu|MF2 zPZ(c>)?I}zG6{z{gjrvx3hXgK#e&}6E$n+U&nvrDblk;1W5svWO5o``*7wKh0=F5f zj}hXbvb_kPJq@|c@G|sjj>2>xgX}Ol49HT?kNdb7)y)OA5_`*aJv6XVHPO2d1%n8A`!LoNtQ*%1;9;}E}#{Zg+xJ+lo5EFQ}!ClLF0@37V=+@ytOy2>ek657v#r-le6n+xL zVJ`44ajaO`!Fc>KU*C=irqcv7kpKkLW@z!QyL$jP|KT92xshjIvYMujr+>eB+3PDt z=pOZfU)RM(2MHc8B^x=|{>|P+M}2Qelg2g%jsZq}d6>6Tb!|Z%aI3nuu{wS%0IP%F ziq0jKNPO!YNFA#*USWI=59XK5^6G~nh%#gbDwc++kR_3<{diN+>^1-5mX0dKp7^kq zo@r)wFV34LK&URGn!qZn$z||(`Ll({+Q{D43MyN%s*f!S-j@~CK!;8~4RAtHDW$gR zcYc%eI;<+M{Ef+=Z-!N6;oUs=$SVmqks3*~(-r_8qD1;DxpkWB5nSLPjwzl|X?@~a zQk>ycQ2t^DnO39#M#1>I*A}N@$sksukdK)8j9vFnPdxKS59%PVR;o1RQzFNfn!q)q zTEKXKD+A-OP_4t-r-z|8y-hz_OzlTQv{=x=W)G&}%PbRN1HYOaNE4SS7zcLw1M1^K zA3=#4zAA1Ot<&XZ9|{CHL?-<2#C0dN)>&StVkcr#a|KfuZDq4IgLm-Vp*d>ge`YHR zX_4{|QDGryl;VsO(q*@;<8daFuo?ZG@)6ocS>QgEs*Jo==}>;e8b5quF;7gV9KTy=zXHDC_8`+o32C6G z?&lHEb`iD16E=!XinT(jWKLXWhO~k3*nm^*EtMY?+J9i1ni@Uo#U5bGN(MkSc;-Y; z6N7yedf=%TW?!Th40bEi&o{_$ka%e0;W~z;&Dm9ei9V@6WO{3!;n+odKbY*r^*#QCgr6>T*A)%sOV^y-M$o8wRNB&iI7=CWZw zBAM75?6p8iiP#zq^XRoBnd>5%Y6_xmYgtwA4!aPtoC2G=f>?OYfXt?C(-m$)1=T=T zr2sjp)gf5>$mybALM7HUEuLpgyws2WXP~N=i(KRS*)93a1B8E1d9dDcE~VsxMy^}G zWc=;1oZdF!r`(!UJa-CJ`~ygkccoyp7UE zB3yI3P4v;UDm^cuS1%f}dPRb*T18^z+-(1iV2BHrnC!xvohn#G6{*)DLl`ZK32C<9Ug+xst;g7SeRfS5g3o!RZe~c6~OPPD{y; z8+g8D%e2tn7>mAC*X^#i*`noJ726zPYlhxI*RI}(+{*LbQj!CEYA;7OGqW3=$5KuR zmK+WT%lTe)Qxroi2i$%?nd+8m-D;V?LUXE--ch|HC^!J?5$OsKYF+G_f5r@pH40rs zz1wxq>sv@XfKZe}2jt`esZU2SM=&m5vv2l^vj0O9PNWiw_`=NxV*R5=#*>TrN4xEp zT^0*OWnRh#T`~8H5LxI!1y%#GHKz$L|ArkC;u<4d*0)$0qFb-Dy*$oVb^RYutTrcS z)TzFNLxxe|l*CMr>mxdHJM9khb-FZCo*joM=ic10SNMWykrQ{ZYlAf@^^(qYqvsST zMGI9!;WX4dy_{Q16%k*9>6&nt4a!QlsQ)wd_CbWj+N(J2`eFbL9u(Ts1UX$6Og?<^AH>M6j9(QSkr~TvO8kS?2owXCx))mFx zpU>-hAH3LDVL1(kz2Kpb?-mgiU>$$va&#GmyJAV4*va5KM8U>88R6RrxKt2-m(M+C z>oSc%;GNZ?APJk4=v5L|b+lWC@Knl8C-Dveo#5c%hB%fNw`kDd&gib&!d!bzoy4ef zQ6V}=$-B)n9-%ljl>N>PR8A`n$}bwJS+{r7j3Hm}3pD=C(H$sl4S8|FVXhGZxM_DN zwz7N@f_!oVyc#Bfjrb1#vg|FSFmOr|pNf?Pv28|lg5kI6pEj7f_#ze0)-@+W{i$9& zBiX??MR-}?`LIlHc?2bOtZ+H|9eUk%&Ay0*40^M%q*_tT)_fJ-iyfI?Hk1WmjXq^e z&*7C!FIF5?b=}ao#F-9^Xqj%*iqw{8nR}6N7?qz9aW3`iw?GOYX}~if6*|&8 z4Kj0noWqd zfSduh#`}C7hAnUjmX-K=<;Dhp2dq7_`hsXImghS|-#|p`RJ?cDh^A(|e5xuR3QgV< zTlZ1MPk>-W%dC5Y5$3Ir18I3Q|cDugssxVK8G6}2#-~mOOgi$xtqk$@W!eWEY?jI-&3o_h^KG}9I z$+NHp*DTJm zdH|Nw&?87)EE=h8Wdzlm)XL$!rWkrZu4i;dDIt?dtOp03C3pQRsUNSM1Q4F{o>vBB zXR`7t1Df*vfs+FNu8HS($|PM-$H>y8$@nT7^)!hLeJImVfJ(%|c6EOc!I=|majk0y z;V>t-yfG}WpMsue;0%qb7+mz(x>g9j_tT&x!saazKK#ce6n87|7GMY6Hpiz&js|T) zt4gV_7#;MDhHa)6mN1L3jd_0=4xDq5LRJ+A5H4=%!mno$4H z5gNFOv0;%13 zgfF*ptQ+IKmd-xxi)CkjMRMI02~w1Dl^(#dne#nDBk zpsi#Y0sdzvS7O-AXzbYoV3W=ZGk$j$E@9Y6eKV&TmR2)PXg2~Jjj^7ny|jp7MeDZ% z1@>X6NQoHhMcxwGX+getPVjYm$Pj~Au`@arBt|!~_%{UuQQ~6RQE13WzGgrwXj|R~ zzh-HfUVZM$KiXWOP5|Y@Mpf4WhmxMtEz?h6M3fawd^otWhqdWc5g+3h&ffilCmmZ~ zPva)nZp+1B{dea%%s+pY_T0CA*uOnl@B5Z zTwAKQ|KiJH8msI;(ebM(rfmjoPzis;{yRF5L$h7nWhzUONJ95~Cjxw`g-n0nP^_43 z=BjjT9t$vePzUg$@B`Sn2!j9d4Hk?702QJU^$krhMNY&A_HycxBO=rIF7Oo0eL9tT zRKcB|nP6!D+8vGj($??!Bh&NoRd2@34{j(0YXt5Vh$Rk&MZ=|=l2J(>yyC@;6wSkB z{c4Y1*bCw;VJWiq@-ChgLF!P7egZ1~a)GO}Bj5Fc2bkugQR`-g;MGzhTJi!R$mBGl zqE?JWYXlg`DnZ~8ex0fUDxv*pr`=EM-$YzfT~0HMWZ8L{K42|le%IkgIUaivkz1Ce zY(WNxhE&a+(8mtA`6O09e-M``S{NM~agXxU{JF)M<<#H};y@wcrgZeFt?Pmmh3^-Y z5BL-r?>|LtnSUN>>G6y=Zp_fl@DZ$z-^KJT;=UN{**1S*|8?F|^f=hCF{NWhgFe}r zctIb*o#xP`N9|ZzF>gX8LPLn47~|8vPBa~lod-YaMsHK$K3K)A{5AyWLDV=~KJHt) zz|l8W_dEh8k1}zBbT;~1nl7g8gkR)kU^4X5eDC*P{ct~!snC`%i^f!qISzFDgnMgY z5r*haplnK~5s^@2N_14p$*c~#tgV9`r0#*>0U9euBf;7t(LX*;@z#fz&kxeQ&zcIp z1PAKY2TkT4H`VhELWFx)Tw;~P=!ia$vxa#h1XCLzQ^?xL+!s_>j$%ReGLz8>-)v2R z5SA7vm{jGvxwexfe{=_qc_DGkhk90hJ9V&gWr@>tL;w!5^`l>9mF&S>t?DwQKfF~g z)ZxLI_e7*&sE`1(99rUim1jlJ&`H6r&23@jQP0zjTXyC;wDE{xRWv`4j>8;MO~fq#osr!t{oOAuhlSVEhJ(5( zGe6fc09gNpulX~(>w@BU(C!UTwB@6<5YXc?;cDp#Y);X9f*H_D8EXr#&pb$tzKT7{ zn(`Ehn8LIDmPAwWvVk$H$ri~);8iAc5!kp>Jn%Yc;9Bpep?c6p$@tAx;0i>6A{asg z!h=30{i4mulIX7e5n>h)LYKv{6V(^!p2NgCNdNT`A{ghM0!jC53hZW%bDq(_{kGxp zW(GQ*tdRT_e{hln4^ePYA#D(PH0a^&ljmJR7%rHiZT7uhM3usDXa&L|)J!%TZ+Ea4iFXBL= z+Va+aA_^I0uf_3(5oR>pOpG^wCSuN8Nq2Kj$<%`WeE)#-n!nDIe1wb=lCen{)0{;yR(CVt+AwdEGS!7qH=%o5E)hsV%XRQBq9DeV* zGzt_xvYd_3t_5he5F>Op(vy~Zu!V)15GynqS;K&g+P29S61x*K!Zh?`>mr@7jbiE( zr#{e{y1kXUK$vROd`(UG@Y^=tu`S$EeD%CFilb4U-LNRjNQ86&?3R>F(y9iHAVQgr zSkx6AgyTcS;5Wbj54T!R=TyP(&A756vEPueD;5obuw& zyl!j@KjddFZ4)Wy_d}n*1>Wj`W-7g(DAN=A5l2j7GMVLrpql24xA;CFQ|#=e(=sG2 z-W6?x1lhglX}sOI>S;aY(y`4%Q~LXI>Rmg!V>~^DuecK`aeG#$+=7KkSrY{<$jjj- zYY+v+lLRAquCX?Or;WzmPkRU*g^oX0q4#xyf*;bz69V6e&z?olz-=u~x1^5^89M2{ zk5FZ;9mNrd0jz7CLW`hQ>51eJHZ)YA?5qG;t+#{)_nB_Qf!M{C*>0ogwIB)YwW#`e5p}up3kO)eMe#ys`xdTRG)?O;HLrR!CzGCV z5^HmCdq~`dW`Lcmi3y!kp1ahr_QJxMp_$HZRpndY!&n{b3nNY*tGz#np$oph!>H_^ zz#`m(Vj!NI+kA`7uBjw$lsSMt`j=tw4=pTt5)8~VUZS5)EUq4#{GH(;7tc=aO!a++ zU1Dz?c8t{bZ26H0n?>-$Fp|DvM-G{Mh)N*$E&5hS2UnN%h(FLy3rv+Flh685)`v6- zrl%v!lx-{{uOmH6i}-ek{?B!Y!(hUZB@!!|BS^L+5>bnwE7&Kaj$sFKr)2N1Fuod~ zeG`nV?vNs44{ZjEy*?T`Q|ZC~$)=*nr;Z_f5tWimwuKP!E#ziZ9e4hJosM6V6FZLj zq1s(cZ{OK3>&b~2WadNg*ndlf?{(K+dHY2dH(D{0{9E`5p3{jd+Vs@6o35O&hBJ*^ zR$7t2C2KzT5VHII9EGU37RCbIXL#WSdp6I4I$}&UkLc{2CS`!U)B&jM1 zGFf+CO0%>n{z7bT;oNnUIUv91uroo|GB&WJFG^P80|hfYJLwE3qLkE9i3BJV!LL|E zrNh$>LZj!}@s`R2t##!GKRRNJ8q_PZZKdOzF(YPg+Lkm7B_AzMbCK{qeJyF6JFlqL zs~uRxTS-P?q8_ee#duV#0(Ag=oD1Tc!y9f^QXgtA!qc#?~BX~ zKU_Cz^t(`14p1W(!r2Ehw(G~>Q1ZWA6Z4lwtJ=(9&5tL#-KdND?IINre8!tkt&Ev? z_6CC*UpeCL*&x%ZSD6}=)6-g)T+FWGdf{`4S>Yr(i}=`p-^7zvEkpf0V_AebT%jJ! z>TGgaRvNng{f?r%rPW9po?OG?Z+tv`fY;U#CV3MW#e~z}`_DBMzC`WInWHgJ^ExRA z-i~#0r~0f`w6j(=>Q&WM&Z})@m4Izo%`!xbYBvWME?*8(n9d&fr51W8HTLkoYzMbN zasE)42=!lDoP)hV9_nWe;&vP-(;5&dg#JLLSulDX(CGh9lG@6hx%&BGZWQ__InKzB5ilY zI02jn=Q9_jM74hrNq1E3IJc+*fH~8v*ZF!ZBI7rK;mxTOR(H(MH4d{@(Fz!5I}Hg}UsYsHM|3%CjX(v%SF*D@{cJttFY4 zKFHb!gFT~Vb7w*dJrr0U1cN;YvyYMd(h%MAvgxu4P!NrT1Ey|x)-JTGA~(PKV}D1mdcM@zv>Sh0{NrhG;Fe9#uk>GQHs0=A8!i-3)o{iN z-{PDD1su|eiB8Ks1K1;$CLeKYo}te8kYFoP6dO~M?|ChU#JTD&iihQ>jE=Fwp|Ps~ zh+lBW+ggFvd6r$Z1r^UIdCf8W+x4JR+zapPjWEs^K{TnLO~>ey>~ifokpQ1KAPuQ4 zfdHy`gGP3ed3DVKWqY3cn=h+8UiAularqpMiVZ}0tV+&E!1+5Fd6j}(ZGVx=i0~UX zOFL0sC4Nva1Wz`b4t=r_W|*2Z@eN9$@$tj%ket{Alz5sy*v6ysA|Lr3UOJt7(Yqi( zD^pJ6eUA;gpF z5_u>Dr^L%12O2rj7Dex=GaZ}!d&O=4_9pb8w1FkyF|*{_oJ)~7vr2=D&@xy|t`K~h zOhz=?t!6>34L~RqZFTl24)YxidbeTJ;s1-ZBVy22VYlS;6?|65ON zNPpi!#>a8b*u%hOMWUaIaxHXk{RG6$h9d3cJ7=YL472hmA>xXIlOm5h_=dE*V2Z(6 zNU4T=R7*UatZ_&JNiQb^n82|s)W&ZI>W7~fFgc^heN>e1;nV?>Wc=IJ0CUBJ*9_1pD3_(5qaEzf#X0TX6J)%3HRa@ z5y7A-m5&enS!6lKxEA9UxKjRJzRnfkC6#N)ob~)apL@h!1N3*2crh0V9sT>=@Vjn3 zES9-MliEPpzBHQhv(Gy8GXj$AZvSll0+Vx{HMd?$X4M9Q8L*IfnAgZhhT%vobsw&H zA_2{mAl~kXPXMwXcWRp2(xYK32YZO4pZ|P;*qy;^nPQzAZB@0>?lZ93lUJOF`P_w; zQA4q*x7Sis0mAzMD}rmbS(`|JTuAGXFlcVQ@L0q|s#0k?M=0-tu+PUTvigyf?kOec zWmOD$^ooFhh@M*y-nWYSAnfrS3-dL{KDKlvV{?4~3#u!d!EAg8go+3g_hRsCZN5vT zCc=GE;Lo5>D3eQn#Ek#Hf&ZCXm81SShw74{zx4So<5XJQ3Zsp9TKlq0Lt(}0WjkX5 zWATHBs8TSGE(Zq)rwgGCs4lDCYU%H%a~u4Pwa)h%T&hbj%0h>5)9B}B%+#BmL$dPq zT;BVv^b(!%5X|qGRPmY(wPOn(=XhV~;I$~tOqh_}j^J!jcK!|@hcmr!6kjs4Hq?6# zk0gs`h%1TtW-1Ycsj;nKZK@B}tp|-@20Qq6euEL3PYgnJZnlW&ZIgWC#-mk6)a`)O zO&ekW$)vHbIYPyigT|vHy{QL4`sxkWT}B94bI1b11b}x6*H?9>M2TMy5kXbJbqEav zL#ngjf)}I0R{OvSxt5s6Hh$`$zbbJgpem-LBB@cWi6!thAlrsR4I+wXKod~ogjqF8 zKB{#eit4X>OoKrko>?i(7r&yMali?C<*W{ookt8Va0Ab}AMfpGPspV|sJ>1+>yL4A zQIfA&hbIZ+@h?p@J`&kt5m%7lbW^e78RwW3WKD;ayl;z`!$`>tc*hI0xK{9h6(@Ie zlByd$ek`n;;GAx42TC$3CLUF&|F>Xrmtxokl(xY4i!^-_@MX{xlEmOCk3B1S;!fii zp9Psv4y80-Y@0aIpi+<*pM11;dX*#L#iubwPtF*i3(re_IQBs{l3XYx8{VXTPGN;X z7b!b8tjcxTn=hO97bk8f@M;~pGOwZQ340oQI06{_{HQo<2ZpA0t1{(hsDH1CYuBM6 zH~{4g{!PxFqyq}kUShCgmW$(1lm@n#g!0Q0;>0`9roaegCOf(D_`^XE0ia{e#$GS{ zp9G2{fi5It1@5!F%gO`$*&=Muw)ax)_g;KwsbrZu;cAv)%woW7$kTQtwjA{=cI)d~ z=!)?)fIf)c$TCThfAo~%?MIt|AozvClNx%vuRy{wFc#Y@KJr{Y;5E^CbWHK+1RxZl zPJYW@Y7FA09|vOT64nBntmI`uomDU$O8z}wI6sS4u^rV>Xk&B3VVafYzs5j+FRwfT zdQ(8VvA}XbrDiU3<>Jy}mCGxDN*wjbx&jpBtH~m=E#Pstvw&kRmqx*AzQA8W>eewq zLnU;l?%$WWhPB>HLbaY%@bO5EK#gfSi4Hp{wMW2Ewb<`G&ae*LsyL7I4G^4ZI$-QK zGjsIY0&qQEJ~OtmLq!IK)5-FN>nDD_}$F6sxhIN_;#nyZZJttP|x z>)q{@GHSpzMCm$fgyyq8CHAgI_ce~?wxmj%oX$_ECf{F3s1YHvM`yh4tF2wUxEPi9 z1=(AjUTvclG42V{U*X8o(k3o-bA4bupX311_-8ss?E8c@nrSh3o(r*a?%H7` zOu7jr!Dy7kt#YavZfI}cnQNU_h+Li4Fw^}Gb=!o zJks`tVh`J!K1GD`sLd=T*|stjjJFWaNVU8w7KoB&*0spMLX;qms>&6`PGizcjsAmz z!4&SS`OovRI!BrGz+K|;A7nqYf5*|u`u21LiL1itFzz%Dp`-VeFC2Q8s%lRS;A-cd zDIbT(61*4Na}k4S)u|AQpRA&*1#4Y4Ir5i3Eve$#xex2|9Nv93}yryd9>TBE#tf)ADrr|&%wr~nd6Q+ z-Wviljv8-`28$e^`e{%zeXYS=VC5aUEi82YzZq4y;vP2#2_^RMft8$L7DIZzcBI zQ{T&Eq76=>ZdmjHPDzg=PoO4^SJ9d=NMyBDo9;}bk>3A%WpH=ShWDf*ub6^vmE@6{ zpt{U#zJM{ozF7ag2W$WBwK(3FZ{3wLb6@U`_k53f!Ng;AWzyQqQj`;4{sLX|bq2+< zK;kCZesaxOWFN46V0vDDpR;2Ow=D87zw%M{ZNVHD=>>{J_anNTUB15hEqm$G!v`?g zov5naFEG`}XP9k=Qs6JdK~!waUa;7QoXtAp*m6@pQWvS>%*sP9Q4J;6x-_?=yh7kp zwjFiFfH9&B25JK`2=nVfKPA~!Yp}-!yv)T=w|PU5UkY3FMh$*ub{51;l+(t6d)70n zMIK*iX4qL{XbhNgGpTdGaj$tORd*e$cqKjf=10A?Ez>JwlUD+dtl|HO_ta3s&S9uw zRR~v{AWO`v<0iG-5>Zi4acMZZl_@LLnEGua>$$PCw;8wN+*j6&$dqHjQG3>^_?T|X zU|sSXvqG2F5Fr4AWnzwnvC2jwLW;V~NKMKpFo6P1g|Kfu`mZ(Vy=`=wX(~Ar2Xv{(`$Ds6pcc zXjlVtZbMcfNZ<8pf!CO2)^g0oAwf_E_{QUEvWkJ*Yq9h;9{)R@*Lu z_}zW@pRSe%)J>J6p%Umus`wl&-WL@ORVz2S6-J8PP0|sqg~rQt&*e7&67#^ge+8D} zc!P)J$&;DgT*`DO?RzMa6O3WI3ueGG!Y>F$XxQ<~Yu-eb0J=(#?~EBYAC$=NGbZUb zvsZ7X1l=B7rea9Os1`FQ47(gdCn1LxMgosQ&EM}cCte7J_Reqkn7knjAQU5SqAsvBZ2w&j#py$%P&!h1CwV zierXXWzeTJYb};ZyE*y)M?Y+rUCu#T=$Ys_&e<++Xi~SL6`U^W99|(h)O*f5J z{K7J~suVdL&#vQy=Qh|}_REOzwxqXT*DD=OMF|*Vl(|(PGa1@uHo8@kz0uv{^sK?0R#x|wv&~1otX=w%tbHv%}T+OD<>$@Qt8Rm3Tv^(ET`|?y{-E6 zQzN<2k@c7bmh$tpP1-PEasm`I@9pyr{%JrJ9l>qy#Uv`!d*0`P=J;Fyw&v0qrF`;3 z;*)2FWG$p&yA^SR`Y-qa$TPAz)vHa~-ID-n5|p^sECKW@PZrEp7;(qGK!A9Ct|A z6m)U(f$!DVdzq*pO?Fr>E5wWFoRcMfTI*xZVUlNvF50Z}7&lQp&2k8LD{QS*QD+fQ zQ28;m&_Hzq0VwT}a?>~U-LG9FPy5++W{XpNW;q?V2T^f|B~fL%M3Z)UF;B+`%>7(b z*F8nt`a>~kZphoLGjLdNoxb@8@Jw9ceI|#dY76%>Y^+@m5kHs+SmY>|B}iXDy_H`{@GZ~FCN*VtX>Cim0k=^+MCe< zYAwVb`TaG_blGCI*&R||9z3(tr0ME5bi+_E(w*pfTrar*ZT+{wu$dFF$ezWF{6_9! zQnR1TGT3}eo^N3rXsAT*Jt??$(%6iPe)qJGQ27P9(1GjEa+&({v;@Eto{-yT&!d1p zF9JbIJ0WvtI`0IfHd8z!`gng*Frv}^J?C!TAsUp~X&yS6lraUF`N78uD#Crs)X{yCz)=uTO){?dPeWNV7e?{g_K^WocAV#@6h^VQ zIZ|G(T5JYP8xZE%7lORUob&X!ezssc@irO#%v+rhV>Qx~nzYBHCcrppuLls6r8tMf zgGwsrn3ljq#h=Gc z7ORrX;myY=9L4H$gY(wMLH)%u@ok49VC1{#R5*OPZ_9~sEwbJ{qz1Ro0DEPx%r>DJ z`*ShjDhZ|u6^#D5omO{}gUyxt>d}3KZNb#GS(z4`VBv~ZNJTtW_WQCFSaCEaa z`YCwcV*9U1vH1egL2wrXFx@4`x^736gyK)w5S)UhMhn{+KM%%>np=sSeUBH1-F2C}%}! zwMMYWR~tGU<3VrOHOUPahYcO?BnG!MQ`bw?Rxsry)$`lLzqRR^3l90=PaiJ+Q0N8| zwt=m9%s1D`z^n(=E$N{n$WhJ&ZmRiq1tw&a?C??mPIL)Pa;i)AH*zFe%7G!C+wCv6 zb)F!1s)s2}pBQQwbDtHj0|3dwr$hRwZ<6MLeG=opb6_)SaFChw-DLZAOR?#u7tfiM zVoTD(JRzNZndh@}R4a!3^}PJy;Ii(LhW1i1W-vAGf$*OhcngbsI~c5%F_IFH9r4s2 z>cj%v5wmnYOM<0Ba?l69Z~VpS^xy+V4{b!S%ATy8ZSdR1;_4I^)~4Cwmvg<7h&|trR9VGi@0oG$aNy5?E+dEvB!bV3NbSTnF zHuV)APWW5`snx!!t*Q@21JJjQ$nH2T}MyusaJuK4ZNb~tz3JA%xR zeiO?*y2I#VeXH3`iRFzmO2xGIAvIR$kPpE0w(yc{KRzV;wDJN!jdc{Vgwz(D_jCg- zgz@kx5sSefX?Qu?xdiblVq65TX%e>B>%NbrRjRm1Z_4M_ex^opAr@2(7oln+Ro(De#JoRO zE^6x~a@cw!Ht32={O+p2q>Hr|@h}DGLUY)*afZupvfQ5L_YM|$nE?FzYo2mOJ{B|` zFeBQH(mGIFOl0X@nJklZod8fkufKj$kx<9NSyU5=@FYnlw?9^4#!{jV z3>)3a0!4wPwUE%quxmQEp!|8E4tho*_f4t;V9WG#SFd2w1+x@duZajLXZ>|&tn)XA z7qj-#J=LM@7uR$P;B&T8ho?y;Y-HYk6wF|Xz#AMi!sf2}L+h1?CZ$EXNT649M)W`< zas@gh@LB@mB1V&Z%H(P%PJG$G?uY7;(}OdRBd{D8Fx4%RTJr-pWKotYi)X@r(v30v z^rsPmPbWuo66?_O4yki#J?i#FvK4@SS*}*td6iP$^6#M^Ku9HTC+h`Dd>{3>jp3G% zmo~N8_O3DJXYjaH8w(R=7=VJ^e7w}Up5_~H z|JA)ywr049=)*sTugweZ`n~=l5P+uFWn}iQH8scNyeGW=glKk>Nru8FEK7ssb2GU- z)n3DDj;;kj;Az-6*J6P*6NFCHp&N2{HP8~y+sCxmGGXgx<{%-vX#+ii0MMCo7&%=G z3pZ?QeH+vk=^GBG>ImS^M1u_u9$m=p71WX@F_i5dEWV@VKGalQ|I}ZLN(2&49G2Nr z*B~G4sjksb+rj%=HF9<3SBGfM62M$QD$Ku{d}0m`o#VTd+t}n=3hlKOitHW+SEvr4DCn}eLKe6rxe+-Un9LE`e!;0dQ8t68lf-zt}C@KmE z8QWXvuE;ZWr8yCaI7qU{5p5`b=Q73(3K_(s@$YrveS634;oaqe0U|RmIy&C<8Bwx` zR*PS&>!48_ZQk4QU#}g{7<5kb%Ip`GMc8rVGfhBp?yy!od=K|O8!(5J>X^|5@2CF^ zdag{SkeJHwJ`HlS;vd*CgLW?+{o?*AN>pmm~Xbr?Bhc$2;mEv%AE>+DP8KM^(nPlf*xAH7vzX|iMzpR!8vxH=U7xK3im z6^%AP@a)rkP(8^-3REZmo0$xyh1?ptuw5yPH6+#pvB((VS9_0Yge!C=%g-0X&PWS^ zoh{bJJ1}q_Hle>gt!Rj0hjcqh$hF19@6m0w9dO@{T8Z_wZ8x@w?dy=L@ER zr`(@k&ksDslAD?qOZm4GPY*3_R_8VUXI1~a*Y(XM)4XbB8?*6Kgrk$^Jui}{B@(= zUJlfK@VuB%=dr%Ow6BRX389DG*{G)#^c5Ch@*H`yqC>tO>WTq=XFoXEp3=7xUJCDX zfEgOY%#@HwP!-x3kkzB6q%J$5|IPdL= z($!>5%RWxGG=s$u+%F;RnPSBXGB?R*k%>-RW zt(*w4h)p9M3S)eb?tP9q|LcZz0Um4ksV##`;4yfbxn@{yO=cNi^zp?cVKo<5YUXxo zUOt@#0pISsbr|e6#JH@UBl1?cC(3QNSQqR8$82AK&?=gxE>2+1J2V{$v9^LCayFVlmZ%D`i2*Xh)$llemoPI z?=k6!py;e)WR(IkS-X#sK5bXdq!g5ZtD`p?>Lre}R#zJZ4Lb}<#Xg#NqRrWW4ONOk zunl#IXyg)u7g^a8^Ckxl{(aRD3 zkQB}K^;dH!m0widAU7(8y@M+A#C6;cv1wHFSdGkp^m>hsI$vw)gzf-ug~;*OZVGCd z`&WjKe9Lc{u-^u*6v~KPJVnOUUbZ-aP}b6@=(qt@Zr3^ zj^yE^yCAYADDM$^8?pP%3>^Ps1clsyxK5jicC7-h?@Je;j*oLsbKd`R$XLvxkdd?+SY zn5W`RlC3UsDNR)$AZB&hBtlO$C90)@dN7tegSWrBlVN2s>h}F$i$Qd`1qx4eRo*Gs znxMYB_a`4M?V5~;ppWt0azM`>4M2FgBJHlAbn$`&+#LOZ#pCh8cBJv3GZ(dd@<>72 zi-|rS`wHblmkzy)N#ccG)$p~YJZWF#P zIO%XEal6D&TW!OCyRB7NR`aZVWoZ1;#`fv*HH5+U+s{evsItCANvwTm&c{HDCXd4s zDqIAeguKX4^tZJ{kE@jmA$3Cu+y+!XBwi0wKkS-Jf0*$Q#}2^ReO=2(6vtQNYZCe~ zS}!C~ls=XDWspvMKdJZI>uPf6{{2{#gha*f{{VSkU{TXO9!{17tX)3dxSZGG<7{(u~5F-rZZu zk`Sh~mj@*)YX)F=UKm7rMakq}>11|J?-4;XD1E~qT}7o#eqZx4DWbl2X%9k>lVsvo!Mf2irMkI-2-%MfXtFU8Kcf}kp5;Bi zIuIDnAwykX?%M!T^#ur=X2ybcQ*wr5ndFQ^1{+Jipm%ihms#x%*9cq(=MtL{03DCJ(ja5l4TQgRQn=dQ1$bV5IpECe&rM zxz3oe;&lVkZ64SbB6P8- z?ubM|3TkGGV#{6oU0aW~nZW%?Zw19m;m2`duL3m26`4e?c8~-~jxUO)F#3=JWw)&X zj33;(7&H~*fIWs2bV?lIwgu|aK+~rh)QWODBU_Vfo(1@?nO6u(?bq(!7}c~t>y=j1 zB~0L)tsoND$)%B`DNNH@iwiW^6Mh$?DPI5!R)@Y6(kG55rc|r26#cRwC}jN!aDvB2 z--n&8J*NV(tyTqv&i@U1um|HpQjv=|>R#Vhi?B~n@^69Tu-YeL&@GSU zId>~;)tpfTWNg}V>kx%0ce4}=O@+BJwZFt~HR~hG%ybb+R&*!p(cm@>C~E}IE^Dj4 zvs-TC9e)@U*pjyFL&NUSAQNzR=LdNgtvO`@9OhY`Vworb*uNpQedJVT;5Dk?dr0jn zcY`f9p>TrnO6_Vf9^dA#)Q}A04~Xx260uLy{}tywu95MC1KHJzE+X2FyP6EB`S-e` zMoTwWXa*4oO=;&GS-e19p^1&teN5<&XU`eR1T z0Q4z`v<*o5@Ny6MZQ^m&MZhnS;|T24DgwNZD>yL*1>y&{6F8=uqqoTc9UEq&nX^_2 zR2IxTLZg~o^xJV(T-l}VkQB-7OZ4G;FPwY4+jjQ}Zc{8b8>@@)fD#SMpW*s5hs-{~)|NQ^>csd)VKn!N0Wi#ukMfQYObf5`F zIv8~H&A0{_Mo#V={tcLogt?FD%6VtYwxkc5Zg-5LgDe^ZCvuXWHiKX#|A+5ON3NDhAPxqv+E@2E^}5IH2bdAvaQ7TP6; zR!BF-UoZ#hwmXi7fX2W(PKEr_Oc33@8Ymlu9hi+{x&u*wY6x{L`_FTrVCnDVX05j) z!yyGEy&2D`&e4+owlz7e?b@d%eLLPTzP>(gaY7-Gra0f{CLV~BnW9|VVM-Z-a3Gyh zN6eM=cEAIPRo@o){;z^0U@Toa*eqFvkRpa%N$!ZXXeR+^7#|L~!}H)cg9yhv7SCDV zqKY7_)ml+->U|Z{KWGvSiL=er5n0?q0E%a<$9ND%Dh@d*jh>qZwFe zaYgT{fBlj$7tjv@Ac&9f$H!j>uS07H7>#9fb&guN&K13Sl0yCIME)br0lV?g$f{ng z5=o&{9z$8o1zX?r9 zP$bPK%|LgxxaYKb5R?p!`Q2ptX)R3Yoas-9mHBIdH5+S;XvO*@*@G$nTvrH4kV(pGE3 zC|-A}{sR)gPm*Twa-HD*XggSF;T&G+3g?#5vs`(xoH%Gm(=1DN|BOrr>X-x<@28$3 z0z{u6G`ZGK2Xv&`Wy6S^63qR7$i@oF&AiqAr$7|UiuN%Bz;>%PahmJM9c!8bRSlUg z7d?N~&5;7F*LW~3i^;wPXie)XD9B8>*| z&>{osDoJSItSrq$u7*OM1voD71yI-^+#LhXV5kj0_0P=qZy;?`sBn)7eQ?Ef28vzlq zEF4*Cn$Jtv)F8l&Iq`@A9k-i zK&F%Ntt*b=A+mKqckn8aeb;$PXGczB?nIom7|6`T`CEHwH4qX=PeykWsM?JISfY$Q5P5Y98k!0YT1P)eDC~%@ak2|23{~m!D^HpWSN$4$W2SF+ zsw}iM`5LuX9xN4GX%hbg{xa0D$h6rStMI8@XZLS2c?&vHi`vl5VIs(J!rjvdcn{rh zOJMxpI?Ky8GFebhq{`~O+io_PcQMc<#VrTNth<|_iZ;pN!Ms^ZDProIuMMAMohtUy z>fEoF!>QW5hiW<PmPa@&R{UFC z&>$jtjOX`#Y|l2!0?BtyM`MrIJH4EQ14Q|Sj>aX3)=bg}d^FxWBj#{x(M}X?C#j&M ztF9wx>0{eE2|+sMty!h1%!(f05w@GKK6eo1j7kw|RByGd3<OQPB5G`Xb0T!mKIxW+98IYipL7h8IRHfpN{qh5T)jOq0=}!ywxQ07(sDH_)?m9E(Z= zxQ%Fo7x0vgMLR_K)aUPkXDFtBfF zMIf&D!Cls&zv0%Ot5%%yuP>+2vF`E0>bxP0)h{9H8X7^mRv*8!i>4&#huP`A-zy1@ zT;g#?e-8@d<|vb- ze>4z$$I?@%M3dc4U8%IcHb0XO+d)hrLZAkx1dHR{*}2V;m_5W?+`f=sp0Y^3NRs=b>GOK3;w_8)#LO3S1!KlvNhvPw9 zy}zdl+VzY)2Hy{2M9TdVDJK8<@sip_0{H%~U8O-T;`~5C?^IzNe?NumFdZ?IDEY|3 zY-2P^{D&0XH->F!+`<$>eV@aAdkb^)2c#9JI(dwLVkrC@fMx+G%&P~dtcc`Qf_t<9 zb$5IWHot?hu0aV{D<3qNX^NagI^@1X)cI-n@Cie`#Pc{&hmZnPTzVqEXzg^o_E5R9 zz2lBP-Sa&pv#=^E4f=g<>Ms?>P}m;YSiEVp!iN2&JI-NlZIV>jRpx~6(k{k#oWY@S zc*1SlP;D&{Fr!DcX(u4;aEj=QxU zCQIL_EgsTa1C1QFJhU4rxJ&SwLmfbbgHTNaiOWCEem2)(sk27WfL$amL8LFT=jtae zN!h~fhiqw|d+PPkI;70P($RDp3NatBC%jK8EKcEk1Sb9PgIg5sbK5@AK)ikE z5!En^R~By?8okrvLT|?Ak25SHD$FS&t{2Q>YaC5pDr;9iC0HuR%0uhtjFS5C)nz%< z_IdkDcKwPTd#i@Ij0BE@``7xzTH|p~+I-4Bni;_F{0IX?wbC*gl2Z~c4li8ZTZZFP zV*We@`L{~rcCKw5;SNM%gk{04T?Sg}yS5y7G1t^fyE-Omg|lP$DA zppQpwpB|LD9q`8_Jhd#7ZNts2{Tl$+En7NL^Pv<3wtod3H{iTN{NQLI*5Pgk_R zOsy2Y(SEAN3AabeVeq0I7;*jxK^i035vi{B%{xH6vtb|e4O{-HLX2ZsF) zwO9NylKOZsTo8$Y)C(Sc2`QJ_P`;yl`oo&ctzyKa#&06W?QYCDztk&Gz?8*d4i;GC zUq#dRQ((ny8Olg(+Y=emxMLXHD_UI=HWli{4|cyzBo9JP6K_Oa2) z)sOQn@IZEerv31u6)hXc7qhe9xy>@rdhRUd(6MtqH;eJzQ8`BbS3uCoV=egOb5dRA zufAA$46FhZZv8y||K-eWxa7NYm|udax@MBbJ0{!V7Z_C`KPQAW=RaWE`kOElg6FMn zip)bdnPE4uv4CQ<{>uytBhf-iN!`kS-ab?3MD5uJ`sfgQEh*h`azvCLF;5i&gfv|K zDfu2GyijN^fSfnDEx5uW#jQf+TF^ZEkWNjboZ7wa zdeci1(M_B5&0;T66aIz{vawN-X?kv3>kh#+6T$Ewz~XVJOq=J5RPlt+w%+rZ1}=#L z(IWfy?PG*5x@o^XRf{;Bstam7Nbxo1U2z``VtPfsP@~&bM`ln@q3wj5shYH>Wv`p1 zY(|>*YraBoC$MI6vZXxYV}PL3W@_mPs=V0LQ-3+&rQqF7z;5inZpx1B^@&_`Qgwpn zstu-ev=y8e#6B3vY!so~6_U1Bx@RTt)R6{L^??x6-lJ{TZH87Tx}G!mAyMEl0f2)^ zDV3xp+TErh3}cih;i(zUW_L0-dJqf6DTYc8j(-h{8}rr zn2>R~G`4_h)^DIE$Cm{ACB^g*1*jk>LmP(05gaHzT~Z(Vc9O zS6YwFJAq69+-R8$x`=~rGp?WSKJ(RDoXZ%&``K_A9+uf8mw}de#Nhm77^=m+Vj~=P zTQsNwNp94A#D;j*LXqo-#L*fL56#ZVZoQUFT--PSM^&>$M%M!_L}B-I-A-tXO)69b zTE`RwwuD`Z0`Sium4SHXutd$Q`X1-`4|XV~>uy}PPNgFw;?EaHS5EW*$8y&@yRZ5$u6+T*dv6gWPm@k4n-+}?rAJb!Aax}8(c_|7Uw8(pKuUZddE zG&%-lP~{5a7krK=G~evxi5{SFBusb|dm0k#3amFQ=j1HsBEoU&fS3^l=nN*0!W`X7 ztqq*y68S1)XAiB=iAsgwb^ue)DcZd#X>l7XuAORc{WY<|>SumU3pDO=RY?kkh3iVcajWPXx; zoUteo*HOt=_wdM2VOVRMc2L<{d= zh#0^qbR47Z7@{Y%7#_1<;qgkx$%0$jj!OOjArqj(&EkxcN19}B6H{@I8eQg7uXiJ%~AmN>@R3l7&*q{m@;^ClR z=!36v2H-w_@~ywg94W}AEg6;rgf(H#%2$JUbUVaQ0#%QoFxt$omLIBA&0aT)$^klw zedmvfCw-TBPj#1@F+y%R$(@u6knW>Cop$EA^cQH{>byqj`b~tZo~{pk&%?Owe#@$= zW_QPehF%{VR&(qX%==#lOpu^#^-K6G%_{Jy5r3ePhhe^_au~dQw-GdpDJ+l;wGMvC zRxW>l`3ZVo;kwa;h)hUq5rYHd*Hv?iG~g|PC}2Ppir%6a&r>A2XH1f^%J|d%EE3cK zWwre?bf`sBX-P5?CE*sJwZqOUDIa9`9Rp>N6b)l9ne;GY8po5p&j`UuB3>#t;)wBf z6QNk0ml0K;&jIEsH$cRb*5ER_mK~acevA-OXghB_(z#n{*}IfH%eh39aktWV3#D-8 zkC)8FZNGZ7xD;~7zu6TQSLH9^k+_zTnYrf&=ZfMdZ6e^aF5_1ot7vFBsr;l%60psdC} z!(Zh*4MTMTa4gS^@pxr&o8z?9Y?r+ELa-bGIGS>$Z; znQgAXItWSb;H0Yw@b5 zh(wz`LKIxpsD(e5GGZurkaAaM($bgM=?GQV;Ax)OfHSG3M2_`(kWToih%`;_y3PWYh=Wo^Qum7c!t!GaXehNZe{F>8UiOrWNt1u1@F`1D7D)%C06fWogkF-h`xR? z@y|vm_8ytJnoK3vl*5h3Svv(lK#3b1`$Humzm(m35m~Og>>COO`u$@a6ECxz7Y*#| z?=zr2LRNKNoLdorybJi`6Iu)W5YsslMdY~xuRwfLJ^rLcd5x3XxX2u~#DJ%Udhdgr zm6nJMlA+DT7dT!i)H5rKiN3k3uMjef=N=atF|W90M1HcH>Pe1+!ElM^W8V~?G1ovY zP)Z4H`RDJ6`rK({G+ty{ry%WupRghfMc_FHgpRZEqKSC(dL;@^XM*4e=iDr-u8hEH;)jR*?g-a-U zO4+e+K~GQ!yZ>Q%N&iWHMamfUd;J(ox^P+sqQ`vxQ{&2a2u@{&Rm>iWCQ7HPyAQqP@3iQOvr`U`mtDOl2fsyOS zJrH$O5RVM}l83wf6*>(Uni5Xo(mM1i4-Fx3$kKyr%gf=4UgM}D92r-u^<%7#%)={; z8lcER>m0KrZk*AWZk=2dv=oniCjQdMW{2xr9zmCIDgdzevTNXpY%qRkdg@gDBg|fS z4wie5?Y}N$2dX%OkuQFdzBUD}0aovKabKIARfs)a4DJii4n9&8c(vX!1<)a*azh+W zZ`^A#RC9eoAoDNIilUEY2kE>j&MIvWm0QXZ*h^zv=+^zmCre;YzDkDo%{;yTE3x zg+Z|S^YS|WEPyX6&QUgso`AKIrxIaSh6o_*l_qYtIhkl?F$3j2tZ4CwUcAOCuLXE} zSQR6EbAJJ$?6n!ndo_lqhd- z!w+W&()?ABsE$a~?9n9h>GVl-D4pe|8liitn@qVyBHK|;ib-;>#ORWXO1vx=RPm?( zB;=3WL@rW(5R8m070s=8v4|Z|{`U;Vkro+*A}ZkJl@;%k`K92un8DCaJ zUn0OFixF-fCrW&dy~$7fe5=ld!x!)8en>HX=e)ApoDoHTye91DR_!sv!mUD2Qf5!> zJmU23R*e3ZFs-W2XqzT-Nc_?v@%TnoqxX?`Rr3w0;Aa9Y+O^&|~0 zm_DNJ8;tp5)LD-y!_9qEo#$%F;q91OYzt)z<(z+6J#JAd-xH_Sy`KFX0>&FkZ?F6T zEKAJiiZt&1Kawz^l5&XL)6ux4=pBHqv?ASih9fqa#72q~cUD_!ypYR82n7=AsHxQZ zl&{bZTOwwc!}%d;Re-lZ49y{qJAK2^Dm!#A!MfQT&~=?nYXqm!2YSb*nsu_xR)3{5 z82=Y9>HWO{=;=wuJ|YUOgIzCvIFOWj$@;9$Qs zh&$`f{5tdJx59Jfks4isbH8G{(b4?pKKPYSass;HqJ=y?fS(Y8hcqISBz|n-exh+; zz6pRUTcbGNi~GU4m5y)-$>B#VX=ja?k+??JP`LJ$*VrOCzcf^R%kTVS(wZlWC`@G| zf?he>kqRFysEyLQqyZ)blwFv}cJTL7o6)B1tM-Il=(dS(-6J3v} zh*@rxE)`dj8XO-w#>=U3*p+IP#CjvPX%5GjbMFei;rnXb9e`AN@I`PGQla~LS%_=K zg{X&~xm5lS$!xD?QDW?yzNiWw;J8hIbN`~5y#cdBTB(rhj@>7x6oLu)V+fm#DJcJj z23;DRXu!%go)!jccK8!Xi$0-vlQav~J8FKrhW-patdN7f0nqYD?tUD=sA9UDQ9&0h zIs^=08bzZA!O@{q-&)3sK#o&Nv!H81gx8P(oFeZlX$BhJhs0F>ehias;^>pn6Cd_f zk$vPu0D7@C0GYi7}Ip|K!7;|JCxmgG?KoXPiAqTo?ZMOXTn{8Pp_7ON*$iRE{| z9{I3xLqID*7|3893!)I#dlV$~kzp{DRSzE$gKqGB48N_y%Z~@Gr~o$)?$1SSXkr+p zV`Z2KV$1MI*X*hO8Z=Z}NFJxkOXACmG;T3}W`gqX`{liCOfO(v)x*`Ij0x4(`@Z_r0@OjOSnCA9bFkZ1c+(G^H8%|}^M=!|y!22L(tu(=pSf2Pg zYzJ&=CQznFC#M$^mcnf2DwPRLGKwFfcePQ-#>HuL&{)4~@wJz%mEI-mq7|>X@2=ZTNj)&L!7b}_^@1?SWQrBHUzpjw(Yl5%=z5H z_vxCJk?8w{;i)E7m2>I_3)zq8h9tkx!P?bWF^ZbMh~SfuaJ!CM;RY_jTtZ5xDH|l~ zp#R9ZjfzY9)3~`^D~%avNEq%iSU6=4(e<5E~YIG zpXC!-RWFw7lMgE7ab4kZuYDG+eLlk53N>$9~vW zucUM?u~eXoG>~vFj8*MmZ7YqGI+xY;N1_ykinn@zjfF0lc!icRnUg~P#N>mWO2EP; zQSuG~SHKE!xnLRjFNRN0hU!yAjxQX#TBxCK&N_ zfnXM07VTEIruh`u`RMI?VS9z^0&;&Vd%eVp+i;vFQNFs($B24k1jA8ItZ)us@CLVK zJA=-RYdUA_RTRajKbmt1zeHNMKx}!7rLq)CrTbBy2LJ`TwxA94^(39I+$8Hy1XCYZC9%$x4yS`2W6)P7dEp$T4(k~6>bnk{!kW{!S zpAViwvUqF1+P8DzuX$1Ej)qrO`{^EmK~S<8mMt3LpLFAt`J2wcNXB)IF1>M+$MGV; zyAkM0>Fh3iV4u^Z_>SpK6I+vdtS2Py0}Qe#(}0EJPT3rTu@8nBw}oOSc}d?F7!o73 zgG7#!)0vln;BN>LE8Z`qoZ5T8=!$#*m4ZL%>rL?Bzqd~5)5p3gW*3v=jQ2)gMWH(R z-c**cXD&O=iaA5t4MVdI<`}VqHh1cc8v;(LCbFg^+d^dWS}Y!IG

T3p$vR;)T7vCm63I#y*-#0Q0(d2Hs}(B2#1d*iJ%wH366KEVUr>`=1Gw~ zUqG)DhTEtO5Ed?w?*h|OYsI_AnTvn?;&=gK3q+TxbI!l}UAjSoZteV>wgyFpw9_17 zy&5=0TdTBI`K$>^BTHU_t!OziZ6b^T0N)w3zuu^<(VJ;*(mI4jxGj5?np+o%R zm$$OaCbW$O&F?q{-ESnvmL5OqPrE$W8#4~Lz8@_g0_kJ+paA0m7Y80~CLYs)5+&&T zDhCov6YH#H>a+~8p8UXmL6Rlz00rwcWCBxtjn1k2AK7JK;7rZ&ar)F^+Igv@iV}*z zhs~|(2D^wKyplPHndGnA^6kz~@p%{uCA5Asx|p74&Q<{CV$%4Hs0EzlVVs?5Qtk{Y ztjMoEOqydaw%|`O!(+sxz7wZ+1{_aK@8;u|S4%Z)#XPGG^{g!RE98qtA&gDEGy?-u zHre4q+Lw;G0VwJcvX3?+%Ri(pkSro zAJmf-osp$Ck}GZ>cckeWi6%%$(r7|>ag&L3wMe6%J+ks~!5a_?=g|mg+0LRW^=Y;( zi(O@mFAP@JjwnuKF;aA#@=CCqnpv^Pjl=485aC13iZKn6#$K+fhHzq@1A5s~H(3%iSd|;`Fxbfo8Y6Q5C1ElE>ZPGUQ>l4zuH3W`zPJ zYp=pDBQMN>oC&M>)a{CXii{IwL;EFptw+OdKL;G<6}?E$>C9SA98PaDqzN58o)Cn{ zP62VE=vAK~(Q&F&=TTnZ9_h`Vli>rLrD@hw3m1^X?g zBUzrg&mN)Yf0f?#i0o#@FTqpIgi86a$k|WUCqTHse!iS;A5vT)9AFx)^S3=H1|5|c z8c8G=noZT4CgdiAim4`o6YQ3{E7QR)HKR&HIRhT(wUdKpKiA&4^gj8r(q4YXs3jFv z%%1bAH0>M9)1}~4+LDs1xG|U(z8$3ClhUsF^$KxoPF&9A`?mZ9++ec^jNckBwQ zWvwBVt3X5cHF<8zF3Re4tj9uiH39V5{b8O@(UYsK1p&qC2`oT}cIxPU`rn-4eEr)A z@9IcuI48hBYL5Ovbiu^5dmRd!(;g+6@?Fxq@Vj00pv4O9Bje?Hk}*2HqVrRSQClHU zGGv;`a6NWAz;HFC-aoWB?G+j&bC8f8x~i`_0NMDIJ=b;*6_x~>8@M1Qg$OKjRGZ)J zv*zDNo@|pHi$Rj|uXv9ZXd{Smsl*~ZUT&=6CvXNiCrxAymW|RucWStm_V-$(7(O_V zyU7t(%S(*L4P%$!b4`lTg~Kxs0NttY`Ru>7%HaN(_nu)=`tdOCkdqmg6Icdvk(`4S zpamK{{-DU8l^l&G&H3KzwvuxSY<;2~@e_HwiPOug{=pe^rKXJN|SE<2! zb6XfdijUlJya_E2<_WebCh8D3f@=sI&Dw`vjP-1Z?vKiDE85UWo7&~wj}7skIcdqC zA)%`5Z6G!!I!iveWps0nvPRlMhS;_gH4`4h?O`xjH2-g};|?0qBQ=Eyq)^o;=DA}w>NT;4Qzxt?%#PkK+x;07 zn&@HK@W;CV*S=H8MAqBq+EP@IYQub9`8psir zXVurmqk>yl$!95W$mr~p_>=RPn>ILub_Ko-&s^aPJhe>7KOJ}c=Er&^wT>|if`~V+ ziIO$VPPRcQWPEU8iPoUq2=aR!cRkJ`k0_^P0lyUx(As$ua^ zzJpw14)I6G|9t$jcupN@GJ^w5@wsl|3O~;AC-Xz^OBdBjM{ERl!llNPplNY7-O@@p z;=6z2&_)5)Nl!;%CQL;oJcET)r03BC%?5;?P1st^7$Qa8xT3VyToCj-E-ZpU?XWl-lIKrUQ6T=YV55eB`F?(yxPi&$va(hIZ;v31hHSmBifk ze49tmQF*r9NUE39<<~8jm0f>rKgPgou)N|;Jo_Mu_}#7Gbv=`QiB6>KZ7N(3%6b(b z+ysOtW{QuI(^9sDtB9^(vCn##<_#}v$3y}={nsTL< zbhgtn4Y7ae!T#S55WV4O0L|#uAd)?@TySa96!kw;rqLD87b9(T54y`Gd&h@v&>S_Q zP3$&-6mHqb7zGb3fxrQfZiR-DgDZ5CUd_Trlcb+>^#JN_(4QXDN^CEZ30V zL=iv+LR~rjpb&H9w5B#w-&l1zE*JZkGIsak@=u~>8MkWi*LCcjVW?7X?e>I&;rji3 zpvXkx{w|gC@wvflV&&jUFr)Z&Isl?iKv!x{Ae_p%w(b0((08njZm(h*C3Q&Rg`gP`1_1Pe&K-^W!St3ZY9V*mYIKJfC9wj4MD! z&KKo4%kcaC3*#Bp!vQ79dgo4*Bicx3_(uBq8P?k>9EC11oGHKsZbCM7DJ^XMhma&?gK(?EMa2d=Ys5GO=S#OppYzxx z5i*?rSNFxkta>nPjv$?n>e6pNCNbxSJXo=KLi|eweT#g@OXNV(_MmoC?S%J*sr$%? z`-d~|wd4SamZs7rfSSkyDFJB0!Qp=Em-OtC3+*dCQRjc;!UC=l(bAD(j+W^*8I@Oe zORj_v@ex#W;qfs8c1)w(sBW?Th~`sY94ZCE(3U%+3+@H@f4uHBgJUInTCoAV86EX~#C99ZmGkuahA#atj9XGSCZ>T<>{WCCwVJ&r=Wgca4OF z2I{QU)(XK-C&wzU>5NYrW2GQsRghv6PYY0ad^gJDUFoVHfsSH=4=zd29l1Aee!dPm zQBqfq3>)eDD;Qs|lH^P1$?PJt78hFN>QkksPXE2dFUr|CidEkwga97_K0%jSvDn(C zhn6GQJ#)g6D7XamgRp`BGcjxy!$v{u z3NUWkGbiUL9Ms55Ad_c=Cch*uSPQ?iw1kcwIo_IMiLCDF9{qLs0BI$P#~Ih6I5dX$ z*lc_YfqOLVXwZIIh?HVW_I#v$bgc@h-AkqkC%c9pBI2%)u=z?Ez&4b3KpOdkZi9Sp zPEonu!hROU8EfqajnD61Vrc35in?qH-_YKR?b;qC@lgF6@|U9AgDWMBJEfNE4}F@% z$B{F`6iMphYXdxjL`kNnNUpgh{8iY?ZoHJ6(x_7Sk;`)NRB^)GL;qrShu~6Bs9BqYVtrTk|qR+kBzs z20VeP9;B4()y3NjLe{tN;BC<&o&{bMfk7NE%Yo_ccfGX}U~i+h-nfmMw%m>jWg1sr zdf9I{hmYN!C}xh_r+%2)Cx+*e?}4SJ~8b~&C zGrs^qK)%1N#cI=)_aXVK0p753Vv;6$;Ug3@N2zu<2%v61-^pQ#Jyg|8=4nx5wVVxK z!6Mjg#AQh6+l!7RXl=@A@F%u2B~Vgh@V!lbflCoD+Q#lx$xT}iJFUg~aeH-% z4+3fulKEya#BIU>6sX)q zFMTy05e@E(DW-s3GkRBV#a@z<=&CiayWjC{4MpNtpBBtU^qz4U|TnIXLY+>!S zC3cv*ErP&)>~t9$47Ht(g?^OU2+Ek+GE4m|=*KkM zjayyX(B72hGwb@Ja6GF#lp=A|3*o2S#eH6C+>P{S>|2=bIq5vC{p(C(Lc@n^L8DqF z69YgR2?^%wu?B# z+w4`~j;7`uT{`?RvrDbFYliZMcOo8QUre5|><1?IfBoywi7jaNwG3czNhgAbI^4BL z59V?895V;KR(a`;h&2~x&)4lP1nv#&0Bn%(#yJy}Uen5?i$(iM2*!>3%T6N5X$}KX zX(6-9Xo%J+t4^OLTjFt5zlzN>n^6~{0pWxHfNNzmV0YHc-0 z%ddOAc4t}9n)@V&^;ix}8d3lGh#(Sc73z zb!Vls(&J0~+PnQ>HXS@AUqo!TJnxJ-Mw)CZow3s5pAu;8BIzTJn^Yt14#fzug}*@u zsCrygT5OybPyM5Yf)_2%A?kkyz%{-U6iCo)h5plzU#W{=E}0Qd5Lv0TblI6ZKQZ-t zT!)$ewFfhe@qB$YOud%5P#-NK(pLaNG^oYw3g-!*^I#Cgp8M%5NfTm=aR#&f)-~^7 zB746fm)|t6{1aa$zDN32j$8-WBh8Hk?a3hSi6>3pA=`wQ|0G%XQAw3HVbKgf@1c;K z=(YOj-iFm6oGPi_^iE%*MrcjclyWr_8bBTjKav=iw?xx7cZf`Rc|rq<-U6ZstX)>P z1i8o_=@!;=&s;(YN5|fQHeL~Ndz~7Cg{(PtFQ?L$5$=6ZiY=-zeZr0I;dNsg$5FaNmV<#WgnUcaR4@&l6PH!A{)huV&xchZYlN zN7jIlcx8Xh{u$q~dYcoRO&7ii%(Hop+MP0S5KYnxakTkR0QT!H@1!g`s53sO5>F6{%9Q3KUm0tn z6yqVRS;$n~+k?f#F{2I8_J$8GJywYC#6d&JrRws~0U%;5kf40JQ>v?))P>)WSPhMD zR10qLeuRx!_s;JP(IX9(m>@yShTCW$_IW7}Wx{n6MxNCY6|H*9#!X-Cmct0t%Iqc5 zlpML3gPE`7k1b`$ji;L3x}cJv%mY3MVV}Y^U}kS(I}hxkimT!#v(Z@awf)~+R|Hzy zP;ZznfWOI2{Ycdau}}=pC?RU((U%Jvk%=2iMWy97Z2q0(apkx@Ud6bVlfhML&9pm^ zxY$8@UMjX<^X!f>rHE(Hhy#ASitmNihBT0!?2jw;$lrzr7#W2>b>jZP&ryFZB3Qfx zO%^#mDIsIDkVCNPHifwDu0zini^U1<{i=vpJVv$KTyDbyC75K zp1EB<(caig>`EU{;>xP|l`h&12y@mFQQFG47#M6oa6sI1%`&EtgF+3V z%3xLxPU2os_I3*%meLB5Ut@%wb**c~4s70RVh1-TrbC^<2i(vgc(_s{?9X8g$v>eUZ--E7O@ zDgU!IWnXRRU4_n&u0{br_^@-?ccGfn^Hq9U**LH`B-&QL*bM&FG`T#pyvb@ddP7pZ zj(G5|7eL{7n-y%ni3BAilo7E9R?3ECkd~YH(m;j>&NBd^b(0_KmDL@`r)prQ)Ha9i zULX#m_-yNm{~xyU2=BE~Z}^*qe}_^@YXgk%^-O<*b{`;r%S+gm@yVZy5JKZH={vy9 z$sF^Bi)`-MN#b}?Or{z5%%NnL^t&LSg2bMeTM>F{pXnZFSew)hb$$mQ) zOa40mZm8(~nr=q^7v7Z?E>@@oe5lDV{5V}--3r^Y^6dm2ppDjt!w6tcdyK%k+*a8Y zEiKn28OYF3x{}>Ck`TG9n!Uzi?xN9^`p&!-q-q={3h$`YgYzt-h@Xyw38|Tr8v(nC zI$v{56{4Uzu^<@l!nCcel0@W*SQ^Lced6fFs%96(scx!S3X>%JjuyQ(Do_t&u9Geb zX3#oZ%sq{;%iP0d?T#LkaT+feg%%%@ntY|?85Bh;Qc&alM;JKOy;vm`*?Hm|He3HsOJ74xb8veYc9rO!67ul`)M{kC51g}7F%I%kS|zJ2!kbxg z@ywcMHMw16;3Fulz?On4w#SAGi6*_>w3v4IBia$V{t>i%1s))!kxdTRyBck=6IqFn zru<&RHtQNxq`W@A`C6Te z5+Il?RiCAARN4I>NLL-#6oyykPg$LIFuF28UD@%~Hwf>w;|MINxg1vV(4&I(ljgGX zWj=iACd()?7$VNNgmDl>Zat4U-;RTvasjzuNDY?SHU+BByBwg*Y}SJ8KSO~cJqR{P zjlmko%@%rZYu`nDMs?QdNKqD39{(x#nx|1P85+|^KbQ^7KBKZDERNFx4>tOyYL}g; zgXsq{nob6?u0AG?8@v*9htSd9{b5p&jtefh&4enf6sWG(nm^q~`9439O=&h5$%#~R z%D0Ux!_3Mc#i50cd5A})HT9dQu<6cE-tN zf^fP5j>Mmt(;JB3d&k8@LDbJz-TVh)D*NZzvE-vf!YNFMQc$%iMco4snf;IfktV47 z)}`F`<-W*PZpq!;t7vqWf@5LBnnCK6)@<(r5cgVBy@T!26h)%iL@LJs(f-Dw#Z{<`DJ;I-@s)d+rmm&azQa&sxHXJodxI_&2NrFWl1 z+OaX*TSg;f4`^H+I#xD@K(_3sdZ^pHc*_@;CNv95$G}eSlKCQJ{$3w~oH^vQk1k)) z1|rErSUy@(D;-eenobd&N??$Oy`mmKTvVwCLc%s#OT4^Eihr}8jqu65y$?;o+mv~K zLuWZ?JEAnNZ{)u4I>qr?<|o1{nL$q)33|zYDin47g}|(m7jby!G|r3z4lf%?HrMY` zodpl2dMk?4PL7gjnYlspP$m*npl|;gz+XosqIycaNT=V3%(o{Bh?JxTS>>CIZEdwcBY4RST3FW6H?R$`n-3BTIfsnF;rv>*qK*@qnlP zG>gEqGPyQKg^od0RGfC##41`GehxY$;$*)h8z4^XZ&MJ*Bf}fet7x3R+rVN1=gPbk z+0KFBCxb{k0WcLrL14p>lvBFPS0D-aP@x8-oCvN8i)W8c)^rCxa`eR{GRF=k@6Bva zE+$#Vh%=ko`4wN~cu1}p5?cQ&I#&@)AM}kSG<6XU%BPsNp45PGtb|lc0GEk0$l|HN z>lz#9zYPK5vkmQikFXg+S-)yVWHh)iQO%Zj<{|qgRKW;Z8*kCQBawWbuE@j+G-t?1 zh@vle#*>*Q5Iuc5fjm4}zQ}qRYDn-552P(0FIXK8EdX6qzAtycOPc=AC*`k!$M zNx{`Fe{i(JI)#GE)2chD zh{oN43g zO+}7<9>)$kdMSL|zj+dECqT7bHJMdnFB7RC*9bCZ_RUan?OfEk^jD%Qg;aZ})+QMj zPN`w;cKEVB%M=MA@FJ09}n0~?QLrrl&++k6H387 z`Q6>Hr|IozNsBk=ck+lPo1BwSKKco^`;NS2!-X5oS_olnu6vSE$cpu}HhZxoS&SC4 z44njG5PTQS?fL`*YGZ9Ub)k$sU~Thd=-FUpC_`7t60RFq`E2n|qnv60!*{yfzg{q% zn&Kf>=E~Js!g-4=vWV(gOM|mvnp4+JRZf|Fnj*R?&eC|kZlO5znoJH?*GDmm4(l3z zh!xH%+*MLVv3B5xwlqlh;7c6f^~(A`Y+x!w&nA0# z$N-27xUf~D1>|#c49f{srkBpOVUWD8xW>WwK{7mMF1(@i{aGeC0g@$8S??-ay!aJg z3)i>S7-cMs;$+n91$=`v)jn=V1fKH!dRXLsqR{8hSe3e zD^4ml?C)u)DIrfdwd1{nEgtA`D{5j61J!4g@#mQn3=3iM=UWgRRnlI>zj=x}IwR+9 z7O}NdJ^H(v6B8{!AI9MU%pitux&TYA`L*rHj!7?@^QRN17zrhJ+N`df$w&D^d5}cH zMgbemCioR)l+k*}4+~h)8G?Xovx(|QOX7Irnt>Cm3ayw3KHquL=}Zek_ueCFAz(?4 z!SifqsI?iyH|8k|r7}qM`BJ$@t`1EJ41clti+|R5_yTQAlY;MV`MI-7a5WEhm2bf) zlp4DvAFp2Y7wVTon61H~ZB*_v|E-fZX}u+)L$FD3IOx!X5e16(Bh? z8c#_ig1bGejeGU4?wdTNI1=g~;x9`l62M^+=NKdrb>Z%Zb_J(991Kz=MypK`kA}P- zoy~dr%a=tm3qz@Wvj+ww=s3qn`CQU`dt58`oQCW}TDH69OW|+4vvl&RUdf!8{avda ztPh%9XKKp#S>hd1`FAp=RY>QE&<2KCwxhR$5tE%NW z;D1d@ne+D=8owlvZ4$?Az3&{6d!Wn|HaEyY2cv?0w(ZE;L3B0dL7Av2CmukLwn-W4 zNc+s#)lSst*xo08?kNy^UQt4YVWs+(nrz+k&m>DS#-!zaiEX7PA966k(s8HvSMduzB`w=m9tX4e=(Z&H~K z{c8MwFJrb(Ens1N#1pX}JJf99cOLPM!-&*YSZIIzLG~(babSokzHI4|05>Zuhk@~U zWpc>EU=2%xWqXGUpNhpny>I8~(>8s6e~QMp1CmQnd+_CJCwW?yA55Fz1Esxqv0dt< z!O)`-Jssuem9MF;I4RTU3}gfmulk)&0t(?Cby=lEd8PjlU<^*NX7rjJBR%ahy%rt~ zuqC@4qlG+|L8Mp#3{%}IKg_(}n^7Kp=~7a?JWU;CU0w_ID|q#4S-GJL>okx)*E$4Y zrZVDYST~Rv$~RpUNHc4v8N4vYgojbjPS!5_L#>bbt{C161i@F9 z+U(XP!pcl7bB&LXVN_!C#dmV~%?yDds;*RE!nND*$w&1?@t@wprTCd9Tu7`u%o$g) z)y!8@J+Xut)BG|fSEiEvZ%^0CeTA<})t;A6IxJz6Z-d$7)oPRhX(q)k%E+({vGz5_-(wz4l5A|u<3 z2b2bijL9uFt%x6LDA+^Wpfu{eDyOeRueF;e=uE?`J<;-cl^{|oQ=!P3n$DsBrICuv z7Q;*C(lyQc8LpK?9Xvu$a4o$caTcrdc73ud#23V`d-V%v8?#TRT%CTDShh^2awoiH z-3A@pdtpNPqiT_`P_ryMr4btGBz7&{A5fIz$VbcQz5V|yJIHokikFQCm;wK5VgYY# z$;4v?%sR&MDzoVVR8q5KYhSvg5CW0<-E_i99@>3lUZnH$xA5xYi=;flPnZW~_iw$e z_plhZJYT*Rh}W{z>%cS^*$vO|+NT<7=@SqBS}&r0hDN(JRdfe+2*s`ci5#wxtpd3~ zO$8fyCd7Jr^zDbr+cqy4a@|w}U1gbp3X_-iO7_5qPFnnazy8@Rv{W}sck;;zQCzqr zq=-r)iZ*&giI3#H+}%MPTzs7dXre)-0lu8bzO%yOR;D(dzJp7(jfP;47MSh3wDR0y zd4y+H(inomV?ugF={R@xNQVd_v(SP+PFO$>Xv|i1yIX&P>SG{k#8ks7`crwOC61Vo zM%wWbZi|<`*4P5+g%@n1_-r0Rp4#A(iHWj#srX>|((NeXrh06KH5LT=YLAiTfQgjA zOF)YO=4+A+{z5csCD@dxju>l40cb*lfpGMCtc~8p?A|o&EL7!IEu8rD<=Jm@&hn~h z-~X!9(<}&d7xjqLISbtNVLQ86gJdSpI&PxgkarL;AG~m4zYu_8h`CU^c2)W%2rNZr za*!Q|96QFS!a_7Z!+BiI*R=cn`N6JPWoRb`smO~E@!~E=!NVcGh_Qj_pO)Z={YO#nvYP;wO$3nhMKgOD zaAy}@jOVALw=vxVG_1HUvl@eSG-w9e9{a?gL@6;5+++JJ!f?;W{aL9-wo>3^5PWz8 z=nDg0)9xB~v6#y8f^iIcPBdQ4ze)J#qUq+*Fr8SsO++9DUEfp&2l9`w?u=d&ar+wh@cT+xCV zb)eQY;dA;Wt2%3meNyma?mDv_WMpmXg~yFwq_}1?LaRo8?yErgIf!-435=O0L+D}h z5Y#~>)tJuBt>vMdRNX6=e23TRxuyOCt3b)hscIbhf1x%P)CeyDeoj_9}tu<`?;?3t>SGlkqpss!wMb1eX#2}>oWW4Ft2#q*@+F# zu&E(+#_LB>`I^;^h<;30IUeE_;5!SRx{r?xSxW)hY4d%P>EuDE8gC<#U!FbM=&aAO zL}HZ6lYE(_byxX~j&K=IOVqzWDuZwp`8A;M)dNG$L)V-q^u~Hxo2NfR@la`TltD|0 zTUHLINJ>zFVAgHM{h-e_CNh&pTvkIcL#yGfN6)?F!vf|w81l5u=wS&PUQqV zy^>7ASXSI%>psS+0GcP6XIkdt6b- zA>#2Ho6VLg5qv`trHaCaqnL)WV0mYXD(@s_?81u;$Y-c^NIMbJ50R3D3> z*}b94>_4?vwT!+}MiKTWpsyhq>3$~~%SPaC+{YlH1FR%U=kUAViSD2~*tJF6m^x4L z;aWruwV6Arp9Wm9i2mUCLQm^EU!ue#_|7&_zTmL6&sWlmyakprl5$pEREMsyhD%EV ziDcDYnEK&eibnhXLy^96#j9~`5CIc8M(qJ&aA-7&)}|CyftF%yOAKWX8x&1=4nE?J z8H%!~%2+voA||NUB|4FpqqK=wY6|=Vn{U&8HN&8rzqW^I^G1VzX%@H8Uj@g9!p6|7wyts zC)-=IVINy4UU=n*k*WR=G`q)^i%Sf*OYe#S?i@Ekl+d(QAC;^-W3n&O`<3FiIqx}C z(_aI5-`}vfuiP2d*?i$vG-&mdX|AeY@Z(Cu`pYeT85q5a(iKc`M(9*i z;sepc4|;C!zjx+>J@>II>Q%T*@swH{*z94-HL6QEf$MjkO|hQAX1f)rnU^{kceWxc z@KX@~1>wno)jSjvt)P^+uxpROOQxS<|2gZH)06($r9{06xi9ylNxutJOko)vr!X4Z*wmw#6Q^nJXzTQLEuRAK`N6|5 z&?L?d@x?L8l;-3p7KFq$?Dfs%LMWgmseJx*A@UM}y0FAbgv)!U=jW2annc6xfXf6j zihX=gEj&}JV&nAI7h zUjx1C$mCJSb|UC;_WI$P{zww|LyXj`64$O_RaxHdMd)z%O2FNSG+~k?h)f6$`A6d% zXM?oTYfbu!CLVQWe>*5)Yh0#!RY*E$=sDB1;pME!U_Cejz$c zvX%l3BD!rBEX&)-hGnbp4>R*bN#4LFL!vd=p#SX|6~ARTOq@{hilF)5(v{pmm45k9 z684~!Af-{Sim$8Plj>onNN>Jk7G#+>K&5d4f0&AwYRy`C#NNX)_L!H(X$MSlRtbzX zB32c!Y%rFvm@_f!Y4XTsh(%cEmE?NpyjJ_=Gr@X*)wG4i6S-EMf=6D3SzQVO zXRQ*jgc_od+bsVf4kT%8pG?yi(5=7}AS#D)W3Gnm>fuQCa}`3V2efO;n>&djoOq4Q z5%#UMrH!^B^n$$CovH7HHhBabJ>TA)ekLAW8AG+LtaGpy;>(A<`1~>>7rURt6p3T< z6?#q*n4y=5d`ggvuLK!=()|w${X+jPTJZ7q^UtXVi=sYy$MNVa-gsDiW~Iiiyb6p3 zdZ9!+JS6aRy-cMYQos#l=*t-kNbR{vj1yecr)rS2C-4VI88a&&TXWGu$fCR~xR&yU z>(rkmJir(F5L;%w-?|!2@e0asKZR6-H=x@k_lGG(M6o)g3)JJp6SGM+K^g zu=cqfOP)wg{jv@wrd8#Cdvcvl@$QGu>Yj38%46z;aD z13Yt`h+;J8j$&bOY{j=AA5A(ftC+3fL5WypS)h`EwA>kHg&Knb3F3~sRkmcCr5|mH$3oEU=G}KA|=tfaC7b=T5r0SN|LfZ zCaW!wapSi#M=#4PjQ}>pfpNt;Hapk~cZ6dyy$(b*yuK9LM?fE$-*s&yH|-vh2PO2! zS6Z)R?*RpGD2xt}25k)U;I-P2xR&E-1a78(>U?HA$af8>MdnR3v0`4rQr91dXLBQ7 z{t_b_5u#4ego;7j?2FHtQ&ocqd?ArVH-zd(R;w-##uKCX8#0wBu9-wq##{2JH0#;T|(%V<6-OvIXR2s0@ z!Niau02Pb|LHI+=oGJmMD5G)vraXZGiKFVfB49M~;kL$wR?w`eSPQUbs9{^&trl^T zwCP@5Iu(&-vChRPcuZ#Kc)- z0P!`+W6qV=y3?fYtgnUTQiI|c=Y4*|u}L%mOuHy3ubSn7cP0&Ko&x#~6e+=EKbD#q z7FWj}H0WLPtGg#Li$DF0jik1f^``ennAwlfcqf{ok{^rFN2|qy7ROGQq;QTNR{u8o zaCdW(_FCI+G0En=Uy5LJKILdmIEJq;1g8f21GxRX$-o2V`fG!o;f9dBWZ&OmM8u8r z&0v7W7xI-CUS>WrC;2$NH3u!;=lw615Mfp=pn(afw6u7j*v>D3X?Q`Fs!z&X2LHa< zDtwx?Jx?m|4ZOhR7E55YlH;i9c2b;Z-iSMUvbFXZVNIe|K#6PS)sXNzOpW9L%h$_; zl+X#|7brI9$s(T`MSU>wo{!PiRmubfF%nahwG#u98Jh6%izTh}mugYpVH}a5x~{qc zs)-Mja)cRD=)L0&oHj#)WE#pS(+ywtp4d33J(9QdtHSlBx`^4jl6=?JU`Y=wyuL^8 z)VyDkntd0QK*8keE?~d|Ge^26?wyaNn>&*?H~0c`d+ZM<;=OGV-6-!25S5m;81-&* zvTOFD_>#NAh>e*0<>uleOwkK6{j))jO1S@ecjK=X-0kAc*ji)~T9(g`TfD{BBi{*PYZ+=X?@%&2|Fp^>!n$m))7;juzT8B9^`k!5 zSXFfNR7$}PG@&Ugc0amr*Rrytw090N=mNlc6O7`ZRYoZ^XqGb&gA+?nr6@epmMSTt zrFai#VsA;LIp0yd5pCcCu3~ zwFp3X#;xAnF6BvpW@Z9MDSIcdSVrRCjD}{)qiY*s-$|a{pae_!4si%PYC9$(FEt{< zT>&OB1{D}g;E;?+1CMUHGUe}z#vMd+E?Fx-Of%%8xcJ30L!x_aF}CCN;Nc#*$LVo3 z{b)_7LETxC0=~M)vg1B{Oo3u8I+KECg3mMd)bZ=$e0-|QTNN;mOK0^c;`P$$2}kl# zF5Q}!K$n`swbu)Z!lfh(*~h=QhXLXW=ho@*%|k{kQOh2D$u?VKq)+xQ<}Bi<8qfi* zw&k?8|S+W)M<)vBn46^D6=1W8JEN z(cU;}9e?AWRT(YH&ttR zXmgsC&|CTrggwCv1|NAvS$Z+NDYpJxAXI&ls6Sd@Cx zo`Jnkv5LaH+klHYxGSIlowVda;yZwxRqZsKay1DuS-NfIt*a$d zh?%@bXtnJc(;}6sQLvS$4lf6&mR%S${a;HH#j}GtwvFg7Txi!i5M_GDUGUoJ6m@KN z%M)Iz{3dJrBYGzZB3jLVh2VIGlU&n@?(L3o5J$lIGOMQ4b%I$ff_${i=SNC~Z9uJe(zHh!lsF;JNTF_ja zt?fC$`91T`AoHL1KIKC9q!R7Bdl~6A4N;``-tC`UEn{BPO=v`Idg#}&Z3v$!w}9bD z0=nzH5z3<7W0ZOZxCf_Fjd;>qqc}P!mG?zV z=}79A-SQ4s>Yq)2RY}qs3R5YZowU{O+uqfzRqD!o=~Kx@n-fsQQPQE|W!&bSx}g+& zM5#Xtp{5ROtSvW3Tb6VJep{Jv#4^pqL@U4@T5%-T7g9|_gL{1tP)ZDV8M#dYJxAo| z5*tMHB>fXoz#BLh@T^`1RlHAMzTxu5G8pU%T`X6x-l9@8$$}^eqy1{kXma-gsheNs z6gCyGoT#LtL7g(-IU@BtqN|Dn9=Z#VGt@A}HV)Am(s%t4Bx(p^Tr4PYFS5T^+!w36 z1qZ+p70@X{PNi)(w~-*FS0LxQ)q-5G+auG%Vx*_i7`Jf zof7^v)`+Ipd{GMy(g+mYjO-BpE>}0gySJ;zE;adO7m3A+?pdLlJ`Tf11`QSR*3#VM zScb9FrNlb4JgU-L#0h{OFDXhG7umvj*q%Wy)8Y~Y-@#YLL`z)sDRI);C*B+mH1w!cn})w4UW3wFfAV|&M%P3tppIvA z1RWJHS{$HngclI%74jwS>2(Xj{nKY_jom#30t`W)4n}L|Yv>|?SXyHadq@#ldVwbD z-jBNL;+r$IBQ6(M^bnvX=Z6G1&P!#B9zu>d2_(QZ7IFg4 zQh@b&WlS|LS8nQ%59`hEe%?3dY^N+L^v8OmAf~X|RJeWDZ89kR9vMaSnPUwC(A5k> zln)sc2+BPn!VmjcR!u1L58=Ibhx=xyTB-Xid?wVf0gTuBNFU-M%wP+z^<9<8bC>}p z#+F63c9bHgxFG5R^D#NxdP*AU&y#~2A^ig4rIYiC~#+>7H*8%)Qn-L+%x$gH}4=5vVi<9%`Li%|mC zf5P%X`cN z@*t>98TTLa>O)jH5g$J3x+`07;Kkq>R{tFF2Q_l3UoqLa^uD%7qiQxh`!R{gK7NG> zbEO$OdZs+{z=_S7#_x~AbXCqSDWpA57gH)PI>TZCf3I-NeU;h)y6Sq>j_eTU+x^#2 z({&plxvZm9)a-`7z}X@FdgX$~N*3{CsP=#&WA=%~;T>KT=TPb-HrOl=A;?Awr-$E0 zDA`4{@OrE34rEmz4k6@U985wvtX31A@TlLF;Wpvzi*EOhc3KKyXmsNSrsNA3H8g;1 zx--Ly?S^2up1Om9kzUmqR^O!G4wVRzBP1drSdUzfwwt7jrezYT2$xB5$ug>o^ZyHI zxaf*Q^GT_oM1)*ttr`pQE4y7|9xv~zjF4;=5^@CKf&4K0C>iFXW`CvoAv^>sXU&H7 zJW325PJ-NHM1Iu3YhNI%w3Wv@fkm-Ii%fOtVWf|Jl5gJR3ZY07yfX)>hg#-T=CL&W zKf?%}S#)*H?PZBi=Yk6ZqKO|0rdsZb14lIE(qPp}|LfK#>oV}ejn(~(%b(5Q^*Nok~I59%VqIg{W+4BLrL{msLShB}Y~nK&O>EVv%(noB55IS(8-&>Hy6$smof0V)7Xun?KapW zXJfNY5}i5Sm-x=8^K=9f@5HdY43CSsFR3XQNhu4Q_{ z!v5yz&f839dINoH1%s|`L+PeW)|zwJRH_D<@zNjAeOfp?p{pG2y1(jjzdJURkNugA z5ZdOC^C^m9vKB8cwnn(c0H0?eu3`yn`y2^_z^TI*dN@V)6LSzvw8Ipi`u%TVAD$rc zr|BsIv4skV$QeB05p8d90z;3TJ6$d2vu}u0iyj;X?mZ*w1$2Zv4)o*V-?bZAL&h$f zr%3PU$3wc#?_Zr7k9;RjN1{l%Glv`?$38fzVuPr#CdW6N@y^xNfZLgUOY`brW$$Vi z$Tt3)#HK(kyjEr|<`O;B**nA_(7O821^Rxdr+gDa9`JWzwtHJmPouBp4y)8kW)9#b z<&PQ{+~^UUAIP1TXh5pdeSu2x(k%bG(NxB!;4cMh1}LX%1l;RZ&0G$r-mp^_gG+kO zsxKZGGBfW-j+OOH;TY|J(G-cL$2%?0sDm-OTI@cmAvIfX>xTUSe-;~Tg0 ztgc&HDf{I0B{roT;M@rBB;zL1NmrLFJEu&rf#}-1 z0ti*SB*JPt)K;2uBBgTMaqBWn3&ly0U-?WAL-Qtj@{_jZeBO9&+0kfz%7a^M4(b~F zx6FD5&<-tA6#18-0-O<}E*q1oTlZKVDoI+$0qFl}FFm!6^Vmh5TjJHx+eZtL249{% z3m$GDr=?S?-NB{QZOZa$ONn zt^m^F)pL=&G8)7hD`APX&dU-ASzAy=-&Pcy!xUXckX{JwMqtY394vb{SmrVUCbuuaNaXMF+Lg&wvsRwRErn7X1|HQ0euQ|px z-R{-2=Zv>KU~eW&O12TgRL1l@=%ybS_P~5agg$YqtKTE6oujXw*~h2X>z_$c@Cg)i znXAq5LIjuk*a?{hmQ+zhm;iI_#7w z&2FaMI#^l4As6oJcnS4tNXI>-7Cwv1WVOY;+wWynoZpo%RWlsj24$^zov#sMA52C- zBsr?@!8S@MSqRO7clSPJA0%RZn44*gxv4o#Nv%y>{rXd2i_rZP__~fl0H?@j! zirmi)rfk=!(pZF4MZ=$TBTC_VdMjS#AzuWX)41B6AA8uw!p(G47)N{m6Dh%Gmcnm zp-stTg8xGG>E#F8Yzip@{a_$CpN94qVx$+6XeEXgw8teVChL1|<^cjs2bQVMF8r>z zU<9jaJ+%sA)ceLgj?7WLO?(e<9Qw**m4RV+52OPPQFoJ`RKM0KOco6F*wu)9Me9SJ zF@}!1F2R=tI|NVZqTu`8Q@&npu;2{6a-iI57AQ(jmT@8eS-egg*b@73uywFZ{WdoX zAWr^KLEgOTQ?Wvg9b?7?S8G3^JdKc!!RjAG<+4@RvIrj2a@y?$aTm=X2zvr}6dcF8 z33!KN0Q?7kLc;H5?UUgX2jfhVp~mEFv;W9$MH7x34=MZ`MSyDJ>bhK)qH2Lv3V^>Y zmr1W6{)oZ?5vKCN=(IyJcOs2%G!!6~v->Eb2`~i{X9fSAmG>k{&tte-w^bBj)=Tt2 zEAiVwP*=Z^Cl@fsqAPv}nxg5dleweW6)_5lPz*YVV{eKm1!nAxBabx{(O=f&_iRo| z7wI5bDM|w1I9SJIc*~=1fc0p+5`RnR#u6(|@ySk=K~6o+q=drSf&=EtQhnhM=ScCaDk+Xw`hA_6NyU6Dr_2b5_HYw5QNFGXy1OGR0pD?5~uymhBE>$WvaZ8ag60b5Bm$ z!#)1`^b>=lJmB~)=^{2{$?(5do*fi0W*?JIkmWmV=ARcWBg!6TC9qUszfVXB|OvfoQLCz<)3mMTw!!-Q;a0;=kt& zk1YR1EoDTo!F6;lHBCB>d4lod&9p!@Ik1AtKgZaIt5q{t*4A-xljUx7PymoLy;(RL z3QnbNYM{pvR59v@if4qxmFYs6nC5q_Mu%$*y%u109Pn-#4}tt`Q}u=ojselG;CdFZeKZ-BEk5M=Jjwc7ZOY58^{C zjD4)rjUPu)DA{HAnixGm8cZfZ68V&PLK*}#N8~wAOVFOLDUXdg=c8W)DREgpkhN<$C!gI2Dk zRio8t{(`(0qMr;#X&UPIyH||MUTs**qe0t<&@L({!K(B^+vQ`?{oayEifSOmIX^Dw{xS;Y@>!KU`KFP7{pmJb=n%u8psDs%B>>;~2fQ zFvY+?=A*UnzL(usIeRK8=stB2<_7zp*zmZ-ZiWP0B*Q(WW_U_Vk($OhcgrE;u!j0a zqQRuL>)c;W^=9x}*wa~KTqt17ZgkfhrP$ca^WubL3ArLooXu>^>itJZGrD5H;2dq^ z^Vp>wYA8a>dB({o^1dUcZH7M*XW9^bvFI^NQz6n0+uL48Abjc?0BZ^}sx-k*I~Oj# zN|jO-$JI28?x#A;@k^m`Dm<8hG}K-4d>PFDiI%fVx*WaW2c+*|N~08Ifyj`e^d0Uz zR=9d1ue2oeY?@pL7r2QTD*?lK`KOQ1JG#M>?L5u;8LWJj;Jkl&rJ*=G4bWnHXs5TRo+cPq|`>;=F zijPH_mEC)o1FeM<(L!Eqz1&j9=;aDnBZaQA*dKqVheWuYI0wt10$phm#g4SIu zK#lRyva)AcI7Sp~3&E=#NmFSAvRjUE5^?BmZuS{*v(jtjDcITG<$LRBB2V z&C@g7m_EyQ4^UL0>u${}Iz`MbK2%0*J#rKaJt5`Z1XW7C=s$8dTvSmCnN*Y2ty$Kr zB1r-2uFb~PChy(s+z}UeG9Haf)1%d~xv{m_EK+nf|WiXPqE{kjR9_=Z# zYzfK0Oa>NCTrK;=-{yNG{vcXIuP226f?cL;!aZ)OG7nWL>jbZoKvg8pl)I1;KQ8_YmTbS9$u@78lNBJ_4wV5Ym(rWx*A8eJH2ny2 zP_M7}c!7(n{xaMh=AM=UJ#ybyZhZuPV)~C^$Y`lluBdN3cZHTz)z)b73=Axl0yd9$ z>>J)xNzD9?Gk{RAGi?ZEeIMu)FaegI;H8#mJUOi7;JFA!?EDA~i2Gt)Dk2JM_NBxT zYW?PB2u>FRyB%dxu&gwX3|uaf$({04iDbU?fW{ZrWIN-O7~SoNW17176}wg?AkZVfs@gATR0q-NH?oct#l`3~eZGGG$_Z&6;Ky z$+wt!1a#RV!Y1V{6%J`FZ9c1Q7|m}u)?bY5c|D^36f2c3MMX?JVOe6{f_}HmZLWu_ zkG{Ty3F8!djw)cg0NqxL#@G-JW%R$S&ih(#nFr!izbfH72u)Vay3vnwwecVSKu7CV z8jQcn0imWU1R`4O?hn&7RbzdvJ2y{GOlvi!V&CsRI=}-mPq%&LL0ugx7&jDO^{h zM{6y1o zvzyiB784YqU5q8bB99H?pQTtG_=`f8?f1&dd)+BKV=EAz`mt&nf!Za3?{=Q|b44m} zASiq4=_S}DZmw(w+k>)NY=>LHrAc(AiAgIkJQ3PrkbKfUa~bJQSEX&ZO+o5iZU7pj zJo8Q>-3zmcM4avl)+mSNGbeC9G7L(AfM~Jp3KaY<#K->}u;qYc()I&;pSd zR>PX$NRD^Uf5V@9Zxe|Q#?MG`KJg?A&h9Ns{Mu_QeM+qhZaWsiC5?Pfq$;|exoob< zn8_8&m?*PPZ067@DXxt>^<<09DVlyDiYsR3MT#GyfwI48QW9))u?%^eu$%@Kv8x&~g{s?fG}sbmL!>fFq7J+H$TckA=Gq=WgA-WK zB_U;~1~pc6_CZhsbMi*o5hbhHt=(d6%Bko}@_tpNF;l=Eb;uafYT>TH5OOtIXrg*y zio3eqG~lSYd?c;FtJ6*mCC`nakPlN*=xHNlFp!qPOMoZl?DY}4>(N5JS3F{})0F>eg{2E9iQTI_^L`1yRyCG>|2o3_5a^&S!Lxe2 zn?>Qj1Q=^S!W4sg_#$<>)B(oWmqs%sP$(oWlne8NV9H#8Tub2iR0ABrQ^tnf-Vwn3 zC;tDqWwdf~!rP7a=hmWz9TxygP0$y@`Mp(0j80{-Ma^}qvZqev!aqI>>I5AfaAxp@ z+?exs6i)lk4xvyL*=NHd1lGUN&_&0Chnmr*<`nayGLsbFgnh#T46KKmOKbDn$5h== zKd}5?k^J30YnUR~^Ceys0Laz$J}yAC?(9Yj+B?-6oDql>O^z3SL;TELoSeK>g}h9eQzfS>O{%l-T8)2~L$6x(afJ9vn4r-A|UGSa?(|aPH{{ zmjq_G4!Q=`YiXyx{c6dgwT!oI`XGommUl+Mf*HCa!Zm-Vho4G+L9U*X%lkwaXTvWN z<%lk)O}g}f2+g0`nQRqQB{rHe=_QtjS=w}qXHJGl>cBb*wTr}fqo|ubh?E)syWWo$ zF{3;j&(-UuieY4V8u|q}Zh6EG3|P{Sw|ipkzn!01mBbd-?iGK_;K9Axl+y&gkDo{= zix~$}tlN*`Y|~gxq!vv(-+@V&kmlXcOE}I-d1dK!yE%crc-umhwfe}Lu?g{51wAad zbQw0Dd1SwfLBX6|oZOJCKvvx1&X<>GEaEUh(T$VZ34}2_TOZzmAqE0wmiHKSX8Ec} zm;L}CTl%+0C`eu;X0 z&UVRNFHyZH;#E8s&vCxl?PCJdi#8jfvxo>yVJ*kaa|>mUAr*ArDe-Wkq!w_T^90bx zMhKPT*ApBrv1k6MWX4GSF3>&jnZpc2FJa;*ZgDv3$le+|dxB=;BGN(=;Q14Gg5(M= za947!JBJgf)!}wFHFa%aL4oK?l2J{Ed<)=F5&tn+KgB=f!35#R7-AOu82|lOYzi_i zYWI#2x8;^U5sQQil6%BC4dT;VJ?{05ri46hod>C^qj_vcQ=vXsxpyDEQJ1f${_s=f zEavG^+o1KR7;fWUv0P?1!cyEX-JYytUru(Y}NS=Yl_nfC2rWOU7v`* zA67fUJL5$I?(1T!GV7*ABo(Ns@yjYHQ`{32Aob>mFTgX{(Z@;h;?m27(&QLBkFaC( z(iZCItT{c#hP-drPtTEL`1XNmvmH*Vg-wj7ca-)=VZ*5cNEh|7dvrW$;f!6|K<^9M z!b9<;{q*Y&N4CtF0X%5_fnIoE$(n*>>T=&kuLejJnMh>abJWxOYYuOJ*YBTt!BQc_mbRJO2-KG)ar6-KY|n_I zE`Um93iQ`J>JC0?E?9$zVNjXJ1(o9dmVNq`Kef{~aO`+g{-jJ77d;3Xg?bA#S#2ev zR9p5$Ap)oebR!ztbJ*B};`teTJ-F6+YCFkyZe#xLHPE!vDPTg9o0S;+VNo$s%?Vzf zgH&gf^z$0HbwE5m-PLsP2f(>4c^5@6OvhX8AQDCtYi!xl+)V=Ct)h}t2UjA+1nH?f z4Z@_LX-Cex%S)&)9+X#WZ*gX~Za&&+U+3Ht^s$X@gBy;~6R=AEo2ruuX&AyK`{H6q z0VdoT6ijF00>~Vzp#MR~Cl^aK6ddXjU2jfBGnmLo9p{ybUu=d&+}Hwl2%Ar5>Fos@ zF-S~C#AgW?b-qCpYCGoJ@PCy8OCC3%lLA~lb6^qi1K~CLu70LPE`HvGJO^2|NwHB- zldCnCn<<8+ukftWg5euz%-*v94%^-K9c{evuH|?MIL6kNvL8nY_!xJ|?jDxJZ;SW% z*P}KJS;l@zRvWA6`mjaFz7S(PiWSmW|BXlSt-+QCtIVatWnt=&azy!f6UF)zS?^{+ z%>eS^;e|rh8jUfEz$>b0?jWKtIY`3d-;vecH4Ejv)tUMao1C*>mit%u_khyC;@(nr zMoLWvvYsHW=Mx-voU>4+i>zqiP3Z{D_nWr<)WCj56O;GFEn$2FES4U9@WXO|One=Y z_Po_6`0sTCzYU%srsRo8+g6jSd`x++#?7<}KrNEfvrWW{DFTV{zF6%!-IFVso74Cj zzjA0Q14CSe5S=>S4CKsJI;2(ZWj?%p5;z(iE+lm5w2Gg|J!Vnrstyo@3I?ZNonh+GlsOJ7m4T$kyNiIk`>hSIj%$eYQ;gOq+ig~%a2^< zmITRVZ)6OiP&Tp1aTpQ$@U{yfISJF(-~6Qf9B)wJqIhDFQ1Pm6CRC7l6P7AzyY4cI zK!%ed4~5~5b<;Gt49%XOhS5q1d@fLEY#BGI&C4!?BVVDotA`1t^=AU4RuPxdwf^UA&1WzVk9h~aR|!a^G^C4}oq zq;p_UxkaMoPd!Qa$09uKJ!2`3tAkzO?MODNNM#H}G#UdKpVUDWek1_)40ORw;;T#= zMs^MzidWqACgkCFIubGbM+Il7Iq0J~I7btv+k`>W6{oTJBWays1;fVlt(WbK=3cWv z!vC?EeBGrVF#9Jm?M*BME#*SI&OLuNR$t5lJn$oKKP2w2VvlNS5a@nc90t;HhXa1< zk*ZMJB)}1l$i)%86b_khjA#CzTFGN#78XQhAGNFd_?gAmPP{AfIAfA3x5eqG*VUUMnuEBRtGzgARB3*+;9cEJ4YgesGFk26s+Sf;CRuc&=icHrJS z(n1pgG7J)hy@}HP#Ne*B-z%b`$mvwG@)R0^pPk3nY%?<`taSE?vn&Wee?%&O>f7gQ zQX3b6?U~?mEt_Cj^7knVZ|@C6*@+6be}m2eE0?Qj)azCNCv>k!tUCaf8zF|Fh>cUk z1(7Ll8%Ag`o4o}hkN_X2bKacblq^;*Qs-p>^Q+OC_)VDXH<-6JeHnIGj6re}Py%zn z@T$xA3$Dw_8spYroGLA_osL*u7mPCX`deOR~r)m(nDWG$xI_2n4e==WXUZ4Kj0(?v{3Fb zCH$Aw?W1!8HKs{xf~}s7Y$&LNsqegY!f;*}HVHK;8=Mo$d#CRIBTN;=rFFLBS1fRz zT(}#8z+}Oi0`rQ$Vo5k4OR<9!?3y`!5(D*v1w&o=2zS8cn-*=f@kFKyYt&t2JyG`{ z?Uga$y(<93xbx}K4|hZuly8hOmeVmC|L_5)^r`tm{q0{nbZ@L08LApf0=7_Hn6ZUD zXTKEMq9;<9QgO-U|F#(3K2Q(z5_MdHD4j=I0Bj8J^iAfaEVGi;U}99S&;!nz_0ClS zm=UK=l}xgQtG}c9xj%Ty%H9rw<$q{&*|1 z?@n*a?!UK^5nr3dwx+Byc>xKM1g|Dq(S&M9hsQ|vEU72YxOGmN&>+9ZKea#}y4UrU zKB3cNz%_xGxGuPx#nTq(-=^*p!A8Dez0`d894^=__#wI8^OMx&Yt|ASdL_DYLkZ|hD=1E{1S*Lh}tYnB?^CcJ&Rat()|@X`i1y{cz@$B z3Rl{`S}D;#sT{-y-~WN#XXF;4^id?nt05GvUe{Wwp5td}3CLs8tU3;=FWh)9@!oFR z=9wCMOm{}kx$?He-?)2WUg4i$?hVSjMRO{byT1(7>{4qoWt7BMV1|?XDaeIS0P=QX z3itz2dzcTicU99J8gC~o1Ns63l$R)+tNwb*HBCL>S%70H>wa?c)v6%UkjU01i6iastN}Ep zDB{axdg;dDEjIHzM!E8;w(5d<#3VaMB}7fuM8ou~rQK}tyta3$tzwLhYrDtJ+arR3 z%56C*^{R@pITm|MCId}cYi_bwhDAN0dKFzrJvjAwoI%Ch2C4QQ2w+x7tE*SI4ws2F zP{LExl1{0K%KbOuZT0hPnRu-4d&=O{@2c!m#XNO9&RMzsYq(dilo)#6m{6Xx>d>7V zNpP5~Tc4s5<^{I5>9l7_dI#m;=e@-+&?}I)q=EV^$kcONyZmESH)KBVBoST!QTgNV z@2@WRg7Tq=*gNX_4oc~6d0{rMa`U4VPrJ)cS%i{0t&?lgrGz!kcHEVEINV8jR)gNW zq`%C>0DJd<72D$McDn6?<0h}+uvFJNmD$VBp*QLZlIB3ECsK|-9e-Y4q2?r{NWH-| zna%2QgY;gidJ|)k%~`hp;^$>h=F?-=afcLbou{?t7S@dB3gx5t7*NbjLNv~U58{bN zZXv7YDE!h6qn!n=Q}_U1avHr?fkXTb3|?Qo9;|`LbKO)AB)JJ$jDp8}VTVes^z1lk zbP*-&p?BoEfR~umz`S+%qg=-z4SUiC(FQ5k7$K{i>#;q5Fr(Bq7V{P437AR<>`-LVmh( zY+KHzAyDmq4_RYhA#{$Hk~RjH^CB1L4;Ubv=CMzKh8^gD8Lbq2+kkgS_;2&00KqXb z_*CB$XKYILZ%NWgv)IoCeda>V&UWLplbdo@xVUP_ZZT+ZQ~S=sUSGPA4NW_PhJg&4 zv*A1)`s=3*Q_=u@rsSOL^v<~-ZGX2I3LM*5F-;ejkqnp%y0+)7;k$X#hF(>u;ye8$ z)01Cd<w5xT9c7a8> zgKCy~H8wEZ1PAx!^ad(;4(X6~Ds*CFn+~uAMG0)ke64nO3>MTXjH`x(k2I|EAEzVH z#fTz})$H&qZ{%uWzCt?BrK9d|IRvpnrC9yf5laJ?g(JyXT?lDD?~h}ZibIkCH1jAi zDd^nSgQRYQ>h}0E)O5Tt$3%K z$QmCtl3|+=J(Dj$CpSp?WX_b}r7LUN)%)7-ZggKoube7)|M5B&n9vBQpzeJLj+KP) zg!+teB%Dc>riY6;kYOglq*$D$5#^v^u&-QU6tU~t$V)Jd60du29)7&m@e7dS!!7l^0yNhp0vF9U5kc2L{Z%v zGyQ3eGDR;yhsWnNZ*lSRiSY~E8Aj6m(BddsQDm)eqnr9{>{36&7#q^mtrLl6xJ|k1 zgMS=lrx$rnmEg*mDl=dB{ws#U*jhNP*q;R&M|_&)nv<0br22SQOJ=VGh^&KeKfERO z;FGn{nxQN<&lX;p9wB80Uho@grJc-42K6s{`~8mRZ|BzK=z3Lg)ibJQ(MyCjL8=1C z(-It!!%+wdJMbvrbc%ToFHGQ$cW|GqiQ59Q6a?kuZ~4DAi{AW#Sk5`1A6h21O*c!Y zXI3cJ{A`Omw%P&iAR2+~zHiY%$B#9P*#p~q(m(^L)DLqyRu1xYjl!e6 z`in^96@kOpxDSH}NRT-nu;O(n9&0Qv29cl`eO|Qf2+Nwmo+|LG1=PWD3Z%jSGC)Wo^7imn z>CkkWTY`PD%?*q8Nn+K*%Zy*6T4saZWYC5m$1h%dkf|%uj0-3z6}=B zblljF>*>|Swv=`gu_cG_0^c(aMT_Uh7*#B*HlOQ{inE>#^VCcG_w7KJv?8>pIIUDo z3M?CxD*x{@_|Yy_PBO6^614R_H2I~d-2diuRT8mhz6_C0(a{ocygP za2qT$QYyoO)cld69^e~{$!CaY06ps>3n;oQiujn*aP;3?fFm0>GQZFf|^woBIEQMJsEMD&!!Mu-PX>=Zuys;T} zqp{Z?4$SCxxzb0LNP^^ws|Iua{P`s{^jWuJ;w&X`J+I_5i15z=Er=AheiI~cwYOym zL^u~aG1BlTnp_WP@?(s}d));o(LIV>X@GZB-fdUZg}W$klgj236wh~YEt}g0qjBiD zzhyN#a*r+u_n)rHTY%Ti_j*K?NZdvi9hQ@(`y_IH)ev6~&j!8SVcn*2`ENr>)QWdd z4}3{y&6Xk=3$~!Z{h9zU`yoQ+!=gask|F-In7hLvlkLw zZ*Vb4u#Chi-kL)~^N*j{i2i#uZltcFlI(e^D!ufbQkMh^hSbLX1YhE?o~ech)$a9L zgXZJWs+08;%25;d0c{}~O6N!6TT6~%_;CX8CRcip6oeQwyHG)WN!@&ug)e4p7nI^=piGD}^?n z0BQcIa80OFPn|de#_l>QZf6Q{OBl%f0Xr z3T>;$RSD6zsP2E;=`ekOPWk;i7N8IL?P|{!uUj*UD)6+QD0&$uU7YJpz=AK8yvfxI zp-ay4R80st`fK1hx|u=Hh@4jDyNUeldSn5opy02^qs4m4cNMk!wW^(@`#t$d&8yMR zHaZaaCwtaKv|#`t2=m|N;}jbzsaOpfY8qFg`~%n&6x@8^bIh;@w041fdBYZ;Z*>*0 zk=2e$A>p^Ad0-w7f>9T|l(JZ@rQ^BhFuex#SEZ0Dh7eGhEI{xWVsp|L>`yE^1!}=4 z;vC$%%IBI3|8IkWL0sptMF}`CH@ynjXRJMI z7(=71P3hE3qSQ|`X#e7GvT+OEV5N5Y1EMO`tyQVg!721?Wl&{!k0YIZ3Jl%Q6hnnylz(>jnq%bhfZp zV^PzM1IXFDw-)4iFlBw}7KE<+cwL8bXZDdN)v?7XR-JFKpT~RFRc>=H)1H*EjO+@) zVEJ%4j7s(4SLwZiD(;@N1@6hMY!!P`kzqrTv9krNgQLIUY%m2OKAR#f&a)^6Dk7Ve z8@tg9?|34bsuD2+eUytFzmLj_w!G~D(<6xn4y?- zy-a$m?%%N(tvND*{7H=lkY-e<3^DLH9~Pij&;P)1LKb)Qe`vJoT+DXSgy6h|TiQlU zrH1yvEYzwX{V(Cueo3?1$1fap=oaacD+;a#7=Wy+Ib%jeBgs)Rk#X1M6*lHI81OV( zvpHU14q%&Ns?pi8UD;|dvBG8lj&OL!d@}Gdf`i<1X^SEa#DVFZ zy&cqgc%rXX)y@PEaIX2*Q8uXIS)VlE(m6cv>C7j6HZ5|6S?eGmV}N@t4Z97hMA(^^ zK)>lCadw`$=Z%GelHI;;{GxD&=gsTsp~kqEmJkV`SEKqJ6o=+{Hy-mk+#MB=JICSz z>^+11z8acD(OjI7wS$Z6w=V}O9k*~h_)LN`_M(-GvB1Eb7lfiaNE`!V?}gU}MIXBE zO&n5s=m;f>=836TnPKlJN>@igQi_>XLtM6r79i>08^Z2Ikk4PR%X)yiA*SJ;=)xpm z*zblDB`3GafZGJODd(~RVO-jRWN7M2#o8LDNyA>I_{c-ftu3I|g%Ve>2Mjv@22g)#pFJ7NiR!Q9e9KqxgWl{n?DD zSW+BWcZPB;@25Zq1TWpBubAxGJmjf57e~R|I~v+f4@k;Wq2KLySwgeRSzT&;$l-pf zuGzn627?nEv!>c}mO8&mms^CZXRt8ITDZ^!q^@24y&HX3O zR>4VUflFxyfJMIU^oW^oktmB~=xJ9w?V&oqPQcw<<16cgu3m;zlRFJA^6O~>G!;Y^ z#g%JF>Zf_FL5H`qApyI~BC9Ta_pWDCw}*V0e$WjR_Mq^L#VuH&>Z(8RO4u z_1Mx(Hs@fFBQc4Uu{rtHiHj>X(ZmDVno6F77dCI4fxOv`$$9*~-sK0_0Ig!S=#zohz=ey!)vI10zkODNc8l|&177lue zl)>rJQtkFzaQdrmLu^J(rn3R&c(rpbfDgecV{CtDF-BRVG7YJ;jn7)32kh3R8#9rg z+o-g}c_RmbqU+a6fHimN734^rJUonBaIos+Z7Y;Z^%dd`|LwYFyKE0_pB~+L1F?fK z6-LHJ3^wzmY{tsw6J;a13L(pWQJd7 zf?KFCyE>@{FK|_Lrc(^g6rE)NZYv6geP39e>TS<11G#%=e2Np%rZ8QR+z|ze(qw>m zuOGOm#HnY;HXYV<3>%vVon)GXZ?BRE+oXqZTm~+xEUv=)3bF7@yh@Vx(5r(&s#XE5 zqC<04{p;FR-8w8fbs(wPFrT3$0ten)RDNT_woDjGGz+mJz^P%`xo1S+;_+~!I9Wd8 z%fOfcdeV~#P*VS}q(Fyte;NXSuSu zfoZUDlF&rz<3}Ts2^dLW706(ljXFDoESR+eQdlf`B9FJ~;NdUH#uD9lrKWaOub}`5 z5}m>QWNvIogEc0Zu;B7Q0NRe?_$oi87RgeI{2trklS=}k_Y@OKd!;4Xp0WSl0O4jg z6xWP5rMvWw-kp%N0>Hvi8Je(PK-*jM@b7s_k{NS?w=gbK z#l+p`c8-259cuHh2C6VXBR>G%gasug%sVFo*X#}W&qAS-Bw)4Ptit;u8|KCWDTVQv zg4^KzT{g@y#Oqjn#_~VUjCDPBkqN(-XaJQDkpo6!0Dl8Ol%`0x zEy|)IHGbnDKDch#1NTdWPj9mKmiUH(U%K>l#HB0Pjs!@h3sWP|k1t6LCX{occ93Zh zU=qr8V3~$J;!o31NRf}UF5(P}?+|3l>H9QeDYImI2ZxSPL{zi8L&s6y+1DzQK_gZs z)M5ONMFA?1{MwWVRqxT|w!-|503(Dp0y#KbmV@h!s{4-4i+>h(5tWnf!V=uYSC5LO zUovPg4yfW<`!h;&C#$~p9zT-|j&BS0#2ki=wwk}htZc6k6r*Jr7W>umJ1GFOe7J;% zK#zF3@0t~QvIM3Pz^SX`tCZQ)p{g0R3(T;T1;^^-g&w-onGn%6QJOxXjjWAba_QeF zQ4>8LrJHcXW)ja6kcnQ-&M*x4C`uVaSam^ve9?;YPc@oW=%~7imW@BbhgVUP$<+op$#qUCD}R6Dl9Y2N-d{H zs$y6Tlj5HxIc&BEJubmK+DkxG_cVo0NKiY^Kbc|d$#j@T(t=h_IhF-xDkTD@Uu~i7 z=`H6)jjYspl7Cehd+-S;Tu#C(2N4?LyB4##!SK@1US%b7|L9I&&D{dmQ>o@^2TouB z_bMIhqQtd*&S~59U7*Sc4LQrj=E<=R?+gNJbE@?b7ghS+zxC6Q+kY;xlB41U>fL*-0Jd+fxd{qs2-U5)Y;j_}C17pG$BVc^b}!wjAsQ zEOs@Z^-*(B&qcS#NP!vYCa3J0Q5EpDp0KD5G;!!JF=(ZZrZ1;n(Z@rH?RZ-(SaQh& z(-_Pl-tpju7`rX(eCy(;EQ`9VkVZ({k#yl`6TU~?0dU1{8cB{@USw-)9||$XvCtnb zTF%rWpd)>US}2aU{h&P0DN@5bekKX!IjS~16CdKSx9&|1X92Q?&Tc78B!6Bx#;u&> z2Rp?4Sd&V<0YLCmPVJ3(=iWSb3dlYOJjjx<^;DWyWF!ZAmhg88Ka?Q)Iq-P}0Jb}U zAIWs{pW2@Adcyx-k%T>_dguwO)FE&xg+BkpJ_pK^a*ymSEy)rPSVSCnE>>#KH+gZP zioM~#?_P2;z&`R8ifCsy5g_G^nj>r+bS{d2YCXUZBV%wz_^kTTfBgKBBHyi3lf+4l zQrdT}3P7}Yob7~|(o#mtKQnI<0_U+(h?oEOxs(ABz;tEg+v*n?*U@XF7qR746It^$ zl_z-w`OY8CMl`DpKNwm2soSu229WA(`udSTOhl-8#ONI!UIi|T zP*S!2vAqLX*;NUZlp)g?|Cam97Kqa(R^?kI79CZs&8?7gfuyfa1ez^ez`m|fe+@Ka zgXD`uK;~opUZ0zRr~1mTqcpRT)ecvBzI+hHBa?@A4QaD$`ff#<@8(OMZ#BT*Z}dKK zGy++>qY|#{gjrUdV6?>8ck;O@*40DPi0w<^G@uQMBcyixnxDr-k{nxN4Nvu9cnX(! zipk(tx#l~Ob5}^l3xx73oGWfvIiG>yD@csezC%$1dMWE>9SIBQFLiw%&TiT7jE3F2 zhr41$vmbChqZyN23kym=Z3E(Jv28Dq) zBH)&h-82N{>iV9sw%|l4tK&vTTOA{GMKnd2k6)m-qfpIW5KyzFIj!j6qofj(6I+lX zQjqq2N@@otTy6PM8yeIlL?_p+)U(?->xxFw%*~xnl4zTbUE9LrH>i1L&~g&x-2Mts z5iUe>&FC&oH?13{)B4M2y14MnMG=Nr4Y(5-?qp|c6xO!YPs8~Ez*D;!n?(6zd0WP- zU|PjYk~hUBkr%WJF&s6kB15GflP!tt9_6B9o94Rn0v!m0eA4injM1bia*$2raOSTQ zL(4?a;u|rnr9iJ7u|ASCh$?bn4ifRm?j4MX)xSMIlAOQmVt5>5w4sUY^~f3>QtS`+ z!dPV&hGHEGUNj6C%-6^&&CWrLT>#sWLcn;mZH)4sm{yPquNV-D1`<)(&UI8~#&Yye zhe}82-I*D0f%sV}k$TqTM{}3c7xYPW%7{5*^hnla*V!bW{cnh^@$WsFphjDR#Kl}q`_w7Uu7uk?qdfa#%wf`T zH0dU-D5QiV2fOPmlGy@U-cRPsP(9Q8fs%s-FO}vnm%K|3+4mwq!SRg;J!)MpHXZ z!RfI?7e@R`5u<5hjoy(zw2g4i7qrW6Z|5GFZyYMRU!lxrTwx7(o1pWPz2L$X6!fDQ z#in2(L4ro)bhpk@x%Mg?KY>4mVUnFLOYr&Ky(AlFPS8lf`m@O~3rxKaO=)@5<4x&c z9vkjauk zr!flOw6tnHAun@eJn>w^)!?yv20aWoEu2lvJEDikp1EtfxMqrVEDp@3Hqd7|%U}HS z@y9e$Y9$r~81B4668sw0~8CzN-JXsSD>ti*{6oLn*FpRvRN1zpTX*v#EP$A} zbWJa&HI)E>l`YdLD=&ijR1zshsbu9ryPmSSlQU8Yvt6SlcZY2lH8RvAOUvs9y`DyF z&m*ky%}`H&=);bEGRd`BQg|wFtuSKa;9SS#xX)Z`(CF~AR*VEv=2WYJ+ulXe@v_p2 z%0f@ErrZ6T->j|m+MH5hX-jkNaAo}Fz`O$U;Wb7K&Wo%|y z&Yt|22-^-Yu=g;X8m8G`*vM#>EU>RrJL&3eyB&b8F6(>#y-K9C3=Dp$bL zIBg*kWV|ysgXR$a672O2YH@GbVQW(Xq&x3!jN z+7UOW+3|QhP?{xBpib>hRsBSCCSjqbr1V#mR)E;gfIyijy`K}*szP#^)v`zULmm4Z zk*?JpDv2z&m3w(&&@oG3e!X!Oj;oWldY}i?>pe5N+hFPs{|8NzO!0SW90VyYbVHA3C8?=9nWd=N8fO{V$>rOH72w>dM%2d z!8E?=9W8c(`E1gYcsos%yEtB<0XP}twCp>zi+xeV1uBh9yY2gaS=D%JDp7 zz=f!{YB&;hr%F{X`{45ML$8VUWNcEuR`OIl_x{Ku74ke!E?@j6ND4-JO?8klMOM3{ zeq zm$>=%?I<+Xht7ReeoGZE;7VuM^1H83943599+a9X8Pg;03n|=(A|KnEHkBd>pbZgF z5P@GV^B61wg6z(v1GqG0-a2#H1#v#p`l~Ddrp8KbAWH zNK+dcXndAFujZa$5;E;c=c;`9^P7`%=Hor{@l=nk;}t|om&Z^PY=ow#T>BX1YTk`` z<)Q9uRP6Tqr!aFjqXObs(?}1^XjBQ=B_Alfi;%s|a}92(=k}s8e)|7VQZ4@u;?=iKtGbmht5yI1)cD7n{i#gb zo&fr^B|*C`JCp)TM5U)Nz(}K4Wx!*MOz2RA$2%NUQlA9)uJAMEoa5?lU{Dw%MDcU$J%GC*AB@bev5m3N`Y#*gM4a zPEF2Ncpiw&*+-?u8 zdS!&vK_$#x&xrBLp5Jl8nww_DR}Vv*Ou^P`=S#R|p|Aw_fP8Kv$*?a(q&VdDM`=u` zIusf(7ACwENZ6mg2EOZ>iOS2&TU!y#L~WT9ivo@=2? z2C6r$8lyU6E9`QN<0hG*cg*XcQWmGk`GN%cgn*$P(ve##%`6SPiXl6ACs`5h(TB*= zVAARVlcAc53)tm5YoK%;C+Bbwdzq>!IRwN|yoc<>0KLG||Lu!N&Owkwi&0}?#f^~&lsi?KGJ3`Aa7)dAvq-VkW?VBLA89Ze0&n6GE% zF8GWoBbTyvfP2EBz~%V;+kKb(M!Y7B8b-|M4OW3%LP$WyqwL@pK%8edej1V3?c~S< zVGUTo=va&l6m^;Rq;)HVXp#%CIMw5R=kc>f-;qG>P~%J3(N{8OOAlWbHW@$A!s0l3 zS|!bjX{xq{mZPWfn^&5aJ7ulme&P+tSt>>^6l@4uM z9x440(?4y!^Q&xh--WY}4s!q7Q9UIrU*9v*I+V_&hqG3$PRox6#N+z%f}(6h?Rc@$ zX`mpKG~iAC-`VBESYqwvlmXGTxdK)_3~#Sd&gw#W+ZdH=$l-6OB?};z566QxNci|; zD`O*2ryB8#3*nx79H@a&9>l!`bktH<99j*qoMP}BX#S)!3=Ng~4g#*`0c0NYz$hN~ zpqQkaWx1OZ@o5(N9MO6cmLW9BP?;>rqXB+~>u$cG$9cDW)_z&A8j@Gi>+$|+1d;OI zAXyB%K@;V?B2pdsIyFTb6&8iHy}L zpLXR0*q{>Bv3k?j3iU}m`$8Ucn*!Nl1{UG-w?>>E-9foADwMSR;`KaH)W|c{nd%18 z8`DKNXbJktHrlbv*QsP2;eXrPcigL>f24cGqr@&r6qq8itfYWa-`PEdk?)*|z9p-8 zUi|`z^!c6W*A6~tJEkMOXJY6(Uq{iAxbNwE)_g3As(QV0k=#HGOZhXnfwYqkQX)v# za)W+p($%u=$M=UmXJEK=%p7qwAfiWGEPjtG=Qud-*&O#sSWihZnTsK9H5Jaeb;nzjA;5Ex<5I?{eW&r>gjeS> zZNMgz9c!S>W%%K+bo(L76IDfZ1DL?{-BxpNfGUoyW~vFRz!Jivu!tPa(^kxJ@QlgJ zo5KUqn3M+ADM~92x+wn9n2;ynyeRqfmlQiChZUMm(DbrecaSP;O8iBant^sCjE2_oO$40> z(DR8?X}~!F+V7xoWkj|Y{}2D^sn(}lpz4Q*)QF{AQ)z}rtGWZkWK?#&1ERx4s=&kO zWfACzo+|Z+5t#Ns49kut(~Ib5kyV&-%DiGMYp^Z|7LOKmpm_`Uoy3WRJGgy-X#*{L z1=vT5;9rb^>pIy2mv&&(JUH?FuyM2KEP<@a6<++$+%D)IhK)$gEYm`yhAQNZEupm4l~GI8UaG`1FK!UEAVCa|-%SGYa+P%H zhfPoRy~OUxc9PX;59XR*emz94iNW5AOU}1|rH>_~pc(XV;Zc(5;Oe84FNs%&Hj}JA zDFvHGGG~32Ih~1q8N0M!?wGxHa_}<)eu{Bc7dOPz{K&$1h13nOTAD}9CjB>B3y$T% ztcN(`iefFu;Jlp#7R|A9Kz$-3tX%K;>kW+NLi})oi?ccWJsTF0KbaYBajLHMd@v3M zZpG7{oQW$|5(t^-gJJt~yvb0lr}S%+S?&pMSaQy1lX&OV_Hi1*6ZB*?pK3XQx z3@q!6xl!H9nV~Q!wJydt!(WEZB9S1jKbkwk>}J9fwA@nigr{NOSIFOX#h~;MAaybx zKsuqn4$b(&O`%1yihw_-UYtAZ$Y}JUl+nA67=`ozfb6SIuX{=eGdG#=pJ~m0gj2w< zYD=G|G2=+p2&06SyvPCQ)&L2~0T*ft`PlXzePazIVv zzG!`3TtBh-d++a)j0ycgy_tOssQdeCFSehyJ+<-@9!tv<*k+w?0Dn-Vie5KlO4Tm7 zq0uV@Xr!{bZP*frxW%=BO1v2$y%pGv**UFa=m9!Yztl1ceHfz?Q7o_{d8_Myz@Z_J~27~@W^`AsXt7%cj6gDXh-uFj7=4H z8t=tkhKeo$6yK0V#~wLU%n7APFytI0$+*6upJh6;z=*XdOcK{=*kY+?w2V$fken6W z?o{Ev2z{S8M1xH`sF-^<1)c0f_oQ#DgoEIM7%YjIcb~0J9!^PBC_F8fSOfT zcrq(UL`}1W+8(loB_KYCZ#h9u?Gzl)e`m6LwI@$>mLzvHZ7lrc#4x{4U77Qcgp}qu8JHrNZ4;y%Oqf=-FXR z-N1{El@@1wE_p)3{OiOp=;H~N`MyjRv&i~Nv$T7&)2L`I1Q95Mn=70g=y)qwX7EsY zeMy~h;(9QFa|ks|3l@$Rfek%2hW~dSq$j8Ax{2Z3aLZrs(NF`l-7q{{U*fPGZ3h4x z?{IYcbbu|P8dXpudRdX{2qu`1R=6K>g8|Tfrn|39AOU<3BrkvqTN+l5omJ9@;}sjY zNDuo{@diE!)38Clw~*2f5DBVrK>{KB(FpsGAPq4SpU5?rJCc+!Yj_Z>V|Nz$v{ewb zwp(NBfS2W6Q&*{^nmU5#%ou|io_=gg(~yftfMrmkc}`GN`o3fy7dAd=E=n_BAi2d$ zqoc=KN~be{9GQ3_IHUax=)Czs`?VS~O#`hiyvN2BC-LCZtg_4fif5vPLn!0|lP5hX!ZC?wyEg!!ezl2qn8ohT{qO%$3Y51gn_W?X zIpPUMJptt-2!!0knVTvP7}e7IxAw%2_(^TXpazV}Ehf-+RmdJv;Q}-^p;8$`PR1LE zoKM~*T<=0Yg^_)Dqsg(mI;5SJJp=30EGmn6mW?zM27C<)NZ#G3B9{WsPT%XMSGz71 z4!U)@RTpS_8W_9h+2WbEd66R3i6RvZgIUTkQS()&E zG!~g%egdwhj@oUbY(_C~CggtfK$3JgB#Jj8M&nySwx49XU-1{}Zft49tA#cZ2lt7? z=VK4;*7dxl?{W>J$x77qP&>@jf2@eT^nN zPPePAOEA7z)>dz;#k1M7`hu+lpoOyLM5f5F;Q%h4CaQN_p3qWOELk3(=OfTK31qbV zMH?>lo(Sb3mS!D^GJ`DQ80jK{)iY z%hO}%WUeLf%2qj($EB#Y;1A@c#~);sh1mixXyXhFt?^f{DIK~ob|qicGu8u;IwBaV zm&KR7(Fsz9%F+s!BC%2rz^z1{=nXiYz9GOUFOM{h{UxC(K}$|nQ^}uDdy1Zh)m8)K zpH~<`^D2x*N-tINs&kC5t2gr_oTq#} zk#uFK?j6>bx^m$OB9pxiN@!>^m`i6N!Yh`_yM50**VfC0YG5rSYvgL)Rc2U(O!OCi z#%^bG0qeWhk@eVVS$zRmjEN&=d$DCVoUSE< z-vl((%H7u07M&dJ=bVFY%R%p|QYpp9sc*PCG|Ms)xM7a(!)TbiSn07O0F~*izh?-- zRssyX*V&OTLECi1+R?X&DuiJ_BN${FG;GVjqdx$w6D z*rF87)tB4qlLlYd3o;Xc#iM1UGt!3KHLIimxgrK@Z8X?&+qJ~12_T`&ifkPZ6m6z= zsy~8-At~5H@*Q*Dh2|t)xHnDxXaZ>pibj9P;o@*aUNrJaV(|M`n7R4lEb)#6U~l=) z$m^&5_ISLQcmU;p(I1TcCs@n6v~u*{JPY>-qd{ZOVlB?l(BcrJ>t={XzUaCKFQmeA zHHD^@-spm5)+j$E6nnOn?9yj)>G>4Bp)K( zX^@c^ysB8fUrsH=ZDDd0m@y5{QC?;FxWh%`YIKbS;N4HjTmJG`cPTVAR?luR}V zO*X(Le|S2Tg!@`{SAU%2a)Y4ta-gtxH_L|qG}D_`8fyr+k5}Z`0G$0t{dPMtyPH67 zf9JGWGXAn9#;;J5l#1f&%vFq{Y-!+_1ef~-;Mra1;uuT~Hi2ZcDp=M=tt9%9fEaG0 zu7rC0eB(Bv>;25<_#ZY@XJ%$OuEu8$FzQO8vxp&fphd381l%}j{crzco`z&qiB*8D z8^3ftk-VTc*Tst9^}f)56E4bOjlY;#h$%l@B)>U;?uyM?ENL^U@kYi9E(>$so?r~m zE`9NE;HxG@{gNA0aNUQJ(`YhrKjE_{IJP1E6zJZ4vNc9)gw55nj^NklURkpi4!5YZ z9pur-n>)Y=AtUt7KXfhV!2mVXv8gS&oldq`Qf5X?XhP=a&LKpIGo``%OF}$Ps|GkK z!B%le^K1RMNwTAH-%YEDe9mO5-zdmaj_zMGX4t~Esx1i-S=%C~+yBOhTVC0!CleoI z1i>2U3~75epglg|xvwSy^p9wb``FbGh0W+pZuS10Elg*a_C|+hWjd%rU zjq}>zS8l~k7b6Y-?o0|tw-?~ErbcF!QL=TO_q8%ukRy#|r#0?&N_qo&32Mi!=m^BN zAm{W5FVTv1pX>LL$vYsscGQgucWj1#rW7WIAcj3_dIV2V3!ayKz z8}14Bo?`H-0@LYSrH11s3vx4VDtkn?>hU@hiI+S|1puKXFAmUtBnYX~$i|~RPyd7| zkYGY6xr@M%M=j2K;0n0@g4o@I-TtB?@T5>szsAjEZ)4E9k0uCopz?y{bYa7fMGuE% zy5$oteNDb4g@Gr1*Nm!?$UJZ!Y?c%Fto}ftYED99k%b^)*@`S(MisESEw|(cutXB+ zZzpo4A$MGKu_5;Btvi&8dJ-NElMCBZwsY)G;`yREi1CBXtUa`p<&nMwOT9_N`UZZV zmqm#HJrYA6MB~V?Uvq#56-4>a($jfLck>gE%)E z@pjzo@aqsG$C z1=8TBSxLDpKuH?Z<#TZspfyp!^V4TI*ywRivD7CuLsZ-8c~W)He_Bkby=HHMG>r|W znx0dBLy7R+(tG!kKzlSh_k#*{R9a%^tVVBDU z9H@c2=o|D|ZO;EiKvwPl$au`#ACFAUfn?RSP|v8atgc*usFTT38umogo2hytA>u(Q z6bG_HEZlJDqJ)c(BW~v!#Ho{F=`GV588&Uv)B(XLucKL~e=M6LL+*WU}Bk~E6)(q9c0 zdD&XMPJ+j61tVxh97JS9kT?Na0Xnjs*LIDi_L#fT^|cR^{<5ENFu*jlSRj@4jj9^oFMAGie z!y)RF0UT-5n8`a@sq*LEi(izJ;gpW2Ai+8@37$&QKWpG&KB_#8+9fOB=GF+O^z>HY zx22)n?G(|uo$mbK-%BZonNnZ5&o*42(9Sy)?5-~``sXlQ+GY+b+)dXsbfRMoPT8cE z(5ei;*EAY@pnU%f;%Su~D9gVL>W4eFyPQy#;)K9mr9aXmSd|~^cqN{HwSyTR{j&D# z0ZH6JS7r>7W#VK@T}{^Sst$6;m4tC zv#K0H1bUtp#?(2)OqfugmTm}urBjf9QlRRORd2O}(aG2(T&ORad$0_uOGIv1M^e0T zd1G_D>0`@y32(=8<@w!`IGTJMnQn^S7{ix>I)QsU|1wnQ1{lvmN|V&yR#r6L*a_h< z!l6Dc#nj@G&fvaeYuUS;t67c;)B`h^4QLp9p+OKXBXO1Do(xG)pag-?Tm49m@4m{7 zFCmaKa^sYI6vU{SNfBv8IwRNHRold&f6wa5ipjLR{i8^Ai(i5LuFv>R!)?DY$34T$ zLtBao<_^cMB*AJa7)tCfxx)Bnb)Rj+Xb@zh(2B#%c;v4iD4Ltu!pMhqtxT>ms3-SW zNT4E~D6v8zy2mA=UnM0&MZy-X;gibWC4tp@?s&uQWT7C7S~uvd3R9KJc{|pFBxP`J zYyJC8guJ{@!=y(&l*6c!NC@o~!@vBsK69(l0C?rh2vKH~nbRx|s>9QpjuQf$iB7*z zQAK;gE-o7(2Ws~D+J)UJOGWt_NO5}DcblID2?a*1CF1v7%J(i+ij1&{o6y5Jb}VeOE;SbTSZ^;8LCy~Q{S@v~2mm6bxFF$*Q+t?J_~y>>VQ_4PCi9jOn9_8KsComt zx{#if%L*c-uUBDhXP80Gr*qu(0{=CQ4KuIDK13t@8r20`xJK5#EU`JuF-mVw;%dUv%Y?2Ni62(tP;YU9YRAE_B?XAg#bLzeWWk(G&leE4f9iffP>(%Ig z!K#a7b}v*q4})akH8l#=mzgGtkV1H!H8}?6y%=!ShV}UysqrS*UD>exxMtm$w(u~m z6#kQDaC!TW$gnt80*tpjml{NA5bI@J-2FM*YZv{-Vtx9iY1%=+wh-c;hKQv7X(BIa5>S56Wn;k>Lqdr z?rZUHAUH7d<(I|~qZ@{>C)0$i=;I!5_$-x@eYro0vGMQ0&iLfGYFq#~{T{R2-DUwo zW9e!?RHsIOnDC~+hhF~E)}2bg_TMT7`++3A1m%swoeaa(I$Q*kbx-42mxPNsBK(x*4(&6%jFh&r2X&jlmYpwBV^?pX zC$L@I&q}kycW<8jJe&1kD^^42dr+o9`eW|@A&ZYhbesVQwanRBAJWyDwc~o4L)2Fs z>2}8)4}oU;PZ=s`QIAGTXG$<#WA{E5^b%6BvU%79t6tNsy6pTJvj#mcw1h@MP~r61@37vKtBefi=sv_HDhE_;0X^buFS7-)I+4t@Qr0Sf`*@jGX$kuGMc|H#xq*;Z*RDHw#N4NQplyC zwHy}mw6x_52=uU)uk)w<$%knI2}1u8G*qQf#uLzW`&Qmx9KnW_YS%0rf880b(+{F# ziU6%T0G&~;1to~;%(b3f9PuzcmzWX=MBugMmS?Wg@w`a) zE)FeMiljptMq55b1j&vdg?VzzrBo1t*GTK9;ZokfaO!KHuJ`-Nu=bNZ1vGPHHM`pR z^uRtb@&vD7C>-;^(n5P*Hc+x8p3@p=OJ+{#bP85fec)e#p*d>KDZ~_}8c{=l!g22Y zROfy989(mD7Ip?;^bk;zfiUBQ2u8qLoZ!QXhUvcLONEyyrja>^);)tF{SXKn$ECOE zgU%|Dt6HDnE2mU9n}nlNImoO-MMx=5;=9K!WJ+2umar(A`-8HVBeeQ z=s*nn7K&YWz(FjKSv{ATJ~@%8EEbB-_4ld>B?)}`N&_5~NQig6bE<;)5lVTLIXpws6Vvc46eya#JndYz z=m~#zes*lEg?fj7GfQq5AqQ45gFmst5}T^Qas)HuN2)L6HbZ4;$oT! zm$8l-i_Q5lID%`wB)xN}VTrBVmR48o24(<&c7gl04MO;Dq{Xsc0+Z_PCSMF<5H*C) zla!#Dk6EtmTV&ai&{GB_e~(9glk^6jNrM5n*vE8JvM^!2e8}Z@M_apI_{l{dk@b!4 z41aIMezAIv!A0}ZZV;H3q-m8E^H9~nfX4R|6~Z8&C+kid^=cY*TTZ|I(C3D{jQ<4} z$FXCpz^hw>Aaz3i;+k6D1>}PAa8v`(Xo~8V1DqBNt$}D7CHWXm+ZP8?cZn>p}QeDAC0c&Gc|IN`5DCu@*V4T1w(r*B=;gsVUBMl6&N~&v>N~@^Mu% zVmP%|Y`O7Pt2ETE(zO;5U$~ge^+n0AL)A!hm}QH&__mbb=iR3xE4<+T?bi69M9HLP z663tVV2vXY{DA%S5xew7OR=qgfluGN%~ii%jLya_dlGT(&eAm?`{lK=fKm+=^ZrF* z@VMDGkWgM=wSQBW!R+ujhm+_VJ&P&e4g|DY>V-nWAJ=ydWzwz*hx|5)yEHo5@kb@C z4j&gliTBW#I~x!lC<>r#=fGOh%8rw{#fx1Z4J^=Ry0jB~zQ+~3M0LhoVL=8vb|9MQ z8ejvbcc~}QR&r*?;WC{}MK_KW(1v5m_zvNArl%K-(BfHoLmL}{C68xDPVvog^73=B zQ88JSAvQlf5PS9FmLwvr)Ai7)8qL6(9tq*^N#|UpiZ>QzuQ}|2_799+a2wT@3n#=u zV*v2ihsgi#aY`XQkn;m^*Xh5B`x`?f z4>}E0tQa?@!?fEm6rbUyU^*4R9ztjQZ%vjTteDqpfM&XRN+Wh8D%7}Rh~E2OEa7r8 zvE)}w#xR$;yww^DrBwUBa8AsY)mhgn1uI02P+h{iJ?14_PeuT7UA2Y)FurYkApvd$ zx;JUGWVP!%sO-W>FL@O5yyf{!>{8EfP~&LAk8kEPRRxl2CJ^ZjUC+KjI?4$g(HJ8` zy}_oPABE2^q3%ow(K7YOZpVD5R&aOR9vD^=H;KGm;p8R2PVwEG$uA2hn> zpD;v6irlo7UFHuTO*5P)o6@FoUtkZMV}<${#WgN#;1Z69y``B7IYSmNcrFobu2rY6 zR{JBHX_V$SGa$$|m$8#6-k@XziZOBdF>o@p=O{+R8qvx(()q9j3;bc&qkLzMED%xu z2BcTQsIZvmlFioYb>hQPn8q7?YL3syfOzmc8@90cIoK_g3|G@H)(cEsUVQ_TA>WTU zfQ#fR4UbyKQZrwKjKlJ$UY$PYE*6Uh#T;#1(WKRn6}4C@{(KLL56mXJYpV@o%3lr; zN>+pewJbt#-<2;5wD!{@-Lj(6zb?6Uz(p?2Gqzxn)-?`b%T5n$3m#|2DCPJlg`6ZF zUnR#2XLqa(&Rnw^eybw9WHjJR6Y7RpbEqLf^~)HHxHCgPpy@l&9Z%e=jcq+I6`_2}IFN~zDJahCAF{-`sWhBh; zs-Tq#ipvXV5}rE|sy-C*~4DOZdELh6_=Xz1$5?eMUR(}8MPAIDOE#&IIOQsk`Zk{7h<+mcXt{K&i{xC6fA51J&Z`_WBp7GE5#2e-^ z4Fos*A&37ym2MH`;$J{BhA%d>2Al%^9aU9nrp2#g?m!F?PUn%UZhwF0Y;Xk4M1FI4O7=>Qyjs;o5P>@*5mF*2 zc)Nr50^v|&w*G>fU&|sGq{NaKCTD2pv|t5Z5pa8OgNL?f50KJuC8I{AcoZ&xN>Tw6 zxyMJRE$xH8g{CvsB=x~jUi2aAjqmXilf6)8iU(;6di9z8{?R}Vcp_ylw@g_{ETvm* z+=o<|i!nl|zLp#qpB|2p@2p*8p&aN^9V+caB;)Z-1FX_kLfa-k?x|m3%yZa{0Bz_K z7Xcq~?l;K*_ZUMfhca|Qg;@m6F-Ef60YKflx=a=g?ckZJq4&(w%6p)v0SRh1rideZ z*NI#9H@I*rN52*?3RIA4p?5Xm%5^p2b!OKi0`u9eG8P|H7Gz*91K|hBX}LV6_SV6F zdobm3t@0m^y3kSIJ$a`fo(`rQUZxHJMi-7kPEaQJV@L?Q~(d)@Uk-6*C0KWzD;O^ zI{lT2w4LI5CtMadyr_%eWtp6d%&nGi_5FN2dEtrYJyAuby@gGMe99!>d{9O8J{p{k z1*q~v&QbUjmZwfL_Q*>z(^0I-L*T;_bI9QdAZNhQihFr3?bdOlD9OH7pjZaAshf7t z0hsNu1U1?jfi5?h%<^Ek(A|T6eozbnS zo~+6Rd2(k99)+z~__}FBwnsdWBIoFiJhkO^8}O!;DcLPVNmzpzhWf$-9JC*kUH!I!x#!8EQ+E zb#H86Pm24+_X;6i^GlE*wh7Pgw2c1cqT%sUhMH*JK3*uH1uXI*H_t(dqJ+O*BdBUe z9z^hQrVU6uL_$SvyVx>ZF*V@>;gfB5e=)(;8GCLXTUj;9#aNOTgENcg`r-PIXFgVD z^VEGRm3d{a{bz_fKsS-BL`aYc5i*z?;&*68LC;-8pU6aVFN(|UViM3p;}7VOW-}vm zWw{YFW<)TaR~urQnQ~59E5C&SA?Ja1;K=0tB+98Qeb=QZd6Y6UX3)}ek<^6Lo1Qfh zu$vW4p!YCfIv--q{fF`CV47IPihOE;Q>DGwE}O=jo|FiZqLH#zZ^vj`!C1KxIjpE$ zs4~9WM&aE*aU6h3d_Ug3)K)%C2OE@b2y&D=^c<6?c2dx&-tuzK9P$pG^NG$)wXj}TSi|e-i3&&@;N8$7E zx6`ls=0CcNF#bKj5knMN+}qdbsZLcqNX%b&FcM-vPSLs`6cuXtVfQtJ2>2R6P#=t$ zXvNKKigp0_4jA?IPOiB!{$z^9Q`WptJ0(N@I`UiaB{d2e-x-YQ1BBP!>`~34 zKCY$X>5XswtNF(Hv+C>HcI*eg^&$8IJu62v33rjJE`dIdy#kek?g}zc1qw zxN*5WoKi0iHSW_CC)W4i2`U2prQG2{GT~C^5yl3|(8>r}icmOIz%&M#F`F#Y3ZQn$ zQyV$5WRjplBygY+>O7S$sdog%34g9KmoP!h(9hxqmVewaKM@mM47OZ!)UZ%3*&95* zS2D>`p^e>m`9!T4IK};Ib%=JWW1OABC6u%3OiE}$!c7lU2$fIxagRnV34O3M`F}I~ z)i0C}3srJ!In+y!R~OCJ9v3vTPd>R(8-zRil}0~B!uA{RXD;{1FCR6>3bl0RfGOfhd><2&!iV0Y)zx=8Y3O%X~xiPP&B$)KSn z$ziUt87Tz_E?V7DDnmU9h&>`N8EnF-M zJD7)gML7wKGne8#V7bE@UTG=U$Py}@J^|8BhS0Q-r5fethCx*_N_8ZlL#23(Ykq?g zy4}ElmHz*%fjr?M+mntLV}DoY@t_i+_nw}>yVa}=5;m!%RK_lQTfrAiN-dhQy^6%W zBOV<$gTq{W?coRlQgt$ ztnVQfwWTY5@Ite!PG!y>F$O}eQqgfnZdcfeT3g`%!K8rVqj<;EeSob(LDfPs>+X<$Aj+v!4lF-}Q> zcXpRL?&Pw%8`oDYShf}4TqT>r<#Kk>;yGl5;ATL07ns;8c6epyP*+Lgu5`jGi9f@{ z!1dz#I94VeA50(Q*T}Z(JtO^O6ukyPLAQYVrLaCFg?6KRV?CY!^ zyj5*0{+ow2xH+vozQUaKF|_n?M-^UXC4|sQ1|#?rxPb1EAC{&nmE6z=LCcK1{8PwgbTQrO~w0U8gpz zX!0KNgSr__AoU}y|HU`M@s-Kmd2qjc6GHw$x@w7n*mUWNO<-3BJCzk$xSd~O-T$W{ zAD8<$gut>hK|L5Cz=>1A8o{oqwmBF`;S0T}MkoovW;9c(q4%1OY8$oB_MjH zz>4cj7tKXwq9&y?>mAJ}0gTbC3J;!>+juLiiMg~92O=#K&8dMMy{zN0PsN$S74bA_ zMw4p;B5ZgXj>Hi<>$DK%m*AuHU*?~Z5$_(+WxE{`*uiNS`ESor3t>_$pD6lb4_J*? znpQVUs57J2K16$>z6l-Jd;@Ds?_2l@!$K8YGACk|RgjTfz7fJqhIvu(zqI3K!9X2} zBhA6JV8mKdj*pw{J|%lsbQK14RX7O6j<3uV00&V`>-kSnGAvMKt*b+To7VDJ%UHj1 z?OpTua9*^>3cDP))up$<3FU|wK2=ZX_!d5ggenW8geb!{$@pxO%hrv<-tT{(aia8d zqS=X%C;bU4L6>hr!?Kc5-}`2S8KQnaVerwFYb~cgVtf`z**TUVb@`W^ z))qe}A|Aw*o z-P{_&&m3N!oIwEN*gA=hw63S)r_Cm0H(mz|)SKn*gVrS5JpDUpoa~&T7JKZ2nU&FX z=UFhi=f;bMUkSj4tf@MA#ld0PGIDl;QLf(u&Xz*}Dt{~c(Ahu<|0hsJL+YwIG$wVM zs+u#fkyZ4k7#@qs>mW6l2{I8TL$twYh@AFaiF}<~jevfu$*G2>6IL~}D9UmmN&I17 zl8^}YLK?4Hcwu5f${U2h!(&;X)L`G`jjw|G*1?IGWPGtz270&l2}k61pp3KLPG`h(a8Yc(Y|1Z|jG-18QE;{!#p(_0EhlQjF% z#=a|3^CMw$ji_}1X!?F6e(jLp$sbe)Tnd>QWRe1&{m|YAyR?X81*z6ZyAZ@{`VlQy zm;o%U_dqkLoZOo_IjW=~+W}Go7>1HCyHx6zFka4u{$G$+V`_D=5eLD|tmYAJxKxfi zqX?c5J#Y>i`~csdZ+Qo`0wK22gz@wTj(6WziM8LH=&4*g`?b;J#FRW=M_Sot?us^p=kM!>Z2&elNefAK^?a+UVmA$4r69v#>D79e6ciF*SyEqgs z1NHiIK%&_m5LQpjXe-ff%|rI((&R%4#Wg#VN=SB|xX z%_|rxDTg!rc5TQSXMoM@GO>oODX)xFDJ7h$4*ms_e(HyZ%YG5q4C+B7}_ zgLZwZr#EL_=MikKyvA={IhHSVTH|16@4Z*TPCkDph_uyUlofoLc4K=NF?`iq4?h0S zmK00*6nPpY@kI#*Q5=)$eXI$Yca|F;f;^Yd_jMURg34cP|Av2*l?wJ8<8ZVF$MR&y z?7*ot01k(9UF+k2EL0}K;Ma*HC}RxZ^=VDW?*?Z_DdarqH^w2)@x zL3!4To=0<{Csbk~74Cxf#B-Zpzj{$r4te5V=~X!8M1ux1shWiz7d?x!izVqTJb#Y+ zBW*=6t-vHP=AVU|83YT9TBXRHwfcmMRnRFRDs7D>dh`{xUJRg9^CGA$RI5>jcTWVE zRFtS;2|sT7J6z_BVv^m!GoIyl@*HP|;=kC5v`l~w^-eiJ5@opgoUE#)fMPfQ|jqDOql0k>&G&A!&9VBeC-_s%+vq~al60n&0 zSzt*mTil&CNJ=Gd8vgnIP|gZ`X{tf~{zbZ0)nP!v@d~62Ie-w@%K3=G>HRv#j#+J? zv-=6FSk5-}+U#5@)SX}T){}=>8{VEt3cm~W{yinF``e|0e2lH#F{0*s)w7y*2-2SV z*0ENN&miP5K@UssmIq)ds?B5zXfU z$D&J%P(A1z=o;MaoxlJY`1ESGDn|Ssdb;D`^<(e3f<~MO7lFwA!FJ?cCDLQMsIa39 z19zl>RkB$ND11}xE8Rr*$Vjs?I5Lnbum}4H0=?79bqDk&4cZ;f>#gcX(qM(7`pt{q z-=8+2iGV|jAKS-oiuPWV!f{5ftdb#34Qj?d{Kk6sf*ftUK)nz&=Ev_T9a7FDYfTH84`GEjTQr+Bug%6W$cHWWf9Q3QoJf$%6;eqs?31;w9Q|43YdTAv4v zYrKLhneVR^e#lj!MpzR;ho0t47>-I9uG~Xl+%)=cOf@x$PUa$DUA4dano8|*;dNM z(TmpOg&p8E1(Aea5e&y}P5ig!j~b=hMuJ2q|JYk`1trwcL?Ndct#4kN<(dMzgZaBUyN5ObZlgGhY*yb&204sb6n;o2yKpp}l= zP%Xa9q79emv=(>4wW`5{F=|3W@(e^r z8KUdxjR5HktTM=)_U=xfR&OWI%m?b1*f1b?4t&4J)lW#jvG@9O<^y0oL}>xv4odN% zY{3zoVHY9O*`1l?jsm z_H#P<*en_g&P8zC=6`rwUcNQ2%GzTe$wW>_shIuoQ@;+P`Bw-Q%Ms4FeODrE8TB9O zq775N6$TSn)^QI`J;d|68Vc+5+Dovr08PO18uZ`Lp-ATnydU6DmRj|Ex%}y?uE8jX z4@vNutb>*NmLJn##|;<89FBo^`P3Nx?IcU5Ac1k4q>?jI9N`VS7Cyd=!ac?`YNpqPxz2n@a=LF(>;`4KonVre4po?wY2>T4Estxe&SZIo=2S|zp3o&5&;BEz@QQ~I%@;|b}`!VYfP!HDpv8VBwH%JIIE_jX>c zNvUXjHN);alk~Tx_eM`UcPI3_Slt@>0VYz%i#9{Qzs;l{^x;7NdI*=J4ibHD`XQa`#N#5q&yWGVG{a07l3EJb)%9cwR`-sRu9cQ==d;YoJw;ghM z$HmQ5kpKXWXp!+UkR0-A$i{TafwZr4F5^A8yk~jDX*@(@R62DWmiqrIr6P5UIh8)B z?X8)s?K@Y;pIH;;@G?5(s_q?tnyhlJ@pO=|?&yFC(vM?n*MXekKUT=^Jsl2fgP~=r z*;@vEFv>I~j@ZuFI)x1YFx4Q1OkH_NU*1-@IJ+Xc$fp)O%=Bi9UJH>;&3*z?AIxzY zqj%p3u7Tw0L}O@!&`b95^4}{7G+C^v)5QYv3pT=yoyFl@9bfK;%vvblzQHVt=6#Z= zjF>hvuW>W8E$ptQrTQP1SbR6Igmv`q{{T|>MMWG;$}c=5O0s9t(IF{agvQ3;9A+f= zcLJ-KsaTw_ve$&JQMKyGApYMYqx960YF*BU_IOCzb=cLy9REhhbzMvCW-!+FQzOa! zj04Kq(@~VsO%!OzJ2baxE~iyH_dBEW)=XmUe&i+;1>+x^0G0?rifx=1ZXW60O*k1 zos43o6}SfaJ|0z&uLBR%`ZTrS9KW{5Sv={G;JXk1k_{7+?ALA3)eR_uON*@RwE6DC zg6`@)PYnf3nj(FNi~#QwP8`bo9SE^Q;cv^tyS+NKlRK{^=GMPeMF|ndvS;I7lJmx) zwK;fr*>mmu1E0RdE-+`=ox^nlZai)oq5F;)@NQw|jIf6rxG**NF+Y7C@(T@9zsW+6=j3zV?Z6d4li(GP z1^=7Nx4~cmD^Dt0-vwZzI1!4m#;3F0Ve$}k;WP)g9R3vI;GRqI+mhIYnOv5e=bWn1 zp>BN3WTv{ZOM^MXzQM%fd|(xlIp%^+qD|yqV!M5UVon$0rCkq5%2c$J9VCnIN#{MC zGFJ`6*M%ggP#`=OQi>*P^5GGjXZ9t$b;pehEFkh*qOcqB_)}DAjILk)$^=7$zN`49 zR+0J974;h=#FRrp%!GZv`+CRItt}k(0OAV{`u5#{J@BaKW)99zF$Y#?EawxZTa7~p zoBMZU7A8MW9SlD|yY`AbVEDVKcM@Dc^rdzuElE#t3LM_=3T|BmZ(wN)}0%#ytARRqns?gFISBz!T!sUVNT8QY)7Lu5=Ly7^+WOIy8f8 zGo75#1wB&Gq~WMneh=9n@|t~7SsTOCoe8L*g0 zQ7F$vrUC5Zeik_xAn)Z-*$zkU^+bjbJMKMcf1?~Rpl$i|Jc)XQD1DV{#Ih{z9sP4Q ztCra5MHeu@3Sq)m)XJNLlwsyK$)1ud>pIipicFNkax!4YZ|AIwFv!E4ESnn6A7aZi z&7&imYtZcJ9&LoQ*Lj3o6sQ>ubn(K5g4ep6s`R1E5I{KO(ub!XC6W`zv<3S`%G+}S z4RaxTY)uzMsYyL+^5Ig2v;)FH%|rc2(ZjnINSoo(_k)&h=&I=zqJ?lb3>2|;7QT=Cu+0U7h)8i;?!BV!sgS0)<|10ce*M&^#BfznIF zK3}@=l42vA9^K|n=(9Wbbch1jDKgU3{>62D_KyRCJX}3w! zyE^ybUiTpV33=vC%UCZ%rYV{-i-WDmRUu+5;%i_SkDm3!oe@4WgNoDo>Zgb1o7pQv z^STckL%lxBJv-+cKMV#2Wy8?il#o3y>BE;IL8`+SIkQZh*a)#B$n^4TF9VZwVOp|` zB4artH#iGbf42DNe2iyvd$!r!&pdT%UM@>85G)R6JPjYh7R2rac602$@Pqa>SsDF_ zcf6*s)h@?dyM4owuVJQ{3TffAYX}Wb>)SQdz&tKCo*(ZS^)FpF)3?W%d4dQPJ_Rft zSg+dwHTT@>hbB>6BZf2YC44Wp*U{yan-8GDfrx5mb!|3MjU1L^S8;~l1;oI_&ziFt z0Ed(8?WreZ9@fyD0T;!mO=D!Y3XrAkl$#rx{PgZkq2Ro0>mG=S2yym{tZhJ9!$(-WYsS)64x_^f9E(z(F5QXyvDmSbM`n8-W z0RE0W5z({YJAAcYK!l%ne1%n&mLyNivplXTG@Yo@zjb>LQYA?gmN?|Km&4xjzVjJe zdEz%y)12@aAOr+K9fs1-B=sV=H2M)j2 zOM{X3ETVgs&>mOf(jY(#=C^I~J`SA<+9 z66&Xh;A_dQ|HhM1&Act4Ce8gb77I3I^?%{5NvZiEe*NkV;AB;jT%3WFCOEW4iaruj z1IOKP03V;4QhGD}rL?XthOieLa6MyQu+V24qMuK8cDa26mFXTF#51b*!6bWrT|nsu z-5b?a%i#oO;CNTRdQuFlIWV+ezc;KIy7BxZg!g)s+3@Qyv%olFx(uK0_|>@lt2PVL zI{|Zfjd95F{lA>k7u7URx7q#dkXF@XUV0IKj0+-?*tpL^#R?l8b|q%r&(b#iELbaZ z@+x%6Nr4VuF{nW+BANrHNHXsDeQo{vEI=4Izu(P9iXe89qu=x>KzOQdaFEW8ME9AT z&PJfZr=WyG`4LjMZ$EPyBWEfkn|I|HpX0AX z=wZW!Uy%iiUB7X^6HiWIGU#$zU?y8EQtOtfAWFGnCKkKSdo5Q_aZ5runE0{4_8W`I zBHxGcm(TM6n?TaQsOYRNagQLwudR8+=r!O@ z%@LBIxH5lu2_<>p$P&|vB+Offo$ze-CD!HTALacw4+?ZA;b@|vAI~&?3z$yldlw&? z8Cl%y5OlFU6T=Bc#^Q?b2X3*K*KO9qAU7AC9%YgdTc$(H(A|M8Bi7gv75t7_dXPQ` zv5VBrsJ=qHCA)aL*DVtQ)&f|t$n%oM;*+}KiV7WihQC`pRV-^IY5W9G%^9!AN=qQt z(7^3JMV+tJT^iqD*m9eq(S{ViC0=UZs?5p;vC1K3wtQ%=B{4t!VA->PUrh+mvt-Yg z-JX!SL$24djlXlzTbUcl5NQjwJ(^M`9U8w{EeVX3ocSIhdOuO{IKeuvi^&^(=}mY5 zg=>s@CM~Z40u%!x5pFw&UBacI_qNlfH2Tq^n0mXd`bfGMrb zueiOuPW%{jchJI$(fVZV zBj3<|g>SV)C%2{LcVecExv*AXi%bWD@p6b$fwa&)guVbln1tF)TT`7UNMLk^x>H@Hf~TE>TMw%_D0wh$L(y!!WV?^ ziamsg**W!NRc#=DsSDqxrSGHdBiB(Wv?)YM0HU!Uo&}r>;JoxHxaH?$H7ZbLFe)`n z+V4w`yqbP3H%Z)B`NI1(OucqErb|TQ7HbtBHR6F|yUHelhlK3s>OU7kygnP1?}S?S zKkD?pP|iP#Z|d5P^5R`7W3!Upw3O41+?Sa(sr;N;dBR@`LI*!@*!KPGI+nGCaQg8^ zO9%l=j8^qm*$eH)tW#tkMDakoc1sB`mXHtb=gfIxa5^=t%OLLNEZ7G0fSg0)x4Qh)`z9TE*(1_$blIS^l3{3I{m&|M4Giv-JZ?m`Ox9|96Vs>A?12OFtFv=FJl-X=3*C}(q zb@x;Ap8DVm74Fl9)#PVHrl0-^WM3T-@eYeNyri1-dgLu|(7rvBAGE!Tfp0(*deQMU z{l2QNm|+M6tzjhxP&5_99#sXRmZNtk5@M6Y$g3J4%au;r$nOyuEWGq?0>kO=BlK7Y zJoaE~anx89D*JOraqL)CbvWg1T5q_Yn1=YUGX1zn#kmg2tL>jy&adR-bC(B?hQ^wS zbgMrsmeE$BRVbL1pOw(`aQq4M&M-E4>ZS)sw1Dpi*=b{N_6~}Fo=PPKLCfXfFt1A% zlk5>Y%@Lo#7R)(`m07I?6Vv|WBg`K8V;u<$S|osAo+njj0U;FL(bp?2UucNlxpObQ#J2)dCHzH-FwPyve z?ASzrjC*vx1!O}FccKz%Jd5x;x6Fqn3nzmh$UUmpdMC#V3c!nS@Tx5UJs(8}Q2G}3{wx<*R8RM!ulB+(i#MHrf>n}{lmXpL4M(r5iffyMJCKN;)|u)X zmam=U(JVwjnL!$imIB}ODMzUQ3Oj284{QZH0Y>vR-weKyQ|j*ht9l~k3K{_dQbYkS^`!I8zCX( zD@l4Y*|NSFjh)o5%aXo;+(;~O9-yq`9YIJfgA3)$6Kvc2Bo1N^jiwsXTuSO89Oj@I zoUDb3NAArMxvBjGIztD4QiMlLdZJ)h`t6^Rr(zQm7pql#2*X24oB^5Z>8n!eULb;} zkVF9#!^=9CttrC{`?UrwK>z{;eC*d=)I_{K&l-VB*0^7eiWSc};l1*B)xCTHWh>J^4y| zz9BME$a|FNJ|yC#LZq!BT?%H@Yi;FFoEdVQAh8Wn>|%7noN^mj&8(e)6SV&$Qjz`pHc zDJSc<=34Kz7|{$h;KPz5wvt7(`y5tG2k-4u>TL_t?h|R=h>i@d-ce0*tC>B7s0^leh~#M>kQWRSdI^4!to;iat)i0>rF8%@p#limL&k0lQhiQ|S``bxbP1u?+JtS0r{reG3vgeVb=cJpq zeILQ3v6=yT)eGc9ch5&KZ0K_O1&%;GBGCHuBV-RE01m&NT6JN2S|0|V1%aqc4iF;ppARQhCl8LcS9xWbiZzUAWzNq@;^J~e&o?TCA%K$+^#mgNCD z#6+PQi6C*=r$${A+ohb}Ck5>xxr#R(4e46o3avNkw;CRMb{; z`os6Qw>j(7WuI6*Pa%R82{blHd)$kCP`&0l<)kBnB?s*ycjK~M4b!{yx6a6~P$)>` z`3+%Gckzi;SJs|rqUoga(X$d!q)Aw;<| zqyoUB-I}yYS|~)8#$A`$@g&} zHOahw%R&j~(7ekb_Y_y#42f&-&ID?7i~O}wD$gmht^lkJ`oElLqT_i*l>4RF-X-+p zo2Ra4&D#tUh9GB{rIt9C*05M5!csbvlOQa+U^2}{M!gOm^feW_IFg#um$)?AoTRsl zW<<#ZrEYncf18__0+_Ec~uL(=4K)d_~N|Nr?*>?wq?d*TVkzw&^oRwYTiv z^o@y8kIPG)6uTiWIeA95ADMf&|DR_TBV>BUkY`4$721S(1-)c1tLsiie?yAB zygnx?1Mq=TrV?>>kbyo7Qh09p(DhG3& z7`61q%$-DmZTPZ|TV|Uq#u-jy0;0+urE&)K&FL8M50SI?yRZ>El72Nj1U5K^>^CGl z1XsMgPRsV<{eR&@Km{uP#zD1DC~FvhoE8fXZ@5}-t~9{h6Di+HVx_jbIeTa$_i?qu z4DbPOA43w*fV##3xQllV@Qo4T53KkGW&$KG?)|!(zWd^9_E4wB=GQD5fYGF=;mqoV zRY=da<5!(jB>!g*l7L5~weKRM6#)3hV`9FJ5bDd4-D7%p_wt8MDV8qzBBopq6Cv%` zI=duSni5b2VXbsjke+c+(f~lp=!(+zTdGGNqLHU?nNDt>*xhp)ldV>HmnPgN@g6k) zjY3$_87;f^&;Pm#mo;Fys4-eMvbfb(HE>;@X2v1#i^u~@_ST_4mw?J#72gB;8ycF? z?IW}PjB=#t%q{gg)L*tS<925f-G>m99$wv+!Ag0)vs22aw444nm2`baGZy zv`51)G3rXWda4R-d>iG0VaPQV-=b2M7D3Ar+UIv#!tT>$b{_kF#HM!nN;?C@d)_ya za{RCtR0OpEa)KpH>u<=v8(Ebi_gx?8xKbPdCOK&-^VF&&DOE2olQLaB!|InzJOIIX zyN6`q2Q|Cu4TgY>UHY1&6&}3JSlf6RdrNbv^a}HY^sD;ZW?YkuoCNx!5yq2o>=fe6 zR+*QBdk_nLHNDhhbDUoxQRHD!#_6Y)YrL8;DpC)JwJnoNrn4#yX_di@GVfhka5{eV?+# z44KwDH#xAtOm zN_?c%g%q#0S*)H{=s(Dsgk;o$n?_Gylw~e{X5U_>ro{7E=VgEu z9FRNt_UP1Ac&l9i1B1s`;=asX8()7YLfrR*#c!)v&Nbz8H!qKtRk~=97&)^Tneu1) zNnpdE%qVjXJ{~FJ%f#ypV#M8h&#D9uOlN?8woM##9{t)Jt5>!jF6VsKBc}9g*nNCN z@ORA735e3TD4xpJSSNpy%?2Ux67lGFctrdjvuJ4icFE52LM3HbmJwsq&h%a9$%~2% zsY?+suz$Yt=7x{?J4l7p?IaI@=DB@S^@S2v38Mt~2b8Qw^!co~DO0dBA^tmnUdMg6 zv=xYistMs`U-6a$?lK|SmUf@79l^|Qd7k5D%3F$xF1wI9!)iW<|6`SW;J`>oask=8 zs{yzpz{Bk7(EHFGx$PwyrV^vLnBh^IQI%8eiNcFpTi)@?tlNET>+O@-V*Nx@`zC2) zr6GVDbeUY00IVUHPxgg*2I0-DaPX!dPVjq|9Od;k-F-?_I<|#vjb{$7d4*re)1b#z zd_RV2OSTOz9dKq^|F&Gq>kHdo<&@PV4NMMMui&Jiz5crEhQ14MYsRw1E_yikr~Iox za{;1mm3Z0CLNxCAq5Z7;0x&J22}U~m0}blow84@Ns-~Gkp*@yw{6L>2Ryqhx~FLPnj>9xO6J`cYIjV1s(H zX(ui?;$wp_6}E8Ju?e_|b$oo5uZ!HtcFg;hJ-7%09lV2A2nJP(z>)hOJdOX@oxhz{ zqsa1e+7PoW7-WeJbj%wb4Ri{~qHN|`n%dt3i@|>s3TC+W=bdd#<2?FJPWTX~Gd4BY zyyDDowQfqI6V~03V`2gusXX=oy`>)qf2Uec=;tn#E08*U8utdpT@IoULfsMlV7Pth zL;@LwpG5FD6HUFH0jcOydh6lH)rV4`tEaws%~Sg;l)AApdi20G5ZVNjbd*YAQXB>v z(vJ)nNH4rVC#FgRcnm;l!wy=z{jopIYp&W&vmDuz<3+}Qj$+y{W z_=svA;y;#r7+TeeQt+r-r5U?PZ{h!+{ZnH`Hr z$OoBP2Rbc-AIcImD+m&sBv)Wjg)iyxF3 zv=MXQp?H8yZDY{wFGM3N)##3@aBe-GGE*sOv<6T`EJFKL0n)B+OjD9_XU;Hinlu$S zlkP(R75Iu;GN*d$vlx6h#g?IBb|UL(refu$d9A|V;ygFW&m~;z4cvd7{PjhtRW6zK zIu2wd2s=#-vVScGN;Q{FlaODlW<*bqn5V1-N?}P9pghxUYXUGC^W0*$3ab?^gXSY*P232*6!xJyPqf z#YrH`=0$>p#1DmpuozxZe6<7C#hc3b_FkmCvydFC*LKX6+tPmaSL(<)G;IF! z%=sU6syOL{(d(_05X{;oYvbv~fgGYfrquAIlAE3%+W5CR6I@L`+~(Bhw8l0cT!zQM zFa|v56Mj@-F#8okq;D6+EP|3oytkdI0mV+*SzrpkR+nc9*91|bBx4lg|z zHDtDyO)~GRYBZJ#Ehnr5;y5GSp}pg2>~)OdYgHA8xP@e$Jg2D9*y>ISaB7he1pHnD zK>-aCUtAg8)-hvSqy!%tLoML6^RiYTcY|O;BhzTNpWvIDFrRfwT>}db0^9$RhI9Lu zxPeQgk4>zg%W2C&(rui@Ni_4USh;$J?f95wTsJ=G&>Y|DFMmq=?P>)c{XEyy86665 z?Ax`Lvqr3*P))C2`ApbDtC|Z>;56HH8pNq$Fv$rS|I+YFWR6VQqvNI^jPkpI*a|aMLD5qgFU{tk(4!pMj`}hi>%j1;y`J za7`W;%CvR-P=3255kU6;ExYK8R{H$C-X@*=xccl89Iy2fZxUp@#zjZWV)C)3>T9bv zUNGx>ZYl{2$uF>~g7|3$GeMm#nA=zk7C(5oG11>YzzGUE#Pcw2DPl*{IlQqHzCR6@ z6-beXV***VySlR#AKuT#>V2WlWlR(FP*u+#U0f>XyaBN~+SOi=`U=A{v}R5taH~J%lK$M< z%TqP7<#mSf-5+hw;|={xfDS)z)nmiL+Lo7AL6mn5-wBn0aDg6AGwjA8Xf|S^oF@21 zVHb{d=7^b#s!j`$e`Jv=$tlXvtNI#5`6(<2iq@bP7YR3}GF9(Q%uLOA_czW2!l!xJ zK08Jf?ZxO2W{Ci&1VwR0l*VuiC7^&&4Uj-gVw{$>HMWE?N=?9S_JUw9P=RLqVk$t7 zFS8pf8RHX^7I&a4k{hJFCf1<2AK$l1L7K_y;v?HYvOtFNWF#;yjkt_=TjX)1=7&T$ z^tV*tt7|BLH_BYVhW%D=9-}vE>=w!8QgwEOSIbhCKW)Yks4Q*isL{x`3$I)*@mS zdBZR1Q`e*yFR!+{r0&r<7n7lA?5UbGyD!gz7Y!HT98E~5c>mlR^#y-*s zwWED7hQ8nj_L+j#^S^}f4Pux3m(A|2M{Pmo*|@%MDo_tF1^fRujmba5AI=SG=ac1f zZ&IfE<3^ho;kJ`IB4VOHr)835nbzC9J{Z;jyg{7Le{&Cn$)(%G$9LH$lxua;Yk zg`f#zD(6nMvsj21lb0^R#@f~9zUcL$mac)U7*W8xY|%BCN3y304~ z8gG#wY4UX~tGsfzL*1(E*Bg0_8_rkXy(oXZJ5&9#zwH|t# zPm4({;dP$+1{I!sVeJxKnc}fG0|=?-^j8X_#Z|+|c{(2^9(&Mbg9V!o_%X^;wa@B? z?slyM*EvRe&rIzlF<9j-elClkO|T4fE9mS^(ZY{-t6J~Rw!wuSTLT_Og-t20a$eoc zQ{CjUGpiCfp`3av@prbYtrqK0XXSR4u@e2Y*`Hbd?wp@eP`;?WICL3zQR=P`=zL)t z^EG^L-Gu?r8Dj-{vu~{%v|!&(hj9`tCTod;QuL8Yo~}f1=p5sLkhvIK*y5~2r*-S) zBkMUkbBdpY;kB6k2s*O?A>PEMf8hPN-&5sBM#`#7#d%{FzNQw??NzQ{r=lNJse83& zyC4*cifcUftT$_BlQ*+CU@}xzvD;?9UH6j{-Ty6pU=VMM@IFiM{>0iqgr#_eEBR7c zWgOoF+fb~0groL=K%-;`b$twp*qW(cp5iwQTT8B#DiL#fZXD*295YCIAq*c(XpjXO zm}}0O_4rNjEb;R8sSjeM>VARt zYP7T{eZ+05#s$R&s}_l~VUOQ_{&k?c7tmbZQ7m5;HT5+aN6Hm10{>s8Yk3m5D9UNQ zio+{z6xanO-o|iLNjOy`)oGLCQxQ7qLkf5;fsf(8B00DwSoTF^eVn1veP!g~l#|_; z9TbYBiL9NHay(cRwF_2YM2R-e`7GeeUq7kb(_jJiS_Qt{jY8Z?vXZQbV>;Baq)&k- zH=;91dveUZXh_L=6^Z@Kk;o;tQ@pP&GQHqp&G4gMrKQ!1#L60pW@auX`3Z1Ot757T z0j(AuJSkkb90NvNmjD}9-u~Q|LWyNp=BzCNR(waf05nfNPpD_KoK$fuWr!8@EF#>< zAn@B4xR-9GdOU2sT^mwIcy;nCn8#8;fx5Uk5>CxrchCeTfkc6y~_hF&Lu!mpMZxxV9SL!ap8qa6vfM4J>p^%-BN~Z-{$1+Lr~03`SW-)(f3_Ri8J409*1GZQK1r5&+nHX z(nHP{LRah3K(vsg8DAh!8oRpSZIOFZh}A^)rh`W*biG}_?8_O8ss+u@7!Vj zg5L#y%QpBkDUt_4FzQ9qJb_qJw=4U4^zX)(6X|Lv1k=byb4=c#9c>8(wKGVGXjMd) z-Ir!(X7@8^f`^)I_;z+gKFHtPDg>28g+NgFjIno7&FBfv-zWBvQn4Y%CBhNqz+=1o zqJspu8RqK?h)+|nmcGK7LgELqb_A=JGrRM`bods>7nQ4m_|By-KfL}u#IVn7Wbw~o zW>A1u-*QVcXrt^|Lz%OvF;qKiuDzJtCRKz7Guhi71}TraiSXOD3>4gBUtGE|7|i;=O1gR_xFt;L0he|{!zaa+=sf5w!n3H$o9d)M!`kN zyvTjOZO7U-kGjN1-TmOXDm_ z`R|X$V_YL5UFsXe=<6l8-cP1^e`1>U9XfmU^N@ z7eM)-FCH?ncFPg9b&xWLf#RwYkVu3M43q_u&&q{!p)JMF7asSsrk1HltMruT$U()i zT|i70?l-9*$s6oEbsUwnpSo^l*|{kv=4H%+z+?S8IY(kk8uBq3*G-De+WoWd>JyH} z-S>B{@)@>HJ=45OQ@V37eNaA`N6gp2<_O)pT!9Sa+{$%P#|r_D?>Mb*<*^`=r(MZCBles%1JsQ&VNhY)LWq#h#)L$A$`xxqgsQ-3Zh(V%F90saLV$RH$$ zQS=RB?#S=~j6W#NK$Prg)0%t{xJM{28SHVSUEZ$VG{8WKO%l^%MKdpB-W$e`U|AB% z*uy(8eWuNaIIA0%?M;I8Z;2%m#Q69cmnV(;cd@93zI8PDXkL#W4hTo5ZNN3ww{ zjg*30U+(b_pyJnw15W3eO$dWxI-7S%G3r|pnf_sPFF@Rq(!5u50DUb6`% z-gDokZi$?csEstJZ)-;sjP8O$Lhu+!i3m4jf&Mdp0C$i5%vIYry6c1gxhaKRaIJB- zO)Z#l?m$?9Ths#9&#S>}4}SIYKIsol;C5yUOkEQG;v^Y2w_1E)S;q(CV;ZG2jaYbh zmD^9^qFgLqSYZo;{2h%h*5Woi(zSeFg?^esG{;F^1Ps6EonjKMHj}?kW#D7Czwy=1{#KS13V)76j5!o z7n}SJd4olqJttPN?%ZA0`eoBC5k)~`d?Jd|{TD!gCjwT}ODm9^@TqU8m96`lq$evq z6TpZQ>}UCCat39Amcp#rbCmW10u|jJ@d(UQY|#ZLXIuzAIxC`3cWOFgNM*`v#z&7N zI@QUiDBMH2N1>7-sqo%au7~P*zlkYNb$ki|zZaL70nvdGBlR=TNnkF$g1RHJi#eB7 z(lx4it!kLR6fB<&=LnuKb0_c%y*1E&3~~9>PNqI%CkaN#m2m6K zK6TBO!E53kBbuBg8(0LfFiv_irbjBf1k5)rQ9&Y`=VK5T0G_D>tXcYK<%$Q9Ps#xw z>Dwm>YyU)hYn?M6rVB=NmkAgIZ=gHtxV$CAaZq%(-dRTzxY1pAB-D-T{Y$vd(FEnB1+_i!! z?#^TU#N&v1uVntib_DA61sips7(XDkeh{k>duvg?mngu~HO|>`XHGx&_mbFD>il0< zgR{%H%E$MF&w+fE>PPZRbbvjjk`}P<7x%#85JgPxyXg=D=Gn|*6r(=3gD`cCc?*hE zN6Z&5{BB#AoRlCeYRmfjHS)v3eQ%e^aK=`BRaPFOgow6XCrH6t!VFM#PH}kb%)kxn zG9By$YmFdqegk;5rWII?(cX*R?9yi*95r6m4nTEM56x$62tdEBkQ%gkJF&pxY3;X! z4Mzw5`?Lt+cf3|!)ZWsTlV%br-CJ?NLLlg$5>f-&S;BQy8cM?N&z3-Ui zjg#3}TjZgspcS?hl>F58cAlibblvCdsq&a=g=#c{bYUpqK}W;h7Kk6dj`7XrueR~$NsNn>P{UBv#$Ns#rsB2(1=+I~Apa$VS;5Ux@H6}$7ZOBk!DoLdIsNuDPTumbv+@<496 z>PPc{MAX4?vG$n@!r88rwnUNwentq(0rU@6yAWJ^VHp*Ln89Y4=C*Re@}J`bcub6F zS`OU$w+cLSUbM0F+PbqV=}QA_kn1f{jhh}BbLczQxtgxa9_qr-j3u-qRyIS3Lg zx=%gNN&P0;?#{#q*$u_R$d-L=BHHRA{I8U-BI1l%L$>@J>@Txy_RbU8+PInCn{GZk zZ%hDQq4Nh~XSWbMTP(IleYx95gx~>AxGWc-s#RCL(s3s)uO|K z*>qX$eNAvYjyReX22sV=@Mt>yq!^-p?BRSAHtQ^5C-Wadk%Br_|1zy0y{gI?40g% z?%3H;;sW6MW>l8uS=CSI5CnplglLmRL)jEr=FDBvWAGuX8E6qJ+7VKCd?*b>rw{2r z;LkN}rngAx)|(-$kd09>8CIoakr?sC43-gvSk<^QlX4So&RT20TWnE@po6rdZ`S?!eQH$I3-RYnJ_}t$afM&lxGbB zRu5CbM{PA^1-PU|N(cW)XL6nVIeU&>qVx_8o^J$Dwruu{pm@xW#9o%A+5lnUZ3 z)GQ>Od%EIc|Fe$}crZxUav$Ad1&guxizVDcWeQ*hx>`2sNmr5$;_rsxb;J&*T{(-S z7ywb2lMD&-#%1M*D*orr&tY2;gc23PN-5<#6hj0-NDpUdl)os|s;8Dc6!rX`d?dc^ zfsj&MRy3S4TOFrG!%p*lR%h#x0;~vmp$mY(#1J;&(YuE|0vEs4jSnnD{p@KekRO!> z#zYgl?_x|@i`k{TQ%EmP3~!HAr?Pvph0PMHck>ShQ?5)y&Lk1mk_+=gwnalE^9_`N zibn4(V2Mia+Cl#3e)D}ooA64;g{AE)7zn|iN;?&q3F8VUw{IkR)X0kGog3uZAKYHe zqFC>i(SGq$HErSfy$6XpVjXT};F6qNY2yO|1!ZfmgX@(s&h=a$lN-;AcWy{mQyB$DatYwW*|o@lk+H`a+_` z3TMl~>86?Bg6CtT*@bAzWevm;>zH0qv}=65`uN1Z2r2ja-BBl;y*f_<`seVbUPN~Q z_fWAO+j2BdC9)Y}gf>mb`K3YBH{_(7;X~Vionp1rh+NF5i5FNC98qwGaGu&Dj)^U& zZ#}iAG!ITC-eirC((42OVtX!3V1Q%GI8c}X_TZGfWoH^VxW9Fj727ifcq+cGv}U&& zE{F5cr~D})YT>CWqUx9YQp^Hi9bGx$Ac47%)wq_?N~=SE+?g}0MD)!C2PJSVwK75p zDbZiTc}bEz=b|w~g5* znZFrKw0>zl+9v2#R*irr&M^&$gOP_mN4TM?A~ub4?23Zh4Aegy(&HUXum_DxWaHBh z)Im3V=?ii8O+@^v6U>BXA)w5T9b($s4Ku{ggjdJ}>ARa*jr}>QPa%jOh8EhM8{3d| zscq4u6n6bx#iIC$rptC%r~V{n#C4R@y!DB6KF3)%(B%o>(6mGX`yv5V^UGD_ci?Tx z)ct!%5Ol=Zm&OQX)k#DM1ww#6I9Og_TIG-4HBqdZNQ(-nUgt@x76yaHRFHL# zLnJdIgl!>0251Nv?4z55*N&Dw4xY?cX@?+BIBmm3rJwrt}RiPxh_Sf9XY)int$FbVSK_tj_OdV$|q-e8`& z=l2Bu$INwAM|YME3IZVJ78u;JQlwat7^t2*Vluq=wj#kKA7wg#Ph|i<;wMM_mX%q} zs#xs;2CL1>BCLMEZ;m9 z7($lWw8;ft>w%sV4l0J3Ib>9CoIzs{j$@kD>%J1XFqI0yH@~&VLx5l@kn~zYr;L}z z7fYty-S|*Wldj=CIAh|{@U|%n8?mxZ;oQHX>80?tii>Zc!y4_$FhnmB7+j?}@T|$L zh)1_(0O+1bqE3tZb*4=|-!ksdgp9W*a}(uV|KDk5ZodpEU2&7WIZ4ETgRTI1=X8>e zc`H`I)D$XkWwu7~S@s4>l@kvi24Hq`X>B&!rMG=YckN4kNY)vtLn920&qhbG{$ap! zpgs?LX?<(cWmap}R8-OuyjD8(X`k1-cwhD8E$WE`@vuCH2}+_p0cno1*sQo!MB_HI zTC2LR1a5usig~FiR}yVAj>bA?GiOuhm1cHg00*`KeC{TD<9gWEyvGnh`davJA?LRf z2^)|P%PVQ6;Ssj?xVT+y>##!#kL>P2zUpm+?VvDnXLZT#=pYA5}#^HpF#^(fK1QB{%PzM z`NJb%Hm4N|8*a!WCj}96i+S_0h86qLXoM+=hZF6wsSL{ALT%ywlSZSUh%Z%@PN|ok z1jz@8=B9}fgKv5YCuhGmIMmVDAV4QrHn=i+>bG3}A_d7AwxM)tNoa6JR%2}EN^Ti% z|B)PC$bNa-+AA$@;)RxF3GhuTdbmB{_bP1ylbcwPl?BAGBm=W}L^~crDWnlghqT1P z5W9^)Rt3=FidYtNQQXbrAMBMlPtL6|<0FxI=g<@F^;xw6AGfNtKCo7NMfuxR$Tygh zf`zlE%95d6ZdylB8lAxvCEXt?(xfU*%mi~_Y=!aKzdB zoP^#L?4oaP$uZ~Z`%!?&v0=E!*~3Q%RsSI2u1qJ%Er@H>%1~n~?ByZvP`1BUX|cMA zDJm6=VUxn3@B6NBLAATY1HwQ@^2D^OU;lPj3-O#B0_}dJpY-5vK&S+(M%?84RLkP# zqylDWYuVig9QZ%}#^vfO{}hfYe9q(Wp!GX9MU}w4_6Rh zDz>e#_0y>QHS&-Hx;ELXx7Qy?W3m8T=oP8Ymbb*0kDb#G_ij&E6R^l{yp1d=c|1hJ z3ioaQzomIfW<_YwSe|F=jD~_-iuN@(z~xIOCU%!~y};PWl>~cgtrgn#b`6(B(PU&4 zjKO1NusUt^#2ykwoB-bcX7Y{K|5kuQ*B#_}rFIL+p6H^Z2=GxlgH(646-}zHixe%P zAhW#NlxgJ9lKG8rmHVHSQjLe17Z7;cS^K{yT@%1;c|@uviY`eh1nuRlACl);ZrNeb zEKOF(r;=LD)U=h3&Z2Wrp(QvB@NkOc+4%~MKkmz3@#Y7Hx?JW@U-#Kj)@kw(29=j@ zLY3n}r|LI6xCecq>r&mwcb|N*Fz%SHHWo!lbIat>->g;rehW|#(zmkb;dN%k9$-xH-gqAg9@+qA%utgQ(w1?aM7g0`{s=}N!N5^(b!D-kG9^lOKtP6{Nel9 z{hBsxnaVA^rH!1+v@Cat;@Z1iKn6{v}0*KSuY+J@u6bCnij0P_9#z zYq9Gylj{~_g^Gi6LaV!*0cSHea*y8Aoj!ktb(ym4zV<(u8m!P)mfomb%EhF{AxCHp zUXsW0Tz49Z;5Io+>pm+rbl4pajA8BVO~l(Dh^TDbZg={_gMn{}J0a)+y=2#7N9G|v zegh0PyrThN{{Y!TiT&SLU|GaizypTZ?%r2gyEVOm1IC75XvyhuN^Bd;d)Yy$CNW&a z!`4eFnXvz4U0MY~TeQ6pm*n|iQ9PZnDFC()SY9`SKW$o-G6{kRuNb3%c>aWI04YG$ zzjHZlf_RF6<~cmgzU89Hr|}qmix99?09I#MVSCubQW?rzLi7?A#eTKB04Hh6aznHWnr;#GpeWU0OjiK8T* zX<(sjji^8!kdi;2)3x|HDo47fX9Ny8F_@xgmp|XsJqfCQ5$!pVm43=8pQn6aG-fb_ zr_ry!X!Y0?AZo6dU;Xr+Iqp0dny7;aR?R|MMK`6C&olhu_Y*73J}g6d3bame6_Sbt zl|Je6K+_P3BC`gi;-7nnZRG2giGKo(=Z;nfm43{2KVY`gARmee%wwKcPaPetgPTy!yy z^gJw((Bc($9ubAa-Gp?kcE6`z`k#M;@=3NXl=9xope2YmtfhLl{eksAqRg= z@!LX-x7PJDq{7mtL4Dbf5IKJt5MOIy01<095mfPP{M!l~f9x54ypkQyG0l#Wn?2Z% z;iCoTa6xgis}ijwomV4?ReXB3*Wm>0njtC9R0z@jg*Y|PF?rzVh1U`|7hMzE=IU^* z(zX?XpG5~a#JwtP?gONAr(>=9(KW$v7;_`R9aJiHEsZ*wotXiz1Wff&KxPMR-)Bn_29@d5ZvLc6f`l`*BHio(84Wt(1?#bYNJec>E zBDQ(;%Rq4H(M@syFV41pO~=p3;lHh!!wt1dEga#TaU=ODANj|H~5^F+1O zZ6z&}11&6^hjKRJ=Jk)qUOjr^RWXG9cDeZGYIylPw*t@jQydiVlp+VLWs3lzB}2`q z46o_25J*-KiqJQ2`^|}nd7@s<+#B^nIyAuV(Qy}2Lf{`g>s`UVEE9w3tlkZ&qql|MytJ zdGH~0!WE=_M}A8$%%3L3qg;T+9a+%%t_z3GPw2uRfyChc0~UNe@P8;)XJXCJ<8eXQGEd04(ZfC2L3qa*NtL1pEg$IjO%d1g z``#a?*DeQECk+ZK%fz&kxJ3zSe%>md9 zjptb5*R5$+(6tJyj_r5#qf%!QhK70*p5aGcgt~ChVi~)rE^NKkgX82qZA(nH<`SIK zm*>r_&~KxsjgOaf2idLJi>j;BJUcpbXwbXOsDjV3Ll^l7scALow3`FYx?X4sWS3WGWYbld|4Ca0-#C0Ba>7l)58?XHG#Y(vlx3$6IGu zOdlw`Y;1k_L;5GRP!&<{uLI%yH$W;yL5dbra!}O3OY~8$W3(XL8}uNrqpL5)>bE_v zp}CocM8?FNCLHz5U)qugMX=KEOWv(d+|C=L%}Vn8P75(>1_>XusB2h+Wz5Y0aPmXp z{SMqnOR;Kfiu^oy3j)gsnwJ7NNrM$ORFRw@ikPq8IMm#v@dHaq8tN7=4$1q>yGu3# zf{MhgP_M4kaf;EH-)EDjzaWkoQf3OOEV3}q0bQD2Dcx9SLWOV8)9P>WqmV37?kIpg z^k2YH`#i=CAe)}dwsw<=P;BR!oR>w%X;b7UZ)Jy3$Zg;9Q=yg}8cOa{ysYkLIh-km zK6f|P@VQ*oEFA8~hD#6?E8gC~{q(Ox4BZwn*%BcX`mca|Wv&YD(02ZA`#xzbxTJGH zJB*wG_xQ`@hBxy4dbimJG9K7qvEWJHYSr*>LrpRVd{!?UElljbEA2h?#}dU>HzAbG z4e9{KlVi2&Mfe1Cwmp_1r+xcF!DBm*@Gw2-&ra!_WR74On*XmDnHI=)AmF*KCDHTA z^N=UW@msWAI^pL4lVH?l9XC?sV3n8dWyP_6xclC=M_dL21B8(~XW^MIzSE$?v;q!Z z%sgaQ-)d8GdCm(J<*9(+I@jT@xx9iJqsrL#j~4gOQA7v2b$IV?GomreSToWI5}70E z9BC8KU$SV_k9?B_R52W^p`#UblUh=s-w8La|SXcf6VDxdi_#; zZY7dd`yGSkF&akZPZi*c%(-yun8;i?5d*WU*L64}zLu69uV=>aSp8`b za=bh>+rWE%%1a8)Duh&Ku6mca_U+k^nCH9;Q9FQj-%irfEE#HFKQKz<0|3H(I6n$&?$C(P~-4a2#6rZ5e6cG|C7+ zM=Lt^W57b}j>Ib?{t%}w4F~Do`|b`!+i(#38%$z#0R-$sftNEcm$ zQo+w1AxE%wRZQiVC@IVIxbN(!;>oThfdgLOCYPyFH}%5U z-BY9H1dS&*z@lUFLo)>KjO($Ushkt ztdmN&IXipNF2;ko?a}>bsd;=-si)ihR_B&(xtmgqTtcIn)Gsc+4p6*aM#jE!s#n)M zQ=^PxwK-|e5G7u2x+UGl=|lB%@)F=hgGyNI+}^KKiV@{(vLUq#9FGo%uskLhWVugZs-r{mse zBIhLq(=CpBF970oOqfjWj0Eyo2`+nY?JHP8o=;SpcKzcF7A9+fCylrcf3ax#+rC_? zm?I~MO>=4P!n8FUE0g;ZcbHu04S+2I$P<11KY_YH$t#IJq&*9pigSfEaY=cU=i|cHZhi?WjzaQn#L(uf z^eR`Kk=O?MbGYk&7EJP!OhCVhO(Fv#6$&G|bRyM-`s)%^x8noaWD5eB)e_wDiDTTY zP}z3Xz!y(@xUH%LvtiYjBn+mUlsqx7i|<08MRgGmu0)B1PXc>U7*V|MoxCvlEBQ~9 zbIX}(@9Jb@WXei|u-B=Neu?}{`;E}QWJP$wKf?eGvdE6)&|Q%5 z`-k)r)urF_0Y-DaS(@Ky(YV;wWJnG4n6|&FD4|^34}JoJUky)6PJ{)m0yXpCWc0i) zR<#rg;x=K&i?Bt~It@W~)PcAem{lQU%bZQ`yu-5{hD7;@5-(82vbeLY<@o3oW#$PE zX;RZhNa83WCB0Zt#yVZHill6$wOXu2l~bqn{49>cwOUiq(O_UtSa%{wcnnGYS_kI+ zd?UzB7F5Tyga0@z30xW*M(f*m{Uda4pjmBcX$o@rqbI-XJ5J#u))3iIXG~2_={3@C z*VT%O>Er|PL-{@bZY=1Z%DEBs^oPcuNjM|;AQ;VbvBArYoe}A#q4VF>hxz>(Q> zuk7RyT*a}+_l0e?!WtZ;8;ubZw&caUJu(0-+ij6)kN_@0=ycaV#7OTV?M-9RJq`p4 z5`)o*v-!k98tv(0-kM0ll(2losrX{L*z*KPogK#&%&uE%lg;Or;|aV1Y>@bDQ$Piu z*%vX?MOcLQE6s!*lvKiPfVGj!69w{<_E(1Iy#++167dtd&S@$jFD?$_o$y_-aEuOo z7dy^BwN~{`K)~yAr|>b>(E%=fepvcl&yr>&!q*pelgQxnsg?jD{!*!I&#iXu&4xmM zN?Wh)w_%f+O=E%9RSghXx2yH1$S6JFd1wNH^7iU|z}T3of>u<5Q3fMgtX~wMpkiSr z>qj~3iU2hNFds9gKuXD^6V$mi0we zQmShmYBND&CdbEarYh4ay#rq=!w)`Fc2oO)^U%O}I{o?Buro!$e%=&oj()!Z2A88R z-6WWwPjVKO2oS0j8?v_IyrKPdn5GS{Q}cE20vIs1UvK{t9aO1p|A zUoP+^uv+N4FNc9rd+;C@Y8FKM9xj=VMB2mG*^6V28b-QCEGA0gElKg#y%xx5#RSH|Jc~>sN(M4IhaspG&=wEyF z&QmH2aG0{fkSd*62PG_$ubEbq7yCcjtMo@F!o`QbCt;ArY78M;k3ubIT;PDBZ53%C z$o=tXs|(V^?--U+OKYmX*$GyOmWG9qU+xbC{9vVS&JP&yP3duzP+%7@EnD-{s~yjG z2>j_bFVa2>Ayscqi^NKwFcR)O9?e&jKud^nEpS&FE7m1%ZW?yq|4*m}5kmqRsfMj^ zegOU82t0x+o2wy(p~w@u!DrcG8^Y)Gt zbT#57W4qomvbL#(;7%99EoG(asEmZO^ck8v?p4y8#LYf{(#6QAw~0i*Ykpa2Qdxrls0j9Q7*tG_o9C0bW7pkO3|=aFc( zosBq8iPQU0WD2%fTqDH>NW1Os1d@ix1Ec#j(k59-AJ)h3j^5t}7Rz@56`=R&&cn0H z_%7Me>wjc|K5rxfDZ=-A`+QM{O<~6-&+%mKWX4u(iAkkpHg$$%NYLRqB<%A2_zEd0 z@a^BH!3CY?waEBIyL_-!=EA*_3~x^qfAKKrK=#(5_&|Q4d4=0Zj9v!BKrG0+v~>Tp zuCkcwUr^v5!^I3V!_u9KP9|QTZpc*Fls<`Pj3G~uBfWj>(NOcyu9 z@(v$Bz{P0A6H!ih<|N7~Y|n>2YFQ^{;f_J*FCrKkob%R*kJPA-z{phb>q>n60kME!k&T{@bv5??ctWZt>Iwe`n!7> zV2ax=c7cetK)s~OOrTK15O;m|1gte-o)>n0pbxnp#H`B^i#%Zi%H3@yLmbPd6FG!N4LTQ@Z;d28jqYR z--^y&aMzOQ>2;+q<1Sy21bsj`-A^mSE7u!hR-ZDw$!nv*2KeDok8q6Mxc!*>$AUVs zu}yPqf_;zzALFD-#3pS-EJv?FL}MvI^;?)!%6#@xoxoQB1qZc%J6*Yk#Ul!GjhHv+ z8YHIwET&yKt=wvIag$8~Z;4JAIN_?iVCi%~#E2pc3Dj42KWahp>^@z^DvuxH!_gmg zEo)dv_RpFCe4f^uOLplfs+O$Jc7dA2-B(U}P0zTsc~wks9EQKpdd;mAb4&u4nl*4D zsglLpf?X8&8a-UZuK4?77(fsrykv0TQEHTQQ6@#@!B%mynrR@H8@G)w+(Q{aTkD0A zj_%d4O)^^Ny7^!orQEH|jB_jT!sQd${&xuK3sy@XbhOaN1oBai*VsL8UKKh|r{D|O zxJ&+z@0rHIQ{NLvvL&7$Jut#!(8Z!l&Zaj*LrZK~k;98PR;vAXc;ttMTJmZ_UuyfC zDpVW1%F9a}7#z-}n*stW`+KM;NPcGXl*Wf&C5WC!&1y@Kxs6Xvn8c|1Wb1we+(mK^ zttkwGrYA!|WbmUI&QO+gy8exiN*~$xYHLYdV&y#EyvA@#XW+`^n?+E_1E`X)6StxX zc#ji#t;z9qWU-~6VP0rr)h?hW#VrDdwgR&9C+})X7-B4?Au)==$1$rh%>p~fG0t^t z-RSf#fbZ_&p*Xq97WTT1n&=R5Y?tJfrHKN)G3ajl!?+aORO>%IoR)wH;03IAhj)fX9Z5v_X=@LBsX1S z`EFfw@iRPchyi2DoVwus856u$-egO`E^?}3u)TrYIt@nVrX0Acjk_Z$^adl&h5~z% zrB|*g0!p$4B_H^aP$Pt$onK z=SZPf^pW`7N!IOB8=XeReeA{LUz z5Y7$c$45(O7GTTt5OmI`{Dl)-lipWPt8HW9<+37~!q7K!rlVfw{6E{!m_JDUdxSMu=m(|3%@?VI3N3u%U+mt)s`eX`Wp5@SSF-SqNBZI-Ir zQeUhq%UjTak)P=W8^a5=a_z!qjo z@z;$LIv@=QU~)kP{(f$LR7dgNx0;`({GkbrS&Lbd{qQi4j~KyQ>N1%aCMg=mA^!wK z#CUqOB)FxVk*PKrH-(CjF@Dj(ScQ}g_;ZM)U2P%8U*g@(w+0n^cJ4s%eeGc!ykLRe zc2ai(ZX4v7YL+?nt3I%Q^W%_qKbXj-fAvW`3|w2O%j$J~M1%CAKs29>dX4ewhax+an-)lVkQKm$U|ygObV`)U zPDK#pm{bBkV?4hOTO&h#h(jL_o#J+ChF7C}NTHXmsdqtVHFj(_Ma9Tx+a^hX;>fP+ zw6#`=YSEth#{0sQtWbKP52$^B4Z~~cBo*t9Vg=v|3k*UQ&DgXH?qs6p8^UAe?tsg} zTJvT*fDnlP}-_j1qh zp8rxQLtb@@5$v!qKn;0zAktq71EJ@yu-wjq{FD}krlOmAH^Yhjvc$$*2B@Z%S^6#a-_bH5aX8SZGIR;FRt-$>VTl)0I`fbfy;d{ z(Jw&;-Pz0Y_*6e1bOXWDy%z&3h@L?c6TpO2_?MHZb@BJ02?zzR`3<{k2d_)8DC~F| zq)Pk@a{FgaRjj}|SGn@rWH#|~MqagHJHezkpGXk`-6lpzq9jSJ@+y%h8PWmFKpbYh zH6*(_7s4X2exG6){X-X-a?%>p^AN0Ncgz{Fvxi!sXPD8JVyZ?0;TgrcFsnHl2 z;~O`RRRWBM{lLg~VUU(&*0%?gN8gZU8EMbd_(VJl)3rBc0~GTi6~P3q5-xyhBorp> zyUgAD=M^szflG@Q6&?qty6$sZh}%p%tDV#gwNsSuL(^Gn30Qk|)Fu zqLWivAKxD{)3hwjT}J7YM%Ip~xJj0(! z#9&CH1Br-)YpSHPW8y1Gf&DQ44P6MV(n~trPXeFxV_9R#)B&&ls}gbF@eYmK806eb zij#+yxoxe!G|3r?w8ONJN&rn?sW<4#>0o)^buA?WDBqjP`%9kY2Pgt5>Mc&IJLDyg zgkz8$b~k*mDBdLTa^tHftTBYBWi`vSF{yXLip?5y44XNdgb| z^ZU2Ck%{InvLF-z69}TjeA6&(U1yh8i3%45r8Rn*+EbwNW$5VF=~*5ZuU)*1bo2r- zMNRUV%mn)Hl|K^Ep%Y+{y`o^Di&AAv=SjY%;S&Duc&%c|-&t9cmZ6jS4*~{0hu-2T ziYts~E99T4>2RxaL9^k*3TO8~I2A&*n~@2Q5a(+cUsYFIJ z5q+1wNr1OM(}wOCD#I5?j`UlsQvMHkj8@mRa=~lT7@eAo#u6o>WXSMGMdS{GZ}sjH zmM)>O#~vHM37W!8My(iOLaMEdFypY#R&x$XLOz@!Z{<8slzmbN@@#qUAr+>p!(d_tb?vE~TXG`q(j9W_@pbDDmKkg}FUfzE z?{n_(Fu{a?AH`6}b{aFTc8HB8V``Lp45T7I?H6T9@gcbh2*kmf)#*zH0sAiy+jG;D z^nETiesVF917vZ~p?04hC4t8@j}&k3|26;HCBcsQo=#(%+9k@W(&sf62mgX%qEE)V zq=hRI8RwE}MYVpKgTQqK=H;$dK=cVlr0PRM@f(xB|C?|hdXY8O3Yu3^d6)->HDu1c zGc8J_?UUOaR-xEvp5K69t9Q-c6cm`)~Vy{sp&v9?-A}p>e6`srdCZJBS?a)5%k#Cz-D#ODkcV2#WAx;j>y@ayP1vv&5 zkh!s196fZ`xwryYs9}Ja%&Y`{NjD|IzIeqthr0@b`t-{rF6MNCF>RUEyy|<%l2)= zzB;P8WH?Nlo8vpq;UAEIK2MO$V>M*@Y(Rn^-+OVAe7=uCcrX?d?5|vhZ|%i*i38G zqGvI-NR5rXc9@0cn1?NCm8AoU>btQ5!A6BytkCr`xb`o&`=kp?fy^sK6(4-DT~*J# zze1%LSHfCj!$_~8uNde%pakg`k-*!hJ(oV+5!|%axBPjp0LahhtjBuOVyNPvWsz`$ zUfze7qBhp2l8oPwI{R39)o?JaF>>+WLTYqR}9jbb*M1(-= zU_1HR?odfIqMJhnWpXF4jIy}KElLwjqy}KXhHem25%U16qIGoOk!=0Y^AlGs3OrKA zhZ7yUk`GRqrHCL9LF2-t4mO(GZ>kvq~KX1gdzjvcsbxFq@^rc&$}0&1BO1L=uvO19nhU8j+(^BiD1b0 z&>qq`%~Kd^1acZ&L1r^xv*XZrorZ0^I`ED}fwmD1@fh8?%w4S_+*mEYzfFoib;BEC1$ZN};Y#c#m=Cmz4Jq@F-0>CBob zMa^35>&}!N0j+UrtVP{(6e>GZ0x&tMB`kS=}XJ09wsSrmmsps z>u$fmkzt%B!Ac&(WN>P@WDMYAS*5au6cFkg64sI!QJV9_u!I3Gc6Nxl%uVTMY>t9x z(v}zc`oKQc5taaQ?q(fMA?wk(ze38P*4(Wr`rZmV1;(kUzHrMy=FSfEmMf_=AzHW5nS->@U-^zTDhTOj{bF!F#?4DY*JT4sk_Wm;pzQqwa52_()92 zK<9jPn)tVcEe3J>yAy`iSf=u)bYD7(Pgx7X)BkeyFG^|_0D`*`c zd$WSZ=@($H|KhEkJP>&-^9|0xdjfG0QDFi3fBOt+MbX(eRMJHN6rHCkwtb-BRCDS% zZKnQ|!_}v1Y&XWIY?3m0DDd%(fW%v)6A^7vXP+Ak!WYNc*bX3I;IS2A;H5cC7h<~o z9S-oVG6VX*TUvor3;a*t% zdYS*bvf}5LNeYrod?gf}P4KlOKeG1{?jF=*REEL14t&UIb?|j?LQN5`)HT+7$@Cck z<)rv0rj;(|K0cWd#HjfbHHYIuFsQ7&V>mu%LtiY#;N|lACbnPH4c&@t_BK&I?kW_1 znWzGmldobtQ4o;QWXPb0&$p4KJHSnb?^Z1+`Te5S{sd?Y@bn4aaMeW4;=5Spy7@7z z!~nG%+4o?l?}G>g^F{-RNmW{zof;-1e6V8Pb%CJD8=mH7K{+kqDh%7|+iD2JrY}(4 zq+Zc%olkh2s$+ihm-s(o(%UW59ey!%zDx6j1$jBDar<90QEeWjaXv>x1nTWry}3LL zNm7YGNh-#j)HpJGh%A|dH*SgK3}T(#dEnRr@A#iT{eo4=>7!?B{#k&DpjB*f*5H1P zf}-2a5yY^wCYCt3^MCDc40{;kn;^rf_0~D`DktY^m^JJcP-Ia;TLfV(ce|gR!HFQ+ zl)mCf^*&+`xiLo4rkNz{d?uUAj9Tm|Re+nCe2~>bQXnJR(ou{%aYAhK4S%y#E|;=f zp+iJE+%v`1p97jzK?g_oXc$hv98GdAg-lz$fIwHjk5QH4cl%=}pI=2(m1A&AY9wuh zy!E=2d)gR4o<`aZs{CmO>gT;6`|@>XPpDOsmgNuU0td6}&kG@K%UXnVeuEWDIydVZ zDaZc=d5OysYmLUI31pM-*}MQt<*}LIjOf|9{46}dosyKdcm1JBUoMiMGzom2^WVwu zZ(aN2IA1khFD}})1Zfii^;wa-dK8-2{~`Cv4RA_!3o=t_9&??hN&A=?{O~2){R<;$ z*36b%+C3R+MTajT&vzv+#Jro!?a^>Xt9T}EjiiW^PgYqJm9Nq#S8~-}eHKuZ|9iZN z1>qm`V|7n!xAFAQ9RUs2H~PV)RM^7A1j+?lSbF=)<1|m7wRCQHyZo$TWDjmY01B@U zP0(Fz8(3ER3%ke*D(v~3%Hxpb*I1vV8TL`?;h1KH50QvOw$?TsP3mPBS_c|n+58U^ zGqG{~EFTj>;HjPC0gv9YDFa@w>Wniem{`7-Cm)+UQ_zh(f75x3lK&F4YW?HhCP5E# zCY^y@{js>)Hr*C88Slh=seeXrK>!!-2rn8?4)l_ucJ(p&9SLoxlY3Sn0^OiC8RT90 zzhf~qfcmt@FalMGhC++`3*PAW%hshD2YeCy?f}y0FDP zV0)qgvk9;|I>{itZS8Q6uqJOSoT#hONxoNH{xEDRrUqOo)ji$>s1w4nE=pxX?>Jgj zb$gYCsqaT@c0!73*1nQ3n`*MpkIlP%Zbqf0=m1%*m|bOYnGkYd$UK5Tl8+cI!22^Wwi!0!392H^(`@s!UPKN-&JM zA+Al9PKrM7C^-PcLNK$9_OH(WD98}2owqz_t#Kc_436sCcfYpbsnCDaK_S`4FlJ*I zS9H74zn3HvVDc9Pz$j`Lw=PPj6c8+14Fm1DV?kTl<{;$R0i?WekFGiu_}5eF$f$nA;Du(VdIf?&X}6& zj*%>pQF=2TEV87|{(|jpCQBd+cd0dII5+zhSxb<;yFW(uIt-2Oq1$XI7_@)105?rtH2iedV%5=i&)Ti5sziK=d+=pmM*oQHJP^u@^fk zU^v3clhJr6or2Hq#~qs>I$-~)*03`k#cg>Uu_=X)DRAQbpB!v-XQ}h*Vub;Qe~D~t zfZty4o$aIzgT#6+~h{ck<&62-7l( ztyLr~#;!0AV?ahLZe>cP#Bq!yVn6Wx9LO-eKe-Li8qlc2#}>*^4HyOewEq-6^7V#A zen{nN6XT}o0ME!TUGbrRq!SlD($w#v7dOmV51>~_WwVPkvjtK(%S$g?F3;wpy4_qM9! zc=WFGgG{qmsx{9F4$rB&NqOz4`*onbeXZg%^a-+%@vd?%1dCb=GEEjspmAOVHvVy_ za8k(TSohO(T%-%w8K6P5Um`TQa&p*;HfSU&ePe~+eGSptOw_+2S)P|L(tTFT8&IIU zh%N){Q7ykNJ9RchE=D2jdJ3JtL4+Mnsuf`x^9Et6oi%erSv`o}*(81q`I_E!Mg zXSn>+#CGy$F>a`cBUZ7dhc@XvU%p#@&Dp%vAZ6_O2fG~C^*rZH?bUc-0Q%LWZ2)8q zx`Dv?ISO|W+IBVPCIRZ=c*_plk!k3O78; z{I?Cx&hyXFFW$TksQ+@Ne4!kCq>-I&Vl4@rtK`Xv(X)W=QilH0WkCm*WEeM$oDzOD=lEiilrC=(%V6_YQ0b#KzV#rtgJA~5|5no z8=wmz#LPuoE3;*1Rrw64@@OyqV^$(;MS>M1(Jm-vtjXSx!B1;3P9xz5t&Jh_~wPIae9hgDsSYb!T3N92YXt z3lHW=EXH;jhNFQs$v{aM(E$a2xR;;eVb?$?{CGi`z+{U^S?(49x<*2(m8fj}Y&RPq#zL2H6!%JpHNj z_3TVRpCl4)|59(hCL}w(XOsuk$%{1Z5-6aXA#nFv1P3e*<&lwew0fl0+_uqwdqkV` z3s{H%3BJ{q%#Toi=}|7y-1=%M|H6WRK|Q7&ua$g3GNFGAB(QN9KUo$7B8*5;9D}x7 zRZcZOp1iasBs4k^Y2vM|*{2f>n`px4L}xii9i~ZU60CaVdSlT_pKfJi{^RH9NkfuB zN504mQh+G=;g%5Yi(AEoeFg?AGZ)124uR_eRPgfc=ZlW_<+S!WIM?j?gng{GdTAv} z^8tnEIMLARZ^uGiYv5C}!}Z*C7(vYhrPNzm_cz;pa#uOyj`%kzjCI1d7u!5q>}{$G z|M&#@R&Ks~@XqqYy-roBf=JC+4Prcjb|vva?D|9t+igjF-$*ta@N*-p3d?T2^hR#e zLonKJmsu5M$_=9@0Oo#iYw@+xprz&u%7P>dzKdjyOCElWL?SM}ghe+8*VTdD7^j>X zeA|ENh8fR$j{to`No%X7n*1gqiqOP`{%->y)x{r|*AJ_A|n=L5(t$zJ> z!(LDpq;B;1tLt=M&&^RSeL841BjEWk0nynOZ?4ptGy3}@8R1`s`?gQ7(M9GH+gI}P z7-q?+c;jdx1AJu5vB+S6+jqyy%>{~)$@IZQwBU7RB1YJ#B}@xXSioOc+qIFlDb$dg zZik>Rd_IzUrsaD{<;HbW)Xm$~`-^Xe+%A-&(T&Dn+T2ivUGn?>A3phCHtO@KZwpPA zIztnB%Jztpp}y<+z)b!*&TZ+yxt91i|1S&vQEop}6uIC`}C5TSRx9H^M5=5wPK&d6S4ZD-aIy#uKFwt5_(RsUx)AzMQ;)S@HiXUzPj zxGse{mS-d7J(zI;tY0IbpdrPo1>H7e6~)ZfIDlGJ`QB?(qosuvI4oB2Ei-@%F?545 zu$p;1>%{rt@|!bWf;_tE(f8AaAYeSm$ed;__j25S?l@p~2KwR#%3{&*NPIV@sNiUw zZdx$j`1xBkKkOB+&_SciEZqYc-6ZjWY0U{tm58oX9V}^z6J>lNPlF$m7LM^k`Mh0j z&jGx2D|qRP1lME5Tx$(!cMW1Km?!u-2n?c4*McU9O;a{0r*3sR5E8!4C4K$9#b{~( zJ-w5M(X65QTmlLH$*O+|4kgyN>%7Of-N}^2ea@4#?BNwaKW>fcl59FAi>H-f^EgWO z7Yxxz6MK8jP0&XgC77lwaOKB5qJ6w<>v`T3F3?5#0Dxu1QW>nlqmt_i(XS} z71F6W6_-Cr5I=7`O20{s!r5eWi&Pi>GqUrEVwS&TZ@Y6RBCx8iW$moDsrE(e?>*xA zSEdFwHS+V}v(X{l)kf5j^O>VVVG zd=l5Jh-Z6Aj0TI$lgt*LotGy%BSon(#F|g1Jr-lbi@=lCNPSF)&*_FhL8>BS#E^`I z0hd?0*uz%0yXyW_n_f>BHmaKT*+_Ftz#YM&is)B=BP=s7bEBy)^&i~~KO2p1?aJI3 zWdg%rIKB)lRa&`HCBt~Qd+$*ESL(wtcnxnmlvj`~#DBd&CbMjJ=B89!n9!TN(AFN8RGW$)S4P?MQE|LXVh!O1di z#7$y(RZ-8@xvorxJ5TGj0DDY?@kYP%mJpF0{}Z-dGy`hpnct%QPA zKny=4%7k*7;=8n&JEbGOI|n0~JF^;s522m75q%JkN9~(}MREDh(zvy2|7o;X;p3>+ zJStC6QI%6ULS;)+JBtvLT{xhZnWFtjZ@`IPHM0(ji%83pvX9pzKm(hNvsfTsI(baJ-M6_vS z*Cr?GnN*>M>uRuiJFTj|zoOUCD~2TT{kA9YXWm9vDg{DA(`VWb=6B-xLi!jNGfPM! zzgGr$ip4hws|kp({gIVS(ro!BUrPI4i~4WmbYN?1(`U) zv0@jS0RaL(xqa1pQOtZd635**!j#uhu-KlwfCdN;{(8=cLmI&>?dT(kj~nx5q!4k7JDWiM$0H98gcl)vH*Y3;*%5dJFDzeX5W06Y!SfWPzURDXa+w4{S9Z5W5J z>Uxd})-16{NZowe38moGyl>>bFpHGP4!Ms*j!qAk*)nXbs>z@Djd|Y#BoXK&N?t0R z#G)*TM`~M6jMu5JkyweKwwFZj#h6D$Cnw1v8U!FHcHX_5TgLv1I0ylEtZSSWq7WvV zyA*mP*RzSQnYhrA0#xAm(zF7{2MtxlCtS=Dm=@lIO9hk4M$ToMRUtNBN*|?We%ga< zHrFVLVjz{^Gf>y@F}`n7Vad-ZAu@l&;=cbJZK{r0#J$+kKWzt_o=Ln}&C?)eVWez) z3@==-2DRTKQuBMD}FFiLJUu^s4xh#t1^HiyvQMGJrGR zCQPMXak+H%P<{@Gf7s5rk^6lSVKfd&Jpjq3E+9j8Rfu(sfd5*(tz+B>ufXU!>VG3$~ZBSJUgAoh~^`NHRR%C1nY}MfC|3Z zeHBy2X3Pqki*;s@AKU!~rYm8ES(L)xLLqC;yytIcb338Y#9WaS(AFFc(WD8TMqHqw zJIZw6Uq{SdyOyp%&Igtr3CI2JlgYUcjhqWfz_5mcO>~4jsMD@8z!OTr;30H%s$yPF z1{F?s8>6twi|oat4_)FWR!(@dZ5wBx;pH7Ec~16lCX-D$MnwU>#+-{dl~MG+iJ|`o zgKrzco*u!T8eWz0GLLcR?6v*%o@t{2!W#HD;7P!p7|biZ-rhP%WgDfM@l^mrK)k=s zNVqF+Nkq+7QgH~N_PcrcZVHoc%Bl4q941}lH_dIH=?eaHP479!jw&jiC^L=3rm}8i zeQsjbAHGs+N*S%ypRv$(%s$9nShH~p?34gkA%Bt1mNJr13 z&vZMu_S+A2L{m{f;J}gMMG&%eON0!ksjly-b1PAr7P;fXP}r2X;;|6o92y10y3ta5 zhF>Q%ptoA|@EpE(rH(r)fGl;G?UlT80bU}n>MRSzvU{ehM7P@6dMOaym{sJozk8%U zV_VQw$P=NTl$WzepAL_URM*!eb}5v;Lr!&PWg5s8*|AmEMal}*|LHnhx8w33G^7)aiY&U)ajtJh2K(72n zDId<}z#~LK%70MIKML@Y{kUo5lg@{{u)j7k@^tY|DBAyNlFggM>< zp;i~B8cQ|c5dcaNrawW>L)|LgA?vKC@KPZqSG2EO`99yZktTZ5wc34Q0rSMEY=V^*kDTV4{RB z_lV@;9Gc7tX$aY{*X|tPOf_2qc2F=b>zb||$k9p4aw;a-D19|q`K^|}p?nC%qfR$w zh2S1RKdTZ!(Q@L}B(%I2k4CUi&?TWlEM`te@l83nFCnw`z)=Xx>x@}>)0F*NJXjfu z#;P(T2|qXOkszs?HP9Yyo}}YBUd&aV_;V=fpD#_njin+^M9a~j5y;8_P5bC6FOuHh z7D>Ey-SK2271VQ1ln=+utoxbLF5QRpXZ!VdhzGg93&yq?qxzhNZHp;L)QB8@Q4n(1 zV5q#Z!0UF$-#al;DR6+_!t*L_1SC6eCdFq;M*`i%qHa#s~U*-VCVWi>9h zU4VOD51>L!WRi?r?vy71Xk?(Sp0=ZiEG$FUP$EK$sIkPBF2MzshHM^2B4dQ>S*FLt zD0@CXf}=G$qYdVhD_d0XXNtjYrRP2Wahb^o$3^MIFgpjXq>v)q{ceSpY;2|) zy!dO(R8-R*{phjY=EY=r$6I4}ZuJX3QK_CETA@=6Swk&xp0E+&sxBRt7m>77rj_e3N4w!3_?o)@$Zo0aHCJ z1y}2<-r;py1YjlS>2JRV3lw3f~?Gp`-|GNGUoyIFWz^1?ZTD-EJ z`PX_xvnyzTDAqn2k{GH9)FT2BD@N-ObgEl;T`2(xSs!jQ4)Eo$5kkfxZM;DPaee7d z&p~51D}B;GI4zD$i9Dm4S^w#Zi~hJ0)-?Xo3p%B5Z24Ao1k&zY%X{geMCYU%DA3NN z$iMn4iC=rJ_#DpY{R|Qt#F{+*Rv6SHw~=f=dYm+3`<2mLelUmGu@hU>!Rb0ihqJPh z)=tztPKO$HsPq{=Cg>K*>LqN6$b_C?tdD?xx_LQQ`#k^R7|yzKzt$=bwWnw~?0CDF zY?HdMb=(ylAJz-Jke!~ldYS6kkik86Y|X?EG&v76K3XxvIU$~j>w)I$z6Lw9=%6?s z^B%RfY_fnd?Ds-11euq1#KJb2oXY!b37Z8KpnCSRmyuI_$L-HqxE&0Op6j0;Og5VA)$ijn5F2>C#;PAq1l$=n z6B`CL7Dwqji`?xQm-yL^fFDr_4e?e1ki$uT4JX(sP=Jb^Suf0qZ{*)t=z*i;LHZOa zv|_JDTc0*%zs4iv@;)E5#)5c^F0+gv_r_z$F0!7=?t1}(9(S>*&GCry+<<~`t_0n9 zN%7jg?`U*g(f%#LP^I}xn(DEy|6-nn_PFdJI_`WxjB58qrNXr z9wkua{RYi}7H`b|ZNPP$yuk8(fqUSQp4!rH**--+s{?jHS^6rDBu;LP01wk79L``i zO;xJgJ`^!&TU2E$141`8@o!Q(R04MJ#p!nZinh-VgB;EdDLC8vlHs%0}uUZ41qZIa;WcZM^|nl7d$=23}jf-GzQ_Z*Av(Oa>aKwS0yqy;I% z%zczTH@bJUWY#xt+1R3ScrlCKV|Edr8HD!F^IGb+QQFJs&>95+@dMBwK(BK}qB1q1 z?!kXU0)=}4v1sQ<3hneM8+ad;&h&fV%Wy?_Qy@~qlE0&*MCS|6xAw6ny&wm=MqF(E zR5bBuWjsiNOm}zN5QXm6mQr^29W*%bLnBX%useg! zH@hgKm_7$pftQ>s>QLGjs{TnFfC=xIp%un zZ` zo#bu60RA=o2eoMpRX&;SJHix62RVN$iO5>9p^{Wtz*_ATJSUH_f3hNcn|mJYyR=V!zWypH&~kH{;%~9T#rp1i-l;4{ zLlH)b$0SJ~h#d?pL|`|FgZ;*t`dvD$?>)GT0fw6-T%Z3mUgp=-I;~7*X&~~GJUjS0 zO1J$HhRb@YoW(BH8J4Q!g=!&0T2eot!6%Ag<;4y02AIT4a8`-lvZUnJ=(?zgCSn{VnQ~lkObnK&$o1r{1viJmY&kq&Yt$3L^gKr z;t1(Vslb}46)gbzA3_b&7{w)l1F_tV2n}1OZ#SfQ(+o#l)#i?>r1F~=eWwW`f6f-Q zI+R-vU8!wQ$dWF3$X01Q@AP@?^7R9St};Xo<1rOpLQZ3)T>wuAx?-<;;VJ@qS*9KOyCyewahk!h>X z4Gt#pYTj7|QdbEU1i7q}=EAbDK+mx;$N_)bNFL-l71=GZ)y_gkNjz`4AZQaAvmw?F zN+okfumfxYMK`E;hz!Qtd;YZP6O-CT3NN@IMP1W{PBa424dyndlL~}%1jQEv!vehi z&%K&ss&ori__|P#6YK(F24Vqfi2ZZ9+ME|XHcAceHMu`L79ZKthqZwre zwZs_Nw{_ywr#_`@4<%^$n>@)_q2MP;g!)-M0n1QP9sbA4_!a8qN`GZ|#)axDIdk$L zZTcQ~zE&bmsA7$U;Zz%R_6+P1LWzhI{q$!@oT3Jh2MNDc5Yvh>=LUA`wxY~XJrD=b*>RWcl_#S@30+(#De2b82T6ho41jsA1yGtwX1R^WNPHvhK1jr z@C@8qwYALWkbnH>aiAm$!HTTa*~y2)x8O8ac}w2m7R`zoE=MY9fK%!CC#porCY`sGTa}?qwF%H8g&WTPkMx05Di47-r#^>tP^c+Ni zg4sjgc{#of|HMnK%I+e*(z1BhC?q*kkk>H0+QAT$CiAra7U5TMziS1a8qTk zCQTQgVW~v0j_9u0Rjc(~u+-sCT~9=@)m`rUN^b6c0OpZRSO{?8f4|nJ{2F`m*JbRQ zzU+$>a3dm6!~L1MUlk}lNUMU`bgGPQPhx?tVY7MIbx)AGvB8;lT37bns~#~5-3Be# zm#?<0FKitt)GIOxi+Ho8`{AEh+Cc?h1))1F=G;C@0`u9^AAM%Q7(~N(&)RW7z+(OR ze8O4G3N(@76FF6bU2fhH5-{Wi7~C=yuc{YV((Pm0f%7Qas`G-UKr*v0Jc|Xj^Xn{#>dvc+ zyi!Dpb&llGow8aE($XB{E9x4MUch-Wg4Jo)Gr#eiM zA!^Q;q%cyd26>9YDZTG>#y@!}DF$DKf^nePbD&;#0iLty&q?33a5sAymja=sj*aHz z)Tke}=lYwpF7Yl=!hwWw3ATPT@%#jTc`N_1p^-}gHI@@i6v;M7mqV;Q+IuXqd5pGZ zF%Tflx!Gl9`hC;;@8~w_Dn;{3CmPwe$4Hk7ER+dyTdYo5f|l9nQ=cIySm0C`raz$H zgkft~3qtj_DZ2@BdP-pB%aL5w6x{-cSgvtm@SDYEdWO<$;~zgd#xf- z7ZXwx)3v{R*(qY_kAfrh4vM+UxV#26^=s&|m1O42()~34=reXlv!Ag#CMb>d*O(j=HiDcHV_h zau{9ToF^EI0Ck@)Zks7&*Q+Ie48GfK#-Z-G=ZpEnk~00dy^TmTw$dz^z=f$5ZL+`Z z*7~YWY((dB5V99fLT2V4*O$An-xnxlmXOoWJh?Hp9`&Q9-%lluhbzNxbQ$bK}k(QX}z^T}0t6F43 zd%S7&?Lhmm*_&nRS9Vqgmpje=n__2lqXrEn#&(MSnO4mOf3~rZx}x{#Zw|S$KE)&X zA8He|IVBY!ATL|cl&Hi6cO9%v{rLnX3Q>Da;=F$n==pC>m<=9J1PfNlq#a7hBZN)2 z%Xb!*w@meZnrjgfx*~t{acuwclaR6%M=FQh67TbdiTB3Vf;@5lWv-NM-teR222~2+ zMO7&dBA4(B-A}aCs*|Ga$^8qF`ZBV3*ZxJGu3+SQl!ImT7T1QGV3>oIF~bStV>Ntf;;|a^S&y(az>!$kdZr zVxGpQ53NCTo~OM#XZa8yJ<2D;N@goswQsdt))k|pfX{;SyEz;KF>W}B_@0!O=etg|~dyKUY z9bxlB8`IxA{f`b!j&;MC;3)gI-owT*JmyMUiDVonKMVyO%8!+^FZ)fF(L2Xh3=CQztiy$?w0T z9YX>;*9BT?CyaAWUPM~_Y)#@CKJj0C=m_;_O?mas4je?Z-IfC8P%pKUE*8qdaR3#-z?N3vGdh@s8K&Ukz{5 zG>HBtIk{?}Cy}F^l2jr1wleA+g6N?$jZL>wW3i7VjtwsK$Jg(r)fas??cf&3(tfS< zelkVqxA_zzRn^jWPYaxgr{*=R>+X8W8QEM^;SQsFr@SK3pRf8u{+AzSlPY#?hk;;_iei8Cit^>mr)2%V1R+qm%)zSevPJ3)(o0iVkogUF#A7^SUWuO}cF3Y+}5n1HFklq!E~ zYSeMf!ZRA?V(FAi#_hPGfq@0h+Tee_5oZxM0_B27b}*m`;xz3CIOi3Gywsigo5gMc zJH`z$a+~49*hCLjIvElAGUq3$iVoW8eas7F363;YP)J`j;(7zseT~kEYSf>ai4lR6 ze(Bg&rMecy(-p&hS6JAxTm0_yVELV*)BPTWyj9bJEuhs*dP z^$K(UWvsV*T4~41q&8Sgx?+q~tyDCP-~GBucCeI8oD(c9kT;3>^?;(eT0ex3O1+2l zZDyzjtcXp;llFl7a&!|8S)k){D__UH3F960&$=cal)8p&rn7i5`out@j^lAj<52NS0zDcwJR9;Kl(r{0wy^FOa1tuoJAfr zW{z)R5l)_PR)QIDcY!SBJ<;Nszyyfzmg7<8s)g+1W;B3Pfh78=S>WRR)prXv(&>|i zUZWy+IcM=y-Z_i)x~F;|2LmjLOJa?S|M*ih9uvfaWstd=<8d4z+B;GWyZUt>FKlG$ z@+1t)LRUepOthceFi2r9nw-_M^@hPvo{)g!2Tct@5;-t19EUDfa)XM*Cb!3^x<5j) zyxxG|{UJsx^m{^sH29R@9XM)d+$3wwMH%m3;-AB*xb4PEZ?P#TSM2qpfk?Te4yWO` zqUGB^3*Yt)Gap)>aTO~yq4u_;n1(#w7d9xtS|Eb>k2d{SqurL#s6|P(;x1KKT+76n z_i^(&x&12}HRi3l7_eBsyKsTPcuRH zL1-OgK>`dWCJX{no(Bz`3{NoiWq(T9Q>T8y-;5k{WNT;tbI|$(#v$h&k(4YC;}JW^ zXiMjXj=-QS-_CA2@e#zjq@yTqP4@`b>ZA^qZtQ9AL1U%r_!}`iS}-1dZTWR}A88$< z7%ucyY>>y#dq8gRe&{*sKn-pDz&W- zZ&#%#ww@LEV?5xVm};^P*&>c0T>JN*dsI-RzE-g0!;)Rys)~xSiYixOpr5G8HM`T@IA=uESCXYPi&O4GBH-|uc;S>BW*9DxtPLt1GdQk za*tcRG0qg^k2(120Ll=jl(4+~bh2UWrX^e75{~^u-L}&*Z({WAZ6>|mOovi&YvnG< z4A!whanE230Fh0yVC(NGU7c~?(O_bry12Vs1S;uBf3^S!IN8bzW&J@Ioz``sR?|C6H zOM*}h>E>8a|J(n|^YT%*aFUlHE=mA_$~)z6IX}U7T?Q6Lzq;3Z=ohcFDa17eW)rJ> z67bz5>Z#eb8GNFl3Fe#R-TisGm63?}S$3Fvd^ez}1%_tcu}|?35Ou2a@H_0iK@nlK zDPB%wmoCo^M`Z+fvQkP&@YTNxQyT?TUpTK90f7BxNvV&?)1yWO$}Y=rKUV{<$pTEz z6bNimp7Of-3F^eSxLPg^c=vP0o;1WybUV^0C_Wm?`kRx1&Ktxkj9$l9*5cJo#Zm*}{N<+$X;*VwzKYPK)b)bqg!eKmfdS z#eY)2D>HN-$9H!=Zm%U_x?vR_7a~qN#DvUFEpeOt>fsesMFNJ&RYIRfnivM^i6*QY zdySxB)bF`OfjiJ>JmLK-+WXF>$we0^mXyJGaWbPFQ*{Hbbw|mO>ti%oa>WPC@MllD zcpusy0QDz{gCVb}+HFC{Uzh zty?EtdE@9ydf6-M6vqXaubVqi6&RPW7{6j)I^MNXEn^zOL&(q`A9u8p9+YpwzvU0A$E} z06wC>Yp^vULppuSO9{_KvUY$`qKRDjA#vVQbC;sTzAGjB}feMl26PT zq4nx9u95hXUeUXG>cqOLyV%qmc>Jv$--J8?ktlvZ*NHNjF32*5UirbXQ9+sU|J9euOP!X}C?9;FpGhueL>IpiJ#86&`0qv>R z52~)F(V8W%zW+{{rQnQ9d1#FbuIgL8hZLlyuw#&Ki08H~ZN8K>XW|gY77%2xUqz6P zuhH)KkGv4`Cow$fS=V0ZoM`7}P=_z)IdhRBKB&^F9=-;`C!}5}7px02K9k?%9yJkb zgpTP!QEIlRAZJxEmgbK_M5$L9R??S&u-XFr@|Yzf%k926j~5|b>Kt?3cScc;KFj{d zn>7s8k&HKl2eo~m!TU@MgyKz{ebbHURx>K_eSsMAI@$~0Kn0ix;d(^qZrj|JSy`1Z zLHWr*7b%WrZZp&N52WPEP}S)X%h?z`(Ncbiip2`6t1XapK0Y_rVz>ej6_0qs>z-84 zH&`s)Adm(9as%(8%Jbn7@gnvWOogc6=l(+d1{WJP$(I+qXnazMVn*h|r(2BMYndiy zY`B$$6om!HV=QyO6O3D4!C9qKW_f z0!ei8XJyP%lB98Hm+#!Z2b9)VSNVcU!zilRBHGuPfe{hQw`KaKWQoxR@mxeMXGe}| zm*vQ=vy=Bmb@9 zvSor+h@TZ-i8v~e0eTB1&`)8c2`lZQf(?yMyVJ4mcsjk!BEf#I0jq;8EMoOE;6}vH zEXw~6ESQpLMU6N443KSym78!Wu9dV*LOO%nQMoANPhe3+I{1C0XLk z3#)Sh-kRwF5iZS3X~X76f4|qiZ$#x}j(;sj_puqtk=YPPDrkQYV6yg_1fxdIt~sKc zA1UwI*QI877fyEuB$r4Wn)f8NK=X^CYE?hCvH^>JE4WN<<)%Z+WVVv-?*}@LzpoHJ4P~|8-7z)rW(5Vay;WmhHSo=TzYg306cIYIA$C&p{@OCYKGXG}z%NkgBD&8lwA%NvuE zE8rC_ZuqSr1W0d3KBcR4Q%hJ64^I@TXc+z!BC{gj6K`J8t%jb!E|KN(6)L0lu)JlKo)2 zn&j;qMq=n7Pz_zFZ>&;^5rUsXD^}3DLu9q(JVhg)LLR=PRPofa+`|*Z!5NjS^`F}S zts@+hpiA2plg5G`?(6oWPg5Q32}7;v4gZ!!9xTw-hl?&e+1_%pGC~vg81tiN zCVR(c^I5p#Zqd)K{@LrX6qb`abJ zs3+ty7Db7LkDcTb6bD{nnAgK)4MX&|((CPu6$HZ|`yt59A0@JYX;GS?5-CXv@!efi zhG4gJ>T2+S9fx~J8`0JcW`OC>{7Fw4+eFU}6D5@7m?TLVnH%gQxjVq4+?F+l>o?57 zCfM2M4W|Vyu-o>mncP@Xd#g^(bPgU{I0p&(Y|8B*%b&TLm=})cS9m_<>Q2TPONeT@ zD8=SPml#eF1(gNae=SFipv7h2oM5W^(aGF30?DRqV(ofB&C#owz|5uxyk{xF(aKh} zj7z!}nSAKVm0d^b(uc%@{`bw*(p8isXcl7_DWkglrOBb!&{}>?gufo;Dgn^RGBO0% zmZqD40PUb>Po2#7Lb3%IwsqVaId+ygmvD4GaXmp%<9KeTzF!11O)7-?EtLJ<1>WB| zcI_^qxZDkT3b!qv}kDCDZQTd&I1ehFpB_3)b?_McWc(NOJkbf-8cHZ*DCsWS!MY2 zk?Y(mOEQeG?UkwsD4eQ#y})eK0ygOW__v_%UXnJe0(+C0SYVqJY@Q{dr-j@6d4(*o=NNE*d4z5UAZ7@t{4ju7>|IxZBqe)^5b#-0NH z-uTv3{l?k7R^uX%9w$(%W5m;Af;Y&x{9w-3Mlc}osE(3^ecOKLkFoQQfA7`!+*6Rc zV=8gz*WLAvi`*um0|^&j_vLiG5p8NYZbmWh;-?UPr$-aGPSK%C5)C|+nki0!AEZMg zwHOmd>)W7#8C?lLK+eEIp!*O})>voi$tsr6ALNghh4`G=`N^w%y6f9T$T9h8OXU4a z`0R0-q=Yza0Q>coQXn^*V=cyju~cWedEoJnP(A@uixYKVch7o-OIV97$4w$Y{J6=Z zMV+M*3>F)jld=>$7_?Ay^ZM+#)w*wUJ~SMGa|$Nk?e>w1V*qoT9&|I3Qfq)b+kfN$ zQu8G;(;93O2NI^Hn_aa4isS0?@oSJOqy{SJU*2De3hS3(YXT7j0?vt-LX`x<_2056 z1&VHfM_tIjoDGsx)l)>t*93D2HbVU@x zO5Cx^5YK_)QX4h}Mm2Sq?7vVoeM%_p*8MrRFkEH-}zj9}#4t+4vn&WPGv zQ39&$+IX^06LUb_a38Mft9Wj;}dHtvfFF z$=&7fz(U5&w8Umw3e+JkkF#tKKN}cwVeWElqNy<4Our87=AnrqTD8E_T0Oq&s@)Kj z$YD+{6}<{B_qJgZkjK|DH^@8)ahh;fA3xpLiRwdM-S?L2N92ySTixqIYUQfy<;Q`0 z#X;|HPHT~Rp{A~y{pSiJ(yQ}2+7it07e&X zy@CWOlLATVKTk<{7zN~`4R4R2~fHdKZgT8r?AW$Irfxq^KF80(~AOS_r{E0f0dlNFu^^~mb%6P(K>9U z1&C;>kBqHord+8Ruf_|psA?k$6`r&THCH1!il{EWs(T>qdTF*F~8fn5wia z2G0h%gu}sEu{vv8ji7*4$!Juae4RXl!sbtAxdtE&ZY{G)CCoI2T_Y&%4UH=P00AeJ zfk#&{Jx&D7rq+d37M;4_btXgG73N9DlSI5Y2!cGt^?{Ex1~F%Z+~7a8P7RA?5j51Z z1ZZ(MqH*Vm_2>^4<5|i}H(N7QK=U{r5xq-O&k{!doL+A)Ow-66Ex@n9K*=qrwBpGp zh*-0%>T9vPNXRNORV9@BgdY_lxwk$N?z3NcQ|r}^nXtrN!RAd@%dvt|mK$&Amb(WpF4CZvYaE57O>jA?Z8kLIQD%q~~JV6g+nPWy(eW3xQ~+ zJ?S@JY#_Z;M?s2Z3F@izKW}X2lij$m=tie=;%^hj)-tiuPpdHM0ArOm-Of)zX1O^!FJu+dSw29#vA^8f&DS8LXw1c3U z$qZ=c=Mea@#73q15b8YWM?Sm=kt+IbRvj9$8d=D|F{1{s+H@@h8M~5RDT-ZeC|)ca z;=uQC7~K54bs4A7s(X?KRSNy9`n$U@et8e&f*sueRj?xq&Z!*Oay$CGLkwuR_85gl zRd>@beyy7<0D-Har<_1+{{}L{W1J(8i&g(Lt_IBA;qQ>5KXQdIt7%G{i3MxMfqwNW* zLZBt5z=c+Tis`iE7-H%%hRKmeec)@^476@F_2b31@FpnCsWWOao4GaeGrgq>h0)|b z#e<-`VlA{n1RdczIUTiWYoK+KYB*JYClh_hKZ6~{368zfH4-G#^KHCT%!WI>t9Xz2 zJ?+XZ&vU9j?j0mI?nvcgqs4SSmN2WWiDBWg=n7%(0{=U`-iX7W4F7D}zJ;#GY}0A~ zqLNfCJnNW@yM-)`X&W>l-m=K^%-PIh>*1%N4RY=VN%(sIK)$-lSmjO!$Em;*J&4R; z{KkE0(1jx8GW7P?OvY%q)&g6HE;&qzJ-vz^bDprHB%p(3WD8Hx#3mMAZDOiN9t);u zqMh-goa-7l9V&k)?!qsv%+_Bx9lLBv>E8nb2r6tw8%?g64)0e^+|xzmX5aCxl2S#o z*XgIzQi!2x*(aRVm7-SrSX*Y^;&Eb5daPf1*gF3FpaY$p)uh2bJjuG{6#t|s9{PKA z^tI2(J7U_BN!%ntsVVs@n+kSvv=wO6O}d;nw@I9MDh+PzutnL8R8}i17yr&i|2YTX zX6|h^7nLlp05muzBxkXu3UI}iG}>=wD(xS?yoD?#=K@!UfpeNC7+rrt_3I9;t^Gi= z_1glLS&S?*-nYO!p9dB3ESoQR-%_@hud{QA7?~-I0A3KEV&M^ZFp7C&ABa#@E^NVW z6}l;5%L)T1D5{IewzusIpDu%BJNqiowInlFjJ}vUDXgl1>6Ci-c$Sw^*y*lv;6GBS zyNQ5ndY0>qoWjaKD`EF z?r}QBzwl%=aB^+s)Gvf~P=PSDLS@e@4Bh|QZ0!3cBRLYbm9QEhV`(t^&i{E@-z7fq zRhFr(15+ccz5ka0L40nsHMJ}Kv3UFk*)f|WheaHbP2TKfi6wA}JIKej32*5TeS^y5 z_RN95`PJ!4?4qY(A_(m<_R3|LQl_{FU;W<3=xLSn-bsUR|2pC#Q=j+O?$wAS#v-wt zpY0)s0mZXrt1s55%L)N zLww_f*X3b7Skb_$fPcDwANDflU-@5U;_argIzcTDjf(C-Ba(rasm3?G|99SyLP`_> zibKFB&>Jx$4iD_gTl+`~>4v2W^gi|$l>XJ6*!@T~5xg(>U+Z4F}{QL_t6)lept zq-ax4prBYjt14?yBrW~9h)_)ceF>59d}UtUx}2j3ou|aP#JlRxmL*Tk{gWUbI^Gu^ zb=N1Fzon&?g4%VI<I@~&P8gder4D6`?sUg%iqT%QeR}!jI`3c^`o_XS$&3keQj=*KIbwpE-94C$B znBNU$MXtRMBQ<`XO+@=Va8B{1;`63;R!%-T05Tg@HOvNLF@SnY#J%kR!xV?Uo`9r3 zmPU-zWL17$*6uAN;V0XGtLHy7jq$Se9^0hWVnn__B-uD;*Jt;yQR@W4tiE-?u>IuW z6*XYPT*~2lyHv1h5ug(E>1kdo+uB0}Lciax!ox!UhVRjUs~I4fca334H_S~YQ6dnO zY3xB)_G~&u#S!@VZQATfEXU9WEoSt6lQ^lp=H z4-X$HcJXVmjmDZFm!pVA|9k&gLTd3T-Nv+FeU*$N7!ui8cA^>y@tWe6>#Aw#51i%r zsl{{fm%GkZBA>n3v-FimeBur)FJ{qC1hvIODP|5cW!a<0o)px{z*GkiS90r^WyVpw z7RC&XoB;S64YZKWT&>1E0%w=TpzJgNF({~VI3bBxYpLVPWrj-M ze%11A+t@A^uizbvQQoG2DBPlF-b*P}V`2*Twak;BH#6G*)Ue_hHz;JY2yxmYpcq&PhvLhb)qMWhK z5sCY9SwgQ!X2&WwnQNv1@DB|=sI_!e+Bz!ZrXLsDmBe~7bW%E^(AC7-MA>9$=vVezpJGTSQDL$Pi;Ol5pqb}hgW zh83#ZbRP%)vZk?2$`w# zd~W7=u1h8o_S8sd^xvxepvBTTo>H#vw+UszBZE5>oAbx&rBe@*;6V)@VT-NbR$d1s z7>b@TnQ)BGxoGdRB8_4kpzVcfW#nT@4i;Lx)<9xTqZXaDYR+xWn_eFw%>a+Ik(Lx@ zi$AwFYGR%f*0?(OfLT6rj#}$cC%00u13drFx$z)MXWfiySo%ss4wx`3HNC9F%~C;4 zF-ti*JPcciH{ruF!oD)|0-%O->y%R>REdn3y}Gy@F#0o~wt*~5dPczwM<%Xl*s$?y zF6c5g{gBm4zP~R63XMtm5hc2fw0R8j@*tm)xDww>8xy4`^*&wj##p(y-wBLCDU@_c z9Qy$w%=cYh=k%VQSIe^rEm*HZSQInHM zj2>6u1B*h_WLieFmZsSrtt+ooOsZ`g1XZa^1LI+p$ct~?-qdXqTgm65et7WWFT&Iu%Nnb)nq)q~dCQ--dqu?BMe={ZRTA*QJP96MCH5h^ z{q0K3^lS(o)QSAB`7bFqhwFD{pu)w}2{@jpk&Z4>6A^ru(d8w{Om!Nf1-q%F-__U! z_(l7Z_a~uQkP!YUY=1$465jE&nW9q6W6#C$@Tsqo@*zZ@Ut;;?BhPxU(?$tq;>^>T zAm)-&*mTkQT~D~C=UJ2~g#P(vv<;3^zfgNOLi|}D=w!KZ2z%2xVD7XVFD&z{f`!r& zhVPLmkk?N)MH3x;j?GbFmyoi7)aunm^G$EzAMT{b&EfGrcUZ%H&msn0I3Y(KCONO@ z<|qA~KA2b!JN?L&?X<{Mz&P+Kg2K(8-#&9Sn3V@79Ey(fIw;c@F(}X3xoJjbl2`qh zN>7lG&joWa8^`3EMeLvxlqhXNsasbcz16R?^sC~WHLQGq8J=b=Ii);6rs5gG7?wQK z_{kGCiu`}#Y5mFXv;A`_Ewt#gBQ9-SXoiT~jkbA|8Tj^6ZEk%b&5RQchfW(OzwWzG z@|E?@qBOK7Eobv1=CbibYqeb+6Oq997^5K0+HlxpNnO{Y2HHS5E}4dN!5jk!&$TA% z3}Hrb0dXN^j*YtmYX1yypsynwaPF~r1kCcJQty7Q3f820lY8y9!sZh&6PQY z3ZbMuaijXOYV{1)iGwA3 zv)wzgB=rON231c?6?rY5Os4VQ*|Kkn-nmT6Hi(2KEKg$811g?O)>f(`^^Xjnri#@s58dYV$5Wr*k2J`WAzBu0#w((=` zDF+;ZIVcG>BvNCk`)VgwVm}uI>!oXfgl_lqyh&mU=OruKc}UTVYW;g zB86`LMA_>#fS^M4wk)@?#MYl8ruL@3G6PB5$4@+4v$lu|+#78wI7mu?Kk(d*I_e-L zs+~oXGXOXIlYhdRLd#h@z)o&cwL+p${9)2>fqhyYIr+s85Qr{m;Jz;it|}f8Bmck= zNB8B`uVi&d8m?J>Xl^XrbGYIm6hvit?C;#ycL`;pI)mQr* zW2Y=?modQu}0wd(j1 zytB(|6X=)jeXa=;Ov9d*8GAK8@|%F9bmz4UY}Wy5TfcMFhc zsxwH!Hv|p{0|l)IV4^R93Ku*T}j zAG_riehbQHdI3wFCSySbg@6G6+6F_?#yJ?Y<*G)IW&GwckcD;98$v8vCYB3JyIZHe z3t&+{L04cqx7!h?h^{=n%{foE}TWc49VQCFqoC% z+!k!ev|B$}DIW8RSsWvmW~XX`I~D;~fDh%K4d5;@LI8j)PEF29u$!KB`38imUm8>XfNSF(J`RV-Ez zmwNQ-%{Kq-`koA>RM)BFl(Rr0HcRX1mtXO)|clj zaQ#Tvac)f>+Rh6}EA-sG={}wZ%}?1xL~mobwk|{X>nia$VDEcb8J^F* zr_|QswY>{V6_y3-ZWYGw?w7mKhR)jJ;|zZTQl1)a>I1G!x(J$E@qVV&D%$NjFE3f! zSZ7fi(GSz;2naw#!HD*a?w>?~TNu~J%&Twbpep|wkOVs1>J;vK%vU)Fbw~3!EXEc zniCt?b0M@ckJ>MmtzNTnC5^&?fROwr^SD*jTK++pXg6A!#bCbg9JZ7JCfjn8>$NTz zPP~rW%4&Fw$sM07r3SRvg?i2aqG= z7Dnao<2zMNAh6a{K88O>88tu^x^%4B*7Y%=Q@at#}akKcm`KyGigXrXb(FGI-9zg-wld>pS4W|xw&q`t7KwB zwfE`maR51(A4>}dCKr9rO-b);Dnje+2+uG*8)>udT->2fB}Jo}uuHSF1k`REiy^lY zmg61?K)GmjHUL#oE;-N@t3x^!UQWpdBM?1(n{UH3oHjXCnZN2g*|cp`<`|nxMw1+j z3oyUO@r4;fo`8*=1jtO7A`WIgX>IItqC?cpNq~k-{5QK#(pU&DQ)!ikf?H&HLfenR zbOFfz)UtyQdst>QP*=lG*Zv zB2FlJEW-)1-`e5j(Em&x!pG5iwGLl?7fz8^EJl+17|_Vz3uE+3 zZk)l6aM8EyL|-P|cWl5K(~leMV_Pl4yDnCFC7kLy**3Og=g)fS*&A&}L74)!D{@&9 zwHY`Iy^(|F$8E5LorPai1nqrc5QR~$-vECro5ePWkFvXv8d7QNZED^h z#@G<_7wpM}Y}KS&A7<0aZyFsI&G0wa^rpqmX#@7w3PusgFbOUu@Dfk+E_^^J{j(fc zO76Vt@J}XC!xV1hNVP@zPQTv7iQ*op^8Ras{&e0#(oYmb(!|O_zJCz3h0meg5wn58 z=5=ds+P*V8zJ6ei)&D;1O@QvnnLf=HwHfD3agifHxQ>uGoIRr?J1GTYe!B+c-OlEx0>2l$ApzK5v&x}kUF<# zU^Q+Ss$deh@v8q4M12lrcq&pHv)`MzQYAD(e)m4yrQ%CHa6-b@xYTn)IJA1flk=Sc^<&>F6N%I#&Yd2AS%lU zGvZ*PT+mLfFpFzlivH0q6USYzY-x>sS1Zpw1kJUcNorC^e*{3qJgb`gSm2dt70~P2 zfTC(RErs7p7>yEnLm&L_B^OJV^NsH ze`&=f!Rw7|HD<@(0;SA9T}>@B zg#;WV(Y#^i!lA#g#1vd_0h7@6ZB2bIL{sHskV#?v7Hd*ijV4fjOk{q$899G4zksvj zuF4$Vb(q(L^}HZrJLExr#`3WR0w?dDnF-5Y_rx3~^lOhKsN;Pavpb`LRS@Z+s7~AS zYTfDJC|Q02KpXROpJG4)+vF|hXN46;!@QR{t8M1l_j!C_86sbMvumLI2NQWD?0bfyDmQ`+X|(Au8uL#$;A+l#AjqF3vDHeeLYKY zPmU0qjfPiPJYq}#v8Ayn=kb0wn*rDk*K&{%T8TP?$1GIziDM#kMy!0s9-XWXzYZe} zBzn=}-A6f^W5fgGxFUjYnwYp|C&w{NRw#VTIG%zg&*|9uP!timnGinhe*Y8MIl$&` zKk73tjx)1oZP(_Dod9hpbz+ug0Czq}Utl(;93ZKKlaZ@SG) z#k8|_6knH^PhH!-m_nW3VElfoB1+Z-_Oi`i(oXaFE2tJcI6*QYP`7J?EwrKeS>8#2 zQ8Ur3Z{w*=xlG2fK#-SSe5wZruK+LT5o>G{uc5y9{eutFm`_`#>43-lMfD+X9X871 zY9s~{O&nmp3*hFjx$T7Q33VChQa;_ zHSXXypruCbO2RX*i59V&`-=sA@pUK22U01q*Sb(BEEqFo{E7E0S4E~oa{(L-CsJZB z8$)NWo}6qrjksf6j}!VaFndw3HyGajBg|zUT$s4`wrI&h81Q0!eYCdd>E!8n*!Hh> zB^YgR)_BX|@0{^!zMooAt?SYWk{3mDTcM4Qm-(+^Yk&Z<&h#+0G*0zy3 z?dck+r~NAXkJFp=VdqdMe)879N&$i!wUuLWf3zN#5;gqZ0>?m6gp3NI3ys?lUX z_u!5&MXFvlFG6GK7O+Ph)ON9$4@fi8{nzNp%5q3{x0XX=7WbwZfy9ih*aQf=huyV1 z-J#&$Oz(63$hF85;gF_tJce(YINrG%)k(ybQ6ICp+Gw+u)7Y8Ag$nx5kl<<`0NMe3v(l=by5`bb=iAhxT;7IU23cRDJ=P5g{osgLD4UErj ze5$G3>$K#9fBxN4eV9y$Ud3oj(I!LFvTnD4LOK`WPY%JS0x0@&QZXjAo5o08{k^JA zSUajoc2w=EhS*~Jvzp8rc znwrzSW8kUj3|tmvlnbkMZyHugE0o2SB_Z@y9<~~!imhbh=WO6}UXykUsAUa^Y)_TQ z<1@_JEm($lM;zCuv5Wwuc$WM^d52_UM<@=wCKJ-zWa&STglsGsVf%En%!myoiR%E%s zl>{;3kDfM2X_6wffzAx{gW|@6^>DW1>LiWmU^xDEt5Vi$85{zzLp>$$AT6nJa#}gm7r|OzW6X(uO8~$E{6)}1uei0G z!ZGpbyfLp71d%1ujvZ6}Tmyhtgr4kh?rRU9R7ln~W9xD49%Td?Y4{2}e(p!b+%w(| z78($&G%*;7gHURz=N?2dBFsjOK2c>GlT}g|o{}^FP+hKt1Jo%0*VT(E6WD2lc@<$$ zA|D|KdmLSfxon!=F#e`-gi)*8Vy0lI%l^)`{#9eX$3S1tBo0_Y!|cvbJ5z4}THlxB z8*CuHo9=p>gA(i8L}vh4)VWxv37S&jn$CyBzW$D&7N3SFGb1`GH=u> zs4QC)^2S7V`>3b~T$*CGWg)LB`ay38NM4eS3{%*^{+*NnB+BZf>m4`+i8~i4e-Ya@ z)}%R(?9xc4^Nb(7hU;ria(dS=9{UKrB_5Z-;nM@O!Ww9Q&{osFLYnJn-mVlF7u~Qb zGn!@d7cL^sd$5K+zVDrL>I}2B{?S{=DG*%mU`qs{U($d_j6>8CWY9cV=fSxS%c7v{ zgeDA&DP9zYL#<#=E>M(8b$2+>{B%|k`tU1UOzZ_OAZago;#k=8Q97QV)@~)5SdxWu z7~M6qyf%jg5in&1aQKZEX@p}@5tE8(p3>8kY=O~wfMYcTjV8vEwY-xDKy>|C9B_M8bvY_X%=a5AQEL_z zri+X5=QgDi<0u9;6}G*^JWYcp8q6n)NyP#EI9@RlnhJm~fJP=-fJ`wGn-KZf1NUZ~ zWK54=7b{TF1*-eL{DR6bt@cM!p}}3&!n|!(Kv&l^aJ^NUMX)EN7|{J9^bA;H??P?s z??F&Os9$4EJfQAC)paDZpfr;z;QT8`WB{#q-jPr<|BT^lAP_>2i%Nyj;klvi zTrgMQc`J5T)?11t%sTa?6@}F1o+VH-yrW2^{x&1VCjwmi|D!(9?K3O51J<6J@-=PA zm9!JIo!kb}e}ehAgAVy>zU+n*ICMR@`vlrm*<&|sbD9Iw%xeEUcMyVI}D*I zQ#JW!`(<$z`V$nN`V+7Y@2`M}*r*)2YyP`{n9K|6T<>m&xxyd7ZPjf3j_bWgEW#%r zwU|8i-52~h?%YEderd@nSve26A3-s6c_}TfJjVLBv1F~Bd4Inck=l$lpZoz=zdvQ) zm;ELHIiinj^6^bE4w8#X3(09s@kl7ljWchAZ%t zV}Np}!D^XEY7kqS!V0HR)q~zZJ+XlSsXG9rO>Gm}o%`btgkacMj&nKrcr^3T?wNp! z(hjN|p+!xC0ku(ub~Y4I+23bun4p2w8BzEs2o$^3jw_hE#L*@c)f||F5|{?fXR}xv zAhELiL1Q%2h4*4j>>W+Xy5XTmLJXr+4#kj4is@yU7x_ewdC zdd;z(ma2v;ZbP)95M={!)a`om`Btwpwy$T7jh~;0veCixw-YD!lzBy#2Z^-3uR2m} zm@K_j<3zMXlHm=yit~T_Sa$+HA*EmjPP-O2F~G7IMkv~{jI=#mh+yHh&F2uN9H(XT zAS(fIq&rt&`C)xgLD<&X?RhHR*!r>w4k174VGE$T)LUlt0WAoY+ z6uEQzQMW76{~9vL8%?|}%hqOr;`=FH-dec#J&5H`@~!A#diIWLKIc zh4|tnar2wJO8=naa9AV_WSRl?*>($x$JAq^HF^AT>RB)$nJ0WK_$rYLi5#ZYNVXp zPwH;JIt7kqdhnhyLW8OV8ERx%@&eL!-KzcX#IxRNN`eFIB|X*~YSwzAaV@V=Glu;O zni6J1$U@u}N+WmbS1Hlb4XzGqFJI0AFGL2!{4Yjfw5lo^Lj(rF4@gRvAQ^8-w+Sd4 z(Zj3WhA}&ID9}B`%yX{AQNUw%(KoH2jwsF841%h>5mtRH%nU710>Za5#^SHV;n_1^ zU)0qW5-VuU_t3BM!F|E+SJtBZBtu>cLL~J09`$isf86lo4u=Mtj7@f=6lMr7t53*M z+G&l}+=LE{K@`+YQT=1)t*>&P2~ zJ9L?soA97rug7z<%mFQL->E~(gr-_5#})1#3}uY({bV|D<`u25X}$qK^(Qg!i2Zme zb((obX+QJM_<{@diT*gDL)l^(H=XrJLP)*Ud3F`MMI$VVC_@jR%bR7n9dX1QFuc75 zTAu}8G@M<$IQmF#aol&RsmaBJh$S{iYZ|oBZc|9M>rbgI{qH35eU9d;J zV~XA?98ii7tLB@8vnoTnNxts^P5`R<`>ccVwUZe;Z@E(0c{w-H9|X`X0FV)Cr$DnmxfVz`Y4`ET=hk<`49h{@m5D!b zudK@=){-c6Kwq?7J+M@!Vh#3&u4nmJNh}!$|>W|iDI*MNdKIAGc_Ue-a)Q|t1YYw5Wob| z4gizD6WeYlYDaTM3>OW+%T4|}|E1wnw6?KDCDoT6c$kUqP7nVteS;Wwjy2as3LYzjV_ku!0SDT>Vg&~{f56IiL22|uzacRNb2y}yR zk&kf||H=#PEaJ3eRo_sy4%YcB%Jjx<4wc($tlp_>%9O`TeToV=R<+dj=s%}x#WiGB z#PaxfnL>@P623O}(Zqf*q_kciWq6+kCxK8yh^IIw)~V^*SkVmk(Q4?4aqWNCDgz^| zs65D%GlabdCYw3)obsO<-hN-`u?~atfqv>QDmI%`onUa-W!vR}-U`@Oc%k-wU9CI8 zGFoUNBBvS*g@W(#@Se%(vNfya2dZ{J#m2(B{z3!R@sKl61U8S)n$Q%ctRlc??F9Q# zS(R8FnHyba>t^W~^$ehW5phm(YKX#qj#84geqo#_({x!_gVzq24GtP|U>>L{NwcO? zy{m=quLo{NRiOVt$>YM6!!x4eV={S2d=MiFg*R~R!_@zK^axt67sX7zxa*&0#vqMo zbg$M1bw;;#UpBa|WFlLkNDEAKbDSatrr|2m(m#*@hj8}4n7zV=npbUa(Xku@534k>mJBT3yBo^~J{U*Xd-lsRI*K zJEnjMuGjXQCyY(IVdTvPe-N%}g0lkNwq!4l1%@lUE0p(lNQoMUeIvT0&ODOxL!cdw zVE7j_YQ@NNN?ayGC*K2sBkcv&S95+ZA1U%G7?$4%ThG0nrKpi7-=5LGnj>1F-+6Y%_8wXH(2n2J_de+VM93La|>E~7Un6${T{57A7I)8kg-QsfRfyN6E&DV)yy6)aj9Hg9cRHfuWr zmNgs*7P1W7JWX#uw+ZbjN4C2Ib7h9IIW$}vsHU#$?KW|P>!G^G~kUAuEOL111zwz2sjLXa33jif%su;NgCmy zx-tS}02GU)am!EC@v6!-)}wn|iD}Hu3~}#pDp&uRWniNTlzIj^-)19163;;hFL*7O z9H0^#PIOhs9)P0tKrCv3LX%G9Vo#O_E?XN@f?s+QOU(^4x7L(i=K2M}JICB?Ue(8IMt z>l-si}Q-SZhUunhBNFtLlTpZ|9y?>!g^eF@l{F5^Zvmrqxj%k=E z=8WNi=*EqaC#IR~WGy6R6Xt13lB;Qm7e6K6e*&n{kW|6s>fb+TlF_NgFkEO3cIp{xf z8Afj`)fEp_T~f+HcHOO|m>x^Lo!4_K{IuI#f9C1i)@#^kkIQ;5GJaFj0OF~$=mUx1 z)~p(hT}|GsI@|*{fAHF1 zws(NTzqGPp6v*t06S=04e87c;s$YNYN#&f0m=3_TAA~QIl;22$izscVfJe0jU7(42 zbMS|?ulV54b`46yu5G9w)`zCi zn9y568ByhGhNTdDIqyf@ZIr8yxL`GrCu2U08mnea1OQEPOjH(n%_<+6Myd@m;4MxO zL_MJ3_RYFjAM>*Q0<0mSi4nHU|B{rrKN$&c9td3J&CQQv1HsHifyTg?RG#}|YARlh z5ftZLkhaE`jwD_=6g%*0FGYAX^3$xW?f-0NFS0#HQ@8;tgv|N}krFgz$$h)#yWV$o z%)JZg=F$X0n+t=KOYT?hBIaC62LfrojpH#hSJ7G=B#WnX%8jT(r@m1SUxOT8+U__7yNZX@oaBHPp9ya(FbKQJ>YNg@n2knj)5)$Rk4Ee zt=g@O`Gf6<-I$aJHP0u|Yv|Ry23->qU2L_M^4zA#cee&YJ;Uo+^}Ls;szKV_D|fhg z!oC!*`SYpq{_uJRx$h&cWm?AAaZrbqzamvT`0fuou#~ORsqPhGk$~`tM{)hy%2eMC zMuVUbxLzIwvf;o`G}qR!HMtihZ>P2*6etbT{naw+Y)t5F#W?xtM&t3jNqZ&)eU~6YwY}F`{b&mgV^@NDKM928+UKdz9FLl zGXt%dk@A8GILSsx8)0`2pvLu$c|VR0ryy>Jyz#wx!i$QVPK)@l2M^v!Tgp1F*XgKLj9Zs^YP3KV*HkK z8;XXN9x{4%|JgBU;Huvc^^YSRL_-Ox9DHW<)2f6%-hw89zNPfPt7H=3b;nHpFokWw z=fjR_Yu~IV85{C1bqp7Es6~*8mdEV%)3O^M(PIssNR*$2B)5{r^|mw3T@Mfl^z>e` z!}Zd|r)aXC#8opT8ji3!@q@tEENSozc#kY#|1NGB@AY9Ju-%A$X7@#LC#OjZoFcF4aVP2}TY#?4&szaSq>e3&xxuu?Q+&!i{KBP~_Fi zyo~jNmdd(bDz(zf7c}M2)I1X4f5KI_f}c8+y-B0gvg}xfDH)eTe>`cc=Ot4w55vD8 zkyy6|(M8|{5M;~twI>6dHS{FftjX0n*_g({vw6}IiuFMvg)1MV7gb%@_~9oVZ`7Cddg+JYv;vMxT+z}1Llr=Q z*}XTCZvd9DvOvP7-oG0c-g|w%5%k%VpNw?bhR-N|jJu^WwWP{pdN=m*l8&u9UPi7x}81Y@mikz6gn5e)!l?1j%) zY^{(omR~(EL)Pi3Bdgdr;u#EG`!Yu1T-11x`;33BNo}zNNiS(muv`kk3 zetpPxA0s@S;ha%mB&N!8pCC5rKit0h<$RNZcNH0-}8l)DK_17XOZ$Z zkihJJ{18Ou(@(!XVA{=5jB+hJ6R=4O4}WEoUT*0iy|ifIR#VHJ-I24%<=qLVXP8iT z_W~lP;@iI8>XtgyrlaP3upVQz0E2=uxC{Ug9pdeD@2V`tx_&X-g;BO6I#Sr_+G}8O zjDrVw98UFdMwub3-X3YWMnP`>VK|u1Ra-RWfn^=3s?z!u|E9ZQ#sPwvFW6-@kDk?f zaxWe`m$k***1}vlgEUGO`K;Niwmsl5KAv97kzkQI$~E<KXj}F zZE>Z{3eb%CTNlxzjnOQ4iyZN`E1RhbUrdSDn0!7x@&%gbdo`B8?@JwF$mwWK#XfJA zgKBNpoGc?R)3lDVM$S*g7k+!&pE7D$u6$_Pr0S#~)>&|^p}ku)P)Hx6#~$Ze(y z(a&}{c$BZRlM@LR>ATF~w|8nJJCHpPKHR_G07d>e<&hCCZq@9;jO8n&KsmeVfshYn zBQE;BU&`v?Mmd}Yi4*+>q_e`@%U+$q6X0@|dc_L1Xvb({)=yqsE~nF8IF)bLgB-%j z)GnjoiJUdy_-=^`@?T&)BY`bX7227HvE?m&YaaEy!e(VL}^46FaSIj*ljYCfnku z8rIg|RGF(gua^YPTj>}8^Z_bg9o+RcOfiKt*P~Q%=G(%`9hTWr!@*H}fCc)5z3oqY z(k(}`5GyOM1gjc%1&6$;k<2vLjXBOS-w{_sB0X?_kex2)3qd&it)N@+zq~d+pd3LP zTdHC6q`@)x#RsDs#B>vHJ?LtL8W{Wsx+b)DDlmJ1i^*3&3j`qM#3sgjkA!}3l|`vo zh}6=#E~^mJMa+eNZ)e<$N@9U<|I=9Uu|f?QWSA>^|6IGeFDsproKsvvd=} zW~S9{WW+FIKdZi{!546S*49Tv_!67D=i2rVDfsz!VVI_}6643fQ{Jg=px_>VsYgED zbd9Sc%%#pmqMGr+iOhO(5>WfF^m zE*oF41m=J~QkxkHx&2GUxsd~j2y4uJ;&+~u5BPURB7#U!7%a*o?I}TyIQeR6lCATIrC$gjKoax4$TS^Q3I!=Fk%g_X?_w~5$U-E0>K%{?vjqTh$0={YI3G3 zl=^a#8Rz1+8QxAdMQWAm?3M@`RWrGSd1)5XIO6U1-pRpz>QilbZ9K7pt}K?z@8eGR zSQw>Tx(?^4Ahje_#qKsZro2}<3U-863)@S-SO zT8Cu;IHyVzKBjQfOB)YT-Qa8m&K#ZC1c9I!hh}Fzd5WmeF%2=>KlGI+0V#L5_ByxqyYUjuF ziQX3Zi(!V?k!3ON@VbB=ruUe*Icf!*8rnn-JKO$oua zFLU2lzg2neP(N_eL8+L zu{@pLeY2jPZ&sOisLRbUy0?lTaT+9KLqu-jxK|U^|K$w(vCJwIK*<&LZ!%Gd z;iDs~OyUL}7?-={FK{bV$CaA1$ldRfZRYogBCOn=;F^9ALcw#@mr35j$OJcZCxgFA zAuZ({uZ!+K7acTrkAX?GhG><6l9YhPOeyB&wi%sw50bMKu6vod%3}FJ?=-A>kxa-t z2!RpPLyDCKCGfH)2?(hA2FkpPh;67mjoune+Ea)0NBW!K9wDGHIYYB>_VGj^J}!7= zwzxo})ntPiTRV1uG`Niv#io~lUQ^2CcWZ!4Xia&}a!b(Av5b;x_9am!)5T!_x8_pM zn_Ba6voQHFUax@&?^g7{QZFm*BDLUL1zAjxr7TiP#qej5@YYs0u9Yy^Mck;!#2mq~ z6Hn4ytcp<@k%yg5K}!1d(qH7!T8AnWB~qCt4=I}jWbK^}Y$&MdXk!QHa@Rb@)&PiX zi!w&F+x@RKp*C3E1zJO^xH-4tA#B3SH+hV2MCmv1K(e|~x8Q(+(lw4{>r<<+;^+&< zDhyEL`-H6Pgvsvk$Oe|g#x;a~Zo*2jX3k7;$3%4v!W;{Yg^6iI1w%`lRiJWIk?ulIgDEL9 zLksNxqtgy$C2?2azbje{clAK{_vgMT2QkQT3YQjBnwt0!CeCAt!bG12CGwfR2qclH z6Fv*rOvoJk(z%2$pU#uEp2y{VDx+yF(GdiDb(K*s_c&Z%xyJxN?1~}t zV+RCU0&OMf44Cnu#l7P^W_@l7u(RIO7nkOd;LCK_oh!0e1jfc+v;4(g@$}mI#Ilia zg8m)}jaF-hbG^iXFp3}m&k)eEne@j0Ik|_X$9HhS9>Qxs`8^TqouPpDc$zFl@i0Rt z*JO@i*q5}mu~E!=6BwmK_mi1HXr1lk-0mZCj?!q+98IB0z6jho8#Ysh!};QSC1+P= zvez@&(hK92dC;x2Ly&h{?Un0&09|a31Ll5f&rWEC?4}r6C}&qLkQaMZXFusE3%n(~ z0?53u-v@Sgi|X#P%GwonOL6o*ssrVRVfCP)m&Ed?+1_5K3#c!A>7{w3|6DPK^(vRP zVJ+n{{p%^s^{P_2h+$&}WwA(UMewp8=+m6}T*dIg8;|Li`+_cO;f`k%SqWU9?vfeQ&-R$x?j z;x&i|{h=DB6So&wx%m4e~@XST_R zg}5x*&Wjcmhyggkzli&F@04^KwLbVMSu@0|4G-y8t9f6KeA!0{9bcI@;*H&>6I3Ei z8}|HUz?~x6GGRXbr9G&5c^LSr><5Gx?IiKwmJ}^;H<~j&UVALmGjO2VUzCsj=a^UX z!@AfI9cpLZM%}~VGvtL9_O+gQ+wgPuc9)%VI(|fT`tr|>%xfQyHTSI=Ko8{&>IHtvKrSSZ{sFHGocnR($* z``LVvy5SnJb0wgl+e>~j?@u}(vI>Bhl;ipT_HpnJK1l0xF&+}=3z%J;TVM* zmyFIvL|Mr*w`B7kmabh^&uGJWDPY#&*93iuF(K_rTPA_i$|Vx`@C&S-c8(X{08e-v zPHNvA@f52o3X(4V<_LIvWPt!PUq0T(!_5jsyh`wBnnMh&04f5Vy6EQiQv@Yk8->e4 z`A!{9GKM-$b16r(!E50^wa&`4N z=6*L?GZLAg=}@e|xUR2e8}3qv$E1cUb0r|MmzBK7^}60XuHHIvHdX*fRLpMioZ(~? zQZOIq;}G)pP$~IF6w*`O$M9lCGV~{;9bysk#vhd<%}bin%3dBdlh^EtzJG?Cxhe^P zdHHy~o>xLZq4@mZ(56c^xH83iGd_fa)MXR=Wf;#uhjy)ck8a4mq9t}JIdtSN^Pe6| z#LwV+Vr-rbe(HnPbqJ+;QZGzs&wHwzJe1QtKNWoFp!<)hkiQpj(>4N{O#cSAyrVxr z&ur`~&ew!fjkPXK zH4R2hyE+a5z{(7b8fsz}B)WZMheoADjImssX)ZU5W{RV=gZ!LqG)ogx>>YFemPj^B ziL3kdxMy0GI06Zc6%PxmjK^r3Q{?IIqmH20sUWi5C|Bj+?I4l&tYEVr!b#^A$x+T? zKx!wE+CEL=IUUk!_E0$S`UlP2RWt?bL6+kvLXnXY@D1!C@G~<0o;*^T;29oQNeA~E zbmMF+6uH{pF-6nq%E{p%8iAfmjAn)0C0f=c@IOjkD?2sz*92wo;1X)c%ndk*P$$oO z>O%GJO{Chpe$)3{fQX8Be*4%q#5*+bdiRJKQ*E@##<0|R@zrUM%X>pA6+`4O%Vi!= zL6VP{7RVi>A`Q180B=4~TOljuJFuA+jW+I^Z90~9|3UgtUD#$E@OGZc9exDc)~ux- zP9M)n)L2j5D-QDD`*|6Nr7>+dPX#`Xfa!7rzk%b|G- zobTL$9VtG8`+KvVT02XXBXj;pxL*zjqk_xt6rm!6>7$^76Frn;C%Kj z^cNa?1Z5{!Q-%wGP?=_Wvx6Aui2=Gb!+gGIpf>KPHTCp~b(_>o)LIle~iXZA^3M|%}? z5{iEzvF2)5>{4;WUs$&wc49McO~7q6j8k^khFs~z72V41D}Y}uf08WsAYn>~`q2Vn z2KHsK-_~kuM2ib00sm8U>G}!=Z&_8*1*1Yxs^hn9vDOAj#G==WLbs=x#Ihr>1y{c% zL5Lc!>mRc)Bo>rr^OuTJNp>#4fpvEVtmQY8m}-dP+jeK$toT#Gs{VJ7Z9Nm@OG~lb zks!Mj3&v`=GPW%cevHv2Oxc96jo*%;d)QMhR$IFR4t!|Pck2_q)QPs! zv7xH_bC+L7dLu_KrSBh>!$HTW3X|JYg7{3I5=ryq`B$3D$J)VGA>Ge-g!>1WDBfkD zZH=85$mfQwxcD$gUDOjid%7oT{EN5e%xgz9Bw&F{m1rfm(OMtMN;D^_zDjg#{|@n3 ziN1y&wVj(pN@J_mZYY}`DG5HeNfsXcH`Y=fG(FGAFFJj^%ae!QnY8#Fsh&tgy#58DU?1aR*-mQVFi>JWnsU;C1bcgT5g{0IPw z{}T3q^;Ys(*e~MURO`BLtt!v6azPeJ^ISO5-7Ts1-A%Y1458yD5 z_Vetv+a~gX^S`=8@U*kWxd>U zDe1s3LnJO8!OnEtCxikmXcz5-QrvrDsF%h8on3@g^)Z`MwtnJnqzf>cZojpJVME_b zO?5gDM(SV|UqOQ(e@|a$-c;O}J1t8n8vt3e_0#DoTF-XkI!_}u827k$$MTxe18%-O z?n&SM(@K+$T++yOIew&4Qo8RO-`ZGc&0GX`CK_+WE3|F+DrxFWUrT@zlnsHC3$4E0 zWrVTbn;0iVVgq#mHi4%+m)*}Uo0&y^!8VV8&}v#f5_jIUJ`9P6vA#iJpRK9Q&w5Nw zd1(lJb^LH4feA{r$swVGKyKND@Jp)PyxF(?_N7>o`xO6-46K6PIZ^pg<}?PY9C1A( z9mic}JHYzX#gv3?${+LQxEcXzef;Ac{4fB^fa{OS5TvmTV{#>R@43L&4;Oj}NY3Io ze7qsXHPY)$sy%zyu>JwpRLG4?y$((vltbJko6y+pO zFL=}4vZ*I@DNeoxtNH%|oDvh(?#UbaH}{yVxd9cAj=%-V*EKr*w`Nz0Nb ztb8cF1*dt-S*d|7dQUCiARmUd!;Wu;)+};^B@+|M@f+Z(7^oOOrhsSN*7PKE>3b>u z1zYv|87_*mKo)<-iYZ#-jbL%*tR?*7o$Qi>(2f;6#}BXxfZ8UlH*q3RY&whvkmB9Y^8%%n!jAJ|RS zH>S{k8kqBeaOu~?m#{dP1z@V1AY+Pf?lLu%Jv3S*0P$)1UcpEPgJiI+ATUsGSPZBh zme)Jr>6Xi4<7Ns-^|t5`=qH1`V;^rfXUOT!_P|pv`QE2G4_!4Eup@Y*6T}UdKg*R` z45seAYsYj9^yI{3$ydxc!Nf=}03i)&l16;F^Bm=3sUb1m1G_n|2M7H%z-qjgsoXlj zm91f9P{Mw3f?{mT$TY2`%(I+nBAducGi3h%hH3At8mTmUW6#duDU9tPA3!3;XFjr4 zn5Dq^we*9TNaAK+wO1MA5d(fwI&PoD(iu zOJ3V%zZ%H|&6!4#Q8b{`sRijd(Fy>VN&q1cX$eVJ2S*KQUkV$T5=fUuBmt0RTFDg7 z?@*{`yu7kz{CWD^w3(P+UzIBpz$u6u_7KPf(+2j4C@bT> z_HK1=@4KuBFFyUW+C|2>%$H3Yl=_O*&w6^rp3`cR&EKy&2k<@^&Q8`;ECqtp96I+D zT$=x{w-@^@*lbB%Tr7o=URf(G7rQ)STvyqSf9@!COPbx+-Da;N{?A4>4{Hw~qoVR} z>ds-U4aYENpZc)tZk~sfFuxNm4r!WYzTZr?KAX5AgVR0&T=OZ|Xmp|a!iK|3ERACf zf0VA;qz+D^h&&K{zPWyB=O8fKl!i5cwAF@T;1_`^S{$%^!tAWxtHrcQH>6jg;WLOk zx>U6ipAs|%=SrCtga30ZWJ5&?6IJiDm?gA;zgY43xO_4xz+f^W83OBE z5-RtimZB@qq5h~Q`#HSO(uXuxdzL@B@C}^-`?M4xqo+clF4jfQuRVYa0Q+;zjYis4 zzBOO1Vh=j$xQUI>$<|f~u$DI=oLm4k_@irIP7lyc)Sb4XGhR3y5oO86oI~`5NE;ZC zy0LZ&kR1df8i>ZwsHOjJ&v|yJ%t4^a4t|iUrl^ErBkfs4S|;5 zP<}??3M2|}cC=^@W5GIP-_()MrR{jvthoyG3C#0NKa_>q;WgoFY-A)l$3#S52$NU@ z^cD7P!=?q$u|#H{$Q)|IYYBLFNi-4I)lGcEXwvtAf3-bmdKY*DGc1j9-mjVyM$SR z-&8W@7`_gHk>b0(J#jmX%2l~hS7l~J+;dmJ{A`@g#~Il}>Q#L85SQJG+~k?tt?!Le zFnYv$tCDowL}yP3NUKVBc!FBSFV8rCmDZ)BD7DBy#iAV_xBiqZ4-W9uk_9Th63i_x z6V4QL1a$noYV_T0dB!Q2m85J;YHDGI#@gSuM9h`C*@KZBFd^V-nvKHdbx zHCB2D((e}XbpK*3uTug)-~FKegCm{H=kn*W@z>A;a4MB(0`KU3_}%9zk%N3`S~zp- zwFGB{!<1j+<^cwRy6@nSt=YcKc=N}*k)v{41wn!#deHd0&GA&dD0JNJr;TQJzrRR; zQ>zdpr(2aH1d^{#+bnqMU(M&SUhw$2N=9&V4`kHK*xP5QIcF^Ewqv{aim|C zW{*DS@^rSEhf^5_b9Y?5H9^(OXE_UDJ>kLvB<<;jAF+BQh-)#)r}%Z=y>%J33*Ui` zYU(mkX9rN7=#0u*hmuAqX*C-q-`T_(iX4aLZ`oi7weo)r^r@ei;GIM}4bRR9(yCdg zl}p((#JALP`q=?#nVKvig?4!g9PS7ni2&SI+o^ zSzKl-rBwR*ce2e-CsQ6r7&)y0r~H@}x@;G8#1dpgorHxQ@|@AqA8Y~iGn*6$Ho%mU z1((fa*JUIgGB0*!PuIEan{x<1&66uX;Q)fme?Db~e@1UL6vo|_5UWYMGNctwr>UXU zpTn%;4tcZ`CP9Y|MuQae4^uZ-GU@Pyww-( z!)0y@iWCMFs%A->4Uq7AlP;7ZAumB`K-Ju%Hrr5K?{2OE4BXojnI#f<5Z#BksIfex ze55@^$zW^T7KRv}+Tb4LaK0`(Y<8RP)bG)6vHi@Lo#$WNsDsD+CS3F47B)|WE_x(V z=5?#87N_e*J%usKR~4yCowk&9E{P(ZK6R6b09$D=j__Xnej-L|;dbIoP{L{_4ZHr$ zPg|VlX`SqO7ks5#dPOmCDO{2V2i0@L$R_ATRX+Wo<+dXFbs@`dO+x!P4jckNbw}^- zuY82kC=eHtPapF1**z&`;#UvQH7jV+ef&e~g1-oJB(3+d~A!4n_wLf9Ve51lm(}!7`2;Zwt#Vf|$WnUq# zT#w;IVl-sHg<_d&I{?VE zyJ-2M6N^C7*~zt(kzl#qa|cv&^&yasxHj{nVF*M%;Su>rD=nDHnSEn~PFd8xX1*^J2rNm}BcFcHMLu%>!gU;7z?;iv0s%GXI zej5%5$%z_I)L*j-XaIFHnxOwUNu0B5=0LH=*_n*G;rtvUj?W&=(T8A)>TcfKK8!b7 zBBvzBr%K$u4WIti6fmUC69SC{P8sP3=|O6U@aBv+gX(fCn^1=&6j7xC(?To|f#=oK zxdOK5E6E|!A{dPRMPjWV_1Q{A~^P<}s+8jKjX5%ZuTqEKIgE7jA@b5>wLxTp_N z(vertAhtMn5ahjbO#9~O^J7K^kHQjBw9bxur{UC|%|x5r#oH5x$1ap6cGga#Ko0D^ z${4AhIw%Ah3yGtMR5;+*KHE8~6Z zxrmQ<>OnY*BP=jKsV{lR{r(zgbo`!XVOILwHHsFmrtgEn?-aZ28#QjD^@hnio!!WI zECQ>OWAIDZ7su}TT2b`0ana2SSx4x-vr&fl7KXz4bq_*9Ao`W3-SbBNH!O%b^Mbz* zH|u6J6hR=hBTg_8VQ-`ji1mA@2K17g-I3D)_|Yh6p1?P}KzbYU9Z=^cvHP{AIxng4 zD2wguC0m(`kh}nKvINX2n`A3aWh>U-E1Lo-+c|Fu6qYyo?2n*tfPGWyE#Ua-)XD0} zfmtH5T1&x{u3_=6=$}kgD<2`P?nPO6EC;^`H^paN2L83hDERpb+|PvPdiT51b#_${ zU^S-b#4+nHX;IlthGXJBk3WWazjvr&7&pH7Vs5X+lY6U+vGgw!Y?=sy|IW!6_v2e( zHB;Owj@)bS@xy0oU%nE)l#bKqA%IAPpDp}kLq&+9L*}e|mvytqu5kHQ8yXU4rK6#& zzf%LXthb+|hqf}P3wOx!%$PKYSd)eG+g5MO@H$D}J zPi^s$MEa?>|0@vb*Lm(<=R)7s3J26jfv0u#r<4g*DnjReTU*d;(D zmw?)POki~Dyal0{v;HZcaIrZ_JX~U1w$!COfpqhnoBuRQ#`<~C@=X7@Eg*P|nQ)-| zehl4ACQKWwl(He3u)vO9^isgn3Ogyci@&6u6{S%(QV!GUUb&a+fS6nL4%nSO-Cg~5e7We;;N3pVigO?dn&CDTxk>RfEB%c ztbk;H>GG=upIz&pD7vcRK-@hxbHPn|J#mFP;4gHs3{(&+i|BQ*72Yx#Ju$9{qJky#jNKPTM{z-~BYw<9OSqzqa>c zbQ#Hs$*7Q7MwoYvPZRB`~fOV@gIgi)(JRC1Ge}X^_xX= zy&S4ZFIs%hBh#a>xvhypxq@V~8F)>pM z)ji;l$_cc-xNYpu6t0_?_`;Cb!8xB1J-D&IW)Aga1qc=PJgex8AGZ7{!KZNHzM+R7 zfyBOf1I1+gCcvDwcZFO_I(Be!42-*Ct;sIlT-L>DUH9VidC7Trb`j2JLcz*PPMv3u z0!LZxchj6ACi-c{KeUNPTU({WYQS8bi>WzSv0gWJl4+@!E!ZQ!=m|a{m+h<+7{tn9 zgEh%E1&EYkbSCs+?W{fbL6%;v&lHkVNU>qKr245TNn_;pRz(@uPwB%0J&Z$nbql#Z z^DfU1AKfLdPlYpRzv1O+gewH}Q%;R9J^apE6OoqMK@MvruVEr^#wZcEdQ1P(qGCyh z<~n~B(p%*o4@Zwlcno>st4Vf3#0o@RHL+!xqMZbHcAdbr-m_6Y!u1c(ILv$W&7i`h%Y?p{OMwRGGz?%~dxEMbc?O1o&LhokDa^A_*2nRfKq8YP%3lWuFTM1`5(G%f` zZ40=LG(f@m@F}^6UG}4Lp{L)QrfI{Bvkh}6&f7SJn&u{*szBIsxnDr?Kt0=ac z>~Jd8rHaU^ZsN}KK=_;~%xRn3>(0e@h^}J4!Ro9vFr0n+pu!7CNatCx+M*;d*m)~o zeWcpg7UyRqiV39yYXAbQaXyxH%dn<^aolt+(9nlE%e2$4SwWYoJL_h>yiAC;*0{zq zTh=8CH=XXe?O;IerS@GR81d0C{Yf?~^3pBvirRExiIEZ9x6_kev?7-2sz8FwUA+1+ zEwdXfPZW%)yO6Hi6n&L$4)exZBMwR9h^qm>@`+U8MaXjCXpcHT;$1*IyKC`-6>CR= zLCz^-EE^u$fj?Irj1|jX3My({m)T2CpS7tXLmMl2ji+qjEB3Mnu>>4A!b`7?TlO3>c{5SFc=)ruKYMEEow>BU-hF9Ggkr zpb${!z*6kcLW$MYaB+f%KVKKTIm<#n0zYcTL9)ybwNT0T!h_bsh(Dqsi}&|CY{q_t z7#qcV<4udxA?pD{sp`5CxxwcS^$fk}5gO#Fa{mq(@Hs^Z4|^J=bZkQ&7eNAwA}1?L zeAO1$6S^oB5Z1fB`tc+k9Q#mg)fsKKmw6d@>lEuy=@=}&QDSy=9dG`pd-QxGtx4Jb7l#ff$ zieW(70Pc-Z^hJwBlNszq8y(zal6EplD?MoEmn+8uu>PKw4)~~LQya`t;`!z)u4!Z9 zNgJPDl3jT4%$y{jgsbNElhFfqJPdyhCV|09R4qU|6PNk4kv$G3mxRB*Sx+` zDQM)gxzD4sKuP>9x|m=qmat#*tqIg%3Q(`OIf?7GbzAX(MY!m1n4mJPhbnyq``}rk zkAx<~mu3Tg));{b+GqQ0>c_C3y;zvSY27}#;y5nt@(2EDWuJ}9ZH%o*s5+{erE_$U zC0on#6oaT%S@+6IjB0IvOyNZOtqi~flJ_+6xkYChBIFQKDgywDbB72k-L6f6Ri+SJ zVeJEJSgjY<5?PTR`nq-RW+5{JmTKJK2ZU}A`kGA-$lytW;_N;In7MD*Es&ATvQraf zmqP=c^Jq**lXjY8;%jkUV>G2lOhhvHS^t^Ld*4aD2;XwSXQJ7(%&vK)*F-AvK1yn# z*SX^Xt-msURn2XHSF06t)30IZ6*su3mC>Byn)Sa7*BGf<41;T$c12^gXQkY&&x*2+ z(av@w@Dq*Xc#7x9V$D{$aBF^;5sl18yp7F-9X*+E5fJVP109@qN-`YjMzyu%jTzcM z*CXB{x;(#>904J6zxKW|WRtqPr%}qJHbVmE2PtOM%o6l-BX2UK8F>UWey!U9y{Z4a6|3t#v?Ka|9zDCLr*QGh`cGzv zUb<|GvHxMOYOuSOGmjXwdAq4E6^vqa(NQlj{KAq&U>0az1OrmVg)_ig+pjeg%Qyy; zh-EiG!~R=ZbL29WGLbOgr1Ai%o9#5vT?xy6*lIT$&-|r7Lca@&);BOZb}*^={DtDb zP-^xRb4l13fD}_Ordury-1r8OH-sptk{PHku_M1hYZ93{n zSd+tAXk~w@dME$#vB^RZoP6iyg{^jloB{%xM<5@8W3(2b{P`t={s8HQ9kD8`=(oYnKESHcINC@m ztZ#zR7|dJ0W}o^=9n;;IAOWqa8w@H3*ffDm&6OinJi4AwVI873%L6ilFmfiYq)MI1 zyR}Jo=OaXIdxkGT*yhRVwr>xSoaL6PCsoZ+uWuvW(dfH%F#Xhk(t|J8)!dVz)yN7M zMwpQw0D-zs&5H<)$&ZevEiSLEftPMb)j`s8_Hl%Ribl~+aAvNonvbFBBYGS=bw zetEy0wn>cKf*jelkgdB~J~H8;{W*qelHVvedBK8-@Gk?r5<+6!Z^?sPC(pqU53qvA zYT_$KbI^%$?;mNHc6oY>A{$c-A5g;?)=SG1&U@&BVs&x%?IK*M&{r4xV_4kQY?D`jrK8xMjJ-&~M2rid%%xQUTj4We8W?z_QU6%;b za^wYub&BQgfxD~}MZJ+b4!*CaL2YbH7~iJs7*M@YN!E6NRlKM!9T|%a9!Lf~YYPMd z1t#J7&@rD|_L1*$GdJ`U26}d5w1l&jds7Po9Z3=b8|7m4BqU0JvWp&1m1uoVK;RM( z!|S@DjKGCitJ_oSb9t0_Tp#A)#PK@kEJty4Kt*9+TiBpuw0kEXd)?haSN|%?xSYae zla6%La)MCX6#2<{9Sl13ijy`cNvmJ`;mJej#SF)tORqPj)-4+ zW&*JIl)jklHRV5%r-uhE4F9ptXok0qg$;nU?wpva*!9&i#6od6&+PYULoUEPAwcTK z6c;O_1*z@Uv)$&>dus})E#eA$(3JLv>?4*B5NMwQF$mW&%5NiDL->-Hf(&3=57!iO zL0tj&0U*|BUbVtGLCI|I-!!RnC^N@$@Tm1N1&feKG0o8?oy3D|aBVX6J6pljC9*XL zGFB1P=pZHY`gUZ!nLG?OD?T_`CM#28{@NFIU;iACdqFnr)a6ogsxZo%MxEh*C)2f3 z1YMqx$Gbkwe!^W_GwCtx5SV>;0N>a}(X+gW9J;J<=rH)o5OPktU?#_Ui9V$Rne5)$7SOn#0k=5&M%o~?4xiqumbIw|}7GC#dtl96#;|-5k z2wGY81_Ltrm|QAIsfK_LY`^sd=kdL$Oj$W~In5B%_H-R^_^{YKu%nTbf8M*-T#z;w zkZF5;5qa)tekHzT9*|kAvMq({19>L-s*apON&pXz#3Djq}3%kc?O=M)ye7@l>q|$mRbtG*1l1} z-wyOfn}VwgiTZXmkiC()_bT|ss9q(7=wpf1+AkBEU{UmFF~PN;NvuEb))6L_<1P4- zutRH~QYyXDkq6cnoE9K7n9qgV%X0yvCH2ISN6>TYQyZz;AT4k05fjUd9q4D=K_-#B z?a&nYxOA)ZIeTiPd*wE>q@En?Z9qjJ3}KSSbQ~bLrcO)0z}>Np9aQ@PI8C9t97o?i z2CxJeTTi2qVlmkv_He`HSOhxV(&{9&E{H5o8ddbtqdxa8 zpetOmEN$s|@`qM7iZ4ewX-a!Cf;f9D3)TyXl2G}|E~0pE*vzRB(~yjK1BX;F5cq|P zi62J=)j?1iinXKfkEJ6M+9O6-%Qkdm^M0X*#ki3LSmwf3IDF%Ww(7RpN$vXoVyzl> zRLi_A(;jXtya4ncOs+k-{Yt;=!-HLbJe}$fF6>Yyv-hX9#Z?ki=Xa6cCf_y)keh)O z$t<{F0lhlr)%M$tdvln1MD;rsAAM6@6femJoOmO|%TK?R3*q5MZwM!Jkx?xAAfm#J zN0ZOB74$9D#3aYt6ngXnYml8WDbk%M?THC8BmCZ#?NMZepp*N^{@Qcj$HyKaExtFS zy$=gLkq-Ugk2Z+{-;**8YT>})kmAYsEr-ZkNZHP~g-$>cp55#QZa1*`=7l`9hUl2N zC*rlQZQ}$rY~?%0rl@FKu{&n9z+)fKl(H#k1|`I0et9%OSrbG$o}p4hbZ|p}-YR&HDO; zgY)=_v|Ah5-2(`nl}`C=cl7Vic4?pW`J~L%K_b@6t|f1pCBp%Us;2MK#ug2OqI?r@ zN3CUGEqfPKJ4h1qz^(21glWWFRE*0~N}f?+9lmqLg7w8jweCleNLTC)Y4+$Tc`IMA z*awZ9GoW=i&;lV*@n+$lXAO#6e4E}09D<@JbWmwT6=IwjOjjb%CYjnlAyTY-u$D^B zqitlYv9ls^H4FnjbHdNzxO;UfE(DLAir5T|t(*TkW@1HAS(LIpBy5l^ruWyrpdjo5 z5wd0(iK2u2CV(z?3W926a#lZK3FiAQ5zl#m_N@Fe0AT%pK#)*zNo%x=f=1;nh})M;I?257x=Yq^KnYqgsndj zVoU>h{}Qnuim;>;nU*@uP0H(s)`-U1%DYts03xD?H=x-vo*GBfnVkrjNmDAqOYD>- z$$Ug-q;3F3S&f|HhkUH%!C`C5>WJu^rtSpt|Jx&bN{Py2z+i~gkn=K7v(>urBzMy5fbncKmC=uEXJ+&ny zY*}pXLLp505aXbi;4Crn@>`YzlNA@@Kr^?O``Yz1YD3gIQOjERiwR;}XOGK9Q(gN( zIl@KP_^|lZ&Xo)|Tz8Y3A;sQ(*l5oIT4|sI;WJTZVBy?19ap(_F))V!Q~<5E;n%&S zw`6v*m3$R3{qK(T`0DD0f*^F|SUeuCYd@!=*;5Peks5$iTI|vX5eesc3ssr}{q*oE z#v?JvjN|{_$zqXy`}7WN=_+CtS~dX3{4q?k9Wn}y9NB&IR~cI$I?w<~F#v@KJqk}w zDc}HVvQKflRZ!!wi1u48zuYW(HY0Ua25nqNzw<^;L*0~e#$z>m)-HL0zE@ulqOwDR z=0D)GtqPqBi&F}nSs0;0anLY#iZ#;DdY7qZFl4X%9CY$#$;eNQAHgkD-$mvsS^%vk zC}QQNjj(M$bY^l>7Xav7`P{Y$x!o`ouJoJ}F!u{m)$LaECUj5OF|ejbP6t>@l;BU# z-g(wsN$xD6qsGpT*B^$v!6Ys=ts^4Zk6CarsG)Cee#RrSbTnrx!xl?DFMgXHNGTWbbJ*ox_ zovBmD%&0NqOVF2ev%Rd`9Dr%pM6Z4H}MNwCT`TefkU<}vIQvGJU-5N$=X4mU^W3f zwZ??ximnb$yADzoz@FEkiS35BMv1#4g=I85TG`tQ`D8JV**p#NbGD~WYY3NYdo*$b zB)MF}fuwW^2f@T~#PoaM15=)sQ_RdA=?oT2RC5W%|0)WE2S%YWA3elWI3U-smG0IO z9iqJEX7Dn%I%$KD5Fyz_&Z*!|>D`Pj?2GlVfs`I)+;5hGUP7wBuy!o>JL~(W+?-v< zs6J~ZYG?6i;m#?%Dsg*b_4}Wx{vqaV29D_-*9B9(#to61>ShcB1|tkM(+p^B`)}W> z0uhSGNzK|2D&&onM1kPXims9UCez$mXZzxSn{?OBy(Bi#(Sd@U&$o@LxG$ln4WxXlhK`LV$|og8{|osNXD zYrh0kA)YOcD1OZe76cn09E3m;Xbz{SiR2J)M<-t^>;`(w-X(mKW2Wb^>-i$N3#y_# z3?YLO*86N0>lM z$FUQYH*jIuCT#ArJmkU#shoANCl#{E|JOS9_LtT?1{OiX^7AxGsYl1jgd0qazCex*H=ijD(|Q+epeO2{4c-DBl1@eT=6lXFNNfE|_NIgy zl5$Q4Y16R>aA{nRJrZur9z+$U=BK(@o-vBeXXhjK+l{_2Lcn>&RaM&(7t%13JgzIA zNTQ8w^mcIFEbI@Zl)HJ^PG^+5G-Mz9;|`arbc$#>j>}(pD>_7lsFse z8=S|2(uk9F*O4`5obYN6V6Yw#Kr5b1`KWo`MD8O+1!WV|MzlEpZprrI1hH>%1J_7+ zrz}4K@AuP6ePdjUO{|xH9T)WVE&kf$W^<-_-%sICOnGmrtz?SBz`Jl^Yq1I}Y+1r|jrZ$hRj2BfN0Dnew zpjQ|8YLboGjn7V7#cJx+d)VKSQGI+}gq^;`l}Ifc=c={YS{t>s670_==pKj15emVj znAfad%VqGM@5#FQa`IE|rV_z3(o-sq{-!PbxEOv2I z5wISnKR!b=u;gU)rM2z}S|`sPoDlnthL!qHZ;FA+Wni_m!mnAfggIJk zOE%w?KC9GWc(1B4m`ym~rlu-One35>MlYv_t7gY2xS&;dKg|!DC^Yec5`-K&!07^6 z5VvX{T+MLQKKp7{(5$?Yvg;7p4-#5fym2;Q0R8)>gE4sUXkw^VW^a9q>3~oJ_LLD& z&lSod5VT_BS7?uzN|_M0O~I#&%l?bn1Y~SUsM(ufa{4W9s8K7VjaG}KX(v7~5pvt} z%ruAx-+p;5DnA%!dM^MbaSMGt3rp@4>8@W-|D^SItdDUD`Y8ULWc*Zt&~eG^$Iin|d^U zT<}p2CZxr%SB}dU<29{B!eREYFRFMgU^AE{UDo~bm`{=GLHU3S9xR zB{=MGz(rV1phVe5nXxXudR_lNX~pKhry(C^4c2MXpHzP>1Zs52=^wIHa> zmc%7PopYq8?fq!Urs`Uf>pUPjunTHB6%b!BlzVnF-7$5UTuBXMZ)Un1QK_*_OS=lg z7q+c@LZLJHJ3`i}{xlEA3Gz`GLB;1TqTwj!6v(ErAor_<8pSeIud52w@R6K<31&o) z6&m7G4d$7VLE&H{TC`zMkEZCXt|cyn>X)&=xvL62sfMWlgJ0WTnn&flTCK4+Zyg(O z|7w(q2@(CPFvH7ugSb{>rw|PZS zXuC@a4r=A>teN1Y?18cFZEL^=lm9N;z^Di(jqjmeb>r%%?mH{XA5L<71p0~O#xg>) zYisjv!gbN&4vM~cx^*(+1#0Ei=wJ4g7@U>6WOm~x4iZB*k}H==mSr4-T=)YtbsV70 zL7wj_st?n{D2ssL-aLRw6z+6W`B{(iNF$?7|eo zseGK;*}?f^hC*JIq+%lMBdH2g_2@xek1E675&UDSn3RPRL9Ew1TZmU?>0}voZvN&J z#L1y{t!ZBFQii#O@w!;#NY&X#%0Kh?@Oze+IVysK?)ylQZ2wpz!Fam$3SC3;XMCSD z45HMsALJnMR&14c0Y%f(K5p^+i*Uv&gE2WL9(2az*+jO%I~q7%oWz*1^U+Ndz!aUM ztIRa#P!@h596lxnflPb>EpnG=9@0%}v@&Wmt2Y}ABy~yVWd?S-Fj``|y-cS=1@58Q zX<)__q7Zmw1t?fx-&(3ZvhRBr_->U>Z+6*ae8FTPAVMYR=&jhUI!d#pRXXX$95-H15$h zc=^xI4Bu(q3FLt7*-->OZw3WfNP&b#hgxTXkm}+?4!OTCfvQ7Jm*W~$WbmGueUVh3 z0k#x-y9R0>B16k02+_|c`#Xi^OBR&NPs#>AJW9KbO^kY>5KMlZ{ndADNYKCBDZVEMYPF6tlhwwO6CFe2BG zwEH}av!oCiN_zS%GKMABX})IWE!JWaM8xsXe)h$zLjf~v z1GX|=zIp&}Tq|me6Em2_Fra1Zn1J;})AtWLrTF>Br?5ddTaEs-=B0GcZ+7KKooC

{hN?$6MAf-Ag$+!bWY8G;^A=$= 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 literal 0 HcmV?d00001 diff --git a/kernel/tools/perf/files/patches/mageia/CVE-2019-12379.patch b/kernel/tools/perf/files/patches/mageia/CVE-2019-12379.patch new file mode 100644 index 0000000000..04d16049ac --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/CVE-2019-12379.patch @@ -0,0 +1,37 @@ +From 84ecc2f6eb1cb12e6d44818f94fa49b50f06e6ac Mon Sep 17 00:00:00 2001 +From: Gen Zhang +Date: Thu, 23 May 2019 08:34:52 +0800 +Subject: consolemap: Fix a memory leaking bug in drivers/tty/vt/consolemap.c + +In function con_insert_unipair(), when allocation for p2 and p1[n] +fails, ENOMEM is returned, but previously allocated p1 is not freed, +remains as leaking memory. Thus we should free p1 as well when this +allocation fails. + +Signed-off-by: Gen Zhang +Reviewed-by: Kees Cook +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/vt/consolemap.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c +index b28aa0d289f8..79fcc96cc7c0 100644 +--- a/drivers/tty/vt/consolemap.c ++++ b/drivers/tty/vt/consolemap.c +@@ -489,7 +489,11 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos) + p2 = p1[n = (unicode >> 6) & 0x1f]; + if (!p2) { + p2 = p1[n] = kmalloc_array(64, sizeof(u16), GFP_KERNEL); +- if (!p2) return -ENOMEM; ++ if (!p2) { ++ kfree(p1); ++ p->uni_pgdir[n] = NULL; ++ return -ENOMEM; ++ } + memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */ + } + +-- +cgit 1.2-0.3.lf.el7 + diff --git a/kernel/tools/perf/files/patches/mageia/fs-aufs-5.4-modular.patch b/kernel/tools/perf/files/patches/mageia/fs-aufs-5.4-modular.patch new file mode 100644 index 0000000000..ec4a91353c --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/fs-aufs-5.4-modular.patch @@ -0,0 +1,321 @@ + + fs/aufs/Kconfig | 2 +- + fs/dcache.c | 2 ++ + fs/exec.c | 1 + + fs/fcntl.c | 1 + + fs/file_table.c | 2 ++ + fs/inode.c | 1 + + fs/namespace.c | 3 +++ + fs/notify/group.c | 1 + + fs/open.c | 1 + + fs/read_write.c | 4 ++++ + fs/splice.c | 2 ++ + fs/sync.c | 1 + + fs/xattr.c | 1 + + kernel/locking/lockdep.c | 1 + + kernel/task_work.c | 1 + + security/device_cgroup.c | 1 + + security/security.c | 8 ++++++++ + 17 files changed, 32 insertions(+), 1 deletion(-) + +diff -Nurp linux-5.4-aufs/fs/aufs/Kconfig linux-5.4-aufs-mod/fs/aufs/Kconfig +--- linux-5.4-aufs/fs/aufs/Kconfig 2019-11-28 01:25:59.062925618 +0200 ++++ linux-5.4-aufs-mod/fs/aufs/Kconfig 2019-11-28 01:38:40.564895255 +0200 +@@ -1,6 +1,6 @@ + # SPDX-License-Identifier: GPL-2.0 + config AUFS_FS +- bool "Aufs (Advanced multi layered unification filesystem) support" ++ tristate "Aufs (Advanced multi layered unification filesystem) support" + help + Aufs is a stackable unification filesystem such as Unionfs, + which unifies several directories and provides a merged single +diff -Nurp linux-5.4-aufs/fs/dcache.c linux-5.4-aufs-mod/fs/dcache.c +--- linux-5.4-aufs/fs/dcache.c 2019-11-28 01:25:59.069925618 +0200 ++++ linux-5.4-aufs-mod/fs/dcache.c 2019-11-28 01:38:40.585895254 +0200 +@@ -1369,6 +1369,7 @@ rename_retry: + seq = 1; + goto again; + } ++EXPORT_SYMBOL_GPL(d_walk); + + struct check_mount { + struct vfsmount *mnt; +@@ -2914,6 +2915,7 @@ void d_exchange(struct dentry *dentry1, + + write_sequnlock(&rename_lock); + } ++EXPORT_SYMBOL_GPL(d_exchange); + + /** + * d_ancestor - search for an ancestor +diff -Nurp linux-5.4-aufs/fs/exec.c linux-5.4-aufs-mod/fs/exec.c +--- linux-5.4-aufs/fs/exec.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs-mod/fs/exec.c 2019-11-28 01:38:40.589895254 +0200 +@@ -110,6 +110,7 @@ bool path_noexec(const struct path *path + return (path->mnt->mnt_flags & MNT_NOEXEC) || + (path->mnt->mnt_sb->s_iflags & SB_I_NOEXEC); + } ++EXPORT_SYMBOL_GPL(path_noexec); + + #ifdef CONFIG_USELIB + /* +diff -Nurp linux-5.4-aufs/fs/fcntl.c linux-5.4-aufs-mod/fs/fcntl.c +--- linux-5.4-aufs/fs/fcntl.c 2019-11-28 01:25:59.069925618 +0200 ++++ linux-5.4-aufs-mod/fs/fcntl.c 2019-11-28 01:38:40.589895254 +0200 +@@ -85,6 +85,7 @@ int setfl(int fd, struct file * filp, un + out: + return error; + } ++EXPORT_SYMBOL_GPL(setfl); + + static void f_modown(struct file *filp, struct pid *pid, enum pid_type type, + int force) +diff -Nurp linux-5.4-aufs/fs/file_table.c linux-5.4-aufs-mod/fs/file_table.c +--- linux-5.4-aufs/fs/file_table.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs-mod/fs/file_table.c 2019-11-28 01:38:40.589895254 +0200 +@@ -162,6 +162,7 @@ over: + } + return ERR_PTR(-ENFILE); + } ++EXPORT_SYMBOL_GPL(alloc_empty_file); + + /* + * Variant of alloc_empty_file() that doesn't check and modify nr_files. +@@ -375,6 +377,7 @@ void __fput_sync(struct file *file) + } + + EXPORT_SYMBOL(fput); ++EXPORT_SYMBOL_GPL(__fput_sync); + + void __init files_init(void) + { +diff -Nurp linux-5.4-aufs/fs/inode.c linux-5.4-aufs-mod/fs/inode.c +--- linux-5.4-aufs/fs/inode.c 2019-11-28 01:25:59.070925617 +0200 ++++ linux-5.4-aufs-mod/fs/inode.c 2019-11-28 01:38:40.589895254 +0200 +@@ -1682,6 +1682,7 @@ int update_time(struct inode *inode, str + + return update_time(inode, time, flags); + } ++EXPORT_SYMBOL_GPL(update_time); + + /** + * touch_atime - update the access time +diff -Nurp linux-5.4-aufs/fs/namespace.c linux-5.4-aufs-mod/fs/namespace.c +--- linux-5.4-aufs/fs/namespace.c 2019-11-28 01:25:59.070925617 +0200 ++++ linux-5.4-aufs-mod/fs/namespace.c 2019-11-28 01:38:40.589895254 +0200 +@@ -431,6 +431,7 @@ void __mnt_drop_write(struct vfsmount *m + mnt_dec_writers(real_mount(mnt)); + preempt_enable(); + } ++EXPORT_SYMBOL_GPL(__mnt_drop_write); + + /** + * mnt_drop_write - give up write access to a mount +@@ -781,6 +782,7 @@ int is_current_mnt_ns(struct vfsmount *m + { + return check_mnt(real_mount(mnt)); + } ++EXPORT_SYMBOL_GPL(is_current_mnt_ns); + + /* + * vfsmount lock must be held for write +@@ -1903,6 +1905,7 @@ int iterate_mounts(int (*f)(struct vfsmo + } + return 0; + } ++EXPORT_SYMBOL_GPL(iterate_mounts); + + static void lock_mnt_tree(struct mount *mnt) + { +diff -Nurp linux-5.4-aufs/fs/notify/group.c linux-5.4-aufs-mod/fs/notify/group.c +--- linux-5.4-aufs/fs/notify/group.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs-mod/fs/notify/group.c 2019-11-28 01:38:40.590895253 +0200 +@@ -99,6 +99,7 @@ void fsnotify_get_group(struct fsnotify_ + { + refcount_inc(&group->refcnt); + } ++EXPORT_SYMBOL_GPL(fsnotify_get_group); + + /* + * Drop a reference to a group. Free it if it's through. +diff -Nurp linux-5.4-aufs/fs/open.c linux-5.4-aufs-mod/fs/open.c +--- linux-5.4-aufs/fs/open.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs-mod/fs/open.c 2019-11-28 01:38:48.762894928 +0200 +@@ -65,6 +65,7 @@ int do_truncate(struct dentry *dentry, l + inode_unlock(dentry->d_inode); + return ret; + } ++EXPORT_SYMBOL_GPL(do_truncate); + + long vfs_truncate(const struct path *path, loff_t length) + { +diff -Nurp linux-5.4-aufs/fs/read_write.c linux-5.4-aufs-mod/fs/read_write.c +--- linux-5.4-aufs/fs/read_write.c 2019-11-28 01:25:59.070925617 +0200 ++++ linux-5.4-aufs-mod/fs/read_write.c 2019-11-28 01:38:48.780894927 +0200 +@@ -468,6 +468,7 @@ ssize_t vfs_read(struct file *file, char + + return ret; + } ++EXPORT_SYMBOL_GPL(vfs_read); + + static ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos) + { +@@ -508,6 +509,7 @@ vfs_readf_t vfs_readf(struct file *file) + return new_sync_read; + return ERR_PTR(-ENOSYS); + } ++EXPORT_SYMBOL_GPL(vfs_readf); + + vfs_writef_t vfs_writef(struct file *file) + { +@@ -519,6 +521,7 @@ vfs_writef_t vfs_writef(struct file *fil + return new_sync_write; + return ERR_PTR(-ENOSYS); + } ++EXPORT_SYMBOL_GPL(vfs_writef); + + ssize_t __kernel_write(struct file *file, const void *buf, size_t count, loff_t *pos) + { +@@ -588,6 +591,7 @@ ssize_t vfs_write(struct file *file, con + + return ret; + } ++EXPORT_SYMBOL_GPL(vfs_write); + + /* file_ppos returns &file->f_pos or NULL if file is stream */ + static inline loff_t *file_ppos(struct file *file) +diff -Nurp linux-5.4-aufs/fs/splice.c linux-5.4-aufs-mod/fs/splice.c +--- linux-5.4-aufs/fs/splice.c 2019-11-28 01:25:59.071925617 +0200 ++++ linux-5.4-aufs-mod/fs/splice.c 2019-11-28 01:38:48.780894927 +0200 +@@ -847,6 +847,7 @@ long do_splice_from(struct pipe_inode_in + + return splice_write(pipe, out, ppos, len, flags); + } ++EXPORT_SYMBOL_GPL(do_splice_from); + + /* + * Attempt to initiate a splice from a file to a pipe. +@@ -876,6 +877,7 @@ long do_splice_to(struct file *in, loff_ + + return splice_read(in, ppos, pipe, len, flags); + } ++EXPORT_SYMBOL_GPL(do_splice_to); + + /** + * splice_direct_to_actor - splices data directly between two non-pipes +diff -Nurp linux-5.4-aufs/fs/sync.c linux-5.4-aufs-mod/fs/sync.c +--- linux-5.4-aufs/fs/sync.c 2019-11-28 01:25:59.071925617 +0200 ++++ linux-5.4-aufs-mod/fs/sync.c 2019-11-28 01:38:48.780894927 +0200 +@@ -39,6 +39,7 @@ int __sync_filesystem(struct super_block + sb->s_op->sync_fs(sb, wait); + return __sync_blockdev(sb->s_bdev, wait); + } ++EXPORT_SYMBOL_GPL(__sync_filesystem); + + /* + * Write out and wait upon all dirty data associated with this +diff -Nurp linux-5.4-aufs/fs/xattr.c linux-5.4-aufs-mod/fs/xattr.c +--- linux-5.4-aufs/fs/xattr.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs-mod/fs/xattr.c 2019-11-28 01:38:48.780894927 +0200 +@@ -296,6 +296,7 @@ vfs_getxattr_alloc(struct dentry *dentry + *xattr_value = value; + return error; + } ++EXPORT_SYMBOL_GPL(vfs_getxattr_alloc); + + ssize_t + __vfs_getxattr(struct dentry *dentry, struct inode *inode, const char *name, +diff -Nurp linux-5.4-aufs/kernel/locking/lockdep.c linux-5.4-aufs-mod/kernel/locking/lockdep.c +--- linux-5.4-aufs/kernel/locking/lockdep.c 2019-11-28 01:25:59.072925617 +0200 ++++ linux-5.4-aufs-mod/kernel/locking/lockdep.c 2019-11-28 01:38:48.780894927 +0200 +@@ -174,6 +174,7 @@ inline struct lock_class *lockdep_hlock_ + */ + return lock_classes + class_idx; + } ++EXPORT_SYMBOL_GPL(lockdep_hlock_class); + #define hlock_class(hlock) lockdep_hlock_class(hlock) + + #ifdef CONFIG_LOCK_STAT +diff -Nurp linux-5.4-aufs/kernel/task_work.c linux-5.4-aufs-mod/kernel/task_work.c +--- linux-5.4-aufs/kernel/task_work.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs-mod/kernel/task_work.c 2019-11-28 01:38:48.786894927 +0200 +@@ -116,3 +116,4 @@ void task_work_run(void) + } while (work); + } + } ++EXPORT_SYMBOL_GPL(task_work_run); +diff -Nurp linux-5.4-aufs/security/device_cgroup.c linux-5.4-aufs-mod/security/device_cgroup.c +--- linux-5.4-aufs/security/device_cgroup.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs-mod/security/device_cgroup.c 2019-11-28 01:38:48.790894927 +0200 +@@ -824,3 +824,4 @@ int __devcgroup_check_permission(short t + + return 0; + } ++EXPORT_SYMBOL_GPL(__devcgroup_check_permission); +diff -Nurp linux-5.4-aufs/security/security.c linux-5.4-aufs-mod/security/security.c +--- linux-5.4-aufs/security/security.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs-mod/security/security.c 2019-11-28 01:38:48.794894926 +0200 +@@ -1036,6 +1036,7 @@ int security_path_rmdir(const struct pat + return 0; + return call_int_hook(path_rmdir, 0, dir, dentry); + } ++EXPORT_SYMBOL_GPL(security_path_rmdir); + + int security_path_unlink(const struct path *dir, struct dentry *dentry) + { +@@ -1052,6 +1053,7 @@ int security_path_symlink(const struct p + return 0; + return call_int_hook(path_symlink, 0, dir, dentry, old_name); + } ++EXPORT_SYMBOL_GPL(security_path_symlink); + + int security_path_link(struct dentry *old_dentry, const struct path *new_dir, + struct dentry *new_dentry) +@@ -1060,6 +1062,7 @@ int security_path_link(struct dentry *ol + return 0; + return call_int_hook(path_link, 0, old_dentry, new_dir, new_dentry); + } ++EXPORT_SYMBOL_GPL(security_path_link); + + int security_path_rename(const struct path *old_dir, struct dentry *old_dentry, + const struct path *new_dir, struct dentry *new_dentry, +@@ -1087,6 +1090,7 @@ int security_path_truncate(const struct + return 0; + return call_int_hook(path_truncate, 0, path); + } ++EXPORT_SYMBOL_GPL(security_path_truncate); + + int security_path_chmod(const struct path *path, umode_t mode) + { +@@ -1094,6 +1098,7 @@ int security_path_chmod(const struct pat + return 0; + return call_int_hook(path_chmod, 0, path, mode); + } ++EXPORT_SYMBOL_GPL(security_path_chmod); + + int security_path_chown(const struct path *path, kuid_t uid, kgid_t gid) + { +@@ -1101,6 +1106,7 @@ int security_path_chown(const struct pat + return 0; + return call_int_hook(path_chown, 0, path, uid, gid); + } ++EXPORT_SYMBOL_GPL(security_path_chown); + + int security_path_chroot(const struct path *path) + { +@@ -1201,6 +1207,7 @@ int security_inode_permission(struct ino + return 0; + return call_int_hook(inode_permission, 0, inode, mask); + } ++EXPORT_SYMBOL_GPL(security_inode_permission); + + int security_inode_setattr(struct dentry *dentry, struct iattr *attr) + { +@@ -1378,6 +1385,7 @@ int security_file_permission(struct file + + return fsnotify_perm(file, mask); + } ++EXPORT_SYMBOL_GPL(security_file_permission); + + int security_file_alloc(struct file *file) + { diff --git a/kernel/tools/perf/files/patches/mageia/fs-aufs-5.4-version.patch b/kernel/tools/perf/files/patches/mageia/fs-aufs-5.4-version.patch new file mode 100755 index 0000000000..85c71bf3c0 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/fs-aufs-5.4-version.patch @@ -0,0 +1,12 @@ +diff -Nurp linux-5.3-aufs/include/uapi/linux/aufs_type.h linux-5.3-aufs-ver/include/uapi/linux/aufs_type.h +--- linux-5.3-aufs/include/uapi/linux/aufs_type.h 2019-09-24 16:13:44.012259519 +0300 ++++ linux-5.3-aufs-ver/include/uapi/linux/aufs_type.h 2019-09-24 20:04:21.924707762 +0300 +@@ -27,7 +27,7 @@ + + #include + +-#define AUFS_VERSION "5.x-rcN" ++#define AUFS_VERSION "5.4" + + /* todo? move this to linux-2.6.19/include/magic.h */ + #define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's') diff --git a/kernel/tools/perf/files/patches/mageia/fs-aufs-5.4.patch b/kernel/tools/perf/files/patches/mageia/fs-aufs-5.4.patch new file mode 100644 index 0000000000..0f717dbf39 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/fs-aufs-5.4.patch @@ -0,0 +1,37876 @@ + + Documentation/ABI/testing/debugfs-aufs | 55 + Documentation/ABI/testing/sysfs-aufs | 31 + Documentation/filesystems/aufs/README | 399 +++ + Documentation/filesystems/aufs/design/01intro.txt | 158 + + Documentation/filesystems/aufs/design/02struct.txt | 245 ++ + Documentation/filesystems/aufs/design/03atomic_open.txt | 72 + Documentation/filesystems/aufs/design/03lookup.txt | 100 + Documentation/filesystems/aufs/design/04branch.txt | 61 + Documentation/filesystems/aufs/design/05wbr_policy.txt | 51 + Documentation/filesystems/aufs/design/06dirren.dot | 31 + Documentation/filesystems/aufs/design/06dirren.txt | 89 + Documentation/filesystems/aufs/design/06fhsm.txt | 105 + Documentation/filesystems/aufs/design/06mmap.txt | 59 + Documentation/filesystems/aufs/design/06xattr.txt | 81 + Documentation/filesystems/aufs/design/07export.txt | 45 + Documentation/filesystems/aufs/design/08shwh.txt | 39 + Documentation/filesystems/aufs/design/10dynop.txt | 34 + MAINTAINERS | 13 + drivers/block/loop.c | 18 + fs/Kconfig | 1 + fs/Makefile | 1 + fs/aufs/Kconfig | 199 + + fs/aufs/Makefile | 39 + fs/aufs/aufs.h | 49 + fs/aufs/branch.c | 1415 +++++++++++ + fs/aufs/branch.h | 353 ++ + fs/aufs/cpup.c | 1445 +++++++++++ + fs/aufs/cpup.h | 87 + fs/aufs/dbgaufs.c | 513 ++++ + fs/aufs/dbgaufs.h | 40 + fs/aufs/dcsub.c | 212 + + fs/aufs/dcsub.h | 124 + + fs/aufs/debug.c | 428 +++ + fs/aufs/debug.h | 213 + + fs/aufs/dentry.c | 1141 +++++++++ + fs/aufs/dentry.h | 255 ++ + fs/aufs/dinfo.c | 541 ++++ + fs/aufs/dir.c | 750 ++++++ + fs/aufs/dir.h | 121 + fs/aufs/dirren.c | 1303 ++++++++++ + fs/aufs/dirren.h | 127 + + fs/aufs/dynop.c | 354 ++ + fs/aufs/dynop.h | 64 + fs/aufs/export.c | 825 ++++++ + fs/aufs/f_op.c | 806 ++++++ + fs/aufs/fhsm.c | 413 +++ + fs/aufs/file.c | 850 ++++++ + fs/aufs/file.h | 329 ++ + fs/aufs/finfo.c | 136 + + fs/aufs/fstype.h | 388 +++ + fs/aufs/hbl.h | 52 + fs/aufs/hfsnotify.c | 275 ++ + fs/aufs/hfsplus.c | 47 + fs/aufs/hnotify.c | 708 +++++ + fs/aufs/i_op.c | 1492 ++++++++++++ + fs/aufs/i_op_add.c | 923 +++++++ + fs/aufs/i_op_del.c | 500 ++++ + fs/aufs/i_op_ren.c | 1237 ++++++++++ + fs/aufs/iinfo.c | 273 ++ + fs/aufs/inode.c | 516 ++++ + fs/aufs/inode.h | 685 +++++ + fs/aufs/ioctl.c | 207 + + fs/aufs/lcnt.h | 173 + + fs/aufs/loop.c | 135 + + fs/aufs/loop.h | 42 + fs/aufs/magic.mk | 31 + fs/aufs/module.c | 259 ++ + fs/aufs/module.h | 153 + + fs/aufs/mvdown.c | 693 +++++ + fs/aufs/opts.c | 1867 +++++++++++++++ + fs/aufs/opts.h | 212 + + fs/aufs/plink.c | 503 ++++ + fs/aufs/poll.c | 38 + fs/aufs/posix_acl.c | 92 + fs/aufs/procfs.c | 158 + + fs/aufs/rdu.c | 371 +++ + fs/aufs/rwsem.h | 60 + fs/aufs/sbinfo.c | 301 ++ + fs/aufs/super.c | 1034 ++++++++ + fs/aufs/super.h | 576 ++++ + fs/aufs/sysaufs.c | 80 + fs/aufs/sysaufs.h | 89 + fs/aufs/sysfs.c | 338 ++ + fs/aufs/sysrq.c | 147 + + fs/aufs/vdir.c | 883 +++++++ + fs/aufs/vfsub.c | 889 +++++++ + fs/aufs/vfsub.h | 341 ++ + fs/aufs/wbr_policy.c | 817 ++++++ + fs/aufs/whout.c | 1049 ++++++++ + fs/aufs/whout.h | 73 + fs/aufs/wkq.c | 379 +++ + fs/aufs/wkq.h | 76 + fs/aufs/xattr.c | 343 ++ + fs/aufs/xino.c | 1952 ++++++++++++++++ + fs/dcache.c | 2 + fs/fcntl.c | 4 + fs/inode.c | 2 + fs/namespace.c | 6 + fs/proc/base.c | 2 + fs/proc/nommu.c | 5 + fs/proc/task_mmu.c | 7 + fs/proc/task_nommu.c | 5 + fs/read_write.c | 22 + fs/splice.c | 10 + fs/sync.c | 2 + include/linux/fs.h | 10 + include/linux/lockdep.h | 3 + include/linux/mm.h | 22 + include/linux/mm_types.h | 2 + include/linux/mnt_namespace.h | 3 + include/linux/splice.h | 6 + include/uapi/linux/aufs_type.h | 439 +++ + kernel/fork.c | 2 + kernel/locking/lockdep.c | 3 + mm/Makefile | 2 + mm/filemap.c | 2 + mm/mmap.c | 33 + mm/nommu.c | 10 + mm/prfile.c | 86 + 119 files changed, 36936 insertions(+), 31 deletions(-) + +diff -Nurp linux-5.4/Documentation/ABI/testing/debugfs-aufs linux-5.4-aufs/Documentation/ABI/testing/debugfs-aufs +--- linux-5.4/Documentation/ABI/testing/debugfs-aufs 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/ABI/testing/debugfs-aufs 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,55 @@ ++What: /debug/aufs/si_/ ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ Under /debug/aufs, a directory named si_ is created ++ per aufs mount, where is a unique id generated ++ internally. ++ ++What: /debug/aufs/si_/plink ++Date: Apr 2013 ++Contact: J. R. Okajima ++Description: ++ It has three lines and shows the information about the ++ pseudo-link. The first line is a single number ++ representing a number of buckets. The second line is a ++ number of pseudo-links per buckets (separated by a ++ blank). The last line is a single number representing a ++ total number of psedo-links. ++ When the aufs mount option 'noplink' is specified, it ++ will show "1\n0\n0\n". ++ ++What: /debug/aufs/si_/xib ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ It shows the consumed blocks by xib (External Inode Number ++ Bitmap), its block size and file size. ++ When the aufs mount option 'noxino' is specified, it ++ will be empty. About XINO files, see the aufs manual. ++ ++What: /debug/aufs/si_/xi0, xi1 ... xiN and xiN-N ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ It shows the consumed blocks by xino (External Inode Number ++ Translation Table), its link count, block size and file ++ size. ++ Due to the file size limit, there may exist multiple ++ xino files per branch. In this case, "-N" is added to ++ the filename and it corresponds to the index of the ++ internal xino array. "-0" is omitted. ++ When the aufs mount option 'noxino' is specified, Those ++ entries won't exist. About XINO files, see the aufs ++ manual. ++ ++What: /debug/aufs/si_/xigen ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ It shows the consumed blocks by xigen (External Inode ++ Generation Table), its block size and file size. ++ If CONFIG_AUFS_EXPORT is disabled, this entry will not ++ be created. ++ When the aufs mount option 'noxino' is specified, it ++ will be empty. About XINO files, see the aufs manual. +diff -Nurp linux-5.4/Documentation/ABI/testing/sysfs-aufs linux-5.4-aufs/Documentation/ABI/testing/sysfs-aufs +--- linux-5.4/Documentation/ABI/testing/sysfs-aufs 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/ABI/testing/sysfs-aufs 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,31 @@ ++What: /sys/fs/aufs/si_/ ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ Under /sys/fs/aufs, a directory named si_ is created ++ per aufs mount, where is a unique id generated ++ internally. ++ ++What: /sys/fs/aufs/si_/br0, br1 ... brN ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ It shows the abolute path of a member directory (which ++ is called branch) in aufs, and its permission. ++ ++What: /sys/fs/aufs/si_/brid0, brid1 ... bridN ++Date: July 2013 ++Contact: J. R. Okajima ++Description: ++ It shows the id of a member directory (which is called ++ branch) in aufs. ++ ++What: /sys/fs/aufs/si_/xi_path ++Date: March 2009 ++Contact: J. R. Okajima ++Description: ++ It shows the abolute path of XINO (External Inode Number ++ Bitmap, Translation Table and Generation Table) file ++ even if it is the default path. ++ When the aufs mount option 'noxino' is specified, it ++ will be empty. About XINO files, see the aufs manual. +diff -Nurp linux-5.4/Documentation/filesystems/aufs/design/01intro.txt linux-5.4-aufs/Documentation/filesystems/aufs/design/01intro.txt +--- linux-5.4/Documentation/filesystems/aufs/design/01intro.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/design/01intro.txt 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,158 @@ ++ ++# Copyright (C) 2005-2019 Junjiro R. Okajima ++ ++Introduction ++---------------------------------------- ++ ++aufs [ei ju: ef es] | /ey-yoo-ef-es/ | [a u f s] ++1. abbrev. for "advanced multi-layered unification filesystem". ++2. abbrev. for "another unionfs". ++3. abbrev. for "auf das" in German which means "on the" in English. ++ Ex. "Butter aufs Brot"(G) means "butter onto bread"(E). ++ But "Filesystem aufs Filesystem" is hard to understand. ++4. abbrev. for "African Urban Fashion Show". ++ ++AUFS is a filesystem with features: ++- multi layered stackable unification filesystem, the member directory ++ is called as a branch. ++- branch permission and attribute, 'readonly', 'real-readonly', ++ 'readwrite', 'whiteout-able', 'link-able whiteout', etc. and their ++ combination. ++- internal "file copy-on-write". ++- logical deletion, whiteout. ++- dynamic branch manipulation, adding, deleting and changing permission. ++- allow bypassing aufs, user's direct branch access. ++- external inode number translation table and bitmap which maintains the ++ persistent aufs inode number. ++- seekable directory, including NFS readdir. ++- file mapping, mmap and sharing pages. ++- pseudo-link, hardlink over branches. ++- loopback mounted filesystem as a branch. ++- several policies to select one among multiple writable branches. ++- revert a single systemcall when an error occurs in aufs. ++- and more... ++ ++ ++Multi Layered Stackable Unification Filesystem ++---------------------------------------------------------------------- ++Most people already knows what it is. ++It is a filesystem which unifies several directories and provides a ++merged single directory. When users access a file, the access will be ++passed/re-directed/converted (sorry, I am not sure which English word is ++correct) to the real file on the member filesystem. The member ++filesystem is called 'lower filesystem' or 'branch' and has a mode ++'readonly' and 'readwrite.' And the deletion for a file on the lower ++readonly branch is handled by creating 'whiteout' on the upper writable ++branch. ++ ++On LKML, there have been discussions about UnionMount (Jan Blunck, ++Bharata B Rao and Valerie Aurora) and Unionfs (Erez Zadok). They took ++different approaches to implement the merged-view. ++The former tries putting it into VFS, and the latter implements as a ++separate filesystem. ++(If I misunderstand about these implementations, please let me know and ++I shall correct it. Because it is a long time ago when I read their ++source files last time). ++ ++UnionMount's approach will be able to small, but may be hard to share ++branches between several UnionMount since the whiteout in it is ++implemented in the inode on branch filesystem and always ++shared. According to Bharata's post, readdir does not seems to be ++finished yet. ++There are several missing features known in this implementations such as ++- for users, the inode number may change silently. eg. copy-up. ++- link(2) may break by copy-up. ++- read(2) may get an obsoleted filedata (fstat(2) too). ++- fcntl(F_SETLK) may be broken by copy-up. ++- unnecessary copy-up may happen, for example mmap(MAP_PRIVATE) after ++ open(O_RDWR). ++ ++In linux-3.18, "overlay" filesystem (formerly known as "overlayfs") was ++merged into mainline. This is another implementation of UnionMount as a ++separated filesystem. All the limitations and known problems which ++UnionMount are equally inherited to "overlay" filesystem. ++ ++Unionfs has a longer history. When I started implementing a stackable ++filesystem (Aug 2005), it already existed. It has virtual super_block, ++inode, dentry and file objects and they have an array pointing lower ++same kind objects. After contributing many patches for Unionfs, I ++re-started my project AUFS (Jun 2006). ++ ++In AUFS, the structure of filesystem resembles to Unionfs, but I ++implemented my own ideas, approaches and enhancements and it became ++totally different one. ++ ++Comparing DM snapshot and fs based implementation ++- the number of bytes to be copied between devices is much smaller. ++- the type of filesystem must be one and only. ++- the fs must be writable, no readonly fs, even for the lower original ++ device. so the compression fs will not be usable. but if we use ++ loopback mount, we may address this issue. ++ for instance, ++ mount /cdrom/squashfs.img /sq ++ losetup /sq/ext2.img ++ losetup /somewhere/cow ++ dmsetup "snapshot /dev/loop0 /dev/loop1 ..." ++- it will be difficult (or needs more operations) to extract the ++ difference between the original device and COW. ++- DM snapshot-merge may help a lot when users try merging. in the ++ fs-layer union, users will use rsync(1). ++ ++You may want to read my old paper "Filesystems in LiveCD" ++(http://aufs.sourceforge.net/aufs2/report/sq/sq.pdf). ++ ++ ++Several characters/aspects/persona of aufs ++---------------------------------------------------------------------- ++ ++Aufs has several characters, aspects or persona. ++1. a filesystem, callee of VFS helper ++2. sub-VFS, caller of VFS helper for branches ++3. a virtual filesystem which maintains persistent inode number ++4. reader/writer of files on branches such like an application ++ ++1. Callee of VFS Helper ++As an ordinary linux filesystem, aufs is a callee of VFS. For instance, ++unlink(2) from an application reaches sys_unlink() kernel function and ++then vfs_unlink() is called. vfs_unlink() is one of VFS helper and it ++calls filesystem specific unlink operation. Actually aufs implements the ++unlink operation but it behaves like a redirector. ++ ++2. Caller of VFS Helper for Branches ++aufs_unlink() passes the unlink request to the branch filesystem as if ++it were called from VFS. So the called unlink operation of the branch ++filesystem acts as usual. As a caller of VFS helper, aufs should handle ++every necessary pre/post operation for the branch filesystem. ++- acquire the lock for the parent dir on a branch ++- lookup in a branch ++- revalidate dentry on a branch ++- mnt_want_write() for a branch ++- vfs_unlink() for a branch ++- mnt_drop_write() for a branch ++- release the lock on a branch ++ ++3. Persistent Inode Number ++One of the most important issue for a filesystem is to maintain inode ++numbers. This is particularly important to support exporting a ++filesystem via NFS. Aufs is a virtual filesystem which doesn't have a ++backend block device for its own. But some storage is necessary to ++keep and maintain the inode numbers. It may be a large space and may not ++suit to keep in memory. Aufs rents some space from its first writable ++branch filesystem (by default) and creates file(s) on it. These files ++are created by aufs internally and removed soon (currently) keeping ++opened. ++Note: Because these files are removed, they are totally gone after ++ unmounting aufs. It means the inode numbers are not persistent ++ across unmount or reboot. I have a plan to make them really ++ persistent which will be important for aufs on NFS server. ++ ++4. Read/Write Files Internally (copy-on-write) ++Because a branch can be readonly, when you write a file on it, aufs will ++"copy-up" it to the upper writable branch internally. And then write the ++originally requested thing to the file. Generally kernel doesn't ++open/read/write file actively. In aufs, even a single write may cause a ++internal "file copy". This behaviour is very similar to cp(1) command. ++ ++Some people may think it is better to pass such work to user space ++helper, instead of doing in kernel space. Actually I am still thinking ++about it. But currently I have implemented it in kernel space. +diff -Nurp linux-5.4/Documentation/filesystems/aufs/design/02struct.txt linux-5.4-aufs/Documentation/filesystems/aufs/design/02struct.txt +--- linux-5.4/Documentation/filesystems/aufs/design/02struct.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/design/02struct.txt 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,245 @@ ++ ++# Copyright (C) 2005-2019 Junjiro R. Okajima ++ ++Basic Aufs Internal Structure ++ ++Superblock/Inode/Dentry/File Objects ++---------------------------------------------------------------------- ++As like an ordinary filesystem, aufs has its own ++superblock/inode/dentry/file objects. All these objects have a ++dynamically allocated array and store the same kind of pointers to the ++lower filesystem, branch. ++For example, when you build a union with one readwrite branch and one ++readonly, mounted /au, /rw and /ro respectively. ++- /au = /rw + /ro ++- /ro/fileA exists but /rw/fileA ++ ++Aufs lookup operation finds /ro/fileA and gets dentry for that. These ++pointers are stored in a aufs dentry. The array in aufs dentry will be, ++- [0] = NULL (because /rw/fileA doesn't exist) ++- [1] = /ro/fileA ++ ++This style of an array is essentially same to the aufs ++superblock/inode/dentry/file objects. ++ ++Because aufs supports manipulating branches, ie. add/delete/change ++branches dynamically, these objects has its own generation. When ++branches are changed, the generation in aufs superblock is ++incremented. And a generation in other object are compared when it is ++accessed. When a generation in other objects are obsoleted, aufs ++refreshes the internal array. ++ ++ ++Superblock ++---------------------------------------------------------------------- ++Additionally aufs superblock has some data for policies to select one ++among multiple writable branches, XIB files, pseudo-links and kobject. ++See below in detail. ++About the policies which supports copy-down a directory, see ++wbr_policy.txt too. ++ ++ ++Branch and XINO(External Inode Number Translation Table) ++---------------------------------------------------------------------- ++Every branch has its own xino (external inode number translation table) ++file. The xino file is created and unlinked by aufs internally. When two ++members of a union exist on the same filesystem, they share the single ++xino file. ++The struct of a xino file is simple, just a sequence of aufs inode ++numbers which is indexed by the lower inode number. ++In the above sample, assume the inode number of /ro/fileA is i111 and ++aufs assigns the inode number i999 for fileA. Then aufs writes 999 as ++4(8) bytes at 111 * 4(8) bytes offset in the xino file. ++ ++When the inode numbers are not contiguous, the xino file will be sparse ++which has a hole in it and doesn't consume as much disk space as it ++might appear. If your branch filesystem consumes disk space for such ++holes, then you should specify 'xino=' option at mounting aufs. ++ ++Aufs has a mount option to free the disk blocks for such holes in XINO ++files on tmpfs or ramdisk. But it is not so effective actually. If you ++meet a problem of disk shortage due to XINO files, then you should try ++"tmpfs-ino.patch" (and "vfs-ino.patch" too) in aufs4-standalone.git. ++The patch localizes the assignment inumbers per tmpfs-mount and avoid ++the holes in XINO files. ++ ++Also a writable branch has three kinds of "whiteout bases". All these ++are existed when the branch is joined to aufs, and their names are ++whiteout-ed doubly, so that users will never see their names in aufs ++hierarchy. ++1. a regular file which will be hardlinked to all whiteouts. ++2. a directory to store a pseudo-link. ++3. a directory to store an "orphan"-ed file temporary. ++ ++1. Whiteout Base ++ When you remove a file on a readonly branch, aufs handles it as a ++ logical deletion and creates a whiteout on the upper writable branch ++ as a hardlink of this file in order not to consume inode on the ++ writable branch. ++2. Pseudo-link Dir ++ See below, Pseudo-link. ++3. Step-Parent Dir ++ When "fileC" exists on the lower readonly branch only and it is ++ opened and removed with its parent dir, and then user writes ++ something into it, then aufs copies-up fileC to this ++ directory. Because there is no other dir to store fileC. After ++ creating a file under this dir, the file is unlinked. ++ ++Because aufs supports manipulating branches, ie. add/delete/change ++dynamically, a branch has its own id. When the branch order changes, ++aufs finds the new index by searching the branch id. ++ ++ ++Pseudo-link ++---------------------------------------------------------------------- ++Assume "fileA" exists on the lower readonly branch only and it is ++hardlinked to "fileB" on the branch. When you write something to fileA, ++aufs copies-up it to the upper writable branch. Additionally aufs ++creates a hardlink under the Pseudo-link Directory of the writable ++branch. The inode of a pseudo-link is kept in aufs super_block as a ++simple list. If fileB is read after unlinking fileA, aufs returns ++filedata from the pseudo-link instead of the lower readonly ++branch. Because the pseudo-link is based upon the inode, to keep the ++inode number by xino (see above) is essentially necessary. ++ ++All the hardlinks under the Pseudo-link Directory of the writable branch ++should be restored in a proper location later. Aufs provides a utility ++to do this. The userspace helpers executed at remounting and unmounting ++aufs by default. ++During this utility is running, it puts aufs into the pseudo-link ++maintenance mode. In this mode, only the process which began the ++maintenance mode (and its child processes) is allowed to operate in ++aufs. Some other processes which are not related to the pseudo-link will ++be allowed to run too, but the rest have to return an error or wait ++until the maintenance mode ends. If a process already acquires an inode ++mutex (in VFS), it has to return an error. ++ ++ ++XIB(external inode number bitmap) ++---------------------------------------------------------------------- ++Addition to the xino file per a branch, aufs has an external inode number ++bitmap in a superblock object. It is also an internal file such like a ++xino file. ++It is a simple bitmap to mark whether the aufs inode number is in-use or ++not. ++To reduce the file I/O, aufs prepares a single memory page to cache xib. ++ ++As well as XINO files, aufs has a feature to truncate/refresh XIB to ++reduce the number of consumed disk blocks for these files. ++ ++ ++Virtual or Vertical Dir, and Readdir in Userspace ++---------------------------------------------------------------------- ++In order to support multiple layers (branches), aufs readdir operation ++constructs a virtual dir block on memory. For readdir, aufs calls ++vfs_readdir() internally for each dir on branches, merges their entries ++with eliminating the whiteout-ed ones, and sets it to file (dir) ++object. So the file object has its entry list until it is closed. The ++entry list will be updated when the file position is zero and becomes ++obsoleted. This decision is made in aufs automatically. ++ ++The dynamically allocated memory block for the name of entries has a ++unit of 512 bytes (by default) and stores the names contiguously (no ++padding). Another block for each entry is handled by kmem_cache too. ++During building dir blocks, aufs creates hash list and judging whether ++the entry is whiteouted by its upper branch or already listed. ++The merged result is cached in the corresponding inode object and ++maintained by a customizable life-time option. ++ ++Some people may call it can be a security hole or invite DoS attack ++since the opened and once readdir-ed dir (file object) holds its entry ++list and becomes a pressure for system memory. But I'd say it is similar ++to files under /proc or /sys. The virtual files in them also holds a ++memory page (generally) while they are opened. When an idea to reduce ++memory for them is introduced, it will be applied to aufs too. ++For those who really hate this situation, I've developed readdir(3) ++library which operates this merging in userspace. You just need to set ++LD_PRELOAD environment variable, and aufs will not consume no memory in ++kernel space for readdir(3). ++ ++ ++Workqueue ++---------------------------------------------------------------------- ++Aufs sometimes requires privilege access to a branch. For instance, ++in copy-up/down operation. When a user process is going to make changes ++to a file which exists in the lower readonly branch only, and the mode ++of one of ancestor directories may not be writable by a user ++process. Here aufs copy-up the file with its ancestors and they may ++require privilege to set its owner/group/mode/etc. ++This is a typical case of a application character of aufs (see ++Introduction). ++ ++Aufs uses workqueue synchronously for this case. It creates its own ++workqueue. The workqueue is a kernel thread and has privilege. Aufs ++passes the request to call mkdir or write (for example), and wait for ++its completion. This approach solves a problem of a signal handler ++simply. ++If aufs didn't adopt the workqueue and changed the privilege of the ++process, then the process may receive the unexpected SIGXFSZ or other ++signals. ++ ++Also aufs uses the system global workqueue ("events" kernel thread) too ++for asynchronous tasks, such like handling inotify/fsnotify, re-creating a ++whiteout base and etc. This is unrelated to a privilege. ++Most of aufs operation tries acquiring a rw_semaphore for aufs ++superblock at the beginning, at the same time waits for the completion ++of all queued asynchronous tasks. ++ ++ ++Whiteout ++---------------------------------------------------------------------- ++The whiteout in aufs is very similar to Unionfs's. That is represented ++by its filename. UnionMount takes an approach of a file mode, but I am ++afraid several utilities (find(1) or something) will have to support it. ++ ++Basically the whiteout represents "logical deletion" which stops aufs to ++lookup further, but also it represents "dir is opaque" which also stop ++further lookup. ++ ++In aufs, rmdir(2) and rename(2) for dir uses whiteout alternatively. ++In order to make several functions in a single systemcall to be ++revertible, aufs adopts an approach to rename a directory to a temporary ++unique whiteouted name. ++For example, in rename(2) dir where the target dir already existed, aufs ++renames the target dir to a temporary unique whiteouted name before the ++actual rename on a branch, and then handles other actions (make it opaque, ++update the attributes, etc). If an error happens in these actions, aufs ++simply renames the whiteouted name back and returns an error. If all are ++succeeded, aufs registers a function to remove the whiteouted unique ++temporary name completely and asynchronously to the system global ++workqueue. ++ ++ ++Copy-up ++---------------------------------------------------------------------- ++It is a well-known feature or concept. ++When user modifies a file on a readonly branch, aufs operate "copy-up" ++internally and makes change to the new file on the upper writable branch. ++When the trigger systemcall does not update the timestamps of the parent ++dir, aufs reverts it after copy-up. ++ ++ ++Move-down (aufs3.9 and later) ++---------------------------------------------------------------------- ++"Copy-up" is one of the essential feature in aufs. It copies a file from ++the lower readonly branch to the upper writable branch when a user ++changes something about the file. ++"Move-down" is an opposite action of copy-up. Basically this action is ++ran manually instead of automatically and internally. ++For desgin and implementation, aufs has to consider these issues. ++- whiteout for the file may exist on the lower branch. ++- ancestor directories may not exist on the lower branch. ++- diropq for the ancestor directories may exist on the upper branch. ++- free space on the lower branch will reduce. ++- another access to the file may happen during moving-down, including ++ UDBA (see "Revalidate Dentry and UDBA"). ++- the file should not be hard-linked nor pseudo-linked. they should be ++ handled by auplink utility later. ++ ++Sometimes users want to move-down a file from the upper writable branch ++to the lower readonly or writable branch. For instance, ++- the free space of the upper writable branch is going to run out. ++- create a new intermediate branch between the upper and lower branch. ++- etc. ++ ++For this purpose, use "aumvdown" command in aufs-util.git. +diff -Nurp linux-5.4/Documentation/filesystems/aufs/design/03atomic_open.txt linux-5.4-aufs/Documentation/filesystems/aufs/design/03atomic_open.txt +--- linux-5.4/Documentation/filesystems/aufs/design/03atomic_open.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/design/03atomic_open.txt 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,72 @@ ++ ++# Copyright (C) 2015-2019 Junjiro R. Okajima ++ ++Support for a branch who has its ->atomic_open() ++---------------------------------------------------------------------- ++The filesystems who implement its ->atomic_open() are not majority. For ++example NFSv4 does, and aufs should call NFSv4 ->atomic_open, ++particularly for open(O_CREAT|O_EXCL, 0400) case. Other than ++->atomic_open(), NFSv4 returns an error for this open(2). While I am not ++sure whether all filesystems who have ->atomic_open() behave like this, ++but NFSv4 surely returns the error. ++ ++In order to support ->atomic_open() for aufs, there are a few ++approaches. ++ ++A. Introduce aufs_atomic_open() ++ - calls one of VFS:do_last(), lookup_open() or atomic_open() for ++ branch fs. ++B. Introduce aufs_atomic_open() calling create, open and chmod. this is ++ an aufs user Pip Cet's approach ++ - calls aufs_create(), VFS finish_open() and notify_change(). ++ - pass fake-mode to finish_open(), and then correct the mode by ++ notify_change(). ++C. Extend aufs_open() to call branch fs's ->atomic_open() ++ - no aufs_atomic_open(). ++ - aufs_lookup() registers the TID to an aufs internal object. ++ - aufs_create() does nothing when the matching TID is registered, but ++ registers the mode. ++ - aufs_open() calls branch fs's ->atomic_open() when the matching ++ TID is registered. ++D. Extend aufs_open() to re-try branch fs's ->open() with superuser's ++ credential ++ - no aufs_atomic_open(). ++ - aufs_create() registers the TID to an internal object. this info ++ represents "this process created this file just now." ++ - when aufs gets EACCES from branch fs's ->open(), then confirm the ++ registered TID and re-try open() with superuser's credential. ++ ++Pros and cons for each approach. ++ ++A. ++ - straightforward but highly depends upon VFS internal. ++ - the atomic behavaiour is kept. ++ - some of parameters such as nameidata are hard to reproduce for ++ branch fs. ++ - large overhead. ++B. ++ - easy to implement. ++ - the atomic behavaiour is lost. ++C. ++ - the atomic behavaiour is kept. ++ - dirty and tricky. ++ - VFS checks whether the file is created correctly after calling ++ ->create(), which means this approach doesn't work. ++D. ++ - easy to implement. ++ - the atomic behavaiour is lost. ++ - to open a file with superuser's credential and give it to a user ++ process is a bad idea, since the file object keeps the credential ++ in it. It may affect LSM or something. This approach doesn't work ++ either. ++ ++The approach A is ideal, but it hard to implement. So here is a ++variation of A, which is to be implemented. ++ ++A-1. Introduce aufs_atomic_open() ++ - calls branch fs ->atomic_open() if exists. otherwise calls ++ vfs_create() and finish_open(). ++ - the demerit is that the several checks after branch fs ++ ->atomic_open() are lost. in the ordinary case, the checks are ++ done by VFS:do_last(), lookup_open() and atomic_open(). some can ++ be implemented in aufs, but not all I am afraid. +diff -Nurp linux-5.4/Documentation/filesystems/aufs/design/03lookup.txt linux-5.4-aufs/Documentation/filesystems/aufs/design/03lookup.txt +--- linux-5.4/Documentation/filesystems/aufs/design/03lookup.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/design/03lookup.txt 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,100 @@ ++ ++# Copyright (C) 2005-2019 Junjiro R. Okajima ++ ++Lookup in a Branch ++---------------------------------------------------------------------- ++Since aufs has a character of sub-VFS (see Introduction), it operates ++lookup for branches as VFS does. It may be a heavy work. But almost all ++lookup operation in aufs is the simplest case, ie. lookup only an entry ++directly connected to its parent. Digging down the directory hierarchy ++is unnecessary. VFS has a function lookup_one_len() for that use, and ++aufs calls it. ++ ++When a branch is a remote filesystem, aufs basically relies upon its ++->d_revalidate(), also aufs forces the hardest revalidate tests for ++them. ++For d_revalidate, aufs implements three levels of revalidate tests. See ++"Revalidate Dentry and UDBA" in detail. ++ ++ ++Test Only the Highest One for the Directory Permission (dirperm1 option) ++---------------------------------------------------------------------- ++Let's try case study. ++- aufs has two branches, upper readwrite and lower readonly. ++ /au = /rw + /ro ++- "dirA" exists under /ro, but /rw. and its mode is 0700. ++- user invoked "chmod a+rx /au/dirA" ++- the internal copy-up is activated and "/rw/dirA" is created and its ++ permission bits are set to world readable. ++- then "/au/dirA" becomes world readable? ++ ++In this case, /ro/dirA is still 0700 since it exists in readonly branch, ++or it may be a natively readonly filesystem. If aufs respects the lower ++branch, it should not respond readdir request from other users. But user ++allowed it by chmod. Should really aufs rejects showing the entries ++under /ro/dirA? ++ ++To be honest, I don't have a good solution for this case. So aufs ++implements 'dirperm1' and 'nodirperm1' mount options, and leave it to ++users. ++When dirperm1 is specified, aufs checks only the highest one for the ++directory permission, and shows the entries. Otherwise, as usual, checks ++every dir existing on all branches and rejects the request. ++ ++As a side effect, dirperm1 option improves the performance of aufs ++because the number of permission check is reduced when the number of ++branch is many. ++ ++ ++Revalidate Dentry and UDBA (User's Direct Branch Access) ++---------------------------------------------------------------------- ++Generally VFS helpers re-validate a dentry as a part of lookup. ++0. digging down the directory hierarchy. ++1. lock the parent dir by its i_mutex. ++2. lookup the final (child) entry. ++3. revalidate it. ++4. call the actual operation (create, unlink, etc.) ++5. unlock the parent dir ++ ++If the filesystem implements its ->d_revalidate() (step 3), then it is ++called. Actually aufs implements it and checks the dentry on a branch is ++still valid. ++But it is not enough. Because aufs has to release the lock for the ++parent dir on a branch at the end of ->lookup() (step 2) and ++->d_revalidate() (step 3) while the i_mutex of the aufs dir is still ++held by VFS. ++If the file on a branch is changed directly, eg. bypassing aufs, after ++aufs released the lock, then the subsequent operation may cause ++something unpleasant result. ++ ++This situation is a result of VFS architecture, ->lookup() and ++->d_revalidate() is separated. But I never say it is wrong. It is a good ++design from VFS's point of view. It is just not suitable for sub-VFS ++character in aufs. ++ ++Aufs supports such case by three level of revalidation which is ++selectable by user. ++1. Simple Revalidate ++ Addition to the native flow in VFS's, confirm the child-parent ++ relationship on the branch just after locking the parent dir on the ++ branch in the "actual operation" (step 4). When this validation ++ fails, aufs returns EBUSY. ->d_revalidate() (step 3) in aufs still ++ checks the validation of the dentry on branches. ++2. Monitor Changes Internally by Inotify/Fsnotify ++ Addition to above, in the "actual operation" (step 4) aufs re-lookup ++ the dentry on the branch, and returns EBUSY if it finds different ++ dentry. ++ Additionally, aufs sets the inotify/fsnotify watch for every dir on branches ++ during it is in cache. When the event is notified, aufs registers a ++ function to kernel 'events' thread by schedule_work(). And the ++ function sets some special status to the cached aufs dentry and inode ++ private data. If they are not cached, then aufs has nothing to ++ do. When the same file is accessed through aufs (step 0-3) later, ++ aufs will detect the status and refresh all necessary data. ++ In this mode, aufs has to ignore the event which is fired by aufs ++ itself. ++3. No Extra Validation ++ This is the simplest test and doesn't add any additional revalidation ++ test, and skip the revalidation in step 4. It is useful and improves ++ aufs performance when system surely hide the aufs branches from user, ++ by over-mounting something (or another method). +diff -Nurp linux-5.4/Documentation/filesystems/aufs/design/04branch.txt linux-5.4-aufs/Documentation/filesystems/aufs/design/04branch.txt +--- linux-5.4/Documentation/filesystems/aufs/design/04branch.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/design/04branch.txt 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,61 @@ ++ ++# Copyright (C) 2005-2019 Junjiro R. Okajima ++ ++Branch Manipulation ++ ++Since aufs supports dynamic branch manipulation, ie. add/remove a branch ++and changing its permission/attribute, there are a lot of works to do. ++ ++ ++Add a Branch ++---------------------------------------------------------------------- ++o Confirm the adding dir exists outside of aufs, including loopback ++ mount, and its various attributes. ++o Initialize the xino file and whiteout bases if necessary. ++ See struct.txt. ++ ++o Check the owner/group/mode of the directory ++ When the owner/group/mode of the adding directory differs from the ++ existing branch, aufs issues a warning because it may impose a ++ security risk. ++ For example, when a upper writable branch has a world writable empty ++ top directory, a malicious user can create any files on the writable ++ branch directly, like copy-up and modify manually. If something like ++ /etc/{passwd,shadow} exists on the lower readonly branch but the upper ++ writable branch, and the writable branch is world-writable, then a ++ malicious guy may create /etc/passwd on the writable branch directly ++ and the infected file will be valid in aufs. ++ I am afraid it can be a security issue, but aufs can do nothing except ++ producing a warning. ++ ++ ++Delete a Branch ++---------------------------------------------------------------------- ++o Confirm the deleting branch is not busy ++ To be general, there is one merit to adopt "remount" interface to ++ manipulate branches. It is to discard caches. At deleting a branch, ++ aufs checks the still cached (and connected) dentries and inodes. If ++ there are any, then they are all in-use. An inode without its ++ corresponding dentry can be alive alone (for example, inotify/fsnotify case). ++ ++ For the cached one, aufs checks whether the same named entry exists on ++ other branches. ++ If the cached one is a directory, because aufs provides a merged view ++ to users, as long as one dir is left on any branch aufs can show the ++ dir to users. In this case, the branch can be removed from aufs. ++ Otherwise aufs rejects deleting the branch. ++ ++ If any file on the deleting branch is opened by aufs, then aufs ++ rejects deleting. ++ ++ ++Modify the Permission of a Branch ++---------------------------------------------------------------------- ++o Re-initialize or remove the xino file and whiteout bases if necessary. ++ See struct.txt. ++ ++o rw --> ro: Confirm the modifying branch is not busy ++ Aufs rejects the request if any of these conditions are true. ++ - a file on the branch is mmap-ed. ++ - a regular file on the branch is opened for write and there is no ++ same named entry on the upper branch. +diff -Nurp linux-5.4/Documentation/filesystems/aufs/design/05wbr_policy.txt linux-5.4-aufs/Documentation/filesystems/aufs/design/05wbr_policy.txt +--- linux-5.4/Documentation/filesystems/aufs/design/05wbr_policy.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/design/05wbr_policy.txt 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,51 @@ ++ ++# Copyright (C) 2005-2019 Junjiro R. Okajima ++ ++Policies to Select One among Multiple Writable Branches ++---------------------------------------------------------------------- ++When the number of writable branch is more than one, aufs has to decide ++the target branch for file creation or copy-up. By default, the highest ++writable branch which has the parent (or ancestor) dir of the target ++file is chosen (top-down-parent policy). ++By user's request, aufs implements some other policies to select the ++writable branch, for file creation several policies, round-robin, ++most-free-space, and other policies. For copy-up, top-down-parent, ++bottom-up-parent, bottom-up and others. ++ ++As expected, the round-robin policy selects the branch in circular. When ++you have two writable branches and creates 10 new files, 5 files will be ++created for each branch. mkdir(2) systemcall is an exception. When you ++create 10 new directories, all will be created on the same branch. ++And the most-free-space policy selects the one which has most free ++space among the writable branches. The amount of free space will be ++checked by aufs internally, and users can specify its time interval. ++ ++The policies for copy-up is more simple, ++top-down-parent is equivalent to the same named on in create policy, ++bottom-up-parent selects the writable branch where the parent dir ++exists and the nearest upper one from the copyup-source, ++bottom-up selects the nearest upper writable branch from the ++copyup-source, regardless the existence of the parent dir. ++ ++There are some rules or exceptions to apply these policies. ++- If there is a readonly branch above the policy-selected branch and ++ the parent dir is marked as opaque (a variation of whiteout), or the ++ target (creating) file is whiteout-ed on the upper readonly branch, ++ then the result of the policy is ignored and the target file will be ++ created on the nearest upper writable branch than the readonly branch. ++- If there is a writable branch above the policy-selected branch and ++ the parent dir is marked as opaque or the target file is whiteouted ++ on the branch, then the result of the policy is ignored and the target ++ file will be created on the highest one among the upper writable ++ branches who has diropq or whiteout. In case of whiteout, aufs removes ++ it as usual. ++- link(2) and rename(2) systemcalls are exceptions in every policy. ++ They try selecting the branch where the source exists as possible ++ since copyup a large file will take long time. If it can't be, ++ ie. the branch where the source exists is readonly, then they will ++ follow the copyup policy. ++- There is an exception for rename(2) when the target exists. ++ If the rename target exists, aufs compares the index of the branches ++ where the source and the target exists and selects the higher ++ one. If the selected branch is readonly, then aufs follows the ++ copyup policy. +diff -Nurp linux-5.4/Documentation/filesystems/aufs/design/06dirren.dot linux-5.4-aufs/Documentation/filesystems/aufs/design/06dirren.dot +--- linux-5.4/Documentation/filesystems/aufs/design/06dirren.dot 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/design/06dirren.dot 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,31 @@ ++ ++// to view this graph, run dot(1) command in GRAPHVIZ. ++ ++digraph G { ++node [shape=box]; ++whinfo [label="detailed info file\n(lower_brid_root-hinum, h_inum, namelen, old name)"]; ++ ++node [shape=oval]; ++ ++aufs_rename -> whinfo [label="store/remove"]; ++ ++node [shape=oval]; ++inode_list [label="h_inum list in branch\ncache"]; ++ ++node [shape=box]; ++whinode [label="h_inum list file"]; ++ ++node [shape=oval]; ++brmgmt [label="br_add/del/mod/umount"]; ++ ++brmgmt -> inode_list [label="create/remove"]; ++brmgmt -> whinode [label="load/store"]; ++ ++inode_list -> whinode [style=dashed,dir=both]; ++ ++aufs_rename -> inode_list [label="add/del"]; ++ ++aufs_lookup -> inode_list [label="search"]; ++ ++aufs_lookup -> whinfo [label="load/remove"]; ++} +diff -Nurp linux-5.4/Documentation/filesystems/aufs/design/06dirren.txt linux-5.4-aufs/Documentation/filesystems/aufs/design/06dirren.txt +--- linux-5.4/Documentation/filesystems/aufs/design/06dirren.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/design/06dirren.txt 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,89 @@ ++ ++# Copyright (C) 2017-2019 Junjiro R. Okajima ++ ++Special handling for renaming a directory (DIRREN) ++---------------------------------------------------------------------- ++First, let's assume we have a simple usecase. ++ ++- /u = /rw + /ro ++- /rw/dirA exists ++- /ro/dirA and /ro/dirA/file exist too ++- there is no dirB on both branches ++- a user issues rename("dirA", "dirB") ++ ++Now, what should aufs behave against this rename(2)? ++There are a few possible cases. ++ ++A. returns EROFS. ++ since dirA exists on a readonly branch which cannot be renamed. ++B. returns EXDEV. ++ it is possible to copy-up dirA (only the dir itself), but the child ++ entries ("file" in this case) should not be. it must be a bad ++ approach to copy-up recursively. ++C. returns a success. ++ even the branch /ro is readonly, aufs tries renaming it. Obviously it ++ is a violation of aufs' policy. ++D. construct an extra information which indicates that /ro/dirA should ++ be handled as the name of dirB. ++ overlayfs has a similar feature called REDIRECT. ++ ++Until now, aufs implements the case B only which returns EXDEV, and ++expects the userspace application behaves like mv(1) which tries ++issueing rename(2) recursively. ++ ++A new aufs feature called DIRREN is introduced which implements the case ++D. There are several "extra information" added. ++ ++1. detailed info per renamed directory ++ path: /rw/dirB/$AUFS_WH_DR_INFO_PFX. ++2. the inode-number list of directories on a branch ++ path: /rw/dirB/$AUFS_WH_DR_BRHINO ++ ++The filename of "detailed info per directory" represents the lower ++branch, and its format is ++- a type of the branch id ++ one of these. ++ + uuid (not implemented yet) ++ + fsid ++ + dev ++- the inode-number of the branch root dir ++ ++And it contains these info in a single regular file. ++- magic number ++- branch's inode-number of the logically renamed dir ++- the name of the before-renamed dir ++ ++The "detailed info per directory" file is created in aufs rename(2), and ++loaded in any lookup. ++The info is considered in lookup for the matching case only. Here ++"matching" means that the root of branch (in the info filename) is same ++to the current looking-up branch. After looking-up the before-renamed ++name, the inode-number is compared. And the matched dentry is used. ++ ++The "inode-number list of directories" is a regular file which contains ++simply the inode-numbers on the branch. The file is created or updated ++in removing the branch, and loaded in adding the branch. Its lifetime is ++equal to the branch. ++The list is refered in lookup, and when the current target inode is ++found in the list, the aufs tries loading the "detailed info per ++directory" and get the changed and valid name of the dir. ++ ++Theoretically these "extra informaiton" may be able to be put into XATTR ++in the dir inode. But aufs doesn't choose this way because ++1. XATTR may not be supported by the branch (or its configuration) ++2. XATTR may have its size limit. ++3. XATTR may be less easy to convert than a regular file, when the ++ format of the info is changed in the future. ++At the same time, I agree that the regular file approach is much slower ++than XATTR approach. So, in the future, aufs may take the XATTR or other ++better approach. ++ ++This DIRREN feature is enabled by aufs configuration, and is activated ++by a new mount option. ++ ++For the more complicated case, there is a work with UDBA option, which ++is to dected the direct access to the branches (by-passing aufs) and to ++maintain the cashes in aufs. Since a single cached aufs dentry may ++contains two names, before- and after-rename, the name comparision in ++UDBA handler may not work correctly. In this case, the behaviour will be ++equivalen to udba=reval case. +diff -Nurp linux-5.4/Documentation/filesystems/aufs/design/06fhsm.txt linux-5.4-aufs/Documentation/filesystems/aufs/design/06fhsm.txt +--- linux-5.4/Documentation/filesystems/aufs/design/06fhsm.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/design/06fhsm.txt 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,105 @@ ++ ++# Copyright (C) 2011-2019 Junjiro R. Okajima ++ ++File-based Hierarchical Storage Management (FHSM) ++---------------------------------------------------------------------- ++Hierarchical Storage Management (or HSM) is a well-known feature in the ++storage world. Aufs provides this feature as file-based with multiple ++writable branches, based upon the principle of "Colder, the Lower". ++Here the word "colder" means that the less used files, and "lower" means ++that the position in the order of the stacked branches vertically. ++These multiple writable branches are prioritized, ie. the topmost one ++should be the fastest drive and be used heavily. ++ ++o Characters in aufs FHSM story ++- aufs itself and a new branch attribute. ++- a new ioctl interface to move-down and to establish a connection with ++ the daemon ("move-down" is a converse of "copy-up"). ++- userspace tool and daemon. ++ ++The userspace daemon establishes a connection with aufs and waits for ++the notification. The notified information is very similar to struct ++statfs containing the number of consumed blocks and inodes. ++When the consumed blocks/inodes of a branch exceeds the user-specified ++upper watermark, the daemon activates its move-down process until the ++consumed blocks/inodes reaches the user-specified lower watermark. ++ ++The actual move-down is done by aufs based upon the request from ++user-space since we need to maintain the inode number and the internal ++pointer arrays in aufs. ++ ++Currently aufs FHSM handles the regular files only. Additionally they ++must not be hard-linked nor pseudo-linked. ++ ++ ++o Cowork of aufs and the user-space daemon ++ During the userspace daemon established the connection, aufs sends a ++ small notification to it whenever aufs writes something into the ++ writable branch. But it may cost high since aufs issues statfs(2) ++ internally. So user can specify a new option to cache the ++ info. Actually the notification is controlled by these factors. ++ + the specified cache time. ++ + classified as "force" by aufs internally. ++ Until the specified time expires, aufs doesn't send the info ++ except the forced cases. When aufs decide forcing, the info is always ++ notified to userspace. ++ For example, the number of free inodes is generally large enough and ++ the shortage of it happens rarely. So aufs doesn't force the ++ notification when creating a new file, directory and others. This is ++ the typical case which aufs doesn't force. ++ When aufs writes the actual filedata and the files consumes any of new ++ blocks, the aufs forces notifying. ++ ++ ++o Interfaces in aufs ++- New branch attribute. ++ + fhsm ++ Specifies that the branch is managed by FHSM feature. In other word, ++ participant in the FHSM. ++ When nofhsm is set to the branch, it will not be the source/target ++ branch of the move-down operation. This attribute is set ++ independently from coo and moo attributes, and if you want full ++ FHSM, you should specify them as well. ++- New mount option. ++ + fhsm_sec ++ Specifies a second to suppress many less important info to be ++ notified. ++- New ioctl. ++ + AUFS_CTL_FHSM_FD ++ create a new file descriptor which userspace can read the notification ++ (a subset of struct statfs) from aufs. ++- Module parameter 'brs' ++ It has to be set to 1. Otherwise the new mount option 'fhsm' will not ++ be set. ++- mount helpers /sbin/mount.aufs and /sbin/umount.aufs ++ When there are two or more branches with fhsm attributes, ++ /sbin/mount.aufs invokes the user-space daemon and /sbin/umount.aufs ++ terminates it. As a result of remounting and branch-manipulation, the ++ number of branches with fhsm attribute can be one. In this case, ++ /sbin/mount.aufs will terminate the user-space daemon. ++ ++ ++Finally the operation is done as these steps in kernel-space. ++- make sure that, ++ + no one else is using the file. ++ + the file is not hard-linked. ++ + the file is not pseudo-linked. ++ + the file is a regular file. ++ + the parent dir is not opaqued. ++- find the target writable branch. ++- make sure the file is not whiteout-ed by the upper (than the target) ++ branch. ++- make the parent dir on the target branch. ++- mutex lock the inode on the branch. ++- unlink the whiteout on the target branch (if exists). ++- lookup and create the whiteout-ed temporary name on the target branch. ++- copy the file as the whiteout-ed temporary name on the target branch. ++- rename the whiteout-ed temporary name to the original name. ++- unlink the file on the source branch. ++- maintain the internal pointer array and the external inode number ++ table (XINO). ++- maintain the timestamps and other attributes of the parent dir and the ++ file. ++ ++And of course, in every step, an error may happen. So the operation ++should restore the original file state after an error happens. +diff -Nurp linux-5.4/Documentation/filesystems/aufs/design/06mmap.txt linux-5.4-aufs/Documentation/filesystems/aufs/design/06mmap.txt +--- linux-5.4/Documentation/filesystems/aufs/design/06mmap.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/design/06mmap.txt 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,59 @@ ++ ++# Copyright (C) 2005-2019 Junjiro R. Okajima ++ ++mmap(2) -- File Memory Mapping ++---------------------------------------------------------------------- ++In aufs, the file-mapped pages are handled by a branch fs directly, no ++interaction with aufs. It means aufs_mmap() calls the branch fs's ++->mmap(). ++This approach is simple and good, but there is one problem. ++Under /proc, several entries show the mmapped files by its path (with ++device and inode number), and the printed path will be the path on the ++branch fs's instead of virtual aufs's. ++This is not a problem in most cases, but some utilities lsof(1) (and its ++user) may expect the path on aufs. ++ ++To address this issue, aufs adds a new member called vm_prfile in struct ++vm_area_struct (and struct vm_region). The original vm_file points to ++the file on the branch fs in order to handle everything correctly as ++usual. The new vm_prfile points to a virtual file in aufs, and the ++show-functions in procfs refers to vm_prfile if it is set. ++Also we need to maintain several other places where touching vm_file ++such like ++- fork()/clone() copies vma and the reference count of vm_file is ++ incremented. ++- merging vma maintains the ref count too. ++ ++This is not a good approach. It just fakes the printed path. But it ++leaves all behaviour around f_mapping unchanged. This is surely an ++advantage. ++Actually aufs had adopted another complicated approach which calls ++generic_file_mmap() and handles struct vm_operations_struct. In this ++approach, aufs met a hard problem and I could not solve it without ++switching the approach. ++ ++There may be one more another approach which is ++- bind-mount the branch-root onto the aufs-root internally ++- grab the new vfsmount (ie. struct mount) ++- lazy-umount the branch-root internally ++- in open(2) the aufs-file, open the branch-file with the hidden ++ vfsmount (instead of the original branch's vfsmount) ++- ideally this "bind-mount and lazy-umount" should be done atomically, ++ but it may be possible from userspace by the mount helper. ++ ++Adding the internal hidden vfsmount and using it in opening a file, the ++file path under /proc will be printed correctly. This approach looks ++smarter, but is not possible I am afraid. ++- aufs-root may be bind-mount later. when it happens, another hidden ++ vfsmount will be required. ++- it is hard to get the chance to bind-mount and lazy-umount ++ + in kernel-space, FS can have vfsmount in open(2) via ++ file->f_path, and aufs can know its vfsmount. But several locks are ++ already acquired, and if aufs tries to bind-mount and lazy-umount ++ here, then it may cause a deadlock. ++ + in user-space, bind-mount doesn't invoke the mount helper. ++- since /proc shows dev and ino, aufs has to give vma these info. it ++ means a new member vm_prinode will be necessary. this is essentially ++ equivalent to vm_prfile described above. ++ ++I have to give up this "looks-smater" approach. +diff -Nurp linux-5.4/Documentation/filesystems/aufs/design/06xattr.txt linux-5.4-aufs/Documentation/filesystems/aufs/design/06xattr.txt +--- linux-5.4/Documentation/filesystems/aufs/design/06xattr.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/design/06xattr.txt 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,81 @@ ++ ++# Copyright (C) 2014-2019 Junjiro R. Okajima ++ ++Listing XATTR/EA and getting the value ++---------------------------------------------------------------------- ++For the inode standard attributes (owner, group, timestamps, etc.), aufs ++shows the values from the topmost existing file. This behaviour is good ++for the non-dir entries since the bahaviour exactly matches the shown ++information. But for the directories, aufs considers all the same named ++entries on the lower branches. Which means, if one of the lower entry ++rejects readdir call, then aufs returns an error even if the topmost ++entry allows it. This behaviour is necessary to respect the branch fs's ++security, but can make users confused since the user-visible standard ++attributes don't match the behaviour. ++To address this issue, aufs has a mount option called dirperm1 which ++checks the permission for the topmost entry only, and ignores the lower ++entry's permission. ++ ++A similar issue can happen around XATTR. ++getxattr(2) and listxattr(2) families behave as if dirperm1 option is ++always set. Otherwise these very unpleasant situation would happen. ++- listxattr(2) may return the duplicated entries. ++- users may not be able to remove or reset the XATTR forever, ++ ++ ++XATTR/EA support in the internal (copy,move)-(up,down) ++---------------------------------------------------------------------- ++Generally the extended attributes of inode are categorized as these. ++- "security" for LSM and capability. ++- "system" for posix ACL, 'acl' mount option is required for the branch ++ fs generally. ++- "trusted" for userspace, CAP_SYS_ADMIN is required. ++- "user" for userspace, 'user_xattr' mount option is required for the ++ branch fs generally. ++ ++Moreover there are some other categories. Aufs handles these rather ++unpopular categories as the ordinary ones, ie. there is no special ++condition nor exception. ++ ++In copy-up, the support for XATTR on the dst branch may differ from the ++src branch. In this case, the copy-up operation will get an error and ++the original user operation which triggered the copy-up will fail. It ++can happen that even all copy-up will fail. ++When both of src and dst branches support XATTR and if an error occurs ++during copying XATTR, then the copy-up should fail obviously. That is a ++good reason and aufs should return an error to userspace. But when only ++the src branch support that XATTR, aufs should not return an error. ++For example, the src branch supports ACL but the dst branch doesn't ++because the dst branch may natively un-support it or temporary ++un-support it due to "noacl" mount option. Of course, the dst branch fs ++may NOT return an error even if the XATTR is not supported. It is ++totally up to the branch fs. ++ ++Anyway when the aufs internal copy-up gets an error from the dst branch ++fs, then aufs tries removing the just copied entry and returns the error ++to the userspace. The worst case of this situation will be all copy-up ++will fail. ++ ++For the copy-up operation, there two basic approaches. ++- copy the specified XATTR only (by category above), and return the ++ error unconditionally if it happens. ++- copy all XATTR, and ignore the error on the specified category only. ++ ++In order to support XATTR and to implement the correct behaviour, aufs ++chooses the latter approach and introduces some new branch attributes, ++"icexsec", "icexsys", "icextr", "icexusr", and "icexoth". ++They correspond to the XATTR namespaces (see above). Additionally, to be ++convenient, "icex" is also provided which means all "icex*" attributes ++are set (here the word "icex" stands for "ignore copy-error on XATTR"). ++ ++The meaning of these attributes is to ignore the error from setting ++XATTR on that branch. ++Note that aufs tries copying all XATTR unconditionally, and ignores the ++error from the dst branch according to the specified attributes. ++ ++Some XATTR may have its default value. The default value may come from ++the parent dir or the environment. If the default value is set at the ++file creating-time, it will be overwritten by copy-up. ++Some contradiction may happen I am afraid. ++Do we need another attribute to stop copying XATTR? I am unsure. For ++now, aufs implements the branch attributes to ignore the error. +diff -Nurp linux-5.4/Documentation/filesystems/aufs/design/07export.txt linux-5.4-aufs/Documentation/filesystems/aufs/design/07export.txt +--- linux-5.4/Documentation/filesystems/aufs/design/07export.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/design/07export.txt 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,45 @@ ++ ++# Copyright (C) 2005-2019 Junjiro R. Okajima ++ ++Export Aufs via NFS ++---------------------------------------------------------------------- ++Here is an approach. ++- like xino/xib, add a new file 'xigen' which stores aufs inode ++ generation. ++- iget_locked(): initialize aufs inode generation for a new inode, and ++ store it in xigen file. ++- destroy_inode(): increment aufs inode generation and store it in xigen ++ file. it is necessary even if it is not unlinked, because any data of ++ inode may be changed by UDBA. ++- encode_fh(): for a root dir, simply return FILEID_ROOT. otherwise ++ build file handle by ++ + branch id (4 bytes) ++ + superblock generation (4 bytes) ++ + inode number (4 or 8 bytes) ++ + parent dir inode number (4 or 8 bytes) ++ + inode generation (4 bytes)) ++ + return value of exportfs_encode_fh() for the parent on a branch (4 ++ bytes) ++ + file handle for a branch (by exportfs_encode_fh()) ++- fh_to_dentry(): ++ + find the index of a branch from its id in handle, and check it is ++ still exist in aufs. ++ + 1st level: get the inode number from handle and search it in cache. ++ + 2nd level: if not found in cache, get the parent inode number from ++ the handle and search it in cache. and then open the found parent ++ dir, find the matching inode number by vfs_readdir() and get its ++ name, and call lookup_one_len() for the target dentry. ++ + 3rd level: if the parent dir is not cached, call ++ exportfs_decode_fh() for a branch and get the parent on a branch, ++ build a pathname of it, convert it a pathname in aufs, call ++ path_lookup(). now aufs gets a parent dir dentry, then handle it as ++ the 2nd level. ++ + to open the dir, aufs needs struct vfsmount. aufs keeps vfsmount ++ for every branch, but not itself. to get this, (currently) aufs ++ searches in current->nsproxy->mnt_ns list. it may not be a good ++ idea, but I didn't get other approach. ++ + test the generation of the gotten inode. ++- every inode operation: they may get EBUSY due to UDBA. in this case, ++ convert it into ESTALE for NFSD. ++- readdir(): call lockdep_on/off() because filldir in NFSD calls ++ lookup_one_len(), vfs_getattr(), encode_fh() and others. +diff -Nurp linux-5.4/Documentation/filesystems/aufs/design/08shwh.txt linux-5.4-aufs/Documentation/filesystems/aufs/design/08shwh.txt +--- linux-5.4/Documentation/filesystems/aufs/design/08shwh.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/design/08shwh.txt 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,39 @@ ++ ++# Copyright (C) 2005-2019 Junjiro R. Okajima ++ ++Show Whiteout Mode (shwh) ++---------------------------------------------------------------------- ++Generally aufs hides the name of whiteouts. But in some cases, to show ++them is very useful for users. For instance, creating a new middle layer ++(branch) by merging existing layers. ++ ++(borrowing aufs1 HOW-TO from a user, Michael Towers) ++When you have three branches, ++- Bottom: 'system', squashfs (underlying base system), read-only ++- Middle: 'mods', squashfs, read-only ++- Top: 'overlay', ram (tmpfs), read-write ++ ++The top layer is loaded at boot time and saved at shutdown, to preserve ++the changes made to the system during the session. ++When larger changes have been made, or smaller changes have accumulated, ++the size of the saved top layer data grows. At this point, it would be ++nice to be able to merge the two overlay branches ('mods' and 'overlay') ++and rewrite the 'mods' squashfs, clearing the top layer and thus ++restoring save and load speed. ++ ++This merging is simplified by the use of another aufs mount, of just the ++two overlay branches using the 'shwh' option. ++# mount -t aufs -o ro,shwh,br:/livesys/overlay=ro+wh:/livesys/mods=rr+wh \ ++ aufs /livesys/merge_union ++ ++A merged view of these two branches is then available at ++/livesys/merge_union, and the new feature is that the whiteouts are ++visible! ++Note that in 'shwh' mode the aufs mount must be 'ro', which will disable ++writing to all branches. Also the default mode for all branches is 'ro'. ++It is now possible to save the combined contents of the two overlay ++branches to a new squashfs, e.g.: ++# mksquashfs /livesys/merge_union /path/to/newmods.squash ++ ++This new squashfs archive can be stored on the boot device and the ++initramfs will use it to replace the old one at the next boot. +diff -Nurp linux-5.4/Documentation/filesystems/aufs/design/10dynop.txt linux-5.4-aufs/Documentation/filesystems/aufs/design/10dynop.txt +--- linux-5.4/Documentation/filesystems/aufs/design/10dynop.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/design/10dynop.txt 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,34 @@ ++ ++# Copyright (C) 2010-2019 Junjiro R. Okajima ++ ++Dynamically customizable FS operations ++---------------------------------------------------------------------- ++Generally FS operations (struct inode_operations, struct ++address_space_operations, struct file_operations, etc.) are defined as ++"static const", but it never means that FS have only one set of ++operation. Some FS have multiple sets of them. For instance, ext2 has ++three sets, one for XIP, for NOBH, and for normal. ++Since aufs overrides and redirects these operations, sometimes aufs has ++to change its behaviour according to the branch FS type. More importantly ++VFS acts differently if a function (member in the struct) is set or ++not. It means aufs should have several sets of operations and select one ++among them according to the branch FS definition. ++ ++In order to solve this problem and not to affect the behaviour of VFS, ++aufs defines these operations dynamically. For instance, aufs defines ++dummy direct_IO function for struct address_space_operations, but it may ++not be set to the address_space_operations actually. When the branch FS ++doesn't have it, aufs doesn't set it to its address_space_operations ++while the function definition itself is still alive. So the behaviour ++itself will not change, and it will return an error when direct_IO is ++not set. ++ ++The lifetime of these dynamically generated operation object is ++maintained by aufs branch object. When the branch is removed from aufs, ++the reference counter of the object is decremented. When it reaches ++zero, the dynamically generated operation object will be freed. ++ ++This approach is designed to support AIO (io_submit), Direct I/O and ++XIP (DAX) mainly. ++Currently this approach is applied to address_space_operations for ++regular files only. +diff -Nurp linux-5.4/Documentation/filesystems/aufs/README linux-5.4-aufs/Documentation/filesystems/aufs/README +--- linux-5.4/Documentation/filesystems/aufs/README 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/Documentation/filesystems/aufs/README 2019-11-28 01:25:59.060925618 +0200 +@@ -0,0 +1,399 @@ ++ ++Aufs5 -- advanced multi layered unification filesystem version 5.x ++http://aufs.sf.net ++Junjiro R. Okajima ++ ++ ++0. Introduction ++---------------------------------------- ++In the early days, aufs was entirely re-designed and re-implemented ++Unionfs Version 1.x series. Adding many original ideas, approaches, ++improvements and implementations, it became totally different from ++Unionfs while keeping the basic features. ++Later, Unionfs Version 2.x series began taking some of the same ++approaches to aufs1's. ++Unionfs was being developed by Professor Erez Zadok at Stony Brook ++University and his team. ++ ++Aufs5 supports linux-v5.0 and later, If you want older kernel version ++support, ++- for linux-v4.x series, try aufs4-linux.git or aufs4-standalone.git ++- for linux-v3.x series, try aufs3-linux.git or aufs3-standalone.git ++- for linux-v2.6.16 and later, try aufs2-2.6.git, aufs2-standalone.git ++ or aufs1 from CVS on SourceForge. ++ ++Note: it becomes clear that "Aufs was rejected. Let's give it up." ++ According to Christoph Hellwig, linux rejects all union-type ++ filesystems but UnionMount. ++ ++ ++PS. Al Viro seems have a plan to merge aufs as well as overlayfs and ++ UnionMount, and he pointed out an issue around a directory mutex ++ lock and aufs addressed it. But it is still unsure whether aufs will ++ be merged (or any other union solution). ++ ++ ++ ++1. Features ++---------------------------------------- ++- unite several directories into a single virtual filesystem. The member ++ directory is called as a branch. ++- you can specify the permission flags to the branch, which are 'readonly', ++ 'readwrite' and 'whiteout-able.' ++- by upper writable branch, internal copyup and whiteout, files/dirs on ++ readonly branch are modifiable logically. ++- dynamic branch manipulation, add, del. ++- etc... ++ ++Also there are many enhancements in aufs, such as: ++- test only the highest one for the directory permission (dirperm1) ++- copyup on open (coo=) ++- 'move' policy for copy-up between two writable branches, after ++ checking free space. ++- xattr, acl ++- readdir(3) in userspace. ++- keep inode number by external inode number table ++- keep the timestamps of file/dir in internal copyup operation ++- seekable directory, supporting NFS readdir. ++- whiteout is hardlinked in order to reduce the consumption of inodes ++ on branch ++- do not copyup, nor create a whiteout when it is unnecessary ++- revert a single systemcall when an error occurs in aufs ++- remount interface instead of ioctl ++- maintain /etc/mtab by an external command, /sbin/mount.aufs. ++- loopback mounted filesystem as a branch ++- kernel thread for removing the dir who has a plenty of whiteouts ++- support copyup sparse file (a file which has a 'hole' in it) ++- default permission flags for branches ++- selectable permission flags for ro branch, whether whiteout can ++ exist or not ++- export via NFS. ++- support /fs/aufs and /aufs. ++- support multiple writable branches, some policies to select one ++ among multiple writable branches. ++- a new semantics for link(2) and rename(2) to support multiple ++ writable branches. ++- no glibc changes are required. ++- pseudo hardlink (hardlink over branches) ++- allow a direct access manually to a file on branch, e.g. bypassing aufs. ++ including NFS or remote filesystem branch. ++- userspace wrapper for pathconf(3)/fpathconf(3) with _PC_LINK_MAX. ++- and more... ++ ++Currently these features are dropped temporary from aufs5. ++See design/08plan.txt in detail. ++- nested mount, i.e. aufs as readonly no-whiteout branch of another aufs ++ (robr) ++- statistics of aufs thread (/sys/fs/aufs/stat) ++ ++Features or just an idea in the future (see also design/*.txt), ++- reorder the branch index without del/re-add. ++- permanent xino files for NFSD ++- an option for refreshing the opened files after add/del branches ++- light version, without branch manipulation. (unnecessary?) ++- copyup in userspace ++- inotify in userspace ++- readv/writev ++ ++ ++2. Download ++---------------------------------------- ++There are three GIT trees for aufs5, aufs5-linux.git, ++aufs5-standalone.git, and aufs-util.git. Note that there is no "5" in ++"aufs-util.git." ++While the aufs-util is always necessary, you need either of aufs5-linux ++or aufs5-standalone. ++ ++The aufs5-linux tree includes the whole linux mainline GIT tree, ++git://git.kernel.org/.../torvalds/linux.git. ++And you cannot select CONFIG_AUFS_FS=m for this version, eg. you cannot ++build aufs5 as an external kernel module. ++Several extra patches are not included in this tree. Only ++aufs5-standalone tree contains them. They are described in the later ++section "Configuration and Compilation." ++ ++On the other hand, the aufs5-standalone tree has only aufs source files ++and necessary patches, and you can select CONFIG_AUFS_FS=m. ++But you need to apply all aufs patches manually. ++ ++You will find GIT branches whose name is in form of "aufs5.x" where "x" ++represents the linux kernel version, "linux-5.x". For instance, ++"aufs5.0" is for linux-5.0. For latest "linux-5.x-rcN", use ++"aufs5.x-rcN" branch. ++ ++o aufs5-linux tree ++$ git clone --reference /your/linux/git/tree \ ++ git://github.com/sfjro/aufs5-linux.git aufs5-linux.git ++- if you don't have linux GIT tree, then remove "--reference ..." ++$ cd aufs5-linux.git ++$ git checkout origin/aufs5.0 ++ ++Or You may want to directly git-pull aufs into your linux GIT tree, and ++leave the patch-work to GIT. ++$ cd /your/linux/git/tree ++$ git remote add aufs5 git://github.com/sfjro/aufs5-linux.git ++$ git fetch aufs5 ++$ git checkout -b my5.0 v5.0 ++$ (add your local change...) ++$ git pull aufs5 aufs5.0 ++- now you have v5.0 + your_changes + aufs5.0 in you my5.0 branch. ++- you may need to solve some conflicts between your_changes and ++ aufs5.0. in this case, git-rerere is recommended so that you can ++ solve the similar conflicts automatically when you upgrade to 5.1 or ++ later in the future. ++ ++o aufs5-standalone tree ++$ git clone git://github.com/sfjro/aufs5-standalone.git aufs5-standalone.git ++$ cd aufs5-standalone.git ++$ git checkout origin/aufs5.0 ++ ++o aufs-util tree ++$ git clone git://git.code.sf.net/p/aufs/aufs-util aufs-util.git ++- note that the public aufs-util.git is on SourceForge instead of ++ GitHUB. ++$ cd aufs-util.git ++$ git checkout origin/aufs5.0 ++ ++Note: The 5.x-rcN branch is to be used with `rc' kernel versions ONLY. ++The minor version number, 'x' in '5.x', of aufs may not always ++follow the minor version number of the kernel. ++Because changes in the kernel that cause the use of a new ++minor version number do not always require changes to aufs-util. ++ ++Since aufs-util has its own minor version number, you may not be ++able to find a GIT branch in aufs-util for your kernel's ++exact minor version number. ++In this case, you should git-checkout the branch for the ++nearest lower number. ++ ++For (an unreleased) example: ++If you are using "linux-5.10" and the "aufs5.10" branch ++does not exist in aufs-util repository, then "aufs5.9", "aufs5.8" ++or something numerically smaller is the branch for your kernel. ++ ++Also you can view all branches by ++ $ git branch -a ++ ++ ++3. Configuration and Compilation ++---------------------------------------- ++Make sure you have git-checkout'ed the correct branch. ++ ++For aufs5-linux tree, ++- enable CONFIG_AUFS_FS. ++- set other aufs configurations if necessary. ++ ++For aufs5-standalone tree, ++There are several ways to build. ++ ++1. ++- apply ./aufs5-kbuild.patch to your kernel source files. ++- apply ./aufs5-base.patch too. ++- apply ./aufs5-mmap.patch too. ++- apply ./aufs5-standalone.patch too, if you have a plan to set ++ CONFIG_AUFS_FS=m. otherwise you don't need ./aufs5-standalone.patch. ++- copy ./{Documentation,fs,include/uapi/linux/aufs_type.h} files to your ++ kernel source tree. Never copy $PWD/include/uapi/linux/Kbuild. ++- enable CONFIG_AUFS_FS, you can select either ++ =m or =y. ++- and build your kernel as usual. ++- install the built kernel. ++- install the header files too by "make headers_install" to the ++ directory where you specify. By default, it is $PWD/usr. ++ "make help" shows a brief note for headers_install. ++- and reboot your system. ++ ++2. ++- module only (CONFIG_AUFS_FS=m). ++- apply ./aufs5-base.patch to your kernel source files. ++- apply ./aufs5-mmap.patch too. ++- apply ./aufs5-standalone.patch too. ++- build your kernel, don't forget "make headers_install", and reboot. ++- edit ./config.mk and set other aufs configurations if necessary. ++ Note: You should read $PWD/fs/aufs/Kconfig carefully which describes ++ every aufs configurations. ++- build the module by simple "make". ++- you can specify ${KDIR} make variable which points to your kernel ++ source tree. ++- install the files ++ + run "make install" to install the aufs module, or copy the built ++ $PWD/aufs.ko to /lib/modules/... and run depmod -a (or reboot simply). ++ + run "make install_headers" (instead of headers_install) to install ++ the modified aufs header file (you can specify DESTDIR which is ++ available in aufs standalone version's Makefile only), or copy ++ $PWD/usr/include/linux/aufs_type.h to /usr/include/linux or wherever ++ you like manually. By default, the target directory is $PWD/usr. ++- no need to apply aufs5-kbuild.patch, nor copying source files to your ++ kernel source tree. ++ ++Note: The header file aufs_type.h is necessary to build aufs-util ++ as well as "make headers_install" in the kernel source tree. ++ headers_install is subject to be forgotten, but it is essentially ++ necessary, not only for building aufs-util. ++ You may not meet problems without headers_install in some older ++ version though. ++ ++And then, ++- read README in aufs-util, build and install it ++- note that your distribution may contain an obsoleted version of ++ aufs_type.h in /usr/include/linux or something. When you build aufs ++ utilities, make sure that your compiler refers the correct aufs header ++ file which is built by "make headers_install." ++- if you want to use readdir(3) in userspace or pathconf(3) wrapper, ++ then run "make install_ulib" too. And refer to the aufs manual in ++ detail. ++ ++There several other patches in aufs5-standalone.git. They are all ++optional. When you meet some problems, they will help you. ++- aufs5-loopback.patch ++ Supports a nested loopback mount in a branch-fs. This patch is ++ unnecessary until aufs produces a message like "you may want to try ++ another patch for loopback file". ++- proc_mounts.patch ++ When there are many mountpoints and many mount(2)/umount(2) are ++ running, then /proc/mounts may not show the all mountpoints. This ++ patch makes /proc/mounts always show the full mountpoints list. ++ If you don't want to apply this patch and meet such problem, then you ++ need to increase the value of 'ProcMounts_Times' make-variable in ++ aufs-util.git as a second best solution. ++- vfs-ino.patch ++ Modifies a system global kernel internal function get_next_ino() in ++ order to stop assigning 0 for an inode-number. Not directly related to ++ aufs, but recommended generally. ++- tmpfs-idr.patch ++ Keeps the tmpfs inode number as the lowest value. Effective to reduce ++ the size of aufs XINO files for tmpfs branch. Also it prevents the ++ duplication of inode number, which is important for backup tools and ++ other utilities. When you find aufs XINO files for tmpfs branch ++ growing too much, try this patch. ++- lockdep-debug.patch ++ Because aufs is not only an ordinary filesystem (callee of VFS), but ++ also a caller of VFS functions for branch filesystems, subclassing of ++ the internal locks for LOCKDEP is necessary. LOCKDEP is a debugging ++ feature of linux kernel. If you enable CONFIG_LOCKDEP, then you will ++ need to apply this debug patch to expand several constant values. ++ If don't know what LOCKDEP is, then you don't have apply this patch. ++ ++ ++4. Usage ++---------------------------------------- ++At first, make sure aufs-util are installed, and please read the aufs ++manual, aufs.5 in aufs-util.git tree. ++$ man -l aufs.5 ++ ++And then, ++$ mkdir /tmp/rw /tmp/aufs ++# mount -t aufs -o br=/tmp/rw:${HOME} none /tmp/aufs ++ ++Here is another example. The result is equivalent. ++# mount -t aufs -o br=/tmp/rw=rw:${HOME}=ro none /tmp/aufs ++ Or ++# mount -t aufs -o br:/tmp/rw none /tmp/aufs ++# mount -o remount,append:${HOME} /tmp/aufs ++ ++Then, you can see whole tree of your home dir through /tmp/aufs. If ++you modify a file under /tmp/aufs, the one on your home directory is ++not affected, instead the same named file will be newly created under ++/tmp/rw. And all of your modification to a file will be applied to ++the one under /tmp/rw. This is called the file based Copy on Write ++(COW) method. ++Aufs mount options are described in aufs.5. ++If you run chroot or something and make your aufs as a root directory, ++then you need to customize the shutdown script. See the aufs manual in ++detail. ++ ++Additionally, there are some sample usages of aufs which are a ++diskless system with network booting, and LiveCD over NFS. ++See sample dir in CVS tree on SourceForge. ++ ++ ++5. Contact ++---------------------------------------- ++When you have any problems or strange behaviour in aufs, please let me ++know with: ++- /proc/mounts (instead of the output of mount(8)) ++- /sys/module/aufs/* ++- /sys/fs/aufs/* (if you have them) ++- /debug/aufs/* (if you have them) ++- linux kernel version ++ if your kernel is not plain, for example modified by distributor, ++ the url where i can download its source is necessary too. ++- aufs version which was printed at loading the module or booting the ++ system, instead of the date you downloaded. ++- configuration (define/undefine CONFIG_AUFS_xxx) ++- kernel configuration or /proc/config.gz (if you have it) ++- behaviour which you think to be incorrect ++- actual operation, reproducible one is better ++- mailto: aufs-users at lists.sourceforge.net ++ ++Usually, I don't watch the Public Areas(Bugs, Support Requests, Patches, ++and Feature Requests) on SourceForge. Please join and write to ++aufs-users ML. ++ ++ ++6. Acknowledgements ++---------------------------------------- ++Thanks to everyone who have tried and are using aufs, whoever ++have reported a bug or any feedback. ++ ++Especially donators: ++Tomas Matejicek(slax.org) made a donation (much more than once). ++ Since Apr 2010, Tomas M (the author of Slax and Linux Live ++ scripts) is making "doubling" donations. ++ Unfortunately I cannot list all of the donators, but I really ++ appreciate. ++ It ends Aug 2010, but the ordinary donation URL is still available. ++ ++Dai Itasaka made a donation (2007/8). ++Chuck Smith made a donation (2008/4, 10 and 12). ++Henk Schoneveld made a donation (2008/9). ++Chih-Wei Huang, ASUS, CTC donated Eee PC 4G (2008/10). ++Francois Dupoux made a donation (2008/11). ++Bruno Cesar Ribas and Luis Carlos Erpen de Bona, C3SL serves public ++ aufs2 GIT tree (2009/2). ++William Grant made a donation (2009/3). ++Patrick Lane made a donation (2009/4). ++The Mail Archive (mail-archive.com) made donations (2009/5). ++Nippy Networks (Ed Wildgoose) made a donation (2009/7). ++New Dream Network, LLC (www.dreamhost.com) made a donation (2009/11). ++Pavel Pronskiy made a donation (2011/2). ++Iridium and Inmarsat satellite phone retailer (www.mailasail.com), Nippy ++ Networks (Ed Wildgoose) made a donation for hardware (2011/3). ++Max Lekomcev (DOM-TV project) made a donation (2011/7, 12, 2012/3, 6 and ++11). ++Sam Liddicott made a donation (2011/9). ++Era Scarecrow made a donation (2013/4). ++Bor Ratajc made a donation (2013/4). ++Alessandro Gorreta made a donation (2013/4). ++POIRETTE Marc made a donation (2013/4). ++Alessandro Gorreta made a donation (2013/4). ++lauri kasvandik made a donation (2013/5). ++"pemasu from Finland" made a donation (2013/7). ++The Parted Magic Project made a donation (2013/9 and 11). ++Pavel Barta made a donation (2013/10). ++Nikolay Pertsev made a donation (2014/5). ++James B made a donation (2014/7 and 2015/7). ++Stefano Di Biase made a donation (2014/8). ++Daniel Epellei made a donation (2015/1). ++OmegaPhil made a donation (2016/1, 2018/4). ++Tomasz Szewczyk made a donation (2016/4). ++James Burry made a donation (2016/12). ++Carsten Rose made a donation (2018/9). ++Porteus Kiosk made a donation (2018/10). ++ ++Thank you very much. ++Donations are always, including future donations, very important and ++helpful for me to keep on developing aufs. ++ ++ ++7. ++---------------------------------------- ++If you are an experienced user, no explanation is needed. Aufs is ++just a linux filesystem. ++ ++ ++Enjoy! ++ ++# Local variables: ; ++# mode: text; ++# End: ; +diff -Nurp linux-5.4/drivers/block/loop.c linux-5.4-aufs/drivers/block/loop.c +--- linux-5.4/drivers/block/loop.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/drivers/block/loop.c 2019-11-28 01:25:59.062925618 +0200 +@@ -738,6 +738,24 @@ out_err: + return error; + } + ++/* ++ * for AUFS ++ * no get/put for file. ++ */ ++struct file *loop_backing_file(struct super_block *sb) ++{ ++ struct file *ret; ++ struct loop_device *l; ++ ++ ret = NULL; ++ if (MAJOR(sb->s_dev) == LOOP_MAJOR) { ++ l = sb->s_bdev->bd_disk->private_data; ++ ret = l->lo_backing_file; ++ } ++ return ret; ++} ++EXPORT_SYMBOL_GPL(loop_backing_file); ++ + /* loop sysfs attributes */ + + static ssize_t loop_attr_show(struct device *dev, char *page, +diff -Nurp linux-5.4/fs/aufs/aufs.h linux-5.4-aufs/fs/aufs/aufs.h +--- linux-5.4/fs/aufs/aufs.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/aufs.h 2019-11-28 01:25:59.062925618 +0200 +@@ -0,0 +1,49 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * all header files ++ */ ++ ++#ifndef __AUFS_H__ ++#define __AUFS_H__ ++ ++#ifdef __KERNEL__ ++ ++#define AuStub(type, name, body, ...) \ ++ static inline type name(__VA_ARGS__) { body; } ++ ++#define AuStubVoid(name, ...) \ ++ AuStub(void, name, , __VA_ARGS__) ++#define AuStubInt0(name, ...) \ ++ AuStub(int, name, return 0, __VA_ARGS__) ++ ++#include "debug.h" ++ ++#include "branch.h" ++#include "cpup.h" ++#include "dcsub.h" ++#include "dbgaufs.h" ++#include "dentry.h" ++#include "dir.h" ++#include "dirren.h" ++#include "dynop.h" ++#include "file.h" ++#include "fstype.h" ++#include "hbl.h" ++#include "inode.h" ++#include "lcnt.h" ++#include "loop.h" ++#include "module.h" ++#include "opts.h" ++#include "rwsem.h" ++#include "super.h" ++#include "sysaufs.h" ++#include "vfsub.h" ++#include "whout.h" ++#include "wkq.h" ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_H__ */ +diff -Nurp linux-5.4/fs/aufs/branch.c linux-5.4-aufs/fs/aufs/branch.c +--- linux-5.4/fs/aufs/branch.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/branch.c 2019-11-28 01:25:59.062925618 +0200 +@@ -0,0 +1,1415 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * branch management ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++/* ++ * free a single branch ++ */ ++static void au_br_do_free(struct au_branch *br) ++{ ++ int i; ++ struct au_wbr *wbr; ++ struct au_dykey **key; ++ ++ au_hnotify_fin_br(br); ++ /* always, regardless the mount option */ ++ au_dr_hino_free(&br->br_dirren); ++ au_xino_put(br); ++ ++ AuLCntZero(au_lcnt_read(&br->br_nfiles, /*do_rev*/0)); ++ au_lcnt_fin(&br->br_nfiles, /*do_sync*/0); ++ AuLCntZero(au_lcnt_read(&br->br_count, /*do_rev*/0)); ++ au_lcnt_fin(&br->br_count, /*do_sync*/0); ++ ++ wbr = br->br_wbr; ++ if (wbr) { ++ for (i = 0; i < AuBrWh_Last; i++) ++ dput(wbr->wbr_wh[i]); ++ AuDebugOn(atomic_read(&wbr->wbr_wh_running)); ++ AuRwDestroy(&wbr->wbr_wh_rwsem); ++ } ++ ++ if (br->br_fhsm) { ++ au_br_fhsm_fin(br->br_fhsm); ++ au_kfree_try_rcu(br->br_fhsm); ++ } ++ ++ key = br->br_dykey; ++ for (i = 0; i < AuBrDynOp; i++, key++) ++ if (*key) ++ au_dy_put(*key); ++ else ++ break; ++ ++ /* recursive lock, s_umount of branch's */ ++ /* synchronize_rcu(); */ /* why? */ ++ lockdep_off(); ++ path_put(&br->br_path); ++ lockdep_on(); ++ au_kfree_rcu(wbr); ++ au_lcnt_wait_for_fin(&br->br_nfiles); ++ au_lcnt_wait_for_fin(&br->br_count); ++ /* I don't know why, but percpu_refcount requires this */ ++ /* synchronize_rcu(); */ ++ au_kfree_rcu(br); ++} ++ ++/* ++ * frees all branches ++ */ ++void au_br_free(struct au_sbinfo *sbinfo) ++{ ++ aufs_bindex_t bmax; ++ struct au_branch **br; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ bmax = sbinfo->si_bbot + 1; ++ br = sbinfo->si_branch; ++ while (bmax--) ++ au_br_do_free(*br++); ++} ++ ++/* ++ * find the index of a branch which is specified by @br_id. ++ */ ++int au_br_index(struct super_block *sb, aufs_bindex_t br_id) ++{ ++ aufs_bindex_t bindex, bbot; ++ ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) ++ if (au_sbr_id(sb, bindex) == br_id) ++ return bindex; ++ return -1; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * add a branch ++ */ ++ ++static int test_overlap(struct super_block *sb, struct dentry *h_adding, ++ struct dentry *h_root) ++{ ++ if (unlikely(h_adding == h_root ++ || au_test_loopback_overlap(sb, h_adding))) ++ return 1; ++ if (h_adding->d_sb != h_root->d_sb) ++ return 0; ++ return au_test_subdir(h_adding, h_root) ++ || au_test_subdir(h_root, h_adding); ++} ++ ++/* ++ * returns a newly allocated branch. @new_nbranch is a number of branches ++ * after adding a branch. ++ */ ++static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch, ++ int perm) ++{ ++ struct au_branch *add_branch; ++ struct dentry *root; ++ struct inode *inode; ++ int err; ++ ++ err = -ENOMEM; ++ add_branch = kzalloc(sizeof(*add_branch), GFP_NOFS); ++ if (unlikely(!add_branch)) ++ goto out; ++ add_branch->br_xino = au_xino_alloc(/*nfile*/1); ++ if (unlikely(!add_branch->br_xino)) ++ goto out_br; ++ err = au_hnotify_init_br(add_branch, perm); ++ if (unlikely(err)) ++ goto out_xino; ++ ++ if (au_br_writable(perm)) { ++ /* may be freed separately at changing the branch permission */ ++ add_branch->br_wbr = kzalloc(sizeof(*add_branch->br_wbr), ++ GFP_NOFS); ++ if (unlikely(!add_branch->br_wbr)) ++ goto out_hnotify; ++ } ++ ++ if (au_br_fhsm(perm)) { ++ err = au_fhsm_br_alloc(add_branch); ++ if (unlikely(err)) ++ goto out_wbr; ++ } ++ ++ root = sb->s_root; ++ err = au_sbr_realloc(au_sbi(sb), new_nbranch, /*may_shrink*/0); ++ if (!err) ++ err = au_di_realloc(au_di(root), new_nbranch, /*may_shrink*/0); ++ if (!err) { ++ inode = d_inode(root); ++ err = au_hinode_realloc(au_ii(inode), new_nbranch, ++ /*may_shrink*/0); ++ } ++ if (!err) ++ return add_branch; /* success */ ++ ++out_wbr: ++ au_kfree_rcu(add_branch->br_wbr); ++out_hnotify: ++ au_hnotify_fin_br(add_branch); ++out_xino: ++ au_xino_put(add_branch); ++out_br: ++ au_kfree_rcu(add_branch); ++out: ++ return ERR_PTR(err); ++} ++ ++/* ++ * test if the branch permission is legal or not. ++ */ ++static int test_br(struct inode *inode, int brperm, char *path) ++{ ++ int err; ++ ++ err = (au_br_writable(brperm) && IS_RDONLY(inode)); ++ if (!err) ++ goto out; ++ ++ err = -EINVAL; ++ pr_err("write permission for readonly mount or inode, %s\n", path); ++ ++out: ++ return err; ++} ++ ++/* ++ * returns: ++ * 0: success, the caller will add it ++ * plus: success, it is already unified, the caller should ignore it ++ * minus: error ++ */ ++static int test_add(struct super_block *sb, struct au_opt_add *add, int remount) ++{ ++ int err; ++ aufs_bindex_t bbot, bindex; ++ struct dentry *root, *h_dentry; ++ struct inode *inode, *h_inode; ++ ++ root = sb->s_root; ++ bbot = au_sbbot(sb); ++ if (unlikely(bbot >= 0 ++ && au_find_dbindex(root, add->path.dentry) >= 0)) { ++ err = 1; ++ if (!remount) { ++ err = -EINVAL; ++ pr_err("%s duplicated\n", add->pathname); ++ } ++ goto out; ++ } ++ ++ err = -ENOSPC; /* -E2BIG; */ ++ if (unlikely(AUFS_BRANCH_MAX <= add->bindex ++ || AUFS_BRANCH_MAX - 1 <= bbot)) { ++ pr_err("number of branches exceeded %s\n", add->pathname); ++ goto out; ++ } ++ ++ err = -EDOM; ++ if (unlikely(add->bindex < 0 || bbot + 1 < add->bindex)) { ++ pr_err("bad index %d\n", add->bindex); ++ goto out; ++ } ++ ++ inode = d_inode(add->path.dentry); ++ err = -ENOENT; ++ if (unlikely(!inode->i_nlink)) { ++ pr_err("no existence %s\n", add->pathname); ++ goto out; ++ } ++ ++ err = -EINVAL; ++ if (unlikely(inode->i_sb == sb)) { ++ pr_err("%s must be outside\n", add->pathname); ++ goto out; ++ } ++ ++ if (unlikely(au_test_fs_unsuppoted(inode->i_sb))) { ++ pr_err("unsupported filesystem, %s (%s)\n", ++ add->pathname, au_sbtype(inode->i_sb)); ++ goto out; ++ } ++ ++ if (unlikely(inode->i_sb->s_stack_depth)) { ++ pr_err("already stacked, %s (%s)\n", ++ add->pathname, au_sbtype(inode->i_sb)); ++ goto out; ++ } ++ ++ err = test_br(d_inode(add->path.dentry), add->perm, add->pathname); ++ if (unlikely(err)) ++ goto out; ++ ++ if (bbot < 0) ++ return 0; /* success */ ++ ++ err = -EINVAL; ++ for (bindex = 0; bindex <= bbot; bindex++) ++ if (unlikely(test_overlap(sb, add->path.dentry, ++ au_h_dptr(root, bindex)))) { ++ pr_err("%s is overlapped\n", add->pathname); ++ goto out; ++ } ++ ++ err = 0; ++ if (au_opt_test(au_mntflags(sb), WARN_PERM)) { ++ h_dentry = au_h_dptr(root, 0); ++ h_inode = d_inode(h_dentry); ++ if ((h_inode->i_mode & S_IALLUGO) != (inode->i_mode & S_IALLUGO) ++ || !uid_eq(h_inode->i_uid, inode->i_uid) ++ || !gid_eq(h_inode->i_gid, inode->i_gid)) ++ pr_warn("uid/gid/perm %s %u/%u/0%o, %u/%u/0%o\n", ++ add->pathname, ++ i_uid_read(inode), i_gid_read(inode), ++ (inode->i_mode & S_IALLUGO), ++ i_uid_read(h_inode), i_gid_read(h_inode), ++ (h_inode->i_mode & S_IALLUGO)); ++ } ++ ++out: ++ return err; ++} ++ ++/* ++ * initialize or clean the whiteouts for an adding branch ++ */ ++static int au_br_init_wh(struct super_block *sb, struct au_branch *br, ++ int new_perm) ++{ ++ int err, old_perm; ++ aufs_bindex_t bindex; ++ struct inode *h_inode; ++ struct au_wbr *wbr; ++ struct au_hinode *hdir; ++ struct dentry *h_dentry; ++ ++ err = vfsub_mnt_want_write(au_br_mnt(br)); ++ if (unlikely(err)) ++ goto out; ++ ++ wbr = br->br_wbr; ++ old_perm = br->br_perm; ++ br->br_perm = new_perm; ++ hdir = NULL; ++ h_inode = NULL; ++ bindex = au_br_index(sb, br->br_id); ++ if (0 <= bindex) { ++ hdir = au_hi(d_inode(sb->s_root), bindex); ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ } else { ++ h_dentry = au_br_dentry(br); ++ h_inode = d_inode(h_dentry); ++ inode_lock_nested(h_inode, AuLsc_I_PARENT); ++ } ++ if (!wbr) ++ err = au_wh_init(br, sb); ++ else { ++ wbr_wh_write_lock(wbr); ++ err = au_wh_init(br, sb); ++ wbr_wh_write_unlock(wbr); ++ } ++ if (hdir) ++ au_hn_inode_unlock(hdir); ++ else ++ inode_unlock(h_inode); ++ vfsub_mnt_drop_write(au_br_mnt(br)); ++ br->br_perm = old_perm; ++ ++ if (!err && wbr && !au_br_writable(new_perm)) { ++ au_kfree_rcu(wbr); ++ br->br_wbr = NULL; ++ } ++ ++out: ++ return err; ++} ++ ++static int au_wbr_init(struct au_branch *br, struct super_block *sb, ++ int perm) ++{ ++ int err; ++ struct kstatfs kst; ++ struct au_wbr *wbr; ++ ++ wbr = br->br_wbr; ++ au_rw_init(&wbr->wbr_wh_rwsem); ++ atomic_set(&wbr->wbr_wh_running, 0); ++ ++ /* ++ * a limit for rmdir/rename a dir ++ * cf. AUFS_MAX_NAMELEN in include/uapi/linux/aufs_type.h ++ */ ++ err = vfs_statfs(&br->br_path, &kst); ++ if (unlikely(err)) ++ goto out; ++ err = -EINVAL; ++ if (kst.f_namelen >= NAME_MAX) ++ err = au_br_init_wh(sb, br, perm); ++ else ++ pr_err("%pd(%s), unsupported namelen %ld\n", ++ au_br_dentry(br), ++ au_sbtype(au_br_dentry(br)->d_sb), kst.f_namelen); ++ ++out: ++ return err; ++} ++ ++/* initialize a new branch */ ++static int au_br_init(struct au_branch *br, struct super_block *sb, ++ struct au_opt_add *add) ++{ ++ int err; ++ struct au_branch *brbase; ++ struct file *xf; ++ struct inode *h_inode; ++ ++ err = 0; ++ br->br_perm = add->perm; ++ br->br_path = add->path; /* set first, path_get() later */ ++ spin_lock_init(&br->br_dykey_lock); ++ au_lcnt_init(&br->br_nfiles, /*release*/NULL); ++ au_lcnt_init(&br->br_count, /*release*/NULL); ++ br->br_id = au_new_br_id(sb); ++ AuDebugOn(br->br_id < 0); ++ ++ /* always, regardless the given option */ ++ err = au_dr_br_init(sb, br, &add->path); ++ if (unlikely(err)) ++ goto out_err; ++ ++ if (au_br_writable(add->perm)) { ++ err = au_wbr_init(br, sb, add->perm); ++ if (unlikely(err)) ++ goto out_err; ++ } ++ ++ if (au_opt_test(au_mntflags(sb), XINO)) { ++ brbase = au_sbr(sb, 0); ++ xf = au_xino_file(brbase->br_xino, /*idx*/-1); ++ AuDebugOn(!xf); ++ h_inode = d_inode(add->path.dentry); ++ err = au_xino_init_br(sb, br, h_inode->i_ino, &xf->f_path); ++ if (unlikely(err)) { ++ AuDebugOn(au_xino_file(br->br_xino, /*idx*/-1)); ++ goto out_err; ++ } ++ } ++ ++ sysaufs_br_init(br); ++ path_get(&br->br_path); ++ goto out; /* success */ ++ ++out_err: ++ memset(&br->br_path, 0, sizeof(br->br_path)); ++out: ++ return err; ++} ++ ++static void au_br_do_add_brp(struct au_sbinfo *sbinfo, aufs_bindex_t bindex, ++ struct au_branch *br, aufs_bindex_t bbot, ++ aufs_bindex_t amount) ++{ ++ struct au_branch **brp; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ brp = sbinfo->si_branch + bindex; ++ memmove(brp + 1, brp, sizeof(*brp) * amount); ++ *brp = br; ++ sbinfo->si_bbot++; ++ if (unlikely(bbot < 0)) ++ sbinfo->si_bbot = 0; ++} ++ ++static void au_br_do_add_hdp(struct au_dinfo *dinfo, aufs_bindex_t bindex, ++ aufs_bindex_t bbot, aufs_bindex_t amount) ++{ ++ struct au_hdentry *hdp; ++ ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ hdp = au_hdentry(dinfo, bindex); ++ memmove(hdp + 1, hdp, sizeof(*hdp) * amount); ++ au_h_dentry_init(hdp); ++ dinfo->di_bbot++; ++ if (unlikely(bbot < 0)) ++ dinfo->di_btop = 0; ++} ++ ++static void au_br_do_add_hip(struct au_iinfo *iinfo, aufs_bindex_t bindex, ++ aufs_bindex_t bbot, aufs_bindex_t amount) ++{ ++ struct au_hinode *hip; ++ ++ AuRwMustWriteLock(&iinfo->ii_rwsem); ++ ++ hip = au_hinode(iinfo, bindex); ++ memmove(hip + 1, hip, sizeof(*hip) * amount); ++ au_hinode_init(hip); ++ iinfo->ii_bbot++; ++ if (unlikely(bbot < 0)) ++ iinfo->ii_btop = 0; ++} ++ ++static void au_br_do_add(struct super_block *sb, struct au_branch *br, ++ aufs_bindex_t bindex) ++{ ++ struct dentry *root, *h_dentry; ++ struct inode *root_inode, *h_inode; ++ aufs_bindex_t bbot, amount; ++ ++ root = sb->s_root; ++ root_inode = d_inode(root); ++ bbot = au_sbbot(sb); ++ amount = bbot + 1 - bindex; ++ h_dentry = au_br_dentry(br); ++ au_sbilist_lock(); ++ au_br_do_add_brp(au_sbi(sb), bindex, br, bbot, amount); ++ au_br_do_add_hdp(au_di(root), bindex, bbot, amount); ++ au_br_do_add_hip(au_ii(root_inode), bindex, bbot, amount); ++ au_set_h_dptr(root, bindex, dget(h_dentry)); ++ h_inode = d_inode(h_dentry); ++ au_set_h_iptr(root_inode, bindex, au_igrab(h_inode), /*flags*/0); ++ au_sbilist_unlock(); ++} ++ ++int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount) ++{ ++ int err; ++ aufs_bindex_t bbot, add_bindex; ++ struct dentry *root, *h_dentry; ++ struct inode *root_inode; ++ struct au_branch *add_branch; ++ ++ root = sb->s_root; ++ root_inode = d_inode(root); ++ IMustLock(root_inode); ++ IiMustWriteLock(root_inode); ++ err = test_add(sb, add, remount); ++ if (unlikely(err < 0)) ++ goto out; ++ if (err) { ++ err = 0; ++ goto out; /* success */ ++ } ++ ++ bbot = au_sbbot(sb); ++ add_branch = au_br_alloc(sb, bbot + 2, add->perm); ++ err = PTR_ERR(add_branch); ++ if (IS_ERR(add_branch)) ++ goto out; ++ ++ err = au_br_init(add_branch, sb, add); ++ if (unlikely(err)) { ++ au_br_do_free(add_branch); ++ goto out; ++ } ++ ++ add_bindex = add->bindex; ++ sysaufs_brs_del(sb, add_bindex); /* remove successors */ ++ au_br_do_add(sb, add_branch, add_bindex); ++ sysaufs_brs_add(sb, add_bindex); /* append successors */ ++ dbgaufs_brs_add(sb, add_bindex, /*topdown*/0); /* rename successors */ ++ ++ h_dentry = add->path.dentry; ++ if (!add_bindex) { ++ au_cpup_attr_all(root_inode, /*force*/1); ++ sb->s_maxbytes = h_dentry->d_sb->s_maxbytes; ++ } else ++ au_add_nlink(root_inode, d_inode(h_dentry)); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static unsigned long long au_farray_cb(struct super_block *sb, void *a, ++ unsigned long long max __maybe_unused, ++ void *arg) ++{ ++ unsigned long long n; ++ struct file **p, *f; ++ struct hlist_bl_head *files; ++ struct hlist_bl_node *pos; ++ struct au_finfo *finfo; ++ ++ n = 0; ++ p = a; ++ files = &au_sbi(sb)->si_files; ++ hlist_bl_lock(files); ++ hlist_bl_for_each_entry(finfo, pos, files, fi_hlist) { ++ f = finfo->fi_file; ++ if (file_count(f) ++ && !special_file(file_inode(f)->i_mode)) { ++ get_file(f); ++ *p++ = f; ++ n++; ++ AuDebugOn(n > max); ++ } ++ } ++ hlist_bl_unlock(files); ++ ++ return n; ++} ++ ++static struct file **au_farray_alloc(struct super_block *sb, ++ unsigned long long *max) ++{ ++ struct au_sbinfo *sbi; ++ ++ sbi = au_sbi(sb); ++ *max = au_lcnt_read(&sbi->si_nfiles, /*do_rev*/1); ++ return au_array_alloc(max, au_farray_cb, sb, /*arg*/NULL); ++} ++ ++static void au_farray_free(struct file **a, unsigned long long max) ++{ ++ unsigned long long ull; ++ ++ for (ull = 0; ull < max; ull++) ++ if (a[ull]) ++ fput(a[ull]); ++ kvfree(a); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * delete a branch ++ */ ++ ++/* to show the line number, do not make it inlined function */ ++#define AuVerbose(do_info, fmt, ...) do { \ ++ if (do_info) \ ++ pr_info(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++static int au_test_ibusy(struct inode *inode, aufs_bindex_t btop, ++ aufs_bindex_t bbot) ++{ ++ return (inode && !S_ISDIR(inode->i_mode)) || btop == bbot; ++} ++ ++static int au_test_dbusy(struct dentry *dentry, aufs_bindex_t btop, ++ aufs_bindex_t bbot) ++{ ++ return au_test_ibusy(d_inode(dentry), btop, bbot); ++} ++ ++/* ++ * test if the branch is deletable or not. ++ */ ++static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex, ++ unsigned int sigen, const unsigned int verbose) ++{ ++ int err, i, j, ndentry; ++ aufs_bindex_t btop, bbot; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry *d; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, root, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ for (i = 0; !err && i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ ndentry = dpage->ndentry; ++ for (j = 0; !err && j < ndentry; j++) { ++ d = dpage->dentries[j]; ++ AuDebugOn(au_dcount(d) <= 0); ++ if (!au_digen_test(d, sigen)) { ++ di_read_lock_child(d, AuLock_IR); ++ if (unlikely(au_dbrange_test(d))) { ++ di_read_unlock(d, AuLock_IR); ++ continue; ++ } ++ } else { ++ di_write_lock_child(d); ++ if (unlikely(au_dbrange_test(d))) { ++ di_write_unlock(d); ++ continue; ++ } ++ err = au_reval_dpath(d, sigen); ++ if (!err) ++ di_downgrade_lock(d, AuLock_IR); ++ else { ++ di_write_unlock(d); ++ break; ++ } ++ } ++ ++ /* AuDbgDentry(d); */ ++ btop = au_dbtop(d); ++ bbot = au_dbbot(d); ++ if (btop <= bindex ++ && bindex <= bbot ++ && au_h_dptr(d, bindex) ++ && au_test_dbusy(d, btop, bbot)) { ++ err = -EBUSY; ++ AuVerbose(verbose, "busy %pd\n", d); ++ AuDbgDentry(d); ++ } ++ di_read_unlock(d, AuLock_IR); ++ } ++ } ++ ++out_dpages: ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++static int test_inode_busy(struct super_block *sb, aufs_bindex_t bindex, ++ unsigned int sigen, const unsigned int verbose) ++{ ++ int err; ++ unsigned long long max, ull; ++ struct inode *i, **array; ++ aufs_bindex_t btop, bbot; ++ ++ array = au_iarray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ err = 0; ++ AuDbg("b%d\n", bindex); ++ for (ull = 0; !err && ull < max; ull++) { ++ i = array[ull]; ++ if (unlikely(!i)) ++ break; ++ if (i->i_ino == AUFS_ROOT_INO) ++ continue; ++ ++ /* AuDbgInode(i); */ ++ if (au_iigen(i, NULL) == sigen) ++ ii_read_lock_child(i); ++ else { ++ ii_write_lock_child(i); ++ err = au_refresh_hinode_self(i); ++ au_iigen_dec(i); ++ if (!err) ++ ii_downgrade_lock(i); ++ else { ++ ii_write_unlock(i); ++ break; ++ } ++ } ++ ++ btop = au_ibtop(i); ++ bbot = au_ibbot(i); ++ if (btop <= bindex ++ && bindex <= bbot ++ && au_h_iptr(i, bindex) ++ && au_test_ibusy(i, btop, bbot)) { ++ err = -EBUSY; ++ AuVerbose(verbose, "busy i%lu\n", i->i_ino); ++ AuDbgInode(i); ++ } ++ ii_read_unlock(i); ++ } ++ au_iarray_free(array, max); ++ ++out: ++ return err; ++} ++ ++static int test_children_busy(struct dentry *root, aufs_bindex_t bindex, ++ const unsigned int verbose) ++{ ++ int err; ++ unsigned int sigen; ++ ++ sigen = au_sigen(root->d_sb); ++ DiMustNoWaiters(root); ++ IiMustNoWaiters(d_inode(root)); ++ di_write_unlock(root); ++ err = test_dentry_busy(root, bindex, sigen, verbose); ++ if (!err) ++ err = test_inode_busy(root->d_sb, bindex, sigen, verbose); ++ di_write_lock_child(root); /* aufs_write_lock() calls ..._child() */ ++ ++ return err; ++} ++ ++static int test_dir_busy(struct file *file, aufs_bindex_t br_id, ++ struct file **to_free, int *idx) ++{ ++ int err; ++ unsigned char matched, root; ++ aufs_bindex_t bindex, bbot; ++ struct au_fidir *fidir; ++ struct au_hfile *hfile; ++ ++ err = 0; ++ root = IS_ROOT(file->f_path.dentry); ++ if (root) { ++ get_file(file); ++ to_free[*idx] = file; ++ (*idx)++; ++ goto out; ++ } ++ ++ matched = 0; ++ fidir = au_fi(file)->fi_hdir; ++ AuDebugOn(!fidir); ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); bindex <= bbot; bindex++) { ++ hfile = fidir->fd_hfile + bindex; ++ if (!hfile->hf_file) ++ continue; ++ ++ if (hfile->hf_br->br_id == br_id) { ++ matched = 1; ++ break; ++ } ++ } ++ if (matched) ++ err = -EBUSY; ++ ++out: ++ return err; ++} ++ ++static int test_file_busy(struct super_block *sb, aufs_bindex_t br_id, ++ struct file **to_free, int opened) ++{ ++ int err, idx; ++ unsigned long long ull, max; ++ aufs_bindex_t btop; ++ struct file *file, **array; ++ struct dentry *root; ++ struct au_hfile *hfile; ++ ++ array = au_farray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ err = 0; ++ idx = 0; ++ root = sb->s_root; ++ di_write_unlock(root); ++ for (ull = 0; ull < max; ull++) { ++ file = array[ull]; ++ if (unlikely(!file)) ++ break; ++ ++ /* AuDbg("%pD\n", file); */ ++ fi_read_lock(file); ++ btop = au_fbtop(file); ++ if (!d_is_dir(file->f_path.dentry)) { ++ hfile = &au_fi(file)->fi_htop; ++ if (hfile->hf_br->br_id == br_id) ++ err = -EBUSY; ++ } else ++ err = test_dir_busy(file, br_id, to_free, &idx); ++ fi_read_unlock(file); ++ if (unlikely(err)) ++ break; ++ } ++ di_write_lock_child(root); ++ au_farray_free(array, max); ++ AuDebugOn(idx > opened); ++ ++out: ++ return err; ++} ++ ++static void br_del_file(struct file **to_free, unsigned long long opened, ++ aufs_bindex_t br_id) ++{ ++ unsigned long long ull; ++ aufs_bindex_t bindex, btop, bbot, bfound; ++ struct file *file; ++ struct au_fidir *fidir; ++ struct au_hfile *hfile; ++ ++ for (ull = 0; ull < opened; ull++) { ++ file = to_free[ull]; ++ if (unlikely(!file)) ++ break; ++ ++ /* AuDbg("%pD\n", file); */ ++ AuDebugOn(!d_is_dir(file->f_path.dentry)); ++ bfound = -1; ++ fidir = au_fi(file)->fi_hdir; ++ AuDebugOn(!fidir); ++ fi_write_lock(file); ++ btop = au_fbtop(file); ++ bbot = au_fbbot_dir(file); ++ for (bindex = btop; bindex <= bbot; bindex++) { ++ hfile = fidir->fd_hfile + bindex; ++ if (!hfile->hf_file) ++ continue; ++ ++ if (hfile->hf_br->br_id == br_id) { ++ bfound = bindex; ++ break; ++ } ++ } ++ AuDebugOn(bfound < 0); ++ au_set_h_fptr(file, bfound, NULL); ++ if (bfound == btop) { ++ for (btop++; btop <= bbot; btop++) ++ if (au_hf_dir(file, btop)) { ++ au_set_fbtop(file, btop); ++ break; ++ } ++ } ++ fi_write_unlock(file); ++ } ++} ++ ++static void au_br_do_del_brp(struct au_sbinfo *sbinfo, ++ const aufs_bindex_t bindex, ++ const aufs_bindex_t bbot) ++{ ++ struct au_branch **brp, **p; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ brp = sbinfo->si_branch + bindex; ++ if (bindex < bbot) ++ memmove(brp, brp + 1, sizeof(*brp) * (bbot - bindex)); ++ sbinfo->si_branch[0 + bbot] = NULL; ++ sbinfo->si_bbot--; ++ ++ p = au_krealloc(sbinfo->si_branch, sizeof(*p) * bbot, AuGFP_SBILIST, ++ /*may_shrink*/1); ++ if (p) ++ sbinfo->si_branch = p; ++ /* harmless error */ ++} ++ ++static void au_br_do_del_hdp(struct au_dinfo *dinfo, const aufs_bindex_t bindex, ++ const aufs_bindex_t bbot) ++{ ++ struct au_hdentry *hdp, *p; ++ ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ hdp = au_hdentry(dinfo, bindex); ++ if (bindex < bbot) ++ memmove(hdp, hdp + 1, sizeof(*hdp) * (bbot - bindex)); ++ /* au_h_dentry_init(au_hdentry(dinfo, bbot); */ ++ dinfo->di_bbot--; ++ ++ p = au_krealloc(dinfo->di_hdentry, sizeof(*p) * bbot, AuGFP_SBILIST, ++ /*may_shrink*/1); ++ if (p) ++ dinfo->di_hdentry = p; ++ /* harmless error */ ++} ++ ++static void au_br_do_del_hip(struct au_iinfo *iinfo, const aufs_bindex_t bindex, ++ const aufs_bindex_t bbot) ++{ ++ struct au_hinode *hip, *p; ++ ++ AuRwMustWriteLock(&iinfo->ii_rwsem); ++ ++ hip = au_hinode(iinfo, bindex); ++ if (bindex < bbot) ++ memmove(hip, hip + 1, sizeof(*hip) * (bbot - bindex)); ++ /* au_hinode_init(au_hinode(iinfo, bbot)); */ ++ iinfo->ii_bbot--; ++ ++ p = au_krealloc(iinfo->ii_hinode, sizeof(*p) * bbot, AuGFP_SBILIST, ++ /*may_shrink*/1); ++ if (p) ++ iinfo->ii_hinode = p; ++ /* harmless error */ ++} ++ ++static void au_br_do_del(struct super_block *sb, aufs_bindex_t bindex, ++ struct au_branch *br) ++{ ++ aufs_bindex_t bbot; ++ struct au_sbinfo *sbinfo; ++ struct dentry *root, *h_root; ++ struct inode *inode, *h_inode; ++ struct au_hinode *hinode; ++ ++ SiMustWriteLock(sb); ++ ++ root = sb->s_root; ++ inode = d_inode(root); ++ sbinfo = au_sbi(sb); ++ bbot = sbinfo->si_bbot; ++ ++ h_root = au_h_dptr(root, bindex); ++ hinode = au_hi(inode, bindex); ++ h_inode = au_igrab(hinode->hi_inode); ++ au_hiput(hinode); ++ ++ au_sbilist_lock(); ++ au_br_do_del_brp(sbinfo, bindex, bbot); ++ au_br_do_del_hdp(au_di(root), bindex, bbot); ++ au_br_do_del_hip(au_ii(inode), bindex, bbot); ++ au_sbilist_unlock(); ++ ++ /* ignore an error */ ++ au_dr_br_fin(sb, br); /* always, regardless the mount option */ ++ ++ dput(h_root); ++ iput(h_inode); ++ au_br_do_free(br); ++} ++ ++static unsigned long long empty_cb(struct super_block *sb, void *array, ++ unsigned long long max, void *arg) ++{ ++ return max; ++} ++ ++int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount) ++{ ++ int err, rerr, i; ++ unsigned long long opened; ++ unsigned int mnt_flags; ++ aufs_bindex_t bindex, bbot, br_id; ++ unsigned char do_wh, verbose; ++ struct au_branch *br; ++ struct au_wbr *wbr; ++ struct dentry *root; ++ struct file **to_free; ++ ++ err = 0; ++ opened = 0; ++ to_free = NULL; ++ root = sb->s_root; ++ bindex = au_find_dbindex(root, del->h_path.dentry); ++ if (bindex < 0) { ++ if (remount) ++ goto out; /* success */ ++ err = -ENOENT; ++ pr_err("%s no such branch\n", del->pathname); ++ goto out; ++ } ++ AuDbg("bindex b%d\n", bindex); ++ ++ err = -EBUSY; ++ mnt_flags = au_mntflags(sb); ++ verbose = !!au_opt_test(mnt_flags, VERBOSE); ++ bbot = au_sbbot(sb); ++ if (unlikely(!bbot)) { ++ AuVerbose(verbose, "no more branches left\n"); ++ goto out; ++ } ++ ++ br = au_sbr(sb, bindex); ++ AuDebugOn(!path_equal(&br->br_path, &del->h_path)); ++ if (unlikely(au_lcnt_read(&br->br_count, /*do_rev*/1))) { ++ AuVerbose(verbose, "br %pd2 is busy now\n", del->h_path.dentry); ++ goto out; ++ } ++ ++ br_id = br->br_id; ++ opened = au_lcnt_read(&br->br_nfiles, /*do_rev*/1); ++ if (unlikely(opened)) { ++ to_free = au_array_alloc(&opened, empty_cb, sb, NULL); ++ err = PTR_ERR(to_free); ++ if (IS_ERR(to_free)) ++ goto out; ++ ++ err = test_file_busy(sb, br_id, to_free, opened); ++ if (unlikely(err)) { ++ AuVerbose(verbose, "%llu file(s) opened\n", opened); ++ goto out; ++ } ++ } ++ ++ wbr = br->br_wbr; ++ do_wh = wbr && (wbr->wbr_whbase || wbr->wbr_plink || wbr->wbr_orph); ++ if (do_wh) { ++ /* instead of WbrWhMustWriteLock(wbr) */ ++ SiMustWriteLock(sb); ++ for (i = 0; i < AuBrWh_Last; i++) { ++ dput(wbr->wbr_wh[i]); ++ wbr->wbr_wh[i] = NULL; ++ } ++ } ++ ++ err = test_children_busy(root, bindex, verbose); ++ if (unlikely(err)) { ++ if (do_wh) ++ goto out_wh; ++ goto out; ++ } ++ ++ err = 0; ++ if (to_free) { ++ /* ++ * now we confirmed the branch is deletable. ++ * let's free the remaining opened dirs on the branch. ++ */ ++ di_write_unlock(root); ++ br_del_file(to_free, opened, br_id); ++ di_write_lock_child(root); ++ } ++ ++ sysaufs_brs_del(sb, bindex); /* remove successors */ ++ dbgaufs_xino_del(br); /* remove one */ ++ au_br_do_del(sb, bindex, br); ++ sysaufs_brs_add(sb, bindex); /* append successors */ ++ dbgaufs_brs_add(sb, bindex, /*topdown*/1); /* rename successors */ ++ ++ if (!bindex) { ++ au_cpup_attr_all(d_inode(root), /*force*/1); ++ sb->s_maxbytes = au_sbr_sb(sb, 0)->s_maxbytes; ++ } else ++ au_sub_nlink(d_inode(root), d_inode(del->h_path.dentry)); ++ if (au_opt_test(mnt_flags, PLINK)) ++ au_plink_half_refresh(sb, br_id); ++ ++ goto out; /* success */ ++ ++out_wh: ++ /* revert */ ++ rerr = au_br_init_wh(sb, br, br->br_perm); ++ if (rerr) ++ pr_warn("failed re-creating base whiteout, %s. (%d)\n", ++ del->pathname, rerr); ++out: ++ if (to_free) ++ au_farray_free(to_free, opened); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_ibusy(struct super_block *sb, struct aufs_ibusy __user *arg) ++{ ++ int err; ++ aufs_bindex_t btop, bbot; ++ struct aufs_ibusy ibusy; ++ struct inode *inode, *h_inode; ++ ++ err = -EPERM; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = copy_from_user(&ibusy, arg, sizeof(ibusy)); ++ if (!err) ++ /* VERIFY_WRITE */ ++ err = !access_ok(&arg->h_ino, sizeof(arg->h_ino)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ ++ err = -EINVAL; ++ si_read_lock(sb, AuLock_FLUSH); ++ if (unlikely(ibusy.bindex < 0 || ibusy.bindex > au_sbbot(sb))) ++ goto out_unlock; ++ ++ err = 0; ++ ibusy.h_ino = 0; /* invalid */ ++ inode = ilookup(sb, ibusy.ino); ++ if (!inode ++ || inode->i_ino == AUFS_ROOT_INO ++ || au_is_bad_inode(inode)) ++ goto out_unlock; ++ ++ ii_read_lock_child(inode); ++ btop = au_ibtop(inode); ++ bbot = au_ibbot(inode); ++ if (btop <= ibusy.bindex && ibusy.bindex <= bbot) { ++ h_inode = au_h_iptr(inode, ibusy.bindex); ++ if (h_inode && au_test_ibusy(inode, btop, bbot)) ++ ibusy.h_ino = h_inode->i_ino; ++ } ++ ii_read_unlock(inode); ++ iput(inode); ++ ++out_unlock: ++ si_read_unlock(sb); ++ if (!err) { ++ err = __put_user(ibusy.h_ino, &arg->h_ino); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ } ++ } ++out: ++ return err; ++} ++ ++long au_ibusy_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_ibusy(file->f_path.dentry->d_sb, (void __user *)arg); ++} ++ ++#ifdef CONFIG_COMPAT ++long au_ibusy_compat_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_ibusy(file->f_path.dentry->d_sb, compat_ptr(arg)); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * change a branch permission ++ */ ++ ++static void au_warn_ima(void) ++{ ++#ifdef CONFIG_IMA ++ /* since it doesn't support mark_files_ro() */ ++ AuWarn1("RW -> RO makes IMA to produce wrong message\n"); ++#endif ++} ++ ++static int do_need_sigen_inc(int a, int b) ++{ ++ return au_br_whable(a) && !au_br_whable(b); ++} ++ ++static int need_sigen_inc(int old, int new) ++{ ++ return do_need_sigen_inc(old, new) ++ || do_need_sigen_inc(new, old); ++} ++ ++static int au_br_mod_files_ro(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ int err, do_warn; ++ unsigned int mnt_flags; ++ unsigned long long ull, max; ++ aufs_bindex_t br_id; ++ unsigned char verbose, writer; ++ struct file *file, *hf, **array; ++ struct au_hfile *hfile; ++ struct inode *h_inode; ++ ++ mnt_flags = au_mntflags(sb); ++ verbose = !!au_opt_test(mnt_flags, VERBOSE); ++ ++ array = au_farray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ do_warn = 0; ++ br_id = au_sbr_id(sb, bindex); ++ for (ull = 0; ull < max; ull++) { ++ file = array[ull]; ++ if (unlikely(!file)) ++ break; ++ ++ /* AuDbg("%pD\n", file); */ ++ fi_read_lock(file); ++ if (unlikely(au_test_mmapped(file))) { ++ err = -EBUSY; ++ AuVerbose(verbose, "mmapped %pD\n", file); ++ AuDbgFile(file); ++ FiMustNoWaiters(file); ++ fi_read_unlock(file); ++ goto out_array; ++ } ++ ++ hfile = &au_fi(file)->fi_htop; ++ hf = hfile->hf_file; ++ if (!d_is_reg(file->f_path.dentry) ++ || !(file->f_mode & FMODE_WRITE) ++ || hfile->hf_br->br_id != br_id ++ || !(hf->f_mode & FMODE_WRITE)) ++ array[ull] = NULL; ++ else { ++ do_warn = 1; ++ get_file(file); ++ } ++ ++ FiMustNoWaiters(file); ++ fi_read_unlock(file); ++ fput(file); ++ } ++ ++ err = 0; ++ if (do_warn) ++ au_warn_ima(); ++ ++ for (ull = 0; ull < max; ull++) { ++ file = array[ull]; ++ if (!file) ++ continue; ++ ++ /* todo: already flushed? */ ++ /* ++ * fs/super.c:mark_files_ro() is gone, but aufs keeps its ++ * approach which resets f_mode and calls mnt_drop_write() and ++ * file_release_write() for each file, because the branch ++ * attribute in aufs world is totally different from the native ++ * fs rw/ro mode. ++ */ ++ /* fi_read_lock(file); */ ++ hfile = &au_fi(file)->fi_htop; ++ hf = hfile->hf_file; ++ /* fi_read_unlock(file); */ ++ spin_lock(&hf->f_lock); ++ writer = !!(hf->f_mode & FMODE_WRITER); ++ hf->f_mode &= ~(FMODE_WRITE | FMODE_WRITER); ++ spin_unlock(&hf->f_lock); ++ if (writer) { ++ h_inode = file_inode(hf); ++ put_write_access(h_inode); ++ __mnt_drop_write(hf->f_path.mnt); ++ if ((hf->f_mode & (FMODE_READ | FMODE_WRITE)) ++ == FMODE_READ) ++ i_readcount_inc(h_inode); ++ } ++ } ++ ++out_array: ++ au_farray_free(array, max); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount, ++ int *do_refresh) ++{ ++ int err, rerr; ++ aufs_bindex_t bindex; ++ struct dentry *root; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ root = sb->s_root; ++ bindex = au_find_dbindex(root, mod->h_root); ++ if (bindex < 0) { ++ if (remount) ++ return 0; /* success */ ++ err = -ENOENT; ++ pr_err("%s no such branch\n", mod->path); ++ goto out; ++ } ++ AuDbg("bindex b%d\n", bindex); ++ ++ err = test_br(d_inode(mod->h_root), mod->perm, mod->path); ++ if (unlikely(err)) ++ goto out; ++ ++ br = au_sbr(sb, bindex); ++ AuDebugOn(mod->h_root != au_br_dentry(br)); ++ if (br->br_perm == mod->perm) ++ return 0; /* success */ ++ ++ /* pre-allocate for non-fhsm --> fhsm */ ++ bf = NULL; ++ if (!au_br_fhsm(br->br_perm) && au_br_fhsm(mod->perm)) { ++ err = au_fhsm_br_alloc(br); ++ if (unlikely(err)) ++ goto out; ++ bf = br->br_fhsm; ++ br->br_fhsm = NULL; ++ } ++ ++ if (au_br_writable(br->br_perm)) { ++ /* remove whiteout base */ ++ err = au_br_init_wh(sb, br, mod->perm); ++ if (unlikely(err)) ++ goto out_bf; ++ ++ if (!au_br_writable(mod->perm)) { ++ /* rw --> ro, file might be mmapped */ ++ DiMustNoWaiters(root); ++ IiMustNoWaiters(d_inode(root)); ++ di_write_unlock(root); ++ err = au_br_mod_files_ro(sb, bindex); ++ /* aufs_write_lock() calls ..._child() */ ++ di_write_lock_child(root); ++ ++ if (unlikely(err)) { ++ rerr = -ENOMEM; ++ br->br_wbr = kzalloc(sizeof(*br->br_wbr), ++ GFP_NOFS); ++ if (br->br_wbr) ++ rerr = au_wbr_init(br, sb, br->br_perm); ++ if (unlikely(rerr)) { ++ AuIOErr("nested error %d (%d)\n", ++ rerr, err); ++ br->br_perm = mod->perm; ++ } ++ } ++ } ++ } else if (au_br_writable(mod->perm)) { ++ /* ro --> rw */ ++ err = -ENOMEM; ++ br->br_wbr = kzalloc(sizeof(*br->br_wbr), GFP_NOFS); ++ if (br->br_wbr) { ++ err = au_wbr_init(br, sb, mod->perm); ++ if (unlikely(err)) { ++ au_kfree_rcu(br->br_wbr); ++ br->br_wbr = NULL; ++ } ++ } ++ } ++ if (unlikely(err)) ++ goto out_bf; ++ ++ if (au_br_fhsm(br->br_perm)) { ++ if (!au_br_fhsm(mod->perm)) { ++ /* fhsm --> non-fhsm */ ++ au_br_fhsm_fin(br->br_fhsm); ++ au_kfree_rcu(br->br_fhsm); ++ br->br_fhsm = NULL; ++ } ++ } else if (au_br_fhsm(mod->perm)) ++ /* non-fhsm --> fhsm */ ++ br->br_fhsm = bf; ++ ++ *do_refresh |= need_sigen_inc(br->br_perm, mod->perm); ++ br->br_perm = mod->perm; ++ goto out; /* success */ ++ ++out_bf: ++ au_kfree_try_rcu(bf); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_br_stfs(struct au_branch *br, struct aufs_stfs *stfs) ++{ ++ int err; ++ struct kstatfs kstfs; ++ ++ err = vfs_statfs(&br->br_path, &kstfs); ++ if (!err) { ++ stfs->f_blocks = kstfs.f_blocks; ++ stfs->f_bavail = kstfs.f_bavail; ++ stfs->f_files = kstfs.f_files; ++ stfs->f_ffree = kstfs.f_ffree; ++ } ++ ++ return err; ++} +diff -Nurp linux-5.4/fs/aufs/branch.h linux-5.4-aufs/fs/aufs/branch.h +--- linux-5.4/fs/aufs/branch.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/branch.h 2019-11-28 01:25:59.062925618 +0200 +@@ -0,0 +1,353 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * branch filesystems and xino for them ++ */ ++ ++#ifndef __AUFS_BRANCH_H__ ++#define __AUFS_BRANCH_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "dirren.h" ++#include "dynop.h" ++#include "lcnt.h" ++#include "rwsem.h" ++#include "super.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* a xino file */ ++struct au_xino { ++ struct file **xi_file; ++ unsigned int xi_nfile; ++ ++ struct { ++ spinlock_t spin; ++ ino_t *array; ++ int total; ++ /* reserved for future use */ ++ /* unsigned long *bitmap; */ ++ wait_queue_head_t wqh; ++ } xi_nondir; ++ ++ struct mutex xi_mtx; /* protects xi_file array */ ++ struct hlist_bl_head xi_writing; ++ ++ atomic_t xi_truncating; ++ ++ struct kref xi_kref; ++}; ++ ++/* File-based Hierarchical Storage Management */ ++struct au_br_fhsm { ++#ifdef CONFIG_AUFS_FHSM ++ struct mutex bf_lock; ++ unsigned long bf_jiffy; ++ struct aufs_stfs bf_stfs; ++ int bf_readable; ++#endif ++}; ++ ++/* members for writable branch only */ ++enum {AuBrWh_BASE, AuBrWh_PLINK, AuBrWh_ORPH, AuBrWh_Last}; ++struct au_wbr { ++ struct au_rwsem wbr_wh_rwsem; ++ struct dentry *wbr_wh[AuBrWh_Last]; ++ atomic_t wbr_wh_running; ++#define wbr_whbase wbr_wh[AuBrWh_BASE] /* whiteout base */ ++#define wbr_plink wbr_wh[AuBrWh_PLINK] /* pseudo-link dir */ ++#define wbr_orph wbr_wh[AuBrWh_ORPH] /* dir for orphans */ ++ ++ /* mfs mode */ ++ unsigned long long wbr_bytes; ++}; ++ ++/* ext2 has 3 types of operations at least, ext3 has 4 */ ++#define AuBrDynOp (AuDyLast * 4) ++ ++#ifdef CONFIG_AUFS_HFSNOTIFY ++/* support for asynchronous destruction */ ++struct au_br_hfsnotify { ++ struct fsnotify_group *hfsn_group; ++}; ++#endif ++ ++/* sysfs entries */ ++struct au_brsysfs { ++ char name[16]; ++ struct attribute attr; ++}; ++ ++enum { ++ AuBrSysfs_BR, ++ AuBrSysfs_BRID, ++ AuBrSysfs_Last ++}; ++ ++/* protected by superblock rwsem */ ++struct au_branch { ++ struct au_xino *br_xino; ++ ++ aufs_bindex_t br_id; ++ ++ int br_perm; ++ struct path br_path; ++ spinlock_t br_dykey_lock; ++ struct au_dykey *br_dykey[AuBrDynOp]; ++ au_lcnt_t br_nfiles; /* opened files */ ++ au_lcnt_t br_count; /* in-use for other */ ++ ++ struct au_wbr *br_wbr; ++ struct au_br_fhsm *br_fhsm; ++ ++#ifdef CONFIG_AUFS_HFSNOTIFY ++ struct au_br_hfsnotify *br_hfsn; ++#endif ++ ++#ifdef CONFIG_SYSFS ++ /* entries under sysfs per mount-point */ ++ struct au_brsysfs br_sysfs[AuBrSysfs_Last]; ++#endif ++ ++#ifdef CONFIG_DEBUG_FS ++ struct dentry *br_dbgaufs; /* xino */ ++#endif ++ ++ struct au_dr_br br_dirren; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct vfsmount *au_br_mnt(struct au_branch *br) ++{ ++ return br->br_path.mnt; ++} ++ ++static inline struct dentry *au_br_dentry(struct au_branch *br) ++{ ++ return br->br_path.dentry; ++} ++ ++static inline struct super_block *au_br_sb(struct au_branch *br) ++{ ++ return au_br_mnt(br)->mnt_sb; ++} ++ ++static inline int au_br_rdonly(struct au_branch *br) ++{ ++ return (sb_rdonly(au_br_sb(br)) ++ || !au_br_writable(br->br_perm)) ++ ? -EROFS : 0; ++} ++ ++static inline int au_br_hnotifyable(int brperm __maybe_unused) ++{ ++#ifdef CONFIG_AUFS_HNOTIFY ++ return !(brperm & AuBrPerm_RR); ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_br_test_oflag(int oflag, struct au_branch *br) ++{ ++ int err, exec_flag; ++ ++ err = 0; ++ exec_flag = oflag & __FMODE_EXEC; ++ if (unlikely(exec_flag && path_noexec(&br->br_path))) ++ err = -EACCES; ++ ++ return err; ++} ++ ++static inline void au_xino_get(struct au_branch *br) ++{ ++ struct au_xino *xi; ++ ++ xi = br->br_xino; ++ if (xi) ++ kref_get(&xi->xi_kref); ++} ++ ++static inline int au_xino_count(struct au_branch *br) ++{ ++ int v; ++ struct au_xino *xi; ++ ++ v = 0; ++ xi = br->br_xino; ++ if (xi) ++ v = kref_read(&xi->xi_kref); ++ ++ return v; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* branch.c */ ++struct au_sbinfo; ++void au_br_free(struct au_sbinfo *sinfo); ++int au_br_index(struct super_block *sb, aufs_bindex_t br_id); ++struct au_opt_add; ++int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount); ++struct au_opt_del; ++int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount); ++long au_ibusy_ioctl(struct file *file, unsigned long arg); ++#ifdef CONFIG_COMPAT ++long au_ibusy_compat_ioctl(struct file *file, unsigned long arg); ++#endif ++struct au_opt_mod; ++int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount, ++ int *do_refresh); ++struct aufs_stfs; ++int au_br_stfs(struct au_branch *br, struct aufs_stfs *stfs); ++ ++/* xino.c */ ++static const loff_t au_loff_max = LLONG_MAX; ++ ++aufs_bindex_t au_xi_root(struct super_block *sb, struct dentry *dentry); ++struct file *au_xino_create(struct super_block *sb, char *fpath, int silent, ++ int wbrtop); ++struct file *au_xino_create2(struct super_block *sb, struct path *base, ++ struct file *copy_src); ++struct au_xi_new { ++ struct au_xino *xi; /* switch between xino and xigen */ ++ int idx; ++ struct path *base; ++ struct file *copy_src; ++}; ++struct file *au_xi_new(struct super_block *sb, struct au_xi_new *xinew); ++ ++int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t *ino); ++int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t ino); ++ssize_t xino_fread(vfs_readf_t func, struct file *file, void *buf, size_t size, ++ loff_t *pos); ++ssize_t xino_fwrite(vfs_writef_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos); ++ ++int au_xib_trunc(struct super_block *sb); ++int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex, int idx_begin); ++ ++struct au_xino *au_xino_alloc(unsigned int nfile); ++int au_xino_put(struct au_branch *br); ++struct file *au_xino_file1(struct au_xino *xi); ++ ++struct au_opt_xino; ++void au_xino_clr(struct super_block *sb); ++int au_xino_set(struct super_block *sb, struct au_opt_xino *xiopt, int remount); ++struct file *au_xino_def(struct super_block *sb); ++int au_xino_init_br(struct super_block *sb, struct au_branch *br, ino_t hino, ++ struct path *base); ++ ++ino_t au_xino_new_ino(struct super_block *sb); ++void au_xino_delete_inode(struct inode *inode, const int unlinked); ++ ++void au_xinondir_leave(struct super_block *sb, aufs_bindex_t bindex, ++ ino_t h_ino, int idx); ++int au_xinondir_enter(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ int *idx); ++ ++int au_xino_path(struct seq_file *seq, struct file *file); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* @idx is signed to accept -1 meaning the first file */ ++static inline struct file *au_xino_file(struct au_xino *xi, int idx) ++{ ++ struct file *file; ++ ++ file = NULL; ++ if (!xi) ++ goto out; ++ ++ if (idx >= 0) { ++ if (idx < xi->xi_nfile) ++ file = xi->xi_file[idx]; ++ } else ++ file = au_xino_file1(xi); ++ ++out: ++ return file; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Superblock to branch */ ++static inline ++aufs_bindex_t au_sbr_id(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_sbr(sb, bindex)->br_id; ++} ++ ++static inline ++struct vfsmount *au_sbr_mnt(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_br_mnt(au_sbr(sb, bindex)); ++} ++ ++static inline ++struct super_block *au_sbr_sb(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_br_sb(au_sbr(sb, bindex)); ++} ++ ++static inline int au_sbr_perm(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_sbr(sb, bindex)->br_perm; ++} ++ ++static inline int au_sbr_whable(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ return au_br_whable(au_sbr_perm(sb, bindex)); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define wbr_wh_read_lock(wbr) au_rw_read_lock(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_write_lock(wbr) au_rw_write_lock(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_read_trylock(wbr) au_rw_read_trylock(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_write_trylock(wbr) au_rw_write_trylock(&(wbr)->wbr_wh_rwsem) ++/* ++#define wbr_wh_read_trylock_nested(wbr) \ ++ au_rw_read_trylock_nested(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_write_trylock_nested(wbr) \ ++ au_rw_write_trylock_nested(&(wbr)->wbr_wh_rwsem) ++*/ ++ ++#define wbr_wh_read_unlock(wbr) au_rw_read_unlock(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_write_unlock(wbr) au_rw_write_unlock(&(wbr)->wbr_wh_rwsem) ++#define wbr_wh_downgrade_lock(wbr) au_rw_dgrade_lock(&(wbr)->wbr_wh_rwsem) ++ ++#define WbrWhMustNoWaiters(wbr) AuRwMustNoWaiters(&(wbr)->wbr_wh_rwsem) ++#define WbrWhMustAnyLock(wbr) AuRwMustAnyLock(&(wbr)->wbr_wh_rwsem) ++#define WbrWhMustWriteLock(wbr) AuRwMustWriteLock(&(wbr)->wbr_wh_rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_FHSM ++static inline void au_br_fhsm_init(struct au_br_fhsm *brfhsm) ++{ ++ mutex_init(&brfhsm->bf_lock); ++ brfhsm->bf_jiffy = 0; ++ brfhsm->bf_readable = 0; ++} ++ ++static inline void au_br_fhsm_fin(struct au_br_fhsm *brfhsm) ++{ ++ mutex_destroy(&brfhsm->bf_lock); ++} ++#else ++AuStubVoid(au_br_fhsm_init, struct au_br_fhsm *brfhsm) ++AuStubVoid(au_br_fhsm_fin, struct au_br_fhsm *brfhsm) ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_BRANCH_H__ */ +diff -Nurp linux-5.4/fs/aufs/cpup.c linux-5.4-aufs/fs/aufs/cpup.c +--- linux-5.4/fs/aufs/cpup.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/cpup.c 2019-11-28 01:25:59.063925618 +0200 +@@ -0,0 +1,1445 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * copy-up functions, see wbr_policy.c for copy-down ++ */ ++ ++#include ++#include ++#include ++#include "aufs.h" ++ ++void au_cpup_attr_flags(struct inode *dst, unsigned int iflags) ++{ ++ const unsigned int mask = S_DEAD | S_SWAPFILE | S_PRIVATE ++ | S_NOATIME | S_NOCMTIME | S_AUTOMOUNT; ++ ++ BUILD_BUG_ON(sizeof(iflags) != sizeof(dst->i_flags)); ++ ++ dst->i_flags |= iflags & ~mask; ++ if (au_test_fs_notime(dst->i_sb)) ++ dst->i_flags |= S_NOATIME | S_NOCMTIME; ++} ++ ++void au_cpup_attr_timesizes(struct inode *inode) ++{ ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ fsstack_copy_attr_times(inode, h_inode); ++ fsstack_copy_inode_size(inode, h_inode); ++} ++ ++void au_cpup_attr_nlink(struct inode *inode, int force) ++{ ++ struct inode *h_inode; ++ struct super_block *sb; ++ aufs_bindex_t bindex, bbot; ++ ++ sb = inode->i_sb; ++ bindex = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, bindex); ++ if (!force ++ && !S_ISDIR(h_inode->i_mode) ++ && au_opt_test(au_mntflags(sb), PLINK) ++ && au_plink_test(inode)) ++ return; ++ ++ /* ++ * 0 can happen in revalidating. ++ * h_inode->i_mutex may not be held here, but it is harmless since once ++ * i_nlink reaches 0, it will never become positive except O_TMPFILE ++ * case. ++ * todo: O_TMPFILE+linkat(AT_SYMLINK_FOLLOW) bypassing aufs may cause ++ * the incorrect link count. ++ */ ++ set_nlink(inode, h_inode->i_nlink); ++ ++ /* ++ * fewer nlink makes find(1) noisy, but larger nlink doesn't. ++ * it may includes whplink directory. ++ */ ++ if (S_ISDIR(h_inode->i_mode)) { ++ bbot = au_ibbot(inode); ++ for (bindex++; bindex <= bbot; bindex++) { ++ h_inode = au_h_iptr(inode, bindex); ++ if (h_inode) ++ au_add_nlink(inode, h_inode); ++ } ++ } ++} ++ ++void au_cpup_attr_changeable(struct inode *inode) ++{ ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ inode->i_mode = h_inode->i_mode; ++ inode->i_uid = h_inode->i_uid; ++ inode->i_gid = h_inode->i_gid; ++ au_cpup_attr_timesizes(inode); ++ au_cpup_attr_flags(inode, h_inode->i_flags); ++} ++ ++void au_cpup_igen(struct inode *inode, struct inode *h_inode) ++{ ++ struct au_iinfo *iinfo = au_ii(inode); ++ ++ IiMustWriteLock(inode); ++ ++ iinfo->ii_higen = h_inode->i_generation; ++ iinfo->ii_hsb1 = h_inode->i_sb; ++} ++ ++void au_cpup_attr_all(struct inode *inode, int force) ++{ ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ au_cpup_attr_changeable(inode); ++ if (inode->i_nlink > 0) ++ au_cpup_attr_nlink(inode, force); ++ inode->i_rdev = h_inode->i_rdev; ++ inode->i_blkbits = h_inode->i_blkbits; ++ au_cpup_igen(inode, h_inode); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Note: dt_dentry and dt_h_dentry are not dget/dput-ed */ ++ ++/* keep the timestamps of the parent dir when cpup */ ++void au_dtime_store(struct au_dtime *dt, struct dentry *dentry, ++ struct path *h_path) ++{ ++ struct inode *h_inode; ++ ++ dt->dt_dentry = dentry; ++ dt->dt_h_path = *h_path; ++ h_inode = d_inode(h_path->dentry); ++ dt->dt_atime = h_inode->i_atime; ++ dt->dt_mtime = h_inode->i_mtime; ++ /* smp_mb(); */ ++} ++ ++void au_dtime_revert(struct au_dtime *dt) ++{ ++ struct iattr attr; ++ int err; ++ ++ attr.ia_atime = dt->dt_atime; ++ attr.ia_mtime = dt->dt_mtime; ++ attr.ia_valid = ATTR_FORCE | ATTR_MTIME | ATTR_MTIME_SET ++ | ATTR_ATIME | ATTR_ATIME_SET; ++ ++ /* no delegation since this is a directory */ ++ err = vfsub_notify_change(&dt->dt_h_path, &attr, /*delegated*/NULL); ++ if (unlikely(err)) ++ pr_warn("restoring timestamps failed(%d). ignored\n", err); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* internal use only */ ++struct au_cpup_reg_attr { ++ int valid; ++ struct kstat st; ++ unsigned int iflags; /* inode->i_flags */ ++}; ++ ++static noinline_for_stack ++int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct dentry *h_src, ++ struct au_cpup_reg_attr *h_src_attr) ++{ ++ int err, sbits, icex; ++ unsigned int mnt_flags; ++ unsigned char verbose; ++ struct iattr ia; ++ struct path h_path; ++ struct inode *h_isrc, *h_idst; ++ struct kstat *h_st; ++ struct au_branch *br; ++ ++ h_path.dentry = au_h_dptr(dst, bindex); ++ h_idst = d_inode(h_path.dentry); ++ br = au_sbr(dst->d_sb, bindex); ++ h_path.mnt = au_br_mnt(br); ++ h_isrc = d_inode(h_src); ++ ia.ia_valid = ATTR_FORCE | ATTR_UID | ATTR_GID ++ | ATTR_ATIME | ATTR_MTIME ++ | ATTR_ATIME_SET | ATTR_MTIME_SET; ++ if (h_src_attr && h_src_attr->valid) { ++ h_st = &h_src_attr->st; ++ ia.ia_uid = h_st->uid; ++ ia.ia_gid = h_st->gid; ++ ia.ia_atime = h_st->atime; ++ ia.ia_mtime = h_st->mtime; ++ if (h_idst->i_mode != h_st->mode ++ && !S_ISLNK(h_idst->i_mode)) { ++ ia.ia_valid |= ATTR_MODE; ++ ia.ia_mode = h_st->mode; ++ } ++ sbits = !!(h_st->mode & (S_ISUID | S_ISGID)); ++ au_cpup_attr_flags(h_idst, h_src_attr->iflags); ++ } else { ++ ia.ia_uid = h_isrc->i_uid; ++ ia.ia_gid = h_isrc->i_gid; ++ ia.ia_atime = h_isrc->i_atime; ++ ia.ia_mtime = h_isrc->i_mtime; ++ if (h_idst->i_mode != h_isrc->i_mode ++ && !S_ISLNK(h_idst->i_mode)) { ++ ia.ia_valid |= ATTR_MODE; ++ ia.ia_mode = h_isrc->i_mode; ++ } ++ sbits = !!(h_isrc->i_mode & (S_ISUID | S_ISGID)); ++ au_cpup_attr_flags(h_idst, h_isrc->i_flags); ++ } ++ /* no delegation since it is just created */ ++ err = vfsub_notify_change(&h_path, &ia, /*delegated*/NULL); ++ ++ /* is this nfs only? */ ++ if (!err && sbits && au_test_nfs(h_path.dentry->d_sb)) { ++ ia.ia_valid = ATTR_FORCE | ATTR_MODE; ++ ia.ia_mode = h_isrc->i_mode; ++ err = vfsub_notify_change(&h_path, &ia, /*delegated*/NULL); ++ } ++ ++ icex = br->br_perm & AuBrAttr_ICEX; ++ if (!err) { ++ mnt_flags = au_mntflags(dst->d_sb); ++ verbose = !!au_opt_test(mnt_flags, VERBOSE); ++ err = au_cpup_xattr(h_path.dentry, h_src, icex, verbose); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_copy_file(struct file *dst, struct file *src, loff_t len, ++ char *buf, unsigned long blksize) ++{ ++ int err; ++ size_t sz, rbytes, wbytes; ++ unsigned char all_zero; ++ char *p, *zp; ++ struct inode *h_inode; ++ /* reduce stack usage */ ++ struct iattr *ia; ++ ++ zp = page_address(ZERO_PAGE(0)); ++ if (unlikely(!zp)) ++ return -ENOMEM; /* possible? */ ++ ++ err = 0; ++ all_zero = 0; ++ while (len) { ++ AuDbg("len %lld\n", len); ++ sz = blksize; ++ if (len < blksize) ++ sz = len; ++ ++ rbytes = 0; ++ /* todo: signal_pending? */ ++ while (!rbytes || err == -EAGAIN || err == -EINTR) { ++ rbytes = vfsub_read_k(src, buf, sz, &src->f_pos); ++ err = rbytes; ++ } ++ if (unlikely(err < 0)) ++ break; ++ ++ all_zero = 0; ++ if (len >= rbytes && rbytes == blksize) ++ all_zero = !memcmp(buf, zp, rbytes); ++ if (!all_zero) { ++ wbytes = rbytes; ++ p = buf; ++ while (wbytes) { ++ size_t b; ++ ++ b = vfsub_write_k(dst, p, wbytes, &dst->f_pos); ++ err = b; ++ /* todo: signal_pending? */ ++ if (unlikely(err == -EAGAIN || err == -EINTR)) ++ continue; ++ if (unlikely(err < 0)) ++ break; ++ wbytes -= b; ++ p += b; ++ } ++ if (unlikely(err < 0)) ++ break; ++ } else { ++ loff_t res; ++ ++ AuLabel(hole); ++ res = vfsub_llseek(dst, rbytes, SEEK_CUR); ++ err = res; ++ if (unlikely(res < 0)) ++ break; ++ } ++ len -= rbytes; ++ err = 0; ++ } ++ ++ /* the last block may be a hole */ ++ if (!err && all_zero) { ++ AuLabel(last hole); ++ ++ err = 1; ++ if (au_test_nfs(dst->f_path.dentry->d_sb)) { ++ /* nfs requires this step to make last hole */ ++ /* is this only nfs? */ ++ do { ++ /* todo: signal_pending? */ ++ err = vfsub_write_k(dst, "\0", 1, &dst->f_pos); ++ } while (err == -EAGAIN || err == -EINTR); ++ if (err == 1) ++ dst->f_pos--; ++ } ++ ++ if (err == 1) { ++ ia = (void *)buf; ++ ia->ia_size = dst->f_pos; ++ ia->ia_valid = ATTR_SIZE | ATTR_FILE; ++ ia->ia_file = dst; ++ h_inode = file_inode(dst); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD2); ++ /* no delegation since it is just created */ ++ err = vfsub_notify_change(&dst->f_path, ia, ++ /*delegated*/NULL); ++ inode_unlock(h_inode); ++ } ++ } ++ ++ return err; ++} ++ ++int au_copy_file(struct file *dst, struct file *src, loff_t len) ++{ ++ int err; ++ unsigned long blksize; ++ unsigned char do_kfree; ++ char *buf; ++ struct super_block *h_sb; ++ ++ err = -ENOMEM; ++ h_sb = file_inode(dst)->i_sb; ++ blksize = h_sb->s_blocksize; ++ if (!blksize || PAGE_SIZE < blksize) ++ blksize = PAGE_SIZE; ++ AuDbg("blksize %lu\n", blksize); ++ do_kfree = (blksize != PAGE_SIZE && blksize >= sizeof(struct iattr *)); ++ if (do_kfree) ++ buf = kmalloc(blksize, GFP_NOFS); ++ else ++ buf = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!buf)) ++ goto out; ++ ++ if (len > (1 << 22)) ++ AuDbg("copying a large file %lld\n", (long long)len); ++ ++ src->f_pos = 0; ++ dst->f_pos = 0; ++ err = au_do_copy_file(dst, src, len, buf, blksize); ++ if (do_kfree) { ++ AuDebugOn(!au_kfree_do_sz_test(blksize)); ++ au_kfree_do_rcu(buf); ++ } else ++ free_page((unsigned long)buf); ++ ++out: ++ return err; ++} ++ ++static int au_do_copy(struct file *dst, struct file *src, loff_t len) ++{ ++ int err; ++ struct super_block *h_src_sb; ++ struct inode *h_src_inode; ++ ++ h_src_inode = file_inode(src); ++ h_src_sb = h_src_inode->i_sb; ++ ++ /* XFS acquires inode_lock */ ++ if (!au_test_xfs(h_src_sb)) ++ err = au_copy_file(dst, src, len); ++ else { ++ inode_unlock_shared(h_src_inode); ++ err = au_copy_file(dst, src, len); ++ inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); ++ } ++ ++ return err; ++} ++ ++static int au_clone_or_copy(struct file *dst, struct file *src, loff_t len) ++{ ++ int err; ++ loff_t lo; ++ struct super_block *h_src_sb; ++ struct inode *h_src_inode; ++ ++ h_src_inode = file_inode(src); ++ h_src_sb = h_src_inode->i_sb; ++ if (h_src_sb != file_inode(dst)->i_sb ++ || !dst->f_op->remap_file_range) { ++ err = au_do_copy(dst, src, len); ++ goto out; ++ } ++ ++ if (!au_test_nfs(h_src_sb)) { ++ inode_unlock_shared(h_src_inode); ++ lo = vfsub_clone_file_range(src, dst, len); ++ inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); ++ } else ++ lo = vfsub_clone_file_range(src, dst, len); ++ if (lo == len) { ++ err = 0; ++ goto out; /* success */ ++ } else if (lo >= 0) ++ /* todo: possible? */ ++ /* paritially succeeded */ ++ AuDbg("lo %lld, len %lld. Retrying.\n", lo, len); ++ else if (lo != -EOPNOTSUPP) { ++ /* older XFS has a condition in cloning */ ++ err = lo; ++ goto out; ++ } ++ ++ /* the backend fs on NFS may not support cloning */ ++ err = au_do_copy(dst, src, len); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * to support a sparse file which is opened with O_APPEND, ++ * we need to close the file. ++ */ ++static int au_cp_regular(struct au_cp_generic *cpg) ++{ ++ int err, i; ++ enum { SRC, DST }; ++ struct { ++ aufs_bindex_t bindex; ++ unsigned int flags; ++ struct dentry *dentry; ++ int force_wr; ++ struct file *file; ++ } *f, file[] = { ++ { ++ .bindex = cpg->bsrc, ++ .flags = O_RDONLY | O_NOATIME | O_LARGEFILE, ++ }, ++ { ++ .bindex = cpg->bdst, ++ .flags = O_WRONLY | O_NOATIME | O_LARGEFILE, ++ .force_wr = !!au_ftest_cpup(cpg->flags, RWDST), ++ } ++ }; ++ struct au_branch *br; ++ struct super_block *sb, *h_src_sb; ++ struct inode *h_src_inode; ++ struct task_struct *tsk = current; ++ ++ /* bsrc branch can be ro/rw. */ ++ sb = cpg->dentry->d_sb; ++ f = file; ++ for (i = 0; i < 2; i++, f++) { ++ f->dentry = au_h_dptr(cpg->dentry, f->bindex); ++ f->file = au_h_open(cpg->dentry, f->bindex, f->flags, ++ /*file*/NULL, f->force_wr); ++ if (IS_ERR(f->file)) { ++ err = PTR_ERR(f->file); ++ if (i == SRC) ++ goto out; ++ else ++ goto out_src; ++ } ++ } ++ ++ /* try stopping to update while we copyup */ ++ h_src_inode = d_inode(file[SRC].dentry); ++ h_src_sb = h_src_inode->i_sb; ++ if (!au_test_nfs(h_src_sb)) ++ IMustLock(h_src_inode); ++ err = au_clone_or_copy(file[DST].file, file[SRC].file, cpg->len); ++ ++ /* i wonder if we had O_NO_DELAY_FPUT flag */ ++ if (tsk->flags & PF_KTHREAD) ++ __fput_sync(file[DST].file); ++ else { ++ /* it happened actually */ ++ fput(file[DST].file); ++ /* ++ * too bad. ++ * we have to call both since we don't know which place the file ++ * was added to. ++ */ ++ task_work_run(); ++ flush_delayed_fput(); ++ } ++ br = au_sbr(sb, file[DST].bindex); ++ au_lcnt_dec(&br->br_nfiles); ++ ++out_src: ++ fput(file[SRC].file); ++ br = au_sbr(sb, file[SRC].bindex); ++ au_lcnt_dec(&br->br_nfiles); ++out: ++ return err; ++} ++ ++static int au_do_cpup_regular(struct au_cp_generic *cpg, ++ struct au_cpup_reg_attr *h_src_attr) ++{ ++ int err, rerr; ++ loff_t l; ++ struct path h_path; ++ struct inode *h_src_inode, *h_dst_inode; ++ ++ err = 0; ++ h_src_inode = au_h_iptr(d_inode(cpg->dentry), cpg->bsrc); ++ l = i_size_read(h_src_inode); ++ if (cpg->len == -1 || l < cpg->len) ++ cpg->len = l; ++ if (cpg->len) { ++ /* try stopping to update while we are referencing */ ++ inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); ++ au_pin_hdir_unlock(cpg->pin); ++ ++ h_path.dentry = au_h_dptr(cpg->dentry, cpg->bsrc); ++ h_path.mnt = au_sbr_mnt(cpg->dentry->d_sb, cpg->bsrc); ++ h_src_attr->iflags = h_src_inode->i_flags; ++ if (!au_test_nfs(h_src_inode->i_sb)) ++ err = vfsub_getattr(&h_path, &h_src_attr->st); ++ else { ++ inode_unlock_shared(h_src_inode); ++ err = vfsub_getattr(&h_path, &h_src_attr->st); ++ inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); ++ } ++ if (unlikely(err)) { ++ inode_unlock_shared(h_src_inode); ++ goto out; ++ } ++ h_src_attr->valid = 1; ++ if (!au_test_nfs(h_src_inode->i_sb)) { ++ err = au_cp_regular(cpg); ++ inode_unlock_shared(h_src_inode); ++ } else { ++ inode_unlock_shared(h_src_inode); ++ err = au_cp_regular(cpg); ++ } ++ rerr = au_pin_hdir_relock(cpg->pin); ++ if (!err && rerr) ++ err = rerr; ++ } ++ if (!err && (h_src_inode->i_state & I_LINKABLE)) { ++ h_path.dentry = au_h_dptr(cpg->dentry, cpg->bdst); ++ h_dst_inode = d_inode(h_path.dentry); ++ spin_lock(&h_dst_inode->i_lock); ++ h_dst_inode->i_state |= I_LINKABLE; ++ spin_unlock(&h_dst_inode->i_lock); ++ } ++ ++out: ++ return err; ++} ++ ++static int au_do_cpup_symlink(struct path *h_path, struct dentry *h_src, ++ struct inode *h_dir) ++{ ++ int err, symlen; ++ mm_segment_t old_fs; ++ union { ++ char *k; ++ char __user *u; ++ } sym; ++ ++ err = -ENOMEM; ++ sym.k = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!sym.k)) ++ goto out; ++ ++ /* unnecessary to support mmap_sem since symlink is not mmap-able */ ++ old_fs = get_fs(); ++ set_fs(KERNEL_DS); ++ symlen = vfs_readlink(h_src, sym.u, PATH_MAX); ++ err = symlen; ++ set_fs(old_fs); ++ ++ if (symlen > 0) { ++ sym.k[symlen] = 0; ++ err = vfsub_symlink(h_dir, h_path, sym.k); ++ } ++ free_page((unsigned long)sym.k); ++ ++out: ++ return err; ++} ++ ++/* ++ * regardless 'acl' option, reset all ACL. ++ * All ACL will be copied up later from the original entry on the lower branch. ++ */ ++static int au_reset_acl(struct inode *h_dir, struct path *h_path, umode_t mode) ++{ ++ int err; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ ++ h_dentry = h_path->dentry; ++ h_inode = d_inode(h_dentry); ++ /* forget_all_cached_acls(h_inode)); */ ++ err = vfsub_removexattr(h_dentry, XATTR_NAME_POSIX_ACL_ACCESS); ++ AuTraceErr(err); ++ if (err == -EOPNOTSUPP) ++ err = 0; ++ if (!err) ++ err = vfsub_acl_chmod(h_inode, mode); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_do_cpup_dir(struct au_cp_generic *cpg, struct dentry *dst_parent, ++ struct inode *h_dir, struct path *h_path) ++{ ++ int err; ++ struct inode *dir, *inode; ++ ++ err = vfsub_removexattr(h_path->dentry, XATTR_NAME_POSIX_ACL_DEFAULT); ++ AuTraceErr(err); ++ if (err == -EOPNOTSUPP) ++ err = 0; ++ if (unlikely(err)) ++ goto out; ++ ++ /* ++ * strange behaviour from the users view, ++ * particularly setattr case ++ */ ++ dir = d_inode(dst_parent); ++ if (au_ibtop(dir) == cpg->bdst) ++ au_cpup_attr_nlink(dir, /*force*/1); ++ inode = d_inode(cpg->dentry); ++ au_cpup_attr_nlink(inode, /*force*/1); ++ ++out: ++ return err; ++} ++ ++static noinline_for_stack ++int cpup_entry(struct au_cp_generic *cpg, struct dentry *dst_parent, ++ struct au_cpup_reg_attr *h_src_attr) ++{ ++ int err; ++ umode_t mode; ++ unsigned int mnt_flags; ++ unsigned char isdir, isreg, force; ++ const unsigned char do_dt = !!au_ftest_cpup(cpg->flags, DTIME); ++ struct au_dtime dt; ++ struct path h_path; ++ struct dentry *h_src, *h_dst, *h_parent; ++ struct inode *h_inode, *h_dir; ++ struct super_block *sb; ++ ++ /* bsrc branch can be ro/rw. */ ++ h_src = au_h_dptr(cpg->dentry, cpg->bsrc); ++ h_inode = d_inode(h_src); ++ AuDebugOn(h_inode != au_h_iptr(d_inode(cpg->dentry), cpg->bsrc)); ++ ++ /* try stopping to be referenced while we are creating */ ++ h_dst = au_h_dptr(cpg->dentry, cpg->bdst); ++ if (au_ftest_cpup(cpg->flags, RENAME)) ++ AuDebugOn(strncmp(h_dst->d_name.name, AUFS_WH_PFX, ++ AUFS_WH_PFX_LEN)); ++ h_parent = h_dst->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ AuDebugOn(h_parent != h_dst->d_parent); ++ ++ sb = cpg->dentry->d_sb; ++ h_path.mnt = au_sbr_mnt(sb, cpg->bdst); ++ if (do_dt) { ++ h_path.dentry = h_parent; ++ au_dtime_store(&dt, dst_parent, &h_path); ++ } ++ h_path.dentry = h_dst; ++ ++ isreg = 0; ++ isdir = 0; ++ mode = h_inode->i_mode; ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ isreg = 1; ++ err = vfsub_create(h_dir, &h_path, 0600, /*want_excl*/true); ++ if (!err) ++ err = au_do_cpup_regular(cpg, h_src_attr); ++ break; ++ case S_IFDIR: ++ isdir = 1; ++ err = vfsub_mkdir(h_dir, &h_path, mode); ++ if (!err) ++ err = au_do_cpup_dir(cpg, dst_parent, h_dir, &h_path); ++ break; ++ case S_IFLNK: ++ err = au_do_cpup_symlink(&h_path, h_src, h_dir); ++ break; ++ case S_IFCHR: ++ case S_IFBLK: ++ AuDebugOn(!capable(CAP_MKNOD)); ++ /*FALLTHROUGH*/ ++ case S_IFIFO: ++ case S_IFSOCK: ++ err = vfsub_mknod(h_dir, &h_path, mode, h_inode->i_rdev); ++ break; ++ default: ++ AuIOErr("Unknown inode type 0%o\n", mode); ++ err = -EIO; ++ } ++ if (!err) ++ err = au_reset_acl(h_dir, &h_path, mode); ++ ++ mnt_flags = au_mntflags(sb); ++ if (!au_opt_test(mnt_flags, UDBA_NONE) ++ && !isdir ++ && au_opt_test(mnt_flags, XINO) ++ && (h_inode->i_nlink == 1 ++ || (h_inode->i_state & I_LINKABLE)) ++ /* todo: unnecessary? */ ++ /* && d_inode(cpg->dentry)->i_nlink == 1 */ ++ && cpg->bdst < cpg->bsrc ++ && !au_ftest_cpup(cpg->flags, KEEPLINO)) ++ au_xino_write(sb, cpg->bsrc, h_inode->i_ino, /*ino*/0); ++ /* ignore this error */ ++ ++ if (!err) { ++ force = 0; ++ if (isreg) { ++ force = !!cpg->len; ++ if (cpg->len == -1) ++ force = !!i_size_read(h_inode); ++ } ++ au_fhsm_wrote(sb, cpg->bdst, force); ++ } ++ ++ if (do_dt) ++ au_dtime_revert(&dt); ++ return err; ++} ++ ++static int au_do_ren_after_cpup(struct au_cp_generic *cpg, struct path *h_path) ++{ ++ int err; ++ struct dentry *dentry, *h_dentry, *h_parent, *parent; ++ struct inode *h_dir; ++ aufs_bindex_t bdst; ++ ++ dentry = cpg->dentry; ++ bdst = cpg->bdst; ++ h_dentry = au_h_dptr(dentry, bdst); ++ if (!au_ftest_cpup(cpg->flags, OVERWRITE)) { ++ dget(h_dentry); ++ au_set_h_dptr(dentry, bdst, NULL); ++ err = au_lkup_neg(dentry, bdst, /*wh*/0); ++ if (!err) ++ h_path->dentry = dget(au_h_dptr(dentry, bdst)); ++ au_set_h_dptr(dentry, bdst, h_dentry); ++ } else { ++ err = 0; ++ parent = dget_parent(dentry); ++ h_parent = au_h_dptr(parent, bdst); ++ dput(parent); ++ h_path->dentry = vfsub_lkup_one(&dentry->d_name, h_parent); ++ if (IS_ERR(h_path->dentry)) ++ err = PTR_ERR(h_path->dentry); ++ } ++ if (unlikely(err)) ++ goto out; ++ ++ h_parent = h_dentry->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ AuDbg("%pd %pd\n", h_dentry, h_path->dentry); ++ /* no delegation since it is just created */ ++ err = vfsub_rename(h_dir, h_dentry, h_dir, h_path, /*delegated*/NULL, ++ /*flags*/0); ++ dput(h_path->dentry); ++ ++out: ++ return err; ++} ++ ++/* ++ * copyup the @dentry from @bsrc to @bdst. ++ * the caller must set the both of lower dentries. ++ * @len is for truncating when it is -1 copyup the entire file. ++ * in link/rename cases, @dst_parent may be different from the real one. ++ * basic->bsrc can be larger than basic->bdst. ++ * aufs doesn't touch the credential so ++ * security_inode_copy_up{,_xattr}() are unnecessary. ++ */ ++static int au_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent) ++{ ++ int err, rerr; ++ aufs_bindex_t old_ibtop; ++ unsigned char isdir, plink; ++ struct dentry *h_src, *h_dst, *h_parent; ++ struct inode *dst_inode, *h_dir, *inode, *delegated, *src_inode; ++ struct super_block *sb; ++ struct au_branch *br; ++ /* to reduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct path h_path; ++ struct au_cpup_reg_attr h_src_attr; ++ } *a; ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ a->h_src_attr.valid = 0; ++ ++ sb = cpg->dentry->d_sb; ++ br = au_sbr(sb, cpg->bdst); ++ a->h_path.mnt = au_br_mnt(br); ++ h_dst = au_h_dptr(cpg->dentry, cpg->bdst); ++ h_parent = h_dst->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ ++ h_src = au_h_dptr(cpg->dentry, cpg->bsrc); ++ inode = d_inode(cpg->dentry); ++ ++ if (!dst_parent) ++ dst_parent = dget_parent(cpg->dentry); ++ else ++ dget(dst_parent); ++ ++ plink = !!au_opt_test(au_mntflags(sb), PLINK); ++ dst_inode = au_h_iptr(inode, cpg->bdst); ++ if (dst_inode) { ++ if (unlikely(!plink)) { ++ err = -EIO; ++ AuIOErr("hi%lu(i%lu) exists on b%d " ++ "but plink is disabled\n", ++ dst_inode->i_ino, inode->i_ino, cpg->bdst); ++ goto out_parent; ++ } ++ ++ if (dst_inode->i_nlink) { ++ const int do_dt = au_ftest_cpup(cpg->flags, DTIME); ++ ++ h_src = au_plink_lkup(inode, cpg->bdst); ++ err = PTR_ERR(h_src); ++ if (IS_ERR(h_src)) ++ goto out_parent; ++ if (unlikely(d_is_negative(h_src))) { ++ err = -EIO; ++ AuIOErr("i%lu exists on b%d " ++ "but not pseudo-linked\n", ++ inode->i_ino, cpg->bdst); ++ dput(h_src); ++ goto out_parent; ++ } ++ ++ if (do_dt) { ++ a->h_path.dentry = h_parent; ++ au_dtime_store(&a->dt, dst_parent, &a->h_path); ++ } ++ ++ a->h_path.dentry = h_dst; ++ delegated = NULL; ++ err = vfsub_link(h_src, h_dir, &a->h_path, &delegated); ++ if (!err && au_ftest_cpup(cpg->flags, RENAME)) ++ err = au_do_ren_after_cpup(cpg, &a->h_path); ++ if (do_dt) ++ au_dtime_revert(&a->dt); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ dput(h_src); ++ goto out_parent; ++ } else ++ /* todo: cpup_wh_file? */ ++ /* udba work */ ++ au_update_ibrange(inode, /*do_put_zero*/1); ++ } ++ ++ isdir = S_ISDIR(inode->i_mode); ++ old_ibtop = au_ibtop(inode); ++ err = cpup_entry(cpg, dst_parent, &a->h_src_attr); ++ if (unlikely(err)) ++ goto out_rev; ++ dst_inode = d_inode(h_dst); ++ inode_lock_nested(dst_inode, AuLsc_I_CHILD2); ++ /* todo: necessary? */ ++ /* au_pin_hdir_unlock(cpg->pin); */ ++ ++ err = cpup_iattr(cpg->dentry, cpg->bdst, h_src, &a->h_src_attr); ++ if (unlikely(err)) { ++ /* todo: necessary? */ ++ /* au_pin_hdir_relock(cpg->pin); */ /* ignore an error */ ++ inode_unlock(dst_inode); ++ goto out_rev; ++ } ++ ++ if (cpg->bdst < old_ibtop) { ++ if (S_ISREG(inode->i_mode)) { ++ err = au_dy_iaop(inode, cpg->bdst, dst_inode); ++ if (unlikely(err)) { ++ /* ignore an error */ ++ /* au_pin_hdir_relock(cpg->pin); */ ++ inode_unlock(dst_inode); ++ goto out_rev; ++ } ++ } ++ au_set_ibtop(inode, cpg->bdst); ++ } else ++ au_set_ibbot(inode, cpg->bdst); ++ au_set_h_iptr(inode, cpg->bdst, au_igrab(dst_inode), ++ au_hi_flags(inode, isdir)); ++ ++ /* todo: necessary? */ ++ /* err = au_pin_hdir_relock(cpg->pin); */ ++ inode_unlock(dst_inode); ++ if (unlikely(err)) ++ goto out_rev; ++ ++ src_inode = d_inode(h_src); ++ if (!isdir ++ && (src_inode->i_nlink > 1 ++ || src_inode->i_state & I_LINKABLE) ++ && plink) ++ au_plink_append(inode, cpg->bdst, h_dst); ++ ++ if (au_ftest_cpup(cpg->flags, RENAME)) { ++ a->h_path.dentry = h_dst; ++ err = au_do_ren_after_cpup(cpg, &a->h_path); ++ } ++ if (!err) ++ goto out_parent; /* success */ ++ ++ /* revert */ ++out_rev: ++ a->h_path.dentry = h_parent; ++ au_dtime_store(&a->dt, dst_parent, &a->h_path); ++ a->h_path.dentry = h_dst; ++ rerr = 0; ++ if (d_is_positive(h_dst)) { ++ if (!isdir) { ++ /* no delegation since it is just created */ ++ rerr = vfsub_unlink(h_dir, &a->h_path, ++ /*delegated*/NULL, /*force*/0); ++ } else ++ rerr = vfsub_rmdir(h_dir, &a->h_path); ++ } ++ au_dtime_revert(&a->dt); ++ if (rerr) { ++ AuIOErr("failed removing broken entry(%d, %d)\n", err, rerr); ++ err = -EIO; ++ } ++out_parent: ++ dput(dst_parent); ++ au_kfree_rcu(a); ++out: ++ return err; ++} ++ ++#if 0 /* reserved */ ++struct au_cpup_single_args { ++ int *errp; ++ struct au_cp_generic *cpg; ++ struct dentry *dst_parent; ++}; ++ ++static void au_call_cpup_single(void *args) ++{ ++ struct au_cpup_single_args *a = args; ++ ++ au_pin_hdir_acquire_nest(a->cpg->pin); ++ *a->errp = au_cpup_single(a->cpg, a->dst_parent); ++ au_pin_hdir_release(a->cpg->pin); ++} ++#endif ++ ++/* ++ * prevent SIGXFSZ in copy-up. ++ * testing CAP_MKNOD is for generic fs, ++ * but CAP_FSETID is for xfs only, currently. ++ */ ++static int au_cpup_sio_test(struct au_pin *pin, umode_t mode) ++{ ++ int do_sio; ++ struct super_block *sb; ++ struct inode *h_dir; ++ ++ do_sio = 0; ++ sb = au_pinned_parent(pin)->d_sb; ++ if (!au_wkq_test() ++ && (!au_sbi(sb)->si_plink_maint_pid ++ || au_plink_maint(sb, AuLock_NOPLM))) { ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ /* no condition about RLIMIT_FSIZE and the file size */ ++ do_sio = 1; ++ break; ++ case S_IFCHR: ++ case S_IFBLK: ++ do_sio = !capable(CAP_MKNOD); ++ break; ++ } ++ if (!do_sio) ++ do_sio = ((mode & (S_ISUID | S_ISGID)) ++ && !capable(CAP_FSETID)); ++ /* this workaround may be removed in the future */ ++ if (!do_sio) { ++ h_dir = au_pinned_h_dir(pin); ++ do_sio = h_dir->i_mode & S_ISVTX; ++ } ++ } ++ ++ return do_sio; ++} ++ ++#if 0 /* reserved */ ++int au_sio_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent) ++{ ++ int err, wkq_err; ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(cpg->dentry, cpg->bsrc); ++ if (!au_cpup_sio_test(pin, d_inode(h_dentry)->i_mode)) ++ err = au_cpup_single(cpg, dst_parent); ++ else { ++ struct au_cpup_single_args args = { ++ .errp = &err, ++ .cpg = cpg, ++ .dst_parent = dst_parent ++ }; ++ wkq_err = au_wkq_wait(au_call_cpup_single, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} ++#endif ++ ++/* ++ * copyup the @dentry from the first active lower branch to @bdst, ++ * using au_cpup_single(). ++ */ ++static int au_cpup_simple(struct au_cp_generic *cpg) ++{ ++ int err; ++ unsigned int flags_orig; ++ struct dentry *dentry; ++ ++ AuDebugOn(cpg->bsrc < 0); ++ ++ dentry = cpg->dentry; ++ DiMustWriteLock(dentry); ++ ++ err = au_lkup_neg(dentry, cpg->bdst, /*wh*/1); ++ if (!err) { ++ flags_orig = cpg->flags; ++ au_fset_cpup(cpg->flags, RENAME); ++ err = au_cpup_single(cpg, NULL); ++ cpg->flags = flags_orig; ++ if (!err) ++ return 0; /* success */ ++ ++ /* revert */ ++ au_set_h_dptr(dentry, cpg->bdst, NULL); ++ au_set_dbtop(dentry, cpg->bsrc); ++ } ++ ++ return err; ++} ++ ++struct au_cpup_simple_args { ++ int *errp; ++ struct au_cp_generic *cpg; ++}; ++ ++static void au_call_cpup_simple(void *args) ++{ ++ struct au_cpup_simple_args *a = args; ++ ++ au_pin_hdir_acquire_nest(a->cpg->pin); ++ *a->errp = au_cpup_simple(a->cpg); ++ au_pin_hdir_release(a->cpg->pin); ++} ++ ++static int au_do_sio_cpup_simple(struct au_cp_generic *cpg) ++{ ++ int err, wkq_err; ++ struct dentry *dentry, *parent; ++ struct file *h_file; ++ struct inode *h_dir; ++ ++ dentry = cpg->dentry; ++ h_file = NULL; ++ if (au_ftest_cpup(cpg->flags, HOPEN)) { ++ AuDebugOn(cpg->bsrc < 0); ++ h_file = au_h_open_pre(dentry, cpg->bsrc, /*force_wr*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ } ++ ++ parent = dget_parent(dentry); ++ h_dir = au_h_iptr(d_inode(parent), cpg->bdst); ++ if (!au_test_h_perm_sio(h_dir, MAY_EXEC | MAY_WRITE) ++ && !au_cpup_sio_test(cpg->pin, d_inode(dentry)->i_mode)) ++ err = au_cpup_simple(cpg); ++ else { ++ struct au_cpup_simple_args args = { ++ .errp = &err, ++ .cpg = cpg ++ }; ++ wkq_err = au_wkq_wait(au_call_cpup_simple, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ dput(parent); ++ if (h_file) ++ au_h_open_post(dentry, cpg->bsrc, h_file); ++ ++out: ++ return err; ++} ++ ++int au_sio_cpup_simple(struct au_cp_generic *cpg) ++{ ++ aufs_bindex_t bsrc, bbot; ++ struct dentry *dentry, *h_dentry; ++ ++ if (cpg->bsrc < 0) { ++ dentry = cpg->dentry; ++ bbot = au_dbbot(dentry); ++ for (bsrc = cpg->bdst + 1; bsrc <= bbot; bsrc++) { ++ h_dentry = au_h_dptr(dentry, bsrc); ++ if (h_dentry) { ++ AuDebugOn(d_is_negative(h_dentry)); ++ break; ++ } ++ } ++ AuDebugOn(bsrc > bbot); ++ cpg->bsrc = bsrc; ++ } ++ AuDebugOn(cpg->bsrc <= cpg->bdst); ++ return au_do_sio_cpup_simple(cpg); ++} ++ ++int au_sio_cpdown_simple(struct au_cp_generic *cpg) ++{ ++ AuDebugOn(cpg->bdst <= cpg->bsrc); ++ return au_do_sio_cpup_simple(cpg); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * copyup the deleted file for writing. ++ */ ++static int au_do_cpup_wh(struct au_cp_generic *cpg, struct dentry *wh_dentry, ++ struct file *file) ++{ ++ int err; ++ unsigned int flags_orig; ++ aufs_bindex_t bsrc_orig; ++ struct au_dinfo *dinfo; ++ struct { ++ struct au_hdentry *hd; ++ struct dentry *h_dentry; ++ } hdst, hsrc; ++ ++ dinfo = au_di(cpg->dentry); ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ bsrc_orig = cpg->bsrc; ++ cpg->bsrc = dinfo->di_btop; ++ hdst.hd = au_hdentry(dinfo, cpg->bdst); ++ hdst.h_dentry = hdst.hd->hd_dentry; ++ hdst.hd->hd_dentry = wh_dentry; ++ dinfo->di_btop = cpg->bdst; ++ ++ hsrc.h_dentry = NULL; ++ if (file) { ++ hsrc.hd = au_hdentry(dinfo, cpg->bsrc); ++ hsrc.h_dentry = hsrc.hd->hd_dentry; ++ hsrc.hd->hd_dentry = au_hf_top(file)->f_path.dentry; ++ } ++ flags_orig = cpg->flags; ++ cpg->flags = !AuCpup_DTIME; ++ err = au_cpup_single(cpg, /*h_parent*/NULL); ++ cpg->flags = flags_orig; ++ if (file) { ++ if (!err) ++ err = au_reopen_nondir(file); ++ hsrc.hd->hd_dentry = hsrc.h_dentry; ++ } ++ hdst.hd->hd_dentry = hdst.h_dentry; ++ dinfo->di_btop = cpg->bsrc; ++ cpg->bsrc = bsrc_orig; ++ ++ return err; ++} ++ ++static int au_cpup_wh(struct au_cp_generic *cpg, struct file *file) ++{ ++ int err; ++ aufs_bindex_t bdst; ++ struct au_dtime dt; ++ struct dentry *dentry, *parent, *h_parent, *wh_dentry; ++ struct au_branch *br; ++ struct path h_path; ++ ++ dentry = cpg->dentry; ++ bdst = cpg->bdst; ++ br = au_sbr(dentry->d_sb, bdst); ++ parent = dget_parent(dentry); ++ h_parent = au_h_dptr(parent, bdst); ++ wh_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out; ++ ++ h_path.dentry = h_parent; ++ h_path.mnt = au_br_mnt(br); ++ au_dtime_store(&dt, parent, &h_path); ++ err = au_do_cpup_wh(cpg, wh_dentry, file); ++ if (unlikely(err)) ++ goto out_wh; ++ ++ dget(wh_dentry); ++ h_path.dentry = wh_dentry; ++ if (!d_is_dir(wh_dentry)) { ++ /* no delegation since it is just created */ ++ err = vfsub_unlink(d_inode(h_parent), &h_path, ++ /*delegated*/NULL, /*force*/0); ++ } else ++ err = vfsub_rmdir(d_inode(h_parent), &h_path); ++ if (unlikely(err)) { ++ AuIOErr("failed remove copied-up tmp file %pd(%d)\n", ++ wh_dentry, err); ++ err = -EIO; ++ } ++ au_dtime_revert(&dt); ++ au_set_hi_wh(d_inode(dentry), bdst, wh_dentry); ++ ++out_wh: ++ dput(wh_dentry); ++out: ++ dput(parent); ++ return err; ++} ++ ++struct au_cpup_wh_args { ++ int *errp; ++ struct au_cp_generic *cpg; ++ struct file *file; ++}; ++ ++static void au_call_cpup_wh(void *args) ++{ ++ struct au_cpup_wh_args *a = args; ++ ++ au_pin_hdir_acquire_nest(a->cpg->pin); ++ *a->errp = au_cpup_wh(a->cpg, a->file); ++ au_pin_hdir_release(a->cpg->pin); ++} ++ ++int au_sio_cpup_wh(struct au_cp_generic *cpg, struct file *file) ++{ ++ int err, wkq_err; ++ aufs_bindex_t bdst; ++ struct dentry *dentry, *parent, *h_orph, *h_parent; ++ struct inode *dir, *h_dir, *h_tmpdir; ++ struct au_wbr *wbr; ++ struct au_pin wh_pin, *pin_orig; ++ ++ dentry = cpg->dentry; ++ bdst = cpg->bdst; ++ parent = dget_parent(dentry); ++ dir = d_inode(parent); ++ h_orph = NULL; ++ h_parent = NULL; ++ h_dir = au_igrab(au_h_iptr(dir, bdst)); ++ h_tmpdir = h_dir; ++ pin_orig = NULL; ++ if (!h_dir->i_nlink) { ++ wbr = au_sbr(dentry->d_sb, bdst)->br_wbr; ++ h_orph = wbr->wbr_orph; ++ ++ h_parent = dget(au_h_dptr(parent, bdst)); ++ au_set_h_dptr(parent, bdst, dget(h_orph)); ++ h_tmpdir = d_inode(h_orph); ++ au_set_h_iptr(dir, bdst, au_igrab(h_tmpdir), /*flags*/0); ++ ++ inode_lock_nested(h_tmpdir, AuLsc_I_PARENT3); ++ /* todo: au_h_open_pre()? */ ++ ++ pin_orig = cpg->pin; ++ au_pin_init(&wh_pin, dentry, bdst, AuLsc_DI_PARENT, ++ AuLsc_I_PARENT3, cpg->pin->udba, AuPin_DI_LOCKED); ++ cpg->pin = &wh_pin; ++ } ++ ++ if (!au_test_h_perm_sio(h_tmpdir, MAY_EXEC | MAY_WRITE) ++ && !au_cpup_sio_test(cpg->pin, d_inode(dentry)->i_mode)) ++ err = au_cpup_wh(cpg, file); ++ else { ++ struct au_cpup_wh_args args = { ++ .errp = &err, ++ .cpg = cpg, ++ .file = file ++ }; ++ wkq_err = au_wkq_wait(au_call_cpup_wh, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ if (h_orph) { ++ inode_unlock(h_tmpdir); ++ /* todo: au_h_open_post()? */ ++ au_set_h_iptr(dir, bdst, au_igrab(h_dir), /*flags*/0); ++ au_set_h_dptr(parent, bdst, h_parent); ++ AuDebugOn(!pin_orig); ++ cpg->pin = pin_orig; ++ } ++ iput(h_dir); ++ dput(parent); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * generic routine for both of copy-up and copy-down. ++ */ ++/* cf. revalidate function in file.c */ ++int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst, ++ int (*cp)(struct dentry *dentry, aufs_bindex_t bdst, ++ struct au_pin *pin, ++ struct dentry *h_parent, void *arg), ++ void *arg) ++{ ++ int err; ++ struct au_pin pin; ++ struct dentry *d, *parent, *h_parent, *real_parent, *h_dentry; ++ ++ err = 0; ++ parent = dget_parent(dentry); ++ if (IS_ROOT(parent)) ++ goto out; ++ ++ au_pin_init(&pin, dentry, bdst, AuLsc_DI_PARENT2, AuLsc_I_PARENT2, ++ au_opt_udba(dentry->d_sb), AuPin_MNT_WRITE); ++ ++ /* do not use au_dpage */ ++ real_parent = parent; ++ while (1) { ++ dput(parent); ++ parent = dget_parent(dentry); ++ h_parent = au_h_dptr(parent, bdst); ++ if (h_parent) ++ goto out; /* success */ ++ ++ /* find top dir which is necessary to cpup */ ++ do { ++ d = parent; ++ dput(parent); ++ parent = dget_parent(d); ++ di_read_lock_parent3(parent, !AuLock_IR); ++ h_parent = au_h_dptr(parent, bdst); ++ di_read_unlock(parent, !AuLock_IR); ++ } while (!h_parent); ++ ++ if (d != real_parent) ++ di_write_lock_child3(d); ++ ++ /* somebody else might create while we were sleeping */ ++ h_dentry = au_h_dptr(d, bdst); ++ if (!h_dentry || d_is_negative(h_dentry)) { ++ if (h_dentry) ++ au_update_dbtop(d); ++ ++ au_pin_set_dentry(&pin, d); ++ err = au_do_pin(&pin); ++ if (!err) { ++ err = cp(d, bdst, &pin, h_parent, arg); ++ au_unpin(&pin); ++ } ++ } ++ ++ if (d != real_parent) ++ di_write_unlock(d); ++ if (unlikely(err)) ++ break; ++ } ++ ++out: ++ dput(parent); ++ return err; ++} ++ ++static int au_cpup_dir(struct dentry *dentry, aufs_bindex_t bdst, ++ struct au_pin *pin, ++ struct dentry *h_parent __maybe_unused, ++ void *arg __maybe_unused) ++{ ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = bdst, ++ .bsrc = -1, ++ .len = 0, ++ .pin = pin, ++ .flags = AuCpup_DTIME ++ }; ++ return au_sio_cpup_simple(&cpg); ++} ++ ++int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst) ++{ ++ return au_cp_dirs(dentry, bdst, au_cpup_dir, NULL); ++} ++ ++int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst) ++{ ++ int err; ++ struct dentry *parent; ++ struct inode *dir; ++ ++ parent = dget_parent(dentry); ++ dir = d_inode(parent); ++ err = 0; ++ if (au_h_iptr(dir, bdst)) ++ goto out; ++ ++ di_read_unlock(parent, AuLock_IR); ++ di_write_lock_parent(parent); ++ /* someone else might change our inode while we were sleeping */ ++ if (!au_h_iptr(dir, bdst)) ++ err = au_cpup_dirs(dentry, bdst); ++ di_downgrade_lock(parent, AuLock_IR); ++ ++out: ++ dput(parent); ++ return err; ++} +diff -Nurp linux-5.4/fs/aufs/cpup.h linux-5.4-aufs/fs/aufs/cpup.h +--- linux-5.4/fs/aufs/cpup.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/cpup.h 2019-11-28 01:25:59.063925618 +0200 +@@ -0,0 +1,87 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * copy-up/down functions ++ */ ++ ++#ifndef __AUFS_CPUP_H__ ++#define __AUFS_CPUP_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++struct inode; ++struct file; ++struct au_pin; ++ ++void au_cpup_attr_flags(struct inode *dst, unsigned int iflags); ++void au_cpup_attr_timesizes(struct inode *inode); ++void au_cpup_attr_nlink(struct inode *inode, int force); ++void au_cpup_attr_changeable(struct inode *inode); ++void au_cpup_igen(struct inode *inode, struct inode *h_inode); ++void au_cpup_attr_all(struct inode *inode, int force); ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_cp_generic { ++ struct dentry *dentry; ++ aufs_bindex_t bdst, bsrc; ++ loff_t len; ++ struct au_pin *pin; ++ unsigned int flags; ++}; ++ ++/* cpup flags */ ++#define AuCpup_DTIME 1 /* do dtime_store/revert */ ++#define AuCpup_KEEPLINO (1 << 1) /* do not clear the lower xino, ++ for link(2) */ ++#define AuCpup_RENAME (1 << 2) /* rename after cpup */ ++#define AuCpup_HOPEN (1 << 3) /* call h_open_pre/post() in ++ cpup */ ++#define AuCpup_OVERWRITE (1 << 4) /* allow overwriting the ++ existing entry */ ++#define AuCpup_RWDST (1 << 5) /* force write target even if ++ the branch is marked as RO */ ++ ++#ifndef CONFIG_AUFS_BR_HFSPLUS ++#undef AuCpup_HOPEN ++#define AuCpup_HOPEN 0 ++#endif ++ ++#define au_ftest_cpup(flags, name) ((flags) & AuCpup_##name) ++#define au_fset_cpup(flags, name) \ ++ do { (flags) |= AuCpup_##name; } while (0) ++#define au_fclr_cpup(flags, name) \ ++ do { (flags) &= ~AuCpup_##name; } while (0) ++ ++int au_copy_file(struct file *dst, struct file *src, loff_t len); ++int au_sio_cpup_simple(struct au_cp_generic *cpg); ++int au_sio_cpdown_simple(struct au_cp_generic *cpg); ++int au_sio_cpup_wh(struct au_cp_generic *cpg, struct file *file); ++ ++int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst, ++ int (*cp)(struct dentry *dentry, aufs_bindex_t bdst, ++ struct au_pin *pin, ++ struct dentry *h_parent, void *arg), ++ void *arg); ++int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst); ++int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* keep timestamps when copyup */ ++struct au_dtime { ++ struct dentry *dt_dentry; ++ struct path dt_h_path; ++ struct timespec64 dt_atime, dt_mtime; ++}; ++void au_dtime_store(struct au_dtime *dt, struct dentry *dentry, ++ struct path *h_path); ++void au_dtime_revert(struct au_dtime *dt); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_CPUP_H__ */ +diff -Nurp linux-5.4/fs/aufs/dbgaufs.c linux-5.4-aufs/fs/aufs/dbgaufs.c +--- linux-5.4/fs/aufs/dbgaufs.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/dbgaufs.c 2019-11-28 01:25:59.063925618 +0200 +@@ -0,0 +1,513 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * debugfs interface ++ */ ++ ++#include ++#include "aufs.h" ++ ++#ifndef CONFIG_SYSFS ++#error DEBUG_FS depends upon SYSFS ++#endif ++ ++static struct dentry *dbgaufs; ++static const mode_t dbgaufs_mode = 0444; ++ ++/* 20 is max digits length of ulong 64 */ ++struct dbgaufs_arg { ++ int n; ++ char a[20 * 4]; ++}; ++ ++/* ++ * common function for all XINO files ++ */ ++static int dbgaufs_xi_release(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ void *p; ++ ++ p = file->private_data; ++ if (p) { ++ /* this is struct dbgaufs_arg */ ++ AuDebugOn(!au_kfree_sz_test(p)); ++ au_kfree_do_rcu(p); ++ } ++ return 0; ++} ++ ++static int dbgaufs_xi_open(struct file *xf, struct file *file, int do_fcnt, ++ int cnt) ++{ ++ int err; ++ struct kstat st; ++ struct dbgaufs_arg *p; ++ ++ err = -ENOMEM; ++ p = kmalloc(sizeof(*p), GFP_NOFS); ++ if (unlikely(!p)) ++ goto out; ++ ++ err = 0; ++ p->n = 0; ++ file->private_data = p; ++ if (!xf) ++ goto out; ++ ++ err = vfsub_getattr(&xf->f_path, &st); ++ if (!err) { ++ if (do_fcnt) ++ p->n = snprintf ++ (p->a, sizeof(p->a), "%d, %llux%u %lld\n", ++ cnt, st.blocks, st.blksize, ++ (long long)st.size); ++ else ++ p->n = snprintf(p->a, sizeof(p->a), "%llux%u %lld\n", ++ st.blocks, st.blksize, ++ (long long)st.size); ++ AuDebugOn(p->n >= sizeof(p->a)); ++ } else { ++ p->n = snprintf(p->a, sizeof(p->a), "err %d\n", err); ++ err = 0; ++ } ++ ++out: ++ return err; ++} ++ ++static ssize_t dbgaufs_xi_read(struct file *file, char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct dbgaufs_arg *p; ++ ++ p = file->private_data; ++ return simple_read_from_buffer(buf, count, ppos, p->a, p->n); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dbgaufs_plink_arg { ++ int n; ++ char a[]; ++}; ++ ++static int dbgaufs_plink_release(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ free_page((unsigned long)file->private_data); ++ return 0; ++} ++ ++static int dbgaufs_plink_open(struct inode *inode, struct file *file) ++{ ++ int err, i, limit; ++ unsigned long n, sum; ++ struct dbgaufs_plink_arg *p; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ struct hlist_bl_head *hbl; ++ ++ err = -ENOMEM; ++ p = (void *)get_zeroed_page(GFP_NOFS); ++ if (unlikely(!p)) ++ goto out; ++ ++ err = -EFBIG; ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ if (au_opt_test(au_mntflags(sb), PLINK)) { ++ limit = PAGE_SIZE - sizeof(p->n); ++ ++ /* the number of buckets */ ++ n = snprintf(p->a + p->n, limit, "%d\n", AuPlink_NHASH); ++ p->n += n; ++ limit -= n; ++ ++ sum = 0; ++ for (i = 0, hbl = sbinfo->si_plink; i < AuPlink_NHASH; ++ i++, hbl++) { ++ n = au_hbl_count(hbl); ++ sum += n; ++ ++ n = snprintf(p->a + p->n, limit, "%lu ", n); ++ p->n += n; ++ limit -= n; ++ if (unlikely(limit <= 0)) ++ goto out_free; ++ } ++ p->a[p->n - 1] = '\n'; ++ ++ /* the sum of plinks */ ++ n = snprintf(p->a + p->n, limit, "%lu\n", sum); ++ p->n += n; ++ limit -= n; ++ if (unlikely(limit <= 0)) ++ goto out_free; ++ } else { ++#define str "1\n0\n0\n" ++ p->n = sizeof(str) - 1; ++ strcpy(p->a, str); ++#undef str ++ } ++ si_read_unlock(sb); ++ ++ err = 0; ++ file->private_data = p; ++ goto out; /* success */ ++ ++out_free: ++ free_page((unsigned long)p); ++out: ++ return err; ++} ++ ++static ssize_t dbgaufs_plink_read(struct file *file, char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct dbgaufs_plink_arg *p; ++ ++ p = file->private_data; ++ return simple_read_from_buffer(buf, count, ppos, p->a, p->n); ++} ++ ++static const struct file_operations dbgaufs_plink_fop = { ++ .owner = THIS_MODULE, ++ .open = dbgaufs_plink_open, ++ .release = dbgaufs_plink_release, ++ .read = dbgaufs_plink_read ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int dbgaufs_xib_open(struct inode *inode, struct file *file) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ err = dbgaufs_xi_open(sbinfo->si_xib, file, /*do_fcnt*/0, /*cnt*/0); ++ si_read_unlock(sb); ++ return err; ++} ++ ++static const struct file_operations dbgaufs_xib_fop = { ++ .owner = THIS_MODULE, ++ .open = dbgaufs_xib_open, ++ .release = dbgaufs_xi_release, ++ .read = dbgaufs_xi_read ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define DbgaufsXi_PREFIX "xi" ++ ++static int dbgaufs_xino_open(struct inode *inode, struct file *file) ++{ ++ int err, idx; ++ long l; ++ aufs_bindex_t bindex; ++ char *p, a[sizeof(DbgaufsXi_PREFIX) + 8]; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ struct au_xino *xi; ++ struct file *xf; ++ struct qstr *name; ++ struct au_branch *br; ++ ++ err = -ENOENT; ++ name = &file->f_path.dentry->d_name; ++ if (unlikely(name->len < sizeof(DbgaufsXi_PREFIX) ++ || memcmp(name->name, DbgaufsXi_PREFIX, ++ sizeof(DbgaufsXi_PREFIX) - 1))) ++ goto out; ++ ++ AuDebugOn(name->len >= sizeof(a)); ++ memcpy(a, name->name, name->len); ++ a[name->len] = '\0'; ++ p = strchr(a, '-'); ++ if (p) ++ *p = '\0'; ++ err = kstrtol(a + sizeof(DbgaufsXi_PREFIX) - 1, 10, &l); ++ if (unlikely(err)) ++ goto out; ++ bindex = l; ++ idx = 0; ++ if (p) { ++ err = kstrtol(p + 1, 10, &l); ++ if (unlikely(err)) ++ goto out; ++ idx = l; ++ } ++ ++ err = -ENOENT; ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ if (unlikely(bindex < 0 || bindex > au_sbbot(sb))) ++ goto out_si; ++ br = au_sbr(sb, bindex); ++ xi = br->br_xino; ++ if (unlikely(idx >= xi->xi_nfile)) ++ goto out_si; ++ xf = au_xino_file(xi, idx); ++ if (xf) ++ err = dbgaufs_xi_open(xf, file, /*do_fcnt*/1, ++ au_xino_count(br)); ++ ++out_si: ++ si_read_unlock(sb); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static const struct file_operations dbgaufs_xino_fop = { ++ .owner = THIS_MODULE, ++ .open = dbgaufs_xino_open, ++ .release = dbgaufs_xi_release, ++ .read = dbgaufs_xi_read ++}; ++ ++void dbgaufs_xino_del(struct au_branch *br) ++{ ++ struct dentry *dbgaufs; ++ ++ dbgaufs = br->br_dbgaufs; ++ if (!dbgaufs) ++ return; ++ ++ br->br_dbgaufs = NULL; ++ /* debugfs acquires the parent i_mutex */ ++ lockdep_off(); ++ debugfs_remove(dbgaufs); ++ lockdep_on(); ++} ++ ++void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ aufs_bindex_t bbot; ++ struct au_branch *br; ++ ++ if (!au_sbi(sb)->si_dbgaufs) ++ return; ++ ++ bbot = au_sbbot(sb); ++ for (; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ dbgaufs_xino_del(br); ++ } ++} ++ ++static void dbgaufs_br_do_add(struct super_block *sb, aufs_bindex_t bindex, ++ unsigned int idx, struct dentry *parent, ++ struct au_sbinfo *sbinfo) ++{ ++ struct au_branch *br; ++ struct dentry *d; ++ /* "xi" bindex(5) "-" idx(2) NULL */ ++ char name[sizeof(DbgaufsXi_PREFIX) + 8]; ++ ++ if (!idx) ++ snprintf(name, sizeof(name), DbgaufsXi_PREFIX "%d", bindex); ++ else ++ snprintf(name, sizeof(name), DbgaufsXi_PREFIX "%d-%u", ++ bindex, idx); ++ br = au_sbr(sb, bindex); ++ if (br->br_dbgaufs) { ++ struct qstr qstr = QSTR_INIT(name, strlen(name)); ++ ++ if (!au_qstreq(&br->br_dbgaufs->d_name, &qstr)) { ++ /* debugfs acquires the parent i_mutex */ ++ lockdep_off(); ++ d = debugfs_rename(parent, br->br_dbgaufs, parent, ++ name); ++ lockdep_on(); ++ if (unlikely(!d)) ++ pr_warn("failed renaming %pd/%s, ignored.\n", ++ parent, name); ++ } ++ } else { ++ lockdep_off(); ++ br->br_dbgaufs = debugfs_create_file(name, dbgaufs_mode, parent, ++ sbinfo, &dbgaufs_xino_fop); ++ lockdep_on(); ++ if (unlikely(!br->br_dbgaufs)) ++ pr_warn("failed creating %pd/%s, ignored.\n", ++ parent, name); ++ } ++} ++ ++static void dbgaufs_br_add(struct super_block *sb, aufs_bindex_t bindex, ++ struct dentry *parent, struct au_sbinfo *sbinfo) ++{ ++ struct au_branch *br; ++ struct au_xino *xi; ++ unsigned int u; ++ ++ br = au_sbr(sb, bindex); ++ xi = br->br_xino; ++ for (u = 0; u < xi->xi_nfile; u++) ++ dbgaufs_br_do_add(sb, bindex, u, parent, sbinfo); ++} ++ ++void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex, int topdown) ++{ ++ struct au_sbinfo *sbinfo; ++ struct dentry *parent; ++ aufs_bindex_t bbot; ++ ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ return; ++ ++ sbinfo = au_sbi(sb); ++ parent = sbinfo->si_dbgaufs; ++ if (!parent) ++ return; ++ ++ bbot = au_sbbot(sb); ++ if (topdown) ++ for (; bindex <= bbot; bindex++) ++ dbgaufs_br_add(sb, bindex, parent, sbinfo); ++ else ++ for (; bbot >= bindex; bbot--) ++ dbgaufs_br_add(sb, bbot, parent, sbinfo); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_EXPORT ++static int dbgaufs_xigen_open(struct inode *inode, struct file *file) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ err = dbgaufs_xi_open(sbinfo->si_xigen, file, /*do_fcnt*/0, /*cnt*/0); ++ si_read_unlock(sb); ++ return err; ++} ++ ++static const struct file_operations dbgaufs_xigen_fop = { ++ .owner = THIS_MODULE, ++ .open = dbgaufs_xigen_open, ++ .release = dbgaufs_xi_release, ++ .read = dbgaufs_xi_read ++}; ++ ++static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo) ++{ ++ int err; ++ ++ /* ++ * This function is a dynamic '__init' function actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++ ++ err = -EIO; ++ sbinfo->si_dbgaufs_xigen = debugfs_create_file ++ ("xigen", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, ++ &dbgaufs_xigen_fop); ++ if (sbinfo->si_dbgaufs_xigen) ++ err = 0; ++ ++ return err; ++} ++#else ++static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo) ++{ ++ return 0; ++} ++#endif /* CONFIG_AUFS_EXPORT */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++void dbgaufs_si_fin(struct au_sbinfo *sbinfo) ++{ ++ /* ++ * This function is a dynamic '__fin' function actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++ ++ debugfs_remove_recursive(sbinfo->si_dbgaufs); ++ sbinfo->si_dbgaufs = NULL; ++} ++ ++int dbgaufs_si_init(struct au_sbinfo *sbinfo) ++{ ++ int err; ++ char name[SysaufsSiNameLen]; ++ ++ /* ++ * This function is a dynamic '__init' function actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++ ++ err = -ENOENT; ++ if (!dbgaufs) { ++ AuErr1("/debug/aufs is uninitialized\n"); ++ goto out; ++ } ++ ++ err = -EIO; ++ sysaufs_name(sbinfo, name); ++ sbinfo->si_dbgaufs = debugfs_create_dir(name, dbgaufs); ++ if (unlikely(!sbinfo->si_dbgaufs)) ++ goto out; ++ ++ /* regardless plink/noplink option */ ++ sbinfo->si_dbgaufs_plink = debugfs_create_file ++ ("plink", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, ++ &dbgaufs_plink_fop); ++ if (unlikely(!sbinfo->si_dbgaufs_plink)) ++ goto out_dir; ++ ++ /* regardless xino/noxino option */ ++ sbinfo->si_dbgaufs_xib = debugfs_create_file ++ ("xib", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, ++ &dbgaufs_xib_fop); ++ if (unlikely(!sbinfo->si_dbgaufs_xib)) ++ goto out_dir; ++ ++ err = dbgaufs_xigen_init(sbinfo); ++ if (!err) ++ goto out; /* success */ ++ ++out_dir: ++ dbgaufs_si_fin(sbinfo); ++out: ++ if (unlikely(err)) ++ pr_err("debugfs/aufs failed\n"); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void dbgaufs_fin(void) ++{ ++ debugfs_remove(dbgaufs); ++} ++ ++int __init dbgaufs_init(void) ++{ ++ int err; ++ ++ err = -EIO; ++ dbgaufs = debugfs_create_dir(AUFS_NAME, NULL); ++ if (dbgaufs) ++ err = 0; ++ return err; ++} +diff -Nurp linux-5.4/fs/aufs/dbgaufs.h linux-5.4-aufs/fs/aufs/dbgaufs.h +--- linux-5.4/fs/aufs/dbgaufs.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/dbgaufs.h 2019-11-28 01:25:59.063925618 +0200 +@@ -0,0 +1,40 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * debugfs interface ++ */ ++ ++#ifndef __DBGAUFS_H__ ++#define __DBGAUFS_H__ ++ ++#ifdef __KERNEL__ ++ ++struct super_block; ++struct au_sbinfo; ++struct au_branch; ++ ++#ifdef CONFIG_DEBUG_FS ++/* dbgaufs.c */ ++void dbgaufs_xino_del(struct au_branch *br); ++void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex); ++void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex, int topdown); ++void dbgaufs_si_fin(struct au_sbinfo *sbinfo); ++int dbgaufs_si_init(struct au_sbinfo *sbinfo); ++void dbgaufs_fin(void); ++int __init dbgaufs_init(void); ++#else ++AuStubVoid(dbgaufs_xino_del, struct au_branch *br) ++AuStubVoid(dbgaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex) ++AuStubVoid(dbgaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex, ++ int topdown) ++AuStubVoid(dbgaufs_si_fin, struct au_sbinfo *sbinfo) ++AuStubInt0(dbgaufs_si_init, struct au_sbinfo *sbinfo) ++AuStubVoid(dbgaufs_fin, void) ++AuStubInt0(__init dbgaufs_init, void) ++#endif /* CONFIG_DEBUG_FS */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __DBGAUFS_H__ */ +diff -Nurp linux-5.4/fs/aufs/dcsub.c linux-5.4-aufs/fs/aufs/dcsub.c +--- linux-5.4/fs/aufs/dcsub.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/dcsub.c 2019-11-28 01:25:59.063925618 +0200 +@@ -0,0 +1,212 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * sub-routines for dentry cache ++ */ ++ ++#include "aufs.h" ++ ++static void au_dpage_free(struct au_dpage *dpage) ++{ ++ int i; ++ struct dentry **p; ++ ++ p = dpage->dentries; ++ for (i = 0; i < dpage->ndentry; i++) ++ dput(*p++); ++ free_page((unsigned long)dpage->dentries); ++} ++ ++int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp) ++{ ++ int err; ++ void *p; ++ ++ err = -ENOMEM; ++ dpages->dpages = kmalloc(sizeof(*dpages->dpages), gfp); ++ if (unlikely(!dpages->dpages)) ++ goto out; ++ ++ p = (void *)__get_free_page(gfp); ++ if (unlikely(!p)) ++ goto out_dpages; ++ ++ dpages->dpages[0].ndentry = 0; ++ dpages->dpages[0].dentries = p; ++ dpages->ndpage = 1; ++ return 0; /* success */ ++ ++out_dpages: ++ au_kfree_try_rcu(dpages->dpages); ++out: ++ return err; ++} ++ ++void au_dpages_free(struct au_dcsub_pages *dpages) ++{ ++ int i; ++ struct au_dpage *p; ++ ++ p = dpages->dpages; ++ for (i = 0; i < dpages->ndpage; i++) ++ au_dpage_free(p++); ++ au_kfree_try_rcu(dpages->dpages); ++} ++ ++static int au_dpages_append(struct au_dcsub_pages *dpages, ++ struct dentry *dentry, gfp_t gfp) ++{ ++ int err, sz; ++ struct au_dpage *dpage; ++ void *p; ++ ++ dpage = dpages->dpages + dpages->ndpage - 1; ++ sz = PAGE_SIZE / sizeof(dentry); ++ if (unlikely(dpage->ndentry >= sz)) { ++ AuLabel(new dpage); ++ err = -ENOMEM; ++ sz = dpages->ndpage * sizeof(*dpages->dpages); ++ p = au_kzrealloc(dpages->dpages, sz, ++ sz + sizeof(*dpages->dpages), gfp, ++ /*may_shrink*/0); ++ if (unlikely(!p)) ++ goto out; ++ ++ dpages->dpages = p; ++ dpage = dpages->dpages + dpages->ndpage; ++ p = (void *)__get_free_page(gfp); ++ if (unlikely(!p)) ++ goto out; ++ ++ dpage->ndentry = 0; ++ dpage->dentries = p; ++ dpages->ndpage++; ++ } ++ ++ AuDebugOn(au_dcount(dentry) <= 0); ++ dpage->dentries[dpage->ndentry++] = dget_dlock(dentry); ++ return 0; /* success */ ++ ++out: ++ return err; ++} ++ ++/* todo: BAD approach */ ++/* copied from linux/fs/dcache.c */ ++enum d_walk_ret { ++ D_WALK_CONTINUE, ++ D_WALK_QUIT, ++ D_WALK_NORETRY, ++ D_WALK_SKIP, ++}; ++ ++extern void d_walk(struct dentry *parent, void *data, ++ enum d_walk_ret (*enter)(void *, struct dentry *)); ++ ++struct ac_dpages_arg { ++ int err; ++ struct au_dcsub_pages *dpages; ++ struct super_block *sb; ++ au_dpages_test test; ++ void *arg; ++}; ++ ++static enum d_walk_ret au_call_dpages_append(void *_arg, struct dentry *dentry) ++{ ++ enum d_walk_ret ret; ++ struct ac_dpages_arg *arg = _arg; ++ ++ ret = D_WALK_CONTINUE; ++ if (dentry->d_sb == arg->sb ++ && !IS_ROOT(dentry) ++ && au_dcount(dentry) > 0 ++ && au_di(dentry) ++ && (!arg->test || arg->test(dentry, arg->arg))) { ++ arg->err = au_dpages_append(arg->dpages, dentry, GFP_ATOMIC); ++ if (unlikely(arg->err)) ++ ret = D_WALK_QUIT; ++ } ++ ++ return ret; ++} ++ ++int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, ++ au_dpages_test test, void *arg) ++{ ++ struct ac_dpages_arg args = { ++ .err = 0, ++ .dpages = dpages, ++ .sb = root->d_sb, ++ .test = test, ++ .arg = arg ++ }; ++ ++ d_walk(root, &args, au_call_dpages_append); ++ ++ return args.err; ++} ++ ++int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry, ++ int do_include, au_dpages_test test, void *arg) ++{ ++ int err; ++ ++ err = 0; ++ write_seqlock(&rename_lock); ++ spin_lock(&dentry->d_lock); ++ if (do_include ++ && au_dcount(dentry) > 0 ++ && (!test || test(dentry, arg))) ++ err = au_dpages_append(dpages, dentry, GFP_ATOMIC); ++ spin_unlock(&dentry->d_lock); ++ if (unlikely(err)) ++ goto out; ++ ++ /* ++ * RCU for vfsmount is unnecessary since this is a traverse in a single ++ * mount ++ */ ++ while (!IS_ROOT(dentry)) { ++ dentry = dentry->d_parent; /* rename_lock is locked */ ++ spin_lock(&dentry->d_lock); ++ if (au_dcount(dentry) > 0 ++ && (!test || test(dentry, arg))) ++ err = au_dpages_append(dpages, dentry, GFP_ATOMIC); ++ spin_unlock(&dentry->d_lock); ++ if (unlikely(err)) ++ break; ++ } ++ ++out: ++ write_sequnlock(&rename_lock); ++ return err; ++} ++ ++static inline int au_dcsub_dpages_aufs(struct dentry *dentry, void *arg) ++{ ++ return au_di(dentry) && dentry->d_sb == arg; ++} ++ ++int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages, ++ struct dentry *dentry, int do_include) ++{ ++ return au_dcsub_pages_rev(dpages, dentry, do_include, ++ au_dcsub_dpages_aufs, dentry->d_sb); ++} ++ ++int au_test_subdir(struct dentry *d1, struct dentry *d2) ++{ ++ struct path path[2] = { ++ { ++ .dentry = d1 ++ }, ++ { ++ .dentry = d2 ++ } ++ }; ++ ++ return path_is_under(path + 0, path + 1); ++} +diff -Nurp linux-5.4/fs/aufs/dcsub.h linux-5.4-aufs/fs/aufs/dcsub.h +--- linux-5.4/fs/aufs/dcsub.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/dcsub.h 2019-11-28 01:25:59.063925618 +0200 +@@ -0,0 +1,124 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * sub-routines for dentry cache ++ */ ++ ++#ifndef __AUFS_DCSUB_H__ ++#define __AUFS_DCSUB_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++ ++struct au_dpage { ++ int ndentry; ++ struct dentry **dentries; ++}; ++ ++struct au_dcsub_pages { ++ int ndpage; ++ struct au_dpage *dpages; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dcsub.c */ ++int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp); ++void au_dpages_free(struct au_dcsub_pages *dpages); ++typedef int (*au_dpages_test)(struct dentry *dentry, void *arg); ++int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, ++ au_dpages_test test, void *arg); ++int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry, ++ int do_include, au_dpages_test test, void *arg); ++int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages, ++ struct dentry *dentry, int do_include); ++int au_test_subdir(struct dentry *d1, struct dentry *d2); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * todo: in linux-3.13, several similar (but faster) helpers are added to ++ * include/linux/dcache.h. Try them (in the future). ++ */ ++ ++static inline int au_d_hashed_positive(struct dentry *d) ++{ ++ int err; ++ struct inode *inode = d_inode(d); ++ ++ err = 0; ++ if (unlikely(d_unhashed(d) ++ || d_is_negative(d) ++ || !inode->i_nlink)) ++ err = -ENOENT; ++ return err; ++} ++ ++static inline int au_d_linkable(struct dentry *d) ++{ ++ int err; ++ struct inode *inode = d_inode(d); ++ ++ err = au_d_hashed_positive(d); ++ if (err ++ && d_is_positive(d) ++ && (inode->i_state & I_LINKABLE)) ++ err = 0; ++ return err; ++} ++ ++static inline int au_d_alive(struct dentry *d) ++{ ++ int err; ++ struct inode *inode; ++ ++ err = 0; ++ if (!IS_ROOT(d)) ++ err = au_d_hashed_positive(d); ++ else { ++ inode = d_inode(d); ++ if (unlikely(d_unlinked(d) ++ || d_is_negative(d) ++ || !inode->i_nlink)) ++ err = -ENOENT; ++ } ++ return err; ++} ++ ++static inline int au_alive_dir(struct dentry *d) ++{ ++ int err; ++ ++ err = au_d_alive(d); ++ if (unlikely(err || IS_DEADDIR(d_inode(d)))) ++ err = -ENOENT; ++ return err; ++} ++ ++static inline int au_qstreq(struct qstr *a, struct qstr *b) ++{ ++ return a->len == b->len ++ && !memcmp(a->name, b->name, a->len); ++} ++ ++/* ++ * by the commit ++ * 360f547 2015-01-25 dcache: let the dentry count go down to zero without ++ * taking d_lock ++ * the type of d_lockref.count became int, but the inlined function d_count() ++ * still returns unsigned int. ++ * I don't know why. Maybe it is for every d_count() users? ++ * Anyway au_dcount() lives on. ++ */ ++static inline int au_dcount(struct dentry *d) ++{ ++ return (int)d_count(d); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DCSUB_H__ */ +diff -Nurp linux-5.4/fs/aufs/debug.c linux-5.4-aufs/fs/aufs/debug.c +--- linux-5.4/fs/aufs/debug.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/debug.c 2019-11-28 01:25:59.063925618 +0200 +@@ -0,0 +1,428 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * debug print functions ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* Returns 0, or -errno. arg is in kp->arg. */ ++static int param_atomic_t_set(const char *val, const struct kernel_param *kp) ++{ ++ int err, n; ++ ++ err = kstrtoint(val, 0, &n); ++ if (!err) { ++ if (n > 0) ++ au_debug_on(); ++ else ++ au_debug_off(); ++ } ++ return err; ++} ++ ++/* Returns length written or -errno. Buffer is 4k (ie. be short!) */ ++static int param_atomic_t_get(char *buffer, const struct kernel_param *kp) ++{ ++ atomic_t *a; ++ ++ a = kp->arg; ++ return sprintf(buffer, "%d", atomic_read(a)); ++} ++ ++static struct kernel_param_ops param_ops_atomic_t = { ++ .set = param_atomic_t_set, ++ .get = param_atomic_t_get ++ /* void (*free)(void *arg) */ ++}; ++ ++atomic_t aufs_debug = ATOMIC_INIT(0); ++MODULE_PARM_DESC(debug, "debug print"); ++module_param_named(debug, aufs_debug, atomic_t, 0664); ++ ++DEFINE_MUTEX(au_dbg_mtx); /* just to serialize the dbg msgs */ ++char *au_plevel = KERN_DEBUG; ++#define dpri(fmt, ...) do { \ ++ if ((au_plevel \ ++ && strcmp(au_plevel, KERN_DEBUG)) \ ++ || au_debug_test()) \ ++ printk("%s" fmt, au_plevel, ##__VA_ARGS__); \ ++} while (0) ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_dpri_whlist(struct au_nhash *whlist) ++{ ++ unsigned long ul, n; ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ ++ n = whlist->nh_num; ++ head = whlist->nh_head; ++ for (ul = 0; ul < n; ul++) { ++ hlist_for_each_entry(pos, head, wh_hash) ++ dpri("b%d, %.*s, %d\n", ++ pos->wh_bindex, ++ pos->wh_str.len, pos->wh_str.name, ++ pos->wh_str.len); ++ head++; ++ } ++} ++ ++void au_dpri_vdir(struct au_vdir *vdir) ++{ ++ unsigned long ul; ++ union au_vdir_deblk_p p; ++ unsigned char *o; ++ ++ if (!vdir || IS_ERR(vdir)) { ++ dpri("err %ld\n", PTR_ERR(vdir)); ++ return; ++ } ++ ++ dpri("deblk %u, nblk %lu, deblk %p, last{%lu, %p}, ver %llu\n", ++ vdir->vd_deblk_sz, vdir->vd_nblk, vdir->vd_deblk, ++ vdir->vd_last.ul, vdir->vd_last.p.deblk, vdir->vd_version); ++ for (ul = 0; ul < vdir->vd_nblk; ul++) { ++ p.deblk = vdir->vd_deblk[ul]; ++ o = p.deblk; ++ dpri("[%lu]: %p\n", ul, o); ++ } ++} ++ ++static int do_pri_inode(aufs_bindex_t bindex, struct inode *inode, int hn, ++ struct dentry *wh) ++{ ++ char *n = NULL; ++ int l = 0; ++ ++ if (!inode || IS_ERR(inode)) { ++ dpri("i%d: err %ld\n", bindex, PTR_ERR(inode)); ++ return -1; ++ } ++ ++ /* the type of i_blocks depends upon CONFIG_LBDAF */ ++ BUILD_BUG_ON(sizeof(inode->i_blocks) != sizeof(unsigned long) ++ && sizeof(inode->i_blocks) != sizeof(u64)); ++ if (wh) { ++ n = (void *)wh->d_name.name; ++ l = wh->d_name.len; ++ } ++ ++ dpri("i%d: %p, i%lu, %s, cnt %d, nl %u, 0%o, sz %llu, blk %llu," ++ " hn %d, ct %lld, np %lu, st 0x%lx, f 0x%x, v %llu, g %x%s%.*s\n", ++ bindex, inode, ++ inode->i_ino, inode->i_sb ? au_sbtype(inode->i_sb) : "??", ++ atomic_read(&inode->i_count), inode->i_nlink, inode->i_mode, ++ i_size_read(inode), (unsigned long long)inode->i_blocks, ++ hn, (long long)timespec64_to_ns(&inode->i_ctime) & 0x0ffff, ++ inode->i_mapping ? inode->i_mapping->nrpages : 0, ++ inode->i_state, inode->i_flags, inode_peek_iversion(inode), ++ inode->i_generation, ++ l ? ", wh " : "", l, n); ++ return 0; ++} ++ ++void au_dpri_inode(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct au_hinode *hi; ++ aufs_bindex_t bindex; ++ int err, hn; ++ ++ err = do_pri_inode(-1, inode, -1, NULL); ++ if (err || !au_test_aufs(inode->i_sb) || au_is_bad_inode(inode)) ++ return; ++ ++ iinfo = au_ii(inode); ++ dpri("i-1: btop %d, bbot %d, gen %d\n", ++ iinfo->ii_btop, iinfo->ii_bbot, au_iigen(inode, NULL)); ++ if (iinfo->ii_btop < 0) ++ return; ++ hn = 0; ++ for (bindex = iinfo->ii_btop; bindex <= iinfo->ii_bbot; bindex++) { ++ hi = au_hinode(iinfo, bindex); ++ hn = !!au_hn(hi); ++ do_pri_inode(bindex, hi->hi_inode, hn, hi->hi_whdentry); ++ } ++} ++ ++void au_dpri_dalias(struct inode *inode) ++{ ++ struct dentry *d; ++ ++ spin_lock(&inode->i_lock); ++ hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias) ++ au_dpri_dentry(d); ++ spin_unlock(&inode->i_lock); ++} ++ ++static int do_pri_dentry(aufs_bindex_t bindex, struct dentry *dentry) ++{ ++ struct dentry *wh = NULL; ++ int hn; ++ struct inode *inode; ++ struct au_iinfo *iinfo; ++ struct au_hinode *hi; ++ ++ if (!dentry || IS_ERR(dentry)) { ++ dpri("d%d: err %ld\n", bindex, PTR_ERR(dentry)); ++ return -1; ++ } ++ /* do not call dget_parent() here */ ++ /* note: access d_xxx without d_lock */ ++ dpri("d%d: %p, %pd2?, %s, cnt %d, flags 0x%x, %shashed\n", ++ bindex, dentry, dentry, ++ dentry->d_sb ? au_sbtype(dentry->d_sb) : "??", ++ au_dcount(dentry), dentry->d_flags, ++ d_unhashed(dentry) ? "un" : ""); ++ hn = -1; ++ inode = NULL; ++ if (d_is_positive(dentry)) ++ inode = d_inode(dentry); ++ if (inode ++ && au_test_aufs(dentry->d_sb) ++ && bindex >= 0 ++ && !au_is_bad_inode(inode)) { ++ iinfo = au_ii(inode); ++ hi = au_hinode(iinfo, bindex); ++ hn = !!au_hn(hi); ++ wh = hi->hi_whdentry; ++ } ++ do_pri_inode(bindex, inode, hn, wh); ++ return 0; ++} ++ ++void au_dpri_dentry(struct dentry *dentry) ++{ ++ struct au_dinfo *dinfo; ++ aufs_bindex_t bindex; ++ int err; ++ ++ err = do_pri_dentry(-1, dentry); ++ if (err || !au_test_aufs(dentry->d_sb)) ++ return; ++ ++ dinfo = au_di(dentry); ++ if (!dinfo) ++ return; ++ dpri("d-1: btop %d, bbot %d, bwh %d, bdiropq %d, gen %d, tmp %d\n", ++ dinfo->di_btop, dinfo->di_bbot, ++ dinfo->di_bwh, dinfo->di_bdiropq, au_digen(dentry), ++ dinfo->di_tmpfile); ++ if (dinfo->di_btop < 0) ++ return; ++ for (bindex = dinfo->di_btop; bindex <= dinfo->di_bbot; bindex++) ++ do_pri_dentry(bindex, au_hdentry(dinfo, bindex)->hd_dentry); ++} ++ ++static int do_pri_file(aufs_bindex_t bindex, struct file *file) ++{ ++ char a[32]; ++ ++ if (!file || IS_ERR(file)) { ++ dpri("f%d: err %ld\n", bindex, PTR_ERR(file)); ++ return -1; ++ } ++ a[0] = 0; ++ if (bindex < 0 ++ && !IS_ERR_OR_NULL(file->f_path.dentry) ++ && au_test_aufs(file->f_path.dentry->d_sb) ++ && au_fi(file)) ++ snprintf(a, sizeof(a), ", gen %d, mmapped %d", ++ au_figen(file), atomic_read(&au_fi(file)->fi_mmapped)); ++ dpri("f%d: mode 0x%x, flags 0%o, cnt %ld, v %llu, pos %llu%s\n", ++ bindex, file->f_mode, file->f_flags, (long)file_count(file), ++ file->f_version, file->f_pos, a); ++ if (!IS_ERR_OR_NULL(file->f_path.dentry)) ++ do_pri_dentry(bindex, file->f_path.dentry); ++ return 0; ++} ++ ++void au_dpri_file(struct file *file) ++{ ++ struct au_finfo *finfo; ++ struct au_fidir *fidir; ++ struct au_hfile *hfile; ++ aufs_bindex_t bindex; ++ int err; ++ ++ err = do_pri_file(-1, file); ++ if (err ++ || IS_ERR_OR_NULL(file->f_path.dentry) ++ || !au_test_aufs(file->f_path.dentry->d_sb)) ++ return; ++ ++ finfo = au_fi(file); ++ if (!finfo) ++ return; ++ if (finfo->fi_btop < 0) ++ return; ++ fidir = finfo->fi_hdir; ++ if (!fidir) ++ do_pri_file(finfo->fi_btop, finfo->fi_htop.hf_file); ++ else ++ for (bindex = finfo->fi_btop; ++ bindex >= 0 && bindex <= fidir->fd_bbot; ++ bindex++) { ++ hfile = fidir->fd_hfile + bindex; ++ do_pri_file(bindex, hfile ? hfile->hf_file : NULL); ++ } ++} ++ ++static int do_pri_br(aufs_bindex_t bindex, struct au_branch *br) ++{ ++ struct vfsmount *mnt; ++ struct super_block *sb; ++ ++ if (!br || IS_ERR(br)) ++ goto out; ++ mnt = au_br_mnt(br); ++ if (!mnt || IS_ERR(mnt)) ++ goto out; ++ sb = mnt->mnt_sb; ++ if (!sb || IS_ERR(sb)) ++ goto out; ++ ++ dpri("s%d: {perm 0x%x, id %d, wbr %p}, " ++ "%s, dev 0x%02x%02x, flags 0x%lx, cnt %d, active %d, " ++ "xino %d\n", ++ bindex, br->br_perm, br->br_id, br->br_wbr, ++ au_sbtype(sb), MAJOR(sb->s_dev), MINOR(sb->s_dev), ++ sb->s_flags, sb->s_count, ++ atomic_read(&sb->s_active), ++ !!au_xino_file(br->br_xino, /*idx*/-1)); ++ return 0; ++ ++out: ++ dpri("s%d: err %ld\n", bindex, PTR_ERR(br)); ++ return -1; ++} ++ ++void au_dpri_sb(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ aufs_bindex_t bindex; ++ int err; ++ /* to reduce stack size */ ++ struct { ++ struct vfsmount mnt; ++ struct au_branch fake; ++ } *a; ++ ++ /* this function can be called from magic sysrq */ ++ a = kzalloc(sizeof(*a), GFP_ATOMIC); ++ if (unlikely(!a)) { ++ dpri("no memory\n"); ++ return; ++ } ++ ++ a->mnt.mnt_sb = sb; ++ a->fake.br_path.mnt = &a->mnt; ++ err = do_pri_br(-1, &a->fake); ++ au_kfree_rcu(a); ++ dpri("dev 0x%x\n", sb->s_dev); ++ if (err || !au_test_aufs(sb)) ++ return; ++ ++ sbinfo = au_sbi(sb); ++ if (!sbinfo) ++ return; ++ dpri("nw %d, gen %u, kobj %d\n", ++ atomic_read(&sbinfo->si_nowait.nw_len), sbinfo->si_generation, ++ kref_read(&sbinfo->si_kobj.kref)); ++ for (bindex = 0; bindex <= sbinfo->si_bbot; bindex++) ++ do_pri_br(bindex, sbinfo->si_branch[0 + bindex]); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line) ++{ ++ struct inode *h_inode, *inode = d_inode(dentry); ++ struct dentry *h_dentry; ++ aufs_bindex_t bindex, bbot, bi; ++ ++ if (!inode /* || au_di(dentry)->di_lsc == AuLsc_DI_TMP */) ++ return; ++ ++ bbot = au_dbbot(dentry); ++ bi = au_ibbot(inode); ++ if (bi < bbot) ++ bbot = bi; ++ bindex = au_dbtop(dentry); ++ bi = au_ibtop(inode); ++ if (bi > bindex) ++ bindex = bi; ++ ++ for (; bindex <= bbot; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ h_inode = au_h_iptr(inode, bindex); ++ if (unlikely(h_inode != d_inode(h_dentry))) { ++ au_debug_on(); ++ AuDbg("b%d, %s:%d\n", bindex, func, line); ++ AuDbgDentry(dentry); ++ AuDbgInode(inode); ++ au_debug_off(); ++ BUG(); ++ } ++ } ++} ++ ++void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen) ++{ ++ int err, i, j; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ AuDebugOn(err); ++ err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/1); ++ AuDebugOn(err); ++ for (i = dpages.ndpage - 1; !err && i >= 0; i--) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ for (j = dpage->ndentry - 1; !err && j >= 0; j--) ++ AuDebugOn(au_digen_test(dentries[j], sigen)); ++ } ++ au_dpages_free(&dpages); ++} ++ ++void au_dbg_verify_kthread(void) ++{ ++ if (au_wkq_test()) { ++ au_dbg_blocked(); ++ /* ++ * It may be recursive, but udba=notify between two aufs mounts, ++ * where a single ro branch is shared, is not a problem. ++ */ ++ /* WARN_ON(1); */ ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int __init au_debug_init(void) ++{ ++ aufs_bindex_t bindex; ++ struct au_vdir_destr destr; ++ ++ bindex = -1; ++ AuDebugOn(bindex >= 0); ++ ++ destr.len = -1; ++ AuDebugOn(destr.len < NAME_MAX); ++ ++#ifdef CONFIG_4KSTACKS ++ pr_warn("CONFIG_4KSTACKS is defined.\n"); ++#endif ++ ++ return 0; ++} +diff -Nurp linux-5.4/fs/aufs/debug.h linux-5.4-aufs/fs/aufs/debug.h +--- linux-5.4/fs/aufs/debug.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/debug.h 2019-11-28 01:25:59.063925618 +0200 +@@ -0,0 +1,213 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * debug print functions ++ */ ++ ++#ifndef __AUFS_DEBUG_H__ ++#define __AUFS_DEBUG_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_AUFS_DEBUG ++#define AuDebugOn(a) BUG_ON(a) ++ ++/* module parameter */ ++extern atomic_t aufs_debug; ++static inline void au_debug_on(void) ++{ ++ atomic_inc(&aufs_debug); ++} ++static inline void au_debug_off(void) ++{ ++ atomic_dec_if_positive(&aufs_debug); ++} ++ ++static inline int au_debug_test(void) ++{ ++ return atomic_read(&aufs_debug) > 0; ++} ++#else ++#define AuDebugOn(a) do {} while (0) ++AuStubVoid(au_debug_on, void) ++AuStubVoid(au_debug_off, void) ++AuStubInt0(au_debug_test, void) ++#endif /* CONFIG_AUFS_DEBUG */ ++ ++#define param_check_atomic_t(name, p) __param_check(name, p, atomic_t) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* debug print */ ++ ++#define AuDbg(fmt, ...) do { \ ++ if (au_debug_test()) \ ++ pr_debug("DEBUG: " fmt, ##__VA_ARGS__); \ ++} while (0) ++#define AuLabel(l) AuDbg(#l "\n") ++#define AuIOErr(fmt, ...) pr_err("I/O Error, " fmt, ##__VA_ARGS__) ++#define AuWarn1(fmt, ...) do { \ ++ static unsigned char _c; \ ++ if (!_c++) \ ++ pr_warn(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++#define AuErr1(fmt, ...) do { \ ++ static unsigned char _c; \ ++ if (!_c++) \ ++ pr_err(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++#define AuIOErr1(fmt, ...) do { \ ++ static unsigned char _c; \ ++ if (!_c++) \ ++ AuIOErr(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++#define AuUnsupportMsg "This operation is not supported." \ ++ " Please report this application to aufs-users ML." ++#define AuUnsupport(fmt, ...) do { \ ++ pr_err(AuUnsupportMsg "\n" fmt, ##__VA_ARGS__); \ ++ dump_stack(); \ ++} while (0) ++ ++#define AuTraceErr(e) do { \ ++ if (unlikely((e) < 0)) \ ++ AuDbg("err %d\n", (int)(e)); \ ++} while (0) ++ ++#define AuTraceErrPtr(p) do { \ ++ if (IS_ERR(p)) \ ++ AuDbg("err %ld\n", PTR_ERR(p)); \ ++} while (0) ++ ++/* dirty macros for debug print, use with "%.*s" and caution */ ++#define AuLNPair(qstr) (qstr)->len, (qstr)->name ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dentry; ++#ifdef CONFIG_AUFS_DEBUG ++extern struct mutex au_dbg_mtx; ++extern char *au_plevel; ++struct au_nhash; ++void au_dpri_whlist(struct au_nhash *whlist); ++struct au_vdir; ++void au_dpri_vdir(struct au_vdir *vdir); ++struct inode; ++void au_dpri_inode(struct inode *inode); ++void au_dpri_dalias(struct inode *inode); ++void au_dpri_dentry(struct dentry *dentry); ++struct file; ++void au_dpri_file(struct file *filp); ++struct super_block; ++void au_dpri_sb(struct super_block *sb); ++ ++#define au_dbg_verify_dinode(d) __au_dbg_verify_dinode(d, __func__, __LINE__) ++void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line); ++void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen); ++void au_dbg_verify_kthread(void); ++ ++int __init au_debug_init(void); ++ ++#define AuDbgWhlist(w) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#w "\n"); \ ++ au_dpri_whlist(w); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgVdir(v) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#v "\n"); \ ++ au_dpri_vdir(v); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgInode(i) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#i "\n"); \ ++ au_dpri_inode(i); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgDAlias(i) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#i "\n"); \ ++ au_dpri_dalias(i); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgDentry(d) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#d "\n"); \ ++ au_dpri_dentry(d); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgFile(f) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#f "\n"); \ ++ au_dpri_file(f); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgSb(sb) do { \ ++ mutex_lock(&au_dbg_mtx); \ ++ AuDbg(#sb "\n"); \ ++ au_dpri_sb(sb); \ ++ mutex_unlock(&au_dbg_mtx); \ ++} while (0) ++ ++#define AuDbgSym(addr) do { \ ++ char sym[KSYM_SYMBOL_LEN]; \ ++ sprint_symbol(sym, (unsigned long)addr); \ ++ AuDbg("%s\n", sym); \ ++} while (0) ++#else ++AuStubVoid(au_dbg_verify_dinode, struct dentry *dentry) ++AuStubVoid(au_dbg_verify_gen, struct dentry *parent, unsigned int sigen) ++AuStubVoid(au_dbg_verify_kthread, void) ++AuStubInt0(__init au_debug_init, void) ++ ++#define AuDbgWhlist(w) do {} while (0) ++#define AuDbgVdir(v) do {} while (0) ++#define AuDbgInode(i) do {} while (0) ++#define AuDbgDAlias(i) do {} while (0) ++#define AuDbgDentry(d) do {} while (0) ++#define AuDbgFile(f) do {} while (0) ++#define AuDbgSb(sb) do {} while (0) ++#define AuDbgSym(addr) do {} while (0) ++#endif /* CONFIG_AUFS_DEBUG */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_MAGIC_SYSRQ ++int __init au_sysrq_init(void); ++void au_sysrq_fin(void); ++ ++#ifdef CONFIG_HW_CONSOLE ++#define au_dbg_blocked() do { \ ++ WARN_ON(1); \ ++ handle_sysrq('w'); \ ++} while (0) ++#else ++AuStubVoid(au_dbg_blocked, void) ++#endif ++ ++#else ++AuStubInt0(__init au_sysrq_init, void) ++AuStubVoid(au_sysrq_fin, void) ++AuStubVoid(au_dbg_blocked, void) ++#endif /* CONFIG_AUFS_MAGIC_SYSRQ */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DEBUG_H__ */ +diff -Nurp linux-5.4/fs/aufs/dentry.c linux-5.4-aufs/fs/aufs/dentry.c +--- linux-5.4/fs/aufs/dentry.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/dentry.c 2019-11-28 01:25:59.063925618 +0200 +@@ -0,0 +1,1141 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * lookup and dentry operations ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++/* ++ * returns positive/negative dentry, NULL or an error. ++ * NULL means whiteout-ed or not-found. ++ */ ++static struct dentry* ++au_do_lookup(struct dentry *h_parent, struct dentry *dentry, ++ aufs_bindex_t bindex, struct au_do_lookup_args *args) ++{ ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct au_branch *br; ++ int wh_found, opq; ++ unsigned char wh_able; ++ const unsigned char allow_neg = !!au_ftest_lkup(args->flags, ALLOW_NEG); ++ const unsigned char ignore_perm = !!au_ftest_lkup(args->flags, ++ IGNORE_PERM); ++ ++ wh_found = 0; ++ br = au_sbr(dentry->d_sb, bindex); ++ wh_able = !!au_br_whable(br->br_perm); ++ if (wh_able) ++ wh_found = au_wh_test(h_parent, &args->whname, ignore_perm); ++ h_dentry = ERR_PTR(wh_found); ++ if (!wh_found) ++ goto real_lookup; ++ if (unlikely(wh_found < 0)) ++ goto out; ++ ++ /* We found a whiteout */ ++ /* au_set_dbbot(dentry, bindex); */ ++ au_set_dbwh(dentry, bindex); ++ if (!allow_neg) ++ return NULL; /* success */ ++ ++real_lookup: ++ if (!ignore_perm) ++ h_dentry = vfsub_lkup_one(args->name, h_parent); ++ else ++ h_dentry = au_sio_lkup_one(args->name, h_parent); ++ if (IS_ERR(h_dentry)) { ++ if (PTR_ERR(h_dentry) == -ENAMETOOLONG ++ && !allow_neg) ++ h_dentry = NULL; ++ goto out; ++ } ++ ++ h_inode = d_inode(h_dentry); ++ if (d_is_negative(h_dentry)) { ++ if (!allow_neg) ++ goto out_neg; ++ } else if (wh_found ++ || (args->type && args->type != (h_inode->i_mode & S_IFMT))) ++ goto out_neg; ++ else if (au_ftest_lkup(args->flags, DIRREN) ++ /* && h_inode */ ++ && !au_dr_lkup_h_ino(args, bindex, h_inode->i_ino)) { ++ AuDbg("b%d %pd ignored hi%llu\n", bindex, h_dentry, ++ (unsigned long long)h_inode->i_ino); ++ goto out_neg; ++ } ++ ++ if (au_dbbot(dentry) <= bindex) ++ au_set_dbbot(dentry, bindex); ++ if (au_dbtop(dentry) < 0 || bindex < au_dbtop(dentry)) ++ au_set_dbtop(dentry, bindex); ++ au_set_h_dptr(dentry, bindex, h_dentry); ++ ++ if (!d_is_dir(h_dentry) ++ || !wh_able ++ || (d_really_is_positive(dentry) && !d_is_dir(dentry))) ++ goto out; /* success */ ++ ++ inode_lock_shared_nested(h_inode, AuLsc_I_CHILD); ++ opq = au_diropq_test(h_dentry); ++ inode_unlock_shared(h_inode); ++ if (opq > 0) ++ au_set_dbdiropq(dentry, bindex); ++ else if (unlikely(opq < 0)) { ++ au_set_h_dptr(dentry, bindex, NULL); ++ h_dentry = ERR_PTR(opq); ++ } ++ goto out; ++ ++out_neg: ++ dput(h_dentry); ++ h_dentry = NULL; ++out: ++ return h_dentry; ++} ++ ++static int au_test_shwh(struct super_block *sb, const struct qstr *name) ++{ ++ if (unlikely(!au_opt_test(au_mntflags(sb), SHWH) ++ && !strncmp(name->name, AUFS_WH_PFX, AUFS_WH_PFX_LEN))) ++ return -EPERM; ++ return 0; ++} ++ ++/* ++ * returns the number of lower positive dentries, ++ * otherwise an error. ++ * can be called at unlinking with @type is zero. ++ */ ++int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t btop, ++ unsigned int flags) ++{ ++ int npositive, err; ++ aufs_bindex_t bindex, btail, bdiropq; ++ unsigned char isdir, dirperm1, dirren; ++ struct au_do_lookup_args args = { ++ .flags = flags, ++ .name = &dentry->d_name ++ }; ++ struct dentry *parent; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ err = au_test_shwh(sb, args.name); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_wh_name_alloc(&args.whname, args.name); ++ if (unlikely(err)) ++ goto out; ++ ++ isdir = !!d_is_dir(dentry); ++ dirperm1 = !!au_opt_test(au_mntflags(sb), DIRPERM1); ++ dirren = !!au_opt_test(au_mntflags(sb), DIRREN); ++ if (dirren) ++ au_fset_lkup(args.flags, DIRREN); ++ ++ npositive = 0; ++ parent = dget_parent(dentry); ++ btail = au_dbtaildir(parent); ++ for (bindex = btop; bindex <= btail; bindex++) { ++ struct dentry *h_parent, *h_dentry; ++ struct inode *h_inode, *h_dir; ++ struct au_branch *br; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry) { ++ if (d_is_positive(h_dentry)) ++ npositive++; ++ break; ++ } ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || !d_is_dir(h_parent)) ++ continue; ++ ++ if (dirren) { ++ /* if the inum matches, then use the prepared name */ ++ err = au_dr_lkup_name(&args, bindex); ++ if (unlikely(err)) ++ goto out_parent; ++ } ++ ++ h_dir = d_inode(h_parent); ++ inode_lock_shared_nested(h_dir, AuLsc_I_PARENT); ++ h_dentry = au_do_lookup(h_parent, dentry, bindex, &args); ++ inode_unlock_shared(h_dir); ++ err = PTR_ERR(h_dentry); ++ if (IS_ERR(h_dentry)) ++ goto out_parent; ++ if (h_dentry) ++ au_fclr_lkup(args.flags, ALLOW_NEG); ++ if (dirperm1) ++ au_fset_lkup(args.flags, IGNORE_PERM); ++ ++ if (au_dbwh(dentry) == bindex) ++ break; ++ if (!h_dentry) ++ continue; ++ if (d_is_negative(h_dentry)) ++ continue; ++ h_inode = d_inode(h_dentry); ++ npositive++; ++ if (!args.type) ++ args.type = h_inode->i_mode & S_IFMT; ++ if (args.type != S_IFDIR) ++ break; ++ else if (isdir) { ++ /* the type of lower may be different */ ++ bdiropq = au_dbdiropq(dentry); ++ if (bdiropq >= 0 && bdiropq <= bindex) ++ break; ++ } ++ br = au_sbr(sb, bindex); ++ if (dirren ++ && au_dr_hino_test_add(&br->br_dirren, h_inode->i_ino, ++ /*add_ent*/NULL)) { ++ /* prepare next name to lookup */ ++ err = au_dr_lkup(&args, dentry, bindex); ++ if (unlikely(err)) ++ goto out_parent; ++ } ++ } ++ ++ if (npositive) { ++ AuLabel(positive); ++ au_update_dbtop(dentry); ++ } ++ err = npositive; ++ if (unlikely(!au_opt_test(au_mntflags(sb), UDBA_NONE) ++ && au_dbtop(dentry) < 0)) { ++ err = -EIO; ++ AuIOErr("both of real entry and whiteout found, %pd, err %d\n", ++ dentry, err); ++ } ++ ++out_parent: ++ dput(parent); ++ au_kfree_try_rcu(args.whname.name); ++ if (dirren) ++ au_dr_lkup_fin(&args); ++out: ++ return err; ++} ++ ++struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent) ++{ ++ struct dentry *dentry; ++ int wkq_err; ++ ++ if (!au_test_h_perm_sio(d_inode(parent), MAY_EXEC)) ++ dentry = vfsub_lkup_one(name, parent); ++ else { ++ struct vfsub_lkup_one_args args = { ++ .errp = &dentry, ++ .name = name, ++ .parent = parent ++ }; ++ ++ wkq_err = au_wkq_wait(vfsub_call_lkup_one, &args); ++ if (unlikely(wkq_err)) ++ dentry = ERR_PTR(wkq_err); ++ } ++ ++ return dentry; ++} ++ ++/* ++ * lookup @dentry on @bindex which should be negative. ++ */ ++int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex, int wh) ++{ ++ int err; ++ struct dentry *parent, *h_parent, *h_dentry; ++ struct au_branch *br; ++ ++ parent = dget_parent(dentry); ++ h_parent = au_h_dptr(parent, bindex); ++ br = au_sbr(dentry->d_sb, bindex); ++ if (wh) ++ h_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name); ++ else ++ h_dentry = au_sio_lkup_one(&dentry->d_name, h_parent); ++ err = PTR_ERR(h_dentry); ++ if (IS_ERR(h_dentry)) ++ goto out; ++ if (unlikely(d_is_positive(h_dentry))) { ++ err = -EIO; ++ AuIOErr("%pd should be negative on b%d.\n", h_dentry, bindex); ++ dput(h_dentry); ++ goto out; ++ } ++ ++ err = 0; ++ if (bindex < au_dbtop(dentry)) ++ au_set_dbtop(dentry, bindex); ++ if (au_dbbot(dentry) < bindex) ++ au_set_dbbot(dentry, bindex); ++ au_set_h_dptr(dentry, bindex, h_dentry); ++ ++out: ++ dput(parent); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* subset of struct inode */ ++struct au_iattr { ++ unsigned long i_ino; ++ /* unsigned int i_nlink; */ ++ kuid_t i_uid; ++ kgid_t i_gid; ++ u64 i_version; ++/* ++ loff_t i_size; ++ blkcnt_t i_blocks; ++*/ ++ umode_t i_mode; ++}; ++ ++static void au_iattr_save(struct au_iattr *ia, struct inode *h_inode) ++{ ++ ia->i_ino = h_inode->i_ino; ++ /* ia->i_nlink = h_inode->i_nlink; */ ++ ia->i_uid = h_inode->i_uid; ++ ia->i_gid = h_inode->i_gid; ++ ia->i_version = inode_query_iversion(h_inode); ++/* ++ ia->i_size = h_inode->i_size; ++ ia->i_blocks = h_inode->i_blocks; ++*/ ++ ia->i_mode = (h_inode->i_mode & S_IFMT); ++} ++ ++static int au_iattr_test(struct au_iattr *ia, struct inode *h_inode) ++{ ++ return ia->i_ino != h_inode->i_ino ++ /* || ia->i_nlink != h_inode->i_nlink */ ++ || !uid_eq(ia->i_uid, h_inode->i_uid) ++ || !gid_eq(ia->i_gid, h_inode->i_gid) ++ || !inode_eq_iversion(h_inode, ia->i_version) ++/* ++ || ia->i_size != h_inode->i_size ++ || ia->i_blocks != h_inode->i_blocks ++*/ ++ || ia->i_mode != (h_inode->i_mode & S_IFMT); ++} ++ ++static int au_h_verify_dentry(struct dentry *h_dentry, struct dentry *h_parent, ++ struct au_branch *br) ++{ ++ int err; ++ struct au_iattr ia; ++ struct inode *h_inode; ++ struct dentry *h_d; ++ struct super_block *h_sb; ++ ++ err = 0; ++ memset(&ia, -1, sizeof(ia)); ++ h_sb = h_dentry->d_sb; ++ h_inode = NULL; ++ if (d_is_positive(h_dentry)) { ++ h_inode = d_inode(h_dentry); ++ au_iattr_save(&ia, h_inode); ++ } else if (au_test_nfs(h_sb) || au_test_fuse(h_sb)) ++ /* nfs d_revalidate may return 0 for negative dentry */ ++ /* fuse d_revalidate always return 0 for negative dentry */ ++ goto out; ++ ++ /* main purpose is namei.c:cached_lookup() and d_revalidate */ ++ h_d = vfsub_lkup_one(&h_dentry->d_name, h_parent); ++ err = PTR_ERR(h_d); ++ if (IS_ERR(h_d)) ++ goto out; ++ ++ err = 0; ++ if (unlikely(h_d != h_dentry ++ || d_inode(h_d) != h_inode ++ || (h_inode && au_iattr_test(&ia, h_inode)))) ++ err = au_busy_or_stale(); ++ dput(h_d); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir, ++ struct dentry *h_parent, struct au_branch *br) ++{ ++ int err; ++ ++ err = 0; ++ if (udba == AuOpt_UDBA_REVAL ++ && !au_test_fs_remote(h_dentry->d_sb)) { ++ IMustLock(h_dir); ++ err = (d_inode(h_dentry->d_parent) != h_dir); ++ } else if (udba != AuOpt_UDBA_NONE) ++ err = au_h_verify_dentry(h_dentry, h_parent, br); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_refresh_hdentry(struct dentry *dentry, struct dentry *parent) ++{ ++ int err; ++ aufs_bindex_t new_bindex, bindex, bbot, bwh, bdiropq; ++ struct au_hdentry tmp, *p, *q; ++ struct au_dinfo *dinfo; ++ struct super_block *sb; ++ ++ DiMustWriteLock(dentry); ++ ++ sb = dentry->d_sb; ++ dinfo = au_di(dentry); ++ bbot = dinfo->di_bbot; ++ bwh = dinfo->di_bwh; ++ bdiropq = dinfo->di_bdiropq; ++ bindex = dinfo->di_btop; ++ p = au_hdentry(dinfo, bindex); ++ for (; bindex <= bbot; bindex++, p++) { ++ if (!p->hd_dentry) ++ continue; ++ ++ new_bindex = au_br_index(sb, p->hd_id); ++ if (new_bindex == bindex) ++ continue; ++ ++ if (dinfo->di_bwh == bindex) ++ bwh = new_bindex; ++ if (dinfo->di_bdiropq == bindex) ++ bdiropq = new_bindex; ++ if (new_bindex < 0) { ++ au_hdput(p); ++ p->hd_dentry = NULL; ++ continue; ++ } ++ ++ /* swap two lower dentries, and loop again */ ++ q = au_hdentry(dinfo, new_bindex); ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hd_dentry) { ++ bindex--; ++ p--; ++ } ++ } ++ ++ dinfo->di_bwh = -1; ++ if (bwh >= 0 && bwh <= au_sbbot(sb) && au_sbr_whable(sb, bwh)) ++ dinfo->di_bwh = bwh; ++ ++ dinfo->di_bdiropq = -1; ++ if (bdiropq >= 0 ++ && bdiropq <= au_sbbot(sb) ++ && au_sbr_whable(sb, bdiropq)) ++ dinfo->di_bdiropq = bdiropq; ++ ++ err = -EIO; ++ dinfo->di_btop = -1; ++ dinfo->di_bbot = -1; ++ bbot = au_dbbot(parent); ++ bindex = 0; ++ p = au_hdentry(dinfo, bindex); ++ for (; bindex <= bbot; bindex++, p++) ++ if (p->hd_dentry) { ++ dinfo->di_btop = bindex; ++ break; ++ } ++ ++ if (dinfo->di_btop >= 0) { ++ bindex = bbot; ++ p = au_hdentry(dinfo, bindex); ++ for (; bindex >= 0; bindex--, p--) ++ if (p->hd_dentry) { ++ dinfo->di_bbot = bindex; ++ err = 0; ++ break; ++ } ++ } ++ ++ return err; ++} ++ ++static void au_do_hide(struct dentry *dentry) ++{ ++ struct inode *inode; ++ ++ if (d_really_is_positive(dentry)) { ++ inode = d_inode(dentry); ++ if (!d_is_dir(dentry)) { ++ if (inode->i_nlink && !d_unhashed(dentry)) ++ drop_nlink(inode); ++ } else { ++ clear_nlink(inode); ++ /* stop next lookup */ ++ inode->i_flags |= S_DEAD; ++ } ++ smp_mb(); /* necessary? */ ++ } ++ d_drop(dentry); ++} ++ ++static int au_hide_children(struct dentry *parent) ++{ ++ int err, i, j, ndentry; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry *dentry; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, parent, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ /* in reverse order */ ++ for (i = dpages.ndpage - 1; i >= 0; i--) { ++ dpage = dpages.dpages + i; ++ ndentry = dpage->ndentry; ++ for (j = ndentry - 1; j >= 0; j--) { ++ dentry = dpage->dentries[j]; ++ if (dentry != parent) ++ au_do_hide(dentry); ++ } ++ } ++ ++out_dpages: ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++static void au_hide(struct dentry *dentry) ++{ ++ int err; ++ ++ AuDbgDentry(dentry); ++ if (d_is_dir(dentry)) { ++ /* shrink_dcache_parent(dentry); */ ++ err = au_hide_children(dentry); ++ if (unlikely(err)) ++ AuIOErr("%pd, failed hiding children, ignored %d\n", ++ dentry, err); ++ } ++ au_do_hide(dentry); ++} ++ ++/* ++ * By adding a dirty branch, a cached dentry may be affected in various ways. ++ * ++ * a dirty branch is added ++ * - on the top of layers ++ * - in the middle of layers ++ * - to the bottom of layers ++ * ++ * on the added branch there exists ++ * - a whiteout ++ * - a diropq ++ * - a same named entry ++ * + exist ++ * * negative --> positive ++ * * positive --> positive ++ * - type is unchanged ++ * - type is changed ++ * + doesn't exist ++ * * negative --> negative ++ * * positive --> negative (rejected by au_br_del() for non-dir case) ++ * - none ++ */ ++static int au_refresh_by_dinfo(struct dentry *dentry, struct au_dinfo *dinfo, ++ struct au_dinfo *tmp) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct { ++ struct dentry *dentry; ++ struct inode *inode; ++ mode_t mode; ++ } orig_h, tmp_h = { ++ .dentry = NULL ++ }; ++ struct au_hdentry *hd; ++ struct inode *inode, *h_inode; ++ struct dentry *h_dentry; ++ ++ err = 0; ++ AuDebugOn(dinfo->di_btop < 0); ++ orig_h.mode = 0; ++ orig_h.dentry = au_hdentry(dinfo, dinfo->di_btop)->hd_dentry; ++ orig_h.inode = NULL; ++ if (d_is_positive(orig_h.dentry)) { ++ orig_h.inode = d_inode(orig_h.dentry); ++ orig_h.mode = orig_h.inode->i_mode & S_IFMT; ++ } ++ if (tmp->di_btop >= 0) { ++ tmp_h.dentry = au_hdentry(tmp, tmp->di_btop)->hd_dentry; ++ if (d_is_positive(tmp_h.dentry)) { ++ tmp_h.inode = d_inode(tmp_h.dentry); ++ tmp_h.mode = tmp_h.inode->i_mode & S_IFMT; ++ } ++ } ++ ++ inode = NULL; ++ if (d_really_is_positive(dentry)) ++ inode = d_inode(dentry); ++ if (!orig_h.inode) { ++ AuDbg("negative originally\n"); ++ if (inode) { ++ au_hide(dentry); ++ goto out; ++ } ++ AuDebugOn(inode); ++ AuDebugOn(dinfo->di_btop != dinfo->di_bbot); ++ AuDebugOn(dinfo->di_bdiropq != -1); ++ ++ if (!tmp_h.inode) { ++ AuDbg("negative --> negative\n"); ++ /* should have only one negative lower */ ++ if (tmp->di_btop >= 0 ++ && tmp->di_btop < dinfo->di_btop) { ++ AuDebugOn(tmp->di_btop != tmp->di_bbot); ++ AuDebugOn(dinfo->di_btop != dinfo->di_bbot); ++ au_set_h_dptr(dentry, dinfo->di_btop, NULL); ++ au_di_cp(dinfo, tmp); ++ hd = au_hdentry(tmp, tmp->di_btop); ++ au_set_h_dptr(dentry, tmp->di_btop, ++ dget(hd->hd_dentry)); ++ } ++ au_dbg_verify_dinode(dentry); ++ } else { ++ AuDbg("negative --> positive\n"); ++ /* ++ * similar to the behaviour of creating with bypassing ++ * aufs. ++ * unhash it in order to force an error in the ++ * succeeding create operation. ++ * we should not set S_DEAD here. ++ */ ++ d_drop(dentry); ++ /* au_di_swap(tmp, dinfo); */ ++ au_dbg_verify_dinode(dentry); ++ } ++ } else { ++ AuDbg("positive originally\n"); ++ /* inode may be NULL */ ++ AuDebugOn(inode && (inode->i_mode & S_IFMT) != orig_h.mode); ++ if (!tmp_h.inode) { ++ AuDbg("positive --> negative\n"); ++ /* or bypassing aufs */ ++ au_hide(dentry); ++ if (tmp->di_bwh >= 0 && tmp->di_bwh <= dinfo->di_btop) ++ dinfo->di_bwh = tmp->di_bwh; ++ if (inode) ++ err = au_refresh_hinode_self(inode); ++ au_dbg_verify_dinode(dentry); ++ } else if (orig_h.mode == tmp_h.mode) { ++ AuDbg("positive --> positive, same type\n"); ++ if (!S_ISDIR(orig_h.mode) ++ && dinfo->di_btop > tmp->di_btop) { ++ /* ++ * similar to the behaviour of removing and ++ * creating. ++ */ ++ au_hide(dentry); ++ if (inode) ++ err = au_refresh_hinode_self(inode); ++ au_dbg_verify_dinode(dentry); ++ } else { ++ /* fill empty slots */ ++ if (dinfo->di_btop > tmp->di_btop) ++ dinfo->di_btop = tmp->di_btop; ++ if (dinfo->di_bbot < tmp->di_bbot) ++ dinfo->di_bbot = tmp->di_bbot; ++ dinfo->di_bwh = tmp->di_bwh; ++ dinfo->di_bdiropq = tmp->di_bdiropq; ++ bbot = dinfo->di_bbot; ++ bindex = tmp->di_btop; ++ hd = au_hdentry(tmp, bindex); ++ for (; bindex <= bbot; bindex++, hd++) { ++ if (au_h_dptr(dentry, bindex)) ++ continue; ++ h_dentry = hd->hd_dentry; ++ if (!h_dentry) ++ continue; ++ AuDebugOn(d_is_negative(h_dentry)); ++ h_inode = d_inode(h_dentry); ++ AuDebugOn(orig_h.mode ++ != (h_inode->i_mode ++ & S_IFMT)); ++ au_set_h_dptr(dentry, bindex, ++ dget(h_dentry)); ++ } ++ if (inode) ++ err = au_refresh_hinode(inode, dentry); ++ au_dbg_verify_dinode(dentry); ++ } ++ } else { ++ AuDbg("positive --> positive, different type\n"); ++ /* similar to the behaviour of removing and creating */ ++ au_hide(dentry); ++ if (inode) ++ err = au_refresh_hinode_self(inode); ++ au_dbg_verify_dinode(dentry); ++ } ++ } ++ ++out: ++ return err; ++} ++ ++void au_refresh_dop(struct dentry *dentry, int force_reval) ++{ ++ const struct dentry_operations *dop ++ = force_reval ? &aufs_dop : dentry->d_sb->s_d_op; ++ static const unsigned int mask ++ = DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE; ++ ++ BUILD_BUG_ON(sizeof(mask) != sizeof(dentry->d_flags)); ++ ++ if (dentry->d_op == dop) ++ return; ++ ++ AuDbg("%pd\n", dentry); ++ spin_lock(&dentry->d_lock); ++ if (dop == &aufs_dop) ++ dentry->d_flags |= mask; ++ else ++ dentry->d_flags &= ~mask; ++ dentry->d_op = dop; ++ spin_unlock(&dentry->d_lock); ++} ++ ++int au_refresh_dentry(struct dentry *dentry, struct dentry *parent) ++{ ++ int err, ebrange, nbr; ++ unsigned int sigen; ++ struct au_dinfo *dinfo, *tmp; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ DiMustWriteLock(dentry); ++ AuDebugOn(IS_ROOT(dentry)); ++ AuDebugOn(d_really_is_negative(parent)); ++ ++ sb = dentry->d_sb; ++ sigen = au_sigen(sb); ++ err = au_digen_test(parent, sigen); ++ if (unlikely(err)) ++ goto out; ++ ++ nbr = au_sbbot(sb) + 1; ++ dinfo = au_di(dentry); ++ err = au_di_realloc(dinfo, nbr, /*may_shrink*/0); ++ if (unlikely(err)) ++ goto out; ++ ebrange = au_dbrange_test(dentry); ++ if (!ebrange) ++ ebrange = au_do_refresh_hdentry(dentry, parent); ++ ++ if (d_unhashed(dentry) || ebrange /* || dinfo->di_tmpfile */) { ++ AuDebugOn(au_dbtop(dentry) < 0 && au_dbbot(dentry) >= 0); ++ if (d_really_is_positive(dentry)) { ++ inode = d_inode(dentry); ++ err = au_refresh_hinode_self(inode); ++ } ++ au_dbg_verify_dinode(dentry); ++ if (!err) ++ goto out_dgen; /* success */ ++ goto out; ++ } ++ ++ /* temporary dinfo */ ++ AuDbgDentry(dentry); ++ err = -ENOMEM; ++ tmp = au_di_alloc(sb, AuLsc_DI_TMP); ++ if (unlikely(!tmp)) ++ goto out; ++ au_di_swap(tmp, dinfo); ++ /* returns the number of positive dentries */ ++ /* ++ * if current working dir is removed, it returns an error. ++ * but the dentry is legal. ++ */ ++ err = au_lkup_dentry(dentry, /*btop*/0, AuLkup_ALLOW_NEG); ++ AuDbgDentry(dentry); ++ au_di_swap(tmp, dinfo); ++ if (err == -ENOENT) ++ err = 0; ++ if (err >= 0) { ++ /* compare/refresh by dinfo */ ++ AuDbgDentry(dentry); ++ err = au_refresh_by_dinfo(dentry, dinfo, tmp); ++ au_dbg_verify_dinode(dentry); ++ AuTraceErr(err); ++ } ++ au_di_realloc(dinfo, nbr, /*may_shrink*/1); /* harmless if err */ ++ au_rw_write_unlock(&tmp->di_rwsem); ++ au_di_free(tmp); ++ if (unlikely(err)) ++ goto out; ++ ++out_dgen: ++ au_update_digen(dentry); ++out: ++ if (unlikely(err && !(dentry->d_flags & DCACHE_NFSFS_RENAMED))) { ++ AuIOErr("failed refreshing %pd, %d\n", dentry, err); ++ AuDbgDentry(dentry); ++ } ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_do_h_d_reval(struct dentry *h_dentry, unsigned int flags, ++ struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ int err, valid; ++ ++ err = 0; ++ if (!(h_dentry->d_flags & DCACHE_OP_REVALIDATE)) ++ goto out; ++ ++ AuDbg("b%d\n", bindex); ++ /* ++ * gave up supporting LOOKUP_CREATE/OPEN for lower fs, ++ * due to whiteout and branch permission. ++ */ ++ flags &= ~(/*LOOKUP_PARENT |*/ LOOKUP_OPEN | LOOKUP_CREATE ++ | LOOKUP_FOLLOW | LOOKUP_EXCL); ++ /* it may return tri-state */ ++ valid = h_dentry->d_op->d_revalidate(h_dentry, flags); ++ ++ if (unlikely(valid < 0)) ++ err = valid; ++ else if (!valid) ++ err = -EINVAL; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* todo: remove this */ ++static int h_d_revalidate(struct dentry *dentry, struct inode *inode, ++ unsigned int flags, int do_udba, int dirren) ++{ ++ int err; ++ umode_t mode, h_mode; ++ aufs_bindex_t bindex, btail, btop, ibs, ibe; ++ unsigned char plus, unhashed, is_root, h_plus, h_nfs, tmpfile; ++ struct inode *h_inode, *h_cached_inode; ++ struct dentry *h_dentry; ++ struct qstr *name, *h_name; ++ ++ err = 0; ++ plus = 0; ++ mode = 0; ++ ibs = -1; ++ ibe = -1; ++ unhashed = !!d_unhashed(dentry); ++ is_root = !!IS_ROOT(dentry); ++ name = &dentry->d_name; ++ tmpfile = au_di(dentry)->di_tmpfile; ++ ++ /* ++ * Theoretically, REVAL test should be unnecessary in case of ++ * {FS,I}NOTIFY. ++ * But {fs,i}notify doesn't fire some necessary events, ++ * IN_ATTRIB for atime/nlink/pageio ++ * Let's do REVAL test too. ++ */ ++ if (do_udba && inode) { ++ mode = (inode->i_mode & S_IFMT); ++ plus = (inode->i_nlink > 0); ++ ibs = au_ibtop(inode); ++ ibe = au_ibbot(inode); ++ } ++ ++ btop = au_dbtop(dentry); ++ btail = btop; ++ if (inode && S_ISDIR(inode->i_mode)) ++ btail = au_dbtaildir(dentry); ++ for (bindex = btop; bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ ++ AuDbg("b%d, %pd\n", bindex, h_dentry); ++ h_nfs = !!au_test_nfs(h_dentry->d_sb); ++ spin_lock(&h_dentry->d_lock); ++ h_name = &h_dentry->d_name; ++ if (unlikely(do_udba ++ && !is_root ++ && ((!h_nfs ++ && (unhashed != !!d_unhashed(h_dentry) ++ || (!tmpfile && !dirren ++ && !au_qstreq(name, h_name)) ++ )) ++ || (h_nfs ++ && !(flags & LOOKUP_OPEN) ++ && (h_dentry->d_flags ++ & DCACHE_NFSFS_RENAMED))) ++ )) { ++ int h_unhashed; ++ ++ h_unhashed = d_unhashed(h_dentry); ++ spin_unlock(&h_dentry->d_lock); ++ AuDbg("unhash 0x%x 0x%x, %pd %pd\n", ++ unhashed, h_unhashed, dentry, h_dentry); ++ goto err; ++ } ++ spin_unlock(&h_dentry->d_lock); ++ ++ err = au_do_h_d_reval(h_dentry, flags, dentry, bindex); ++ if (unlikely(err)) ++ /* do not goto err, to keep the errno */ ++ break; ++ ++ /* todo: plink too? */ ++ if (!do_udba) ++ continue; ++ ++ /* UDBA tests */ ++ if (unlikely(!!inode != d_is_positive(h_dentry))) ++ goto err; ++ ++ h_inode = NULL; ++ if (d_is_positive(h_dentry)) ++ h_inode = d_inode(h_dentry); ++ h_plus = plus; ++ h_mode = mode; ++ h_cached_inode = h_inode; ++ if (h_inode) { ++ h_mode = (h_inode->i_mode & S_IFMT); ++ h_plus = (h_inode->i_nlink > 0); ++ } ++ if (inode && ibs <= bindex && bindex <= ibe) ++ h_cached_inode = au_h_iptr(inode, bindex); ++ ++ if (!h_nfs) { ++ if (unlikely(plus != h_plus && !tmpfile)) ++ goto err; ++ } else { ++ if (unlikely(!(h_dentry->d_flags & DCACHE_NFSFS_RENAMED) ++ && !is_root ++ && !IS_ROOT(h_dentry) ++ && unhashed != d_unhashed(h_dentry))) ++ goto err; ++ } ++ if (unlikely(mode != h_mode ++ || h_cached_inode != h_inode)) ++ goto err; ++ continue; ++ ++err: ++ err = -EINVAL; ++ break; ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* todo: consolidate with do_refresh() and au_reval_for_attr() */ ++static int simple_reval_dpath(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ struct dentry *parent; ++ ++ if (!au_digen_test(dentry, sigen)) ++ return 0; ++ ++ parent = dget_parent(dentry); ++ di_read_lock_parent(parent, AuLock_IR); ++ AuDebugOn(au_digen_test(parent, sigen)); ++ au_dbg_verify_gen(parent, sigen); ++ err = au_refresh_dentry(dentry, parent); ++ di_read_unlock(parent, AuLock_IR); ++ dput(parent); ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_reval_dpath(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ struct dentry *d, *parent; ++ ++ if (!au_ftest_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR)) ++ return simple_reval_dpath(dentry, sigen); ++ ++ /* slow loop, keep it simple and stupid */ ++ /* cf: au_cpup_dirs() */ ++ err = 0; ++ parent = NULL; ++ while (au_digen_test(dentry, sigen)) { ++ d = dentry; ++ while (1) { ++ dput(parent); ++ parent = dget_parent(d); ++ if (!au_digen_test(parent, sigen)) ++ break; ++ d = parent; ++ } ++ ++ if (d != dentry) ++ di_write_lock_child2(d); ++ ++ /* someone might update our dentry while we were sleeping */ ++ if (au_digen_test(d, sigen)) { ++ /* ++ * todo: consolidate with simple_reval_dpath(), ++ * do_refresh() and au_reval_for_attr(). ++ */ ++ di_read_lock_parent(parent, AuLock_IR); ++ err = au_refresh_dentry(d, parent); ++ di_read_unlock(parent, AuLock_IR); ++ } ++ ++ if (d != dentry) ++ di_write_unlock(d); ++ dput(parent); ++ if (unlikely(err)) ++ break; ++ } ++ ++ return err; ++} ++ ++/* ++ * if valid returns 1, otherwise 0. ++ */ ++static int aufs_d_revalidate(struct dentry *dentry, unsigned int flags) ++{ ++ int valid, err; ++ unsigned int sigen; ++ unsigned char do_udba, dirren; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ /* todo: support rcu-walk? */ ++ if (flags & LOOKUP_RCU) ++ return -ECHILD; ++ ++ valid = 0; ++ if (unlikely(!au_di(dentry))) ++ goto out; ++ ++ valid = 1; ++ sb = dentry->d_sb; ++ /* ++ * todo: very ugly ++ * i_mutex of parent dir may be held, ++ * but we should not return 'invalid' due to busy. ++ */ ++ err = aufs_read_lock(dentry, AuLock_FLUSH | AuLock_DW | AuLock_NOPLM); ++ if (unlikely(err)) { ++ valid = err; ++ AuTraceErr(err); ++ goto out; ++ } ++ inode = NULL; ++ if (d_really_is_positive(dentry)) ++ inode = d_inode(dentry); ++ if (unlikely(inode && au_is_bad_inode(inode))) { ++ err = -EINVAL; ++ AuTraceErr(err); ++ goto out_dgrade; ++ } ++ if (unlikely(au_dbrange_test(dentry))) { ++ err = -EINVAL; ++ AuTraceErr(err); ++ goto out_dgrade; ++ } ++ ++ sigen = au_sigen(sb); ++ if (au_digen_test(dentry, sigen)) { ++ AuDebugOn(IS_ROOT(dentry)); ++ err = au_reval_dpath(dentry, sigen); ++ if (unlikely(err)) { ++ AuTraceErr(err); ++ goto out_dgrade; ++ } ++ } ++ di_downgrade_lock(dentry, AuLock_IR); ++ ++ err = -EINVAL; ++ if (!(flags & (LOOKUP_OPEN | LOOKUP_EMPTY)) ++ && inode ++ && !(inode->i_state && I_LINKABLE) ++ && (IS_DEADDIR(inode) || !inode->i_nlink)) { ++ AuTraceErr(err); ++ goto out_inval; ++ } ++ ++ do_udba = !au_opt_test(au_mntflags(sb), UDBA_NONE); ++ if (do_udba && inode) { ++ aufs_bindex_t btop = au_ibtop(inode); ++ struct inode *h_inode; ++ ++ if (btop >= 0) { ++ h_inode = au_h_iptr(inode, btop); ++ if (h_inode && au_test_higen(inode, h_inode)) { ++ AuTraceErr(err); ++ goto out_inval; ++ } ++ } ++ } ++ ++ dirren = !!au_opt_test(au_mntflags(sb), DIRREN); ++ err = h_d_revalidate(dentry, inode, flags, do_udba, dirren); ++ if (unlikely(!err && do_udba && au_dbtop(dentry) < 0)) { ++ err = -EIO; ++ AuDbg("both of real entry and whiteout found, %p, err %d\n", ++ dentry, err); ++ } ++ goto out_inval; ++ ++out_dgrade: ++ di_downgrade_lock(dentry, AuLock_IR); ++out_inval: ++ aufs_read_unlock(dentry, AuLock_IR); ++ AuTraceErr(err); ++ valid = !err; ++out: ++ if (!valid) { ++ AuDbg("%pd invalid, %d\n", dentry, valid); ++ d_drop(dentry); ++ } ++ return valid; ++} ++ ++static void aufs_d_release(struct dentry *dentry) ++{ ++ if (au_di(dentry)) { ++ au_di_fin(dentry); ++ au_hn_di_reinit(dentry); ++ } ++} ++ ++const struct dentry_operations aufs_dop = { ++ .d_revalidate = aufs_d_revalidate, ++ .d_weak_revalidate = aufs_d_revalidate, ++ .d_release = aufs_d_release ++}; ++ ++/* aufs_dop without d_revalidate */ ++const struct dentry_operations aufs_dop_noreval = { ++ .d_release = aufs_d_release ++}; +diff -Nurp linux-5.4/fs/aufs/dentry.h linux-5.4-aufs/fs/aufs/dentry.h +--- linux-5.4/fs/aufs/dentry.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/dentry.h 2019-11-28 01:25:59.063925618 +0200 +@@ -0,0 +1,255 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * lookup and dentry operations ++ */ ++ ++#ifndef __AUFS_DENTRY_H__ ++#define __AUFS_DENTRY_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "dirren.h" ++#include "rwsem.h" ++ ++struct au_hdentry { ++ struct dentry *hd_dentry; ++ aufs_bindex_t hd_id; ++}; ++ ++struct au_dinfo { ++ atomic_t di_generation; ++ ++ struct au_rwsem di_rwsem; ++ aufs_bindex_t di_btop, di_bbot, di_bwh, di_bdiropq; ++ unsigned char di_tmpfile; /* to allow the different name */ ++ struct au_hdentry *di_hdentry; ++ struct rcu_head rcu; ++} ____cacheline_aligned_in_smp; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* flags for au_lkup_dentry() */ ++#define AuLkup_ALLOW_NEG 1 ++#define AuLkup_IGNORE_PERM (1 << 1) ++#define AuLkup_DIRREN (1 << 2) ++#define au_ftest_lkup(flags, name) ((flags) & AuLkup_##name) ++#define au_fset_lkup(flags, name) \ ++ do { (flags) |= AuLkup_##name; } while (0) ++#define au_fclr_lkup(flags, name) \ ++ do { (flags) &= ~AuLkup_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_DIRREN ++#undef AuLkup_DIRREN ++#define AuLkup_DIRREN 0 ++#endif ++ ++struct au_do_lookup_args { ++ unsigned int flags; ++ mode_t type; ++ struct qstr whname, *name; ++ struct au_dr_lookup dirren; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dentry.c */ ++extern const struct dentry_operations aufs_dop, aufs_dop_noreval; ++struct au_branch; ++struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent); ++int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir, ++ struct dentry *h_parent, struct au_branch *br); ++ ++int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t btop, ++ unsigned int flags); ++int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex, int wh); ++int au_refresh_dentry(struct dentry *dentry, struct dentry *parent); ++int au_reval_dpath(struct dentry *dentry, unsigned int sigen); ++void au_refresh_dop(struct dentry *dentry, int force_reval); ++ ++/* dinfo.c */ ++void au_di_init_once(void *_di); ++struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc); ++void au_di_free(struct au_dinfo *dinfo); ++void au_di_swap(struct au_dinfo *a, struct au_dinfo *b); ++void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src); ++int au_di_init(struct dentry *dentry); ++void au_di_fin(struct dentry *dentry); ++int au_di_realloc(struct au_dinfo *dinfo, int nbr, int may_shrink); ++ ++void di_read_lock(struct dentry *d, int flags, unsigned int lsc); ++void di_read_unlock(struct dentry *d, int flags); ++void di_downgrade_lock(struct dentry *d, int flags); ++void di_write_lock(struct dentry *d, unsigned int lsc); ++void di_write_unlock(struct dentry *d); ++void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir); ++void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir); ++void di_write_unlock2(struct dentry *d1, struct dentry *d2); ++ ++struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex); ++struct dentry *au_h_d_alias(struct dentry *dentry, aufs_bindex_t bindex); ++aufs_bindex_t au_dbtail(struct dentry *dentry); ++aufs_bindex_t au_dbtaildir(struct dentry *dentry); ++ ++void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_dentry); ++int au_digen_test(struct dentry *dentry, unsigned int sigen); ++int au_dbrange_test(struct dentry *dentry); ++void au_update_digen(struct dentry *dentry); ++void au_update_dbrange(struct dentry *dentry, int do_put_zero); ++void au_update_dbtop(struct dentry *dentry); ++void au_update_dbbot(struct dentry *dentry); ++int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_dinfo *au_di(struct dentry *dentry) ++{ ++ return dentry->d_fsdata; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for dinfo */ ++enum { ++ AuLsc_DI_CHILD, /* child first */ ++ AuLsc_DI_CHILD2, /* rename(2), link(2), and cpup at hnotify */ ++ AuLsc_DI_CHILD3, /* copyup dirs */ ++ AuLsc_DI_PARENT, ++ AuLsc_DI_PARENT2, ++ AuLsc_DI_PARENT3, ++ AuLsc_DI_TMP /* temp for replacing dinfo */ ++}; ++ ++/* ++ * di_read_lock_child, di_write_lock_child, ++ * di_read_lock_child2, di_write_lock_child2, ++ * di_read_lock_child3, di_write_lock_child3, ++ * di_read_lock_parent, di_write_lock_parent, ++ * di_read_lock_parent2, di_write_lock_parent2, ++ * di_read_lock_parent3, di_write_lock_parent3, ++ */ ++#define AuReadLockFunc(name, lsc) \ ++static inline void di_read_lock_##name(struct dentry *d, int flags) \ ++{ di_read_lock(d, flags, AuLsc_DI_##lsc); } ++ ++#define AuWriteLockFunc(name, lsc) \ ++static inline void di_write_lock_##name(struct dentry *d) \ ++{ di_write_lock(d, AuLsc_DI_##lsc); } ++ ++#define AuRWLockFuncs(name, lsc) \ ++ AuReadLockFunc(name, lsc) \ ++ AuWriteLockFunc(name, lsc) ++ ++AuRWLockFuncs(child, CHILD); ++AuRWLockFuncs(child2, CHILD2); ++AuRWLockFuncs(child3, CHILD3); ++AuRWLockFuncs(parent, PARENT); ++AuRWLockFuncs(parent2, PARENT2); ++AuRWLockFuncs(parent3, PARENT3); ++ ++#undef AuReadLockFunc ++#undef AuWriteLockFunc ++#undef AuRWLockFuncs ++ ++#define DiMustNoWaiters(d) AuRwMustNoWaiters(&au_di(d)->di_rwsem) ++#define DiMustAnyLock(d) AuRwMustAnyLock(&au_di(d)->di_rwsem) ++#define DiMustWriteLock(d) AuRwMustWriteLock(&au_di(d)->di_rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* todo: memory barrier? */ ++static inline unsigned int au_digen(struct dentry *d) ++{ ++ return atomic_read(&au_di(d)->di_generation); ++} ++ ++static inline void au_h_dentry_init(struct au_hdentry *hdentry) ++{ ++ hdentry->hd_dentry = NULL; ++} ++ ++static inline struct au_hdentry *au_hdentry(struct au_dinfo *di, ++ aufs_bindex_t bindex) ++{ ++ return di->di_hdentry + bindex; ++} ++ ++static inline void au_hdput(struct au_hdentry *hd) ++{ ++ if (hd) ++ dput(hd->hd_dentry); ++} ++ ++static inline aufs_bindex_t au_dbtop(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_btop; ++} ++ ++static inline aufs_bindex_t au_dbbot(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_bbot; ++} ++ ++static inline aufs_bindex_t au_dbwh(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_bwh; ++} ++ ++static inline aufs_bindex_t au_dbdiropq(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_bdiropq; ++} ++ ++/* todo: hard/soft set? */ ++static inline void au_set_dbtop(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ au_di(dentry)->di_btop = bindex; ++} ++ ++static inline void au_set_dbbot(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ au_di(dentry)->di_bbot = bindex; ++} ++ ++static inline void au_set_dbwh(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ /* dbwh can be outside of btop - bbot range */ ++ au_di(dentry)->di_bwh = bindex; ++} ++ ++static inline void au_set_dbdiropq(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ au_di(dentry)->di_bdiropq = bindex; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_HNOTIFY ++static inline void au_digen_dec(struct dentry *d) ++{ ++ atomic_dec(&au_di(d)->di_generation); ++} ++ ++static inline void au_hn_di_reinit(struct dentry *dentry) ++{ ++ dentry->d_fsdata = NULL; ++} ++#else ++AuStubVoid(au_hn_di_reinit, struct dentry *dentry __maybe_unused) ++#endif /* CONFIG_AUFS_HNOTIFY */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DENTRY_H__ */ +diff -Nurp linux-5.4/fs/aufs/dinfo.c linux-5.4-aufs/fs/aufs/dinfo.c +--- linux-5.4/fs/aufs/dinfo.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/dinfo.c 2019-11-28 01:25:59.063925618 +0200 +@@ -0,0 +1,541 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * dentry private data ++ */ ++ ++#include "aufs.h" ++ ++void au_di_init_once(void *_dinfo) ++{ ++ struct au_dinfo *dinfo = _dinfo; ++ ++ au_rw_init(&dinfo->di_rwsem); ++} ++ ++struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc) ++{ ++ struct au_dinfo *dinfo; ++ int nbr, i; ++ ++ dinfo = au_cache_alloc_dinfo(); ++ if (unlikely(!dinfo)) ++ goto out; ++ ++ nbr = au_sbbot(sb) + 1; ++ if (nbr <= 0) ++ nbr = 1; ++ dinfo->di_hdentry = kcalloc(nbr, sizeof(*dinfo->di_hdentry), GFP_NOFS); ++ if (dinfo->di_hdentry) { ++ au_rw_write_lock_nested(&dinfo->di_rwsem, lsc); ++ dinfo->di_btop = -1; ++ dinfo->di_bbot = -1; ++ dinfo->di_bwh = -1; ++ dinfo->di_bdiropq = -1; ++ dinfo->di_tmpfile = 0; ++ for (i = 0; i < nbr; i++) ++ dinfo->di_hdentry[i].hd_id = -1; ++ goto out; ++ } ++ ++ au_cache_free_dinfo(dinfo); ++ dinfo = NULL; ++ ++out: ++ return dinfo; ++} ++ ++void au_di_free(struct au_dinfo *dinfo) ++{ ++ struct au_hdentry *p; ++ aufs_bindex_t bbot, bindex; ++ ++ /* dentry may not be revalidated */ ++ bindex = dinfo->di_btop; ++ if (bindex >= 0) { ++ bbot = dinfo->di_bbot; ++ p = au_hdentry(dinfo, bindex); ++ while (bindex++ <= bbot) ++ au_hdput(p++); ++ } ++ au_kfree_try_rcu(dinfo->di_hdentry); ++ au_cache_free_dinfo(dinfo); ++} ++ ++void au_di_swap(struct au_dinfo *a, struct au_dinfo *b) ++{ ++ struct au_hdentry *p; ++ aufs_bindex_t bi; ++ ++ AuRwMustWriteLock(&a->di_rwsem); ++ AuRwMustWriteLock(&b->di_rwsem); ++ ++#define DiSwap(v, name) \ ++ do { \ ++ v = a->di_##name; \ ++ a->di_##name = b->di_##name; \ ++ b->di_##name = v; \ ++ } while (0) ++ ++ DiSwap(p, hdentry); ++ DiSwap(bi, btop); ++ DiSwap(bi, bbot); ++ DiSwap(bi, bwh); ++ DiSwap(bi, bdiropq); ++ /* smp_mb(); */ ++ ++#undef DiSwap ++} ++ ++void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src) ++{ ++ AuRwMustWriteLock(&dst->di_rwsem); ++ AuRwMustWriteLock(&src->di_rwsem); ++ ++ dst->di_btop = src->di_btop; ++ dst->di_bbot = src->di_bbot; ++ dst->di_bwh = src->di_bwh; ++ dst->di_bdiropq = src->di_bdiropq; ++ /* smp_mb(); */ ++} ++ ++int au_di_init(struct dentry *dentry) ++{ ++ int err; ++ struct super_block *sb; ++ struct au_dinfo *dinfo; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ dinfo = au_di_alloc(sb, AuLsc_DI_CHILD); ++ if (dinfo) { ++ atomic_set(&dinfo->di_generation, au_sigen(sb)); ++ /* smp_mb(); */ /* atomic_set */ ++ dentry->d_fsdata = dinfo; ++ } else ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++void au_di_fin(struct dentry *dentry) ++{ ++ struct au_dinfo *dinfo; ++ ++ dinfo = au_di(dentry); ++ AuRwDestroy(&dinfo->di_rwsem); ++ au_di_free(dinfo); ++} ++ ++int au_di_realloc(struct au_dinfo *dinfo, int nbr, int may_shrink) ++{ ++ int err, sz; ++ struct au_hdentry *hdp; ++ ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ err = -ENOMEM; ++ sz = sizeof(*hdp) * (dinfo->di_bbot + 1); ++ if (!sz) ++ sz = sizeof(*hdp); ++ hdp = au_kzrealloc(dinfo->di_hdentry, sz, sizeof(*hdp) * nbr, GFP_NOFS, ++ may_shrink); ++ if (hdp) { ++ dinfo->di_hdentry = hdp; ++ err = 0; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void do_ii_write_lock(struct inode *inode, unsigned int lsc) ++{ ++ switch (lsc) { ++ case AuLsc_DI_CHILD: ++ ii_write_lock_child(inode); ++ break; ++ case AuLsc_DI_CHILD2: ++ ii_write_lock_child2(inode); ++ break; ++ case AuLsc_DI_CHILD3: ++ ii_write_lock_child3(inode); ++ break; ++ case AuLsc_DI_PARENT: ++ ii_write_lock_parent(inode); ++ break; ++ case AuLsc_DI_PARENT2: ++ ii_write_lock_parent2(inode); ++ break; ++ case AuLsc_DI_PARENT3: ++ ii_write_lock_parent3(inode); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++static void do_ii_read_lock(struct inode *inode, unsigned int lsc) ++{ ++ switch (lsc) { ++ case AuLsc_DI_CHILD: ++ ii_read_lock_child(inode); ++ break; ++ case AuLsc_DI_CHILD2: ++ ii_read_lock_child2(inode); ++ break; ++ case AuLsc_DI_CHILD3: ++ ii_read_lock_child3(inode); ++ break; ++ case AuLsc_DI_PARENT: ++ ii_read_lock_parent(inode); ++ break; ++ case AuLsc_DI_PARENT2: ++ ii_read_lock_parent2(inode); ++ break; ++ case AuLsc_DI_PARENT3: ++ ii_read_lock_parent3(inode); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++void di_read_lock(struct dentry *d, int flags, unsigned int lsc) ++{ ++ struct inode *inode; ++ ++ au_rw_read_lock_nested(&au_di(d)->di_rwsem, lsc); ++ if (d_really_is_positive(d)) { ++ inode = d_inode(d); ++ if (au_ftest_lock(flags, IW)) ++ do_ii_write_lock(inode, lsc); ++ else if (au_ftest_lock(flags, IR)) ++ do_ii_read_lock(inode, lsc); ++ } ++} ++ ++void di_read_unlock(struct dentry *d, int flags) ++{ ++ struct inode *inode; ++ ++ if (d_really_is_positive(d)) { ++ inode = d_inode(d); ++ if (au_ftest_lock(flags, IW)) { ++ au_dbg_verify_dinode(d); ++ ii_write_unlock(inode); ++ } else if (au_ftest_lock(flags, IR)) { ++ au_dbg_verify_dinode(d); ++ ii_read_unlock(inode); ++ } ++ } ++ au_rw_read_unlock(&au_di(d)->di_rwsem); ++} ++ ++void di_downgrade_lock(struct dentry *d, int flags) ++{ ++ if (d_really_is_positive(d) && au_ftest_lock(flags, IR)) ++ ii_downgrade_lock(d_inode(d)); ++ au_rw_dgrade_lock(&au_di(d)->di_rwsem); ++} ++ ++void di_write_lock(struct dentry *d, unsigned int lsc) ++{ ++ au_rw_write_lock_nested(&au_di(d)->di_rwsem, lsc); ++ if (d_really_is_positive(d)) ++ do_ii_write_lock(d_inode(d), lsc); ++} ++ ++void di_write_unlock(struct dentry *d) ++{ ++ au_dbg_verify_dinode(d); ++ if (d_really_is_positive(d)) ++ ii_write_unlock(d_inode(d)); ++ au_rw_write_unlock(&au_di(d)->di_rwsem); ++} ++ ++void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir) ++{ ++ AuDebugOn(d1 == d2 ++ || d_inode(d1) == d_inode(d2) ++ || d1->d_sb != d2->d_sb); ++ ++ if ((isdir && au_test_subdir(d1, d2)) ++ || d1 < d2) { ++ di_write_lock_child(d1); ++ di_write_lock_child2(d2); ++ } else { ++ di_write_lock_child(d2); ++ di_write_lock_child2(d1); ++ } ++} ++ ++void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir) ++{ ++ AuDebugOn(d1 == d2 ++ || d_inode(d1) == d_inode(d2) ++ || d1->d_sb != d2->d_sb); ++ ++ if ((isdir && au_test_subdir(d1, d2)) ++ || d1 < d2) { ++ di_write_lock_parent(d1); ++ di_write_lock_parent2(d2); ++ } else { ++ di_write_lock_parent(d2); ++ di_write_lock_parent2(d1); ++ } ++} ++ ++void di_write_unlock2(struct dentry *d1, struct dentry *d2) ++{ ++ di_write_unlock(d1); ++ if (d_inode(d1) == d_inode(d2)) ++ au_rw_write_unlock(&au_di(d2)->di_rwsem); ++ else ++ di_write_unlock(d2); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ struct dentry *d; ++ ++ DiMustAnyLock(dentry); ++ ++ if (au_dbtop(dentry) < 0 || bindex < au_dbtop(dentry)) ++ return NULL; ++ AuDebugOn(bindex < 0); ++ d = au_hdentry(au_di(dentry), bindex)->hd_dentry; ++ AuDebugOn(d && au_dcount(d) <= 0); ++ return d; ++} ++ ++/* ++ * extended version of au_h_dptr(). ++ * returns a hashed and positive (or linkable) h_dentry in bindex, NULL, or ++ * error. ++ */ ++struct dentry *au_h_d_alias(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ struct dentry *h_dentry; ++ struct inode *inode, *h_inode; ++ ++ AuDebugOn(d_really_is_negative(dentry)); ++ ++ h_dentry = NULL; ++ if (au_dbtop(dentry) <= bindex ++ && bindex <= au_dbbot(dentry)) ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && !au_d_linkable(h_dentry)) { ++ dget(h_dentry); ++ goto out; /* success */ ++ } ++ ++ inode = d_inode(dentry); ++ AuDebugOn(bindex < au_ibtop(inode)); ++ AuDebugOn(au_ibbot(inode) < bindex); ++ h_inode = au_h_iptr(inode, bindex); ++ h_dentry = d_find_alias(h_inode); ++ if (h_dentry) { ++ if (!IS_ERR(h_dentry)) { ++ if (!au_d_linkable(h_dentry)) ++ goto out; /* success */ ++ dput(h_dentry); ++ } else ++ goto out; ++ } ++ ++ if (au_opt_test(au_mntflags(dentry->d_sb), PLINK)) { ++ h_dentry = au_plink_lkup(inode, bindex); ++ AuDebugOn(!h_dentry); ++ if (!IS_ERR(h_dentry)) { ++ if (!au_d_hashed_positive(h_dentry)) ++ goto out; /* success */ ++ dput(h_dentry); ++ h_dentry = NULL; ++ } ++ } ++ ++out: ++ AuDbgDentry(h_dentry); ++ return h_dentry; ++} ++ ++aufs_bindex_t au_dbtail(struct dentry *dentry) ++{ ++ aufs_bindex_t bbot, bwh; ++ ++ bbot = au_dbbot(dentry); ++ if (0 <= bbot) { ++ bwh = au_dbwh(dentry); ++ if (!bwh) ++ return bwh; ++ if (0 < bwh && bwh < bbot) ++ return bwh - 1; ++ } ++ return bbot; ++} ++ ++aufs_bindex_t au_dbtaildir(struct dentry *dentry) ++{ ++ aufs_bindex_t bbot, bopq; ++ ++ bbot = au_dbtail(dentry); ++ if (0 <= bbot) { ++ bopq = au_dbdiropq(dentry); ++ if (0 <= bopq && bopq < bbot) ++ bbot = bopq; ++ } ++ return bbot; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_dentry) ++{ ++ struct au_dinfo *dinfo; ++ struct au_hdentry *hd; ++ struct au_branch *br; ++ ++ DiMustWriteLock(dentry); ++ ++ dinfo = au_di(dentry); ++ hd = au_hdentry(dinfo, bindex); ++ au_hdput(hd); ++ hd->hd_dentry = h_dentry; ++ if (h_dentry) { ++ br = au_sbr(dentry->d_sb, bindex); ++ hd->hd_id = br->br_id; ++ } ++} ++ ++int au_dbrange_test(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t btop, bbot; ++ ++ err = 0; ++ btop = au_dbtop(dentry); ++ bbot = au_dbbot(dentry); ++ if (btop >= 0) ++ AuDebugOn(bbot < 0 && btop > bbot); ++ else { ++ err = -EIO; ++ AuDebugOn(bbot >= 0); ++ } ++ ++ return err; ++} ++ ++int au_digen_test(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ ++ err = 0; ++ if (unlikely(au_digen(dentry) != sigen ++ || au_iigen_test(d_inode(dentry), sigen))) ++ err = -EIO; ++ ++ return err; ++} ++ ++void au_update_digen(struct dentry *dentry) ++{ ++ atomic_set(&au_di(dentry)->di_generation, au_sigen(dentry->d_sb)); ++ /* smp_mb(); */ /* atomic_set */ ++} ++ ++void au_update_dbrange(struct dentry *dentry, int do_put_zero) ++{ ++ struct au_dinfo *dinfo; ++ struct dentry *h_d; ++ struct au_hdentry *hdp; ++ aufs_bindex_t bindex, bbot; ++ ++ DiMustWriteLock(dentry); ++ ++ dinfo = au_di(dentry); ++ if (!dinfo || dinfo->di_btop < 0) ++ return; ++ ++ if (do_put_zero) { ++ bbot = dinfo->di_bbot; ++ bindex = dinfo->di_btop; ++ hdp = au_hdentry(dinfo, bindex); ++ for (; bindex <= bbot; bindex++, hdp++) { ++ h_d = hdp->hd_dentry; ++ if (h_d && d_is_negative(h_d)) ++ au_set_h_dptr(dentry, bindex, NULL); ++ } ++ } ++ ++ dinfo->di_btop = 0; ++ hdp = au_hdentry(dinfo, dinfo->di_btop); ++ for (; dinfo->di_btop <= dinfo->di_bbot; dinfo->di_btop++, hdp++) ++ if (hdp->hd_dentry) ++ break; ++ if (dinfo->di_btop > dinfo->di_bbot) { ++ dinfo->di_btop = -1; ++ dinfo->di_bbot = -1; ++ return; ++ } ++ ++ hdp = au_hdentry(dinfo, dinfo->di_bbot); ++ for (; dinfo->di_bbot >= 0; dinfo->di_bbot--, hdp--) ++ if (hdp->hd_dentry) ++ break; ++ AuDebugOn(dinfo->di_btop > dinfo->di_bbot || dinfo->di_bbot < 0); ++} ++ ++void au_update_dbtop(struct dentry *dentry) ++{ ++ aufs_bindex_t bindex, bbot; ++ struct dentry *h_dentry; ++ ++ bbot = au_dbbot(dentry); ++ for (bindex = au_dbtop(dentry); bindex <= bbot; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ if (d_is_positive(h_dentry)) { ++ au_set_dbtop(dentry, bindex); ++ return; ++ } ++ au_set_h_dptr(dentry, bindex, NULL); ++ } ++} ++ ++void au_update_dbbot(struct dentry *dentry) ++{ ++ aufs_bindex_t bindex, btop; ++ struct dentry *h_dentry; ++ ++ btop = au_dbtop(dentry); ++ for (bindex = au_dbbot(dentry); bindex >= btop; bindex--) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ if (d_is_positive(h_dentry)) { ++ au_set_dbbot(dentry, bindex); ++ return; ++ } ++ au_set_h_dptr(dentry, bindex, NULL); ++ } ++} ++ ++int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry) ++{ ++ aufs_bindex_t bindex, bbot; ++ ++ bbot = au_dbbot(dentry); ++ for (bindex = au_dbtop(dentry); bindex <= bbot; bindex++) ++ if (au_h_dptr(dentry, bindex) == h_dentry) ++ return bindex; ++ return -1; ++} +diff -Nurp linux-5.4/fs/aufs/dir.c linux-5.4-aufs/fs/aufs/dir.c +--- linux-5.4/fs/aufs/dir.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/dir.c 2019-11-28 01:25:59.064925618 +0200 +@@ -0,0 +1,750 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * directory operations ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++void au_add_nlink(struct inode *dir, struct inode *h_dir) ++{ ++ unsigned int nlink; ++ ++ AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); ++ ++ nlink = dir->i_nlink; ++ nlink += h_dir->i_nlink - 2; ++ if (h_dir->i_nlink < 2) ++ nlink += 2; ++ smp_mb(); /* for i_nlink */ ++ /* 0 can happen in revaliding */ ++ set_nlink(dir, nlink); ++} ++ ++void au_sub_nlink(struct inode *dir, struct inode *h_dir) ++{ ++ unsigned int nlink; ++ ++ AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); ++ ++ nlink = dir->i_nlink; ++ nlink -= h_dir->i_nlink - 2; ++ if (h_dir->i_nlink < 2) ++ nlink -= 2; ++ smp_mb(); /* for i_nlink */ ++ /* nlink == 0 means the branch-fs is broken */ ++ set_nlink(dir, nlink); ++} ++ ++loff_t au_dir_size(struct file *file, struct dentry *dentry) ++{ ++ loff_t sz; ++ aufs_bindex_t bindex, bbot; ++ struct file *h_file; ++ struct dentry *h_dentry; ++ ++ sz = 0; ++ if (file) { ++ AuDebugOn(!d_is_dir(file->f_path.dentry)); ++ ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); ++ bindex <= bbot && sz < KMALLOC_MAX_SIZE; ++ bindex++) { ++ h_file = au_hf_dir(file, bindex); ++ if (h_file && file_inode(h_file)) ++ sz += vfsub_f_size_read(h_file); ++ } ++ } else { ++ AuDebugOn(!dentry); ++ AuDebugOn(!d_is_dir(dentry)); ++ ++ bbot = au_dbtaildir(dentry); ++ for (bindex = au_dbtop(dentry); ++ bindex <= bbot && sz < KMALLOC_MAX_SIZE; ++ bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && d_is_positive(h_dentry)) ++ sz += i_size_read(d_inode(h_dentry)); ++ } ++ } ++ if (sz < KMALLOC_MAX_SIZE) ++ sz = roundup_pow_of_two(sz); ++ if (sz > KMALLOC_MAX_SIZE) ++ sz = KMALLOC_MAX_SIZE; ++ else if (sz < NAME_MAX) { ++ BUILD_BUG_ON(AUFS_RDBLK_DEF < NAME_MAX); ++ sz = AUFS_RDBLK_DEF; ++ } ++ return sz; ++} ++ ++struct au_dir_ts_arg { ++ struct dentry *dentry; ++ aufs_bindex_t brid; ++}; ++ ++static void au_do_dir_ts(void *arg) ++{ ++ struct au_dir_ts_arg *a = arg; ++ struct au_dtime dt; ++ struct path h_path; ++ struct inode *dir, *h_dir; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_hinode *hdir; ++ int err; ++ aufs_bindex_t btop, bindex; ++ ++ sb = a->dentry->d_sb; ++ if (d_really_is_negative(a->dentry)) ++ goto out; ++ /* no dir->i_mutex lock */ ++ aufs_read_lock(a->dentry, AuLock_DW); /* noflush */ ++ ++ dir = d_inode(a->dentry); ++ btop = au_ibtop(dir); ++ bindex = au_br_index(sb, a->brid); ++ if (bindex < btop) ++ goto out_unlock; ++ ++ br = au_sbr(sb, bindex); ++ h_path.dentry = au_h_dptr(a->dentry, bindex); ++ if (!h_path.dentry) ++ goto out_unlock; ++ h_path.mnt = au_br_mnt(br); ++ au_dtime_store(&dt, a->dentry, &h_path); ++ ++ br = au_sbr(sb, btop); ++ if (!au_br_writable(br->br_perm)) ++ goto out_unlock; ++ h_path.dentry = au_h_dptr(a->dentry, btop); ++ h_path.mnt = au_br_mnt(br); ++ err = vfsub_mnt_want_write(h_path.mnt); ++ if (err) ++ goto out_unlock; ++ hdir = au_hi(dir, btop); ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ h_dir = au_h_iptr(dir, btop); ++ if (h_dir->i_nlink ++ && timespec64_compare(&h_dir->i_mtime, &dt.dt_mtime) < 0) { ++ dt.dt_h_path = h_path; ++ au_dtime_revert(&dt); ++ } ++ au_hn_inode_unlock(hdir); ++ vfsub_mnt_drop_write(h_path.mnt); ++ au_cpup_attr_timesizes(dir); ++ ++out_unlock: ++ aufs_read_unlock(a->dentry, AuLock_DW); ++out: ++ dput(a->dentry); ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ au_kfree_try_rcu(arg); ++} ++ ++void au_dir_ts(struct inode *dir, aufs_bindex_t bindex) ++{ ++ int perm, wkq_err; ++ aufs_bindex_t btop; ++ struct au_dir_ts_arg *arg; ++ struct dentry *dentry; ++ struct super_block *sb; ++ ++ IMustLock(dir); ++ ++ dentry = d_find_any_alias(dir); ++ AuDebugOn(!dentry); ++ sb = dentry->d_sb; ++ btop = au_ibtop(dir); ++ if (btop == bindex) { ++ au_cpup_attr_timesizes(dir); ++ goto out; ++ } ++ ++ perm = au_sbr_perm(sb, btop); ++ if (!au_br_writable(perm)) ++ goto out; ++ ++ arg = kmalloc(sizeof(*arg), GFP_NOFS); ++ if (!arg) ++ goto out; ++ ++ arg->dentry = dget(dentry); /* will be dput-ted by au_do_dir_ts() */ ++ arg->brid = au_sbr_id(sb, bindex); ++ wkq_err = au_wkq_nowait(au_do_dir_ts, arg, sb, /*flags*/0); ++ if (unlikely(wkq_err)) { ++ pr_err("wkq %d\n", wkq_err); ++ dput(dentry); ++ au_kfree_try_rcu(arg); ++ } ++ ++out: ++ dput(dentry); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int reopen_dir(struct file *file) ++{ ++ int err; ++ unsigned int flags; ++ aufs_bindex_t bindex, btail, btop; ++ struct dentry *dentry, *h_dentry; ++ struct file *h_file; ++ ++ /* open all lower dirs */ ++ dentry = file->f_path.dentry; ++ btop = au_dbtop(dentry); ++ for (bindex = au_fbtop(file); bindex < btop; bindex++) ++ au_set_h_fptr(file, bindex, NULL); ++ au_set_fbtop(file, btop); ++ ++ btail = au_dbtaildir(dentry); ++ for (bindex = au_fbbot_dir(file); btail < bindex; bindex--) ++ au_set_h_fptr(file, bindex, NULL); ++ au_set_fbbot_dir(file, btail); ++ ++ flags = vfsub_file_flags(file); ++ for (bindex = btop; bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ h_file = au_hf_dir(file, bindex); ++ if (h_file) ++ continue; ++ ++ h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; /* close all? */ ++ au_set_h_fptr(file, bindex, h_file); ++ } ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ err = 0; ++ ++out: ++ return err; ++} ++ ++static int do_open_dir(struct file *file, int flags, struct file *h_file) ++{ ++ int err; ++ aufs_bindex_t bindex, btail; ++ struct dentry *dentry, *h_dentry; ++ struct vfsmount *mnt; ++ ++ FiMustWriteLock(file); ++ AuDebugOn(h_file); ++ ++ err = 0; ++ mnt = file->f_path.mnt; ++ dentry = file->f_path.dentry; ++ file->f_version = inode_query_iversion(d_inode(dentry)); ++ bindex = au_dbtop(dentry); ++ au_set_fbtop(file, bindex); ++ btail = au_dbtaildir(dentry); ++ au_set_fbbot_dir(file, btail); ++ for (; !err && bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ ++ err = vfsub_test_mntns(mnt, h_dentry->d_sb); ++ if (unlikely(err)) ++ break; ++ h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); ++ if (IS_ERR(h_file)) { ++ err = PTR_ERR(h_file); ++ break; ++ } ++ au_set_h_fptr(file, bindex, h_file); ++ } ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ if (!err) ++ return 0; /* success */ ++ ++ /* close all */ ++ for (bindex = au_fbtop(file); bindex <= btail; bindex++) ++ au_set_h_fptr(file, bindex, NULL); ++ au_set_fbtop(file, -1); ++ au_set_fbbot_dir(file, -1); ++ ++ return err; ++} ++ ++static int aufs_open_dir(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ int err; ++ struct super_block *sb; ++ struct au_fidir *fidir; ++ ++ err = -ENOMEM; ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ fidir = au_fidir_alloc(sb); ++ if (fidir) { ++ struct au_do_open_args args = { ++ .open = do_open_dir, ++ .fidir = fidir ++ }; ++ err = au_do_open(file, &args); ++ if (unlikely(err)) ++ au_kfree_rcu(fidir); ++ } ++ si_read_unlock(sb); ++ return err; ++} ++ ++static int aufs_release_dir(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ struct au_vdir *vdir_cache; ++ struct au_finfo *finfo; ++ struct au_fidir *fidir; ++ struct au_hfile *hf; ++ aufs_bindex_t bindex, bbot; ++ ++ finfo = au_fi(file); ++ fidir = finfo->fi_hdir; ++ if (fidir) { ++ au_hbl_del(&finfo->fi_hlist, ++ &au_sbi(file->f_path.dentry->d_sb)->si_files); ++ vdir_cache = fidir->fd_vdir_cache; /* lock-free */ ++ if (vdir_cache) ++ au_vdir_free(vdir_cache); ++ ++ bindex = finfo->fi_btop; ++ if (bindex >= 0) { ++ hf = fidir->fd_hfile + bindex; ++ /* ++ * calls fput() instead of filp_close(), ++ * since no dnotify or lock for the lower file. ++ */ ++ bbot = fidir->fd_bbot; ++ for (; bindex <= bbot; bindex++, hf++) ++ if (hf->hf_file) ++ au_hfput(hf, /*execed*/0); ++ } ++ au_kfree_rcu(fidir); ++ finfo->fi_hdir = NULL; ++ } ++ au_finfo_fin(file); ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_flush_dir(struct file *file, fl_owner_t id) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct file *h_file; ++ ++ err = 0; ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); !err && bindex <= bbot; bindex++) { ++ h_file = au_hf_dir(file, bindex); ++ if (h_file) ++ err = vfsub_flush(h_file, id); ++ } ++ return err; ++} ++ ++static int aufs_flush_dir(struct file *file, fl_owner_t id) ++{ ++ return au_do_flush(file, id, au_do_flush_dir); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_fsync_dir_no_file(struct dentry *dentry, int datasync) ++{ ++ int err; ++ aufs_bindex_t bbot, bindex; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ bbot = au_dbbot(dentry); ++ for (bindex = au_dbtop(dentry); !err && bindex <= bbot; bindex++) { ++ struct path h_path; ++ ++ if (au_test_ro(sb, bindex, inode)) ++ continue; ++ h_path.dentry = au_h_dptr(dentry, bindex); ++ if (!h_path.dentry) ++ continue; ++ ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ err = vfsub_fsync(NULL, &h_path, datasync); ++ } ++ ++ return err; ++} ++ ++static int au_do_fsync_dir(struct file *file, int datasync) ++{ ++ int err; ++ aufs_bindex_t bbot, bindex; ++ struct file *h_file; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1, /*fi_lsc*/0); ++ if (unlikely(err)) ++ goto out; ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); !err && bindex <= bbot; bindex++) { ++ h_file = au_hf_dir(file, bindex); ++ if (!h_file || au_test_ro(sb, bindex, inode)) ++ continue; ++ ++ err = vfsub_fsync(h_file, &h_file->f_path, datasync); ++ } ++ ++out: ++ return err; ++} ++ ++/* ++ * @file may be NULL ++ */ ++static int aufs_fsync_dir(struct file *file, loff_t start, loff_t end, ++ int datasync) ++{ ++ int err; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ err = 0; ++ dentry = file->f_path.dentry; ++ inode = d_inode(dentry); ++ inode_lock(inode); ++ sb = dentry->d_sb; ++ si_noflush_read_lock(sb); ++ if (file) ++ err = au_do_fsync_dir(file, datasync); ++ else { ++ di_write_lock_child(dentry); ++ err = au_do_fsync_dir_no_file(dentry, datasync); ++ } ++ au_cpup_attr_timesizes(inode); ++ di_write_unlock(dentry); ++ if (file) ++ fi_write_unlock(file); ++ ++ si_read_unlock(sb); ++ inode_unlock(inode); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_iterate_shared(struct file *file, struct dir_context *ctx) ++{ ++ int err; ++ struct dentry *dentry; ++ struct inode *inode, *h_inode; ++ struct super_block *sb; ++ ++ AuDbg("%pD, ctx{%ps, %llu}\n", file, ctx->actor, ctx->pos); ++ ++ dentry = file->f_path.dentry; ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ ++ sb = dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1, /*fi_lsc*/0); ++ if (unlikely(err)) ++ goto out; ++ err = au_alive_dir(dentry); ++ if (!err) ++ err = au_vdir_init(file); ++ di_downgrade_lock(dentry, AuLock_IR); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ if (!au_test_nfsd()) { ++ err = au_vdir_fill_de(file, ctx); ++ fsstack_copy_attr_atime(inode, h_inode); ++ } else { ++ /* ++ * nfsd filldir may call lookup_one_len(), vfs_getattr(), ++ * encode_fh() and others. ++ */ ++ atomic_inc(&h_inode->i_count); ++ di_read_unlock(dentry, AuLock_IR); ++ si_read_unlock(sb); ++ err = au_vdir_fill_de(file, ctx); ++ fsstack_copy_attr_atime(inode, h_inode); ++ fi_write_unlock(file); ++ iput(h_inode); ++ ++ AuTraceErr(err); ++ return err; ++ } ++ ++out_unlock: ++ di_read_unlock(dentry, AuLock_IR); ++ fi_write_unlock(file); ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AuTestEmpty_WHONLY 1 ++#define AuTestEmpty_CALLED (1 << 1) ++#define AuTestEmpty_SHWH (1 << 2) ++#define au_ftest_testempty(flags, name) ((flags) & AuTestEmpty_##name) ++#define au_fset_testempty(flags, name) \ ++ do { (flags) |= AuTestEmpty_##name; } while (0) ++#define au_fclr_testempty(flags, name) \ ++ do { (flags) &= ~AuTestEmpty_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_SHWH ++#undef AuTestEmpty_SHWH ++#define AuTestEmpty_SHWH 0 ++#endif ++ ++struct test_empty_arg { ++ struct dir_context ctx; ++ struct au_nhash *whlist; ++ unsigned int flags; ++ int err; ++ aufs_bindex_t bindex; ++}; ++ ++static int test_empty_cb(struct dir_context *ctx, const char *__name, ++ int namelen, loff_t offset __maybe_unused, u64 ino, ++ unsigned int d_type) ++{ ++ struct test_empty_arg *arg = container_of(ctx, struct test_empty_arg, ++ ctx); ++ char *name = (void *)__name; ++ ++ arg->err = 0; ++ au_fset_testempty(arg->flags, CALLED); ++ /* smp_mb(); */ ++ if (name[0] == '.' ++ && (namelen == 1 || (name[1] == '.' && namelen == 2))) ++ goto out; /* success */ ++ ++ if (namelen <= AUFS_WH_PFX_LEN ++ || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { ++ if (au_ftest_testempty(arg->flags, WHONLY) ++ && !au_nhash_test_known_wh(arg->whlist, name, namelen)) ++ arg->err = -ENOTEMPTY; ++ goto out; ++ } ++ ++ name += AUFS_WH_PFX_LEN; ++ namelen -= AUFS_WH_PFX_LEN; ++ if (!au_nhash_test_known_wh(arg->whlist, name, namelen)) ++ arg->err = au_nhash_append_wh ++ (arg->whlist, name, namelen, ino, d_type, arg->bindex, ++ au_ftest_testempty(arg->flags, SHWH)); ++ ++out: ++ /* smp_mb(); */ ++ AuTraceErr(arg->err); ++ return arg->err; ++} ++ ++static int do_test_empty(struct dentry *dentry, struct test_empty_arg *arg) ++{ ++ int err; ++ struct file *h_file; ++ struct au_branch *br; ++ ++ h_file = au_h_open(dentry, arg->bindex, ++ O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_LARGEFILE, ++ /*file*/NULL, /*force_wr*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = 0; ++ if (!au_opt_test(au_mntflags(dentry->d_sb), UDBA_NONE) ++ && !file_inode(h_file)->i_nlink) ++ goto out_put; ++ ++ do { ++ arg->err = 0; ++ au_fclr_testempty(arg->flags, CALLED); ++ /* smp_mb(); */ ++ err = vfsub_iterate_dir(h_file, &arg->ctx); ++ if (err >= 0) ++ err = arg->err; ++ } while (!err && au_ftest_testempty(arg->flags, CALLED)); ++ ++out_put: ++ fput(h_file); ++ br = au_sbr(dentry->d_sb, arg->bindex); ++ au_lcnt_dec(&br->br_nfiles); ++out: ++ return err; ++} ++ ++struct do_test_empty_args { ++ int *errp; ++ struct dentry *dentry; ++ struct test_empty_arg *arg; ++}; ++ ++static void call_do_test_empty(void *args) ++{ ++ struct do_test_empty_args *a = args; ++ *a->errp = do_test_empty(a->dentry, a->arg); ++} ++ ++static int sio_test_empty(struct dentry *dentry, struct test_empty_arg *arg) ++{ ++ int err, wkq_err; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ ++ h_dentry = au_h_dptr(dentry, arg->bindex); ++ h_inode = d_inode(h_dentry); ++ /* todo: i_mode changes anytime? */ ++ inode_lock_shared_nested(h_inode, AuLsc_I_CHILD); ++ err = au_test_h_perm_sio(h_inode, MAY_EXEC | MAY_READ); ++ inode_unlock_shared(h_inode); ++ if (!err) ++ err = do_test_empty(dentry, arg); ++ else { ++ struct do_test_empty_args args = { ++ .errp = &err, ++ .dentry = dentry, ++ .arg = arg ++ }; ++ unsigned int flags = arg->flags; ++ ++ wkq_err = au_wkq_wait(call_do_test_empty, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ arg->flags = flags; ++ } ++ ++ return err; ++} ++ ++int au_test_empty_lower(struct dentry *dentry) ++{ ++ int err; ++ unsigned int rdhash; ++ aufs_bindex_t bindex, btop, btail; ++ struct au_nhash whlist; ++ struct test_empty_arg arg = { ++ .ctx = { ++ .actor = test_empty_cb ++ } ++ }; ++ int (*test_empty)(struct dentry *dentry, struct test_empty_arg *arg); ++ ++ SiMustAnyLock(dentry->d_sb); ++ ++ rdhash = au_sbi(dentry->d_sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, dentry)); ++ err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ ++ arg.flags = 0; ++ arg.whlist = &whlist; ++ btop = au_dbtop(dentry); ++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)) ++ au_fset_testempty(arg.flags, SHWH); ++ test_empty = do_test_empty; ++ if (au_opt_test(au_mntflags(dentry->d_sb), DIRPERM1)) ++ test_empty = sio_test_empty; ++ arg.bindex = btop; ++ err = test_empty(dentry, &arg); ++ if (unlikely(err)) ++ goto out_whlist; ++ ++ au_fset_testempty(arg.flags, WHONLY); ++ btail = au_dbtaildir(dentry); ++ for (bindex = btop + 1; !err && bindex <= btail; bindex++) { ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && d_is_positive(h_dentry)) { ++ arg.bindex = bindex; ++ err = test_empty(dentry, &arg); ++ } ++ } ++ ++out_whlist: ++ au_nhash_wh_free(&whlist); ++out: ++ return err; ++} ++ ++int au_test_empty(struct dentry *dentry, struct au_nhash *whlist) ++{ ++ int err; ++ struct test_empty_arg arg = { ++ .ctx = { ++ .actor = test_empty_cb ++ } ++ }; ++ aufs_bindex_t bindex, btail; ++ ++ err = 0; ++ arg.whlist = whlist; ++ arg.flags = AuTestEmpty_WHONLY; ++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)) ++ au_fset_testempty(arg.flags, SHWH); ++ btail = au_dbtaildir(dentry); ++ for (bindex = au_dbtop(dentry); !err && bindex <= btail; bindex++) { ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && d_is_positive(h_dentry)) { ++ arg.bindex = bindex; ++ err = sio_test_empty(dentry, &arg); ++ } ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++const struct file_operations aufs_dir_fop = { ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++ .read = generic_read_dir, ++ .iterate_shared = aufs_iterate_shared, ++ .unlocked_ioctl = aufs_ioctl_dir, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = aufs_compat_ioctl_dir, ++#endif ++ .open = aufs_open_dir, ++ .release = aufs_release_dir, ++ .flush = aufs_flush_dir, ++ .fsync = aufs_fsync_dir ++}; +diff -Nurp linux-5.4/fs/aufs/dir.h linux-5.4-aufs/fs/aufs/dir.h +--- linux-5.4/fs/aufs/dir.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/dir.h 2019-11-28 01:25:59.064925618 +0200 +@@ -0,0 +1,121 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * directory operations ++ */ ++ ++#ifndef __AUFS_DIR_H__ ++#define __AUFS_DIR_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* need to be faster and smaller */ ++ ++struct au_nhash { ++ unsigned int nh_num; ++ struct hlist_head *nh_head; ++}; ++ ++struct au_vdir_destr { ++ unsigned char len; ++ unsigned char name[0]; ++} __packed; ++ ++struct au_vdir_dehstr { ++ struct hlist_node hash; ++ struct au_vdir_destr *str; ++ struct rcu_head rcu; ++} ____cacheline_aligned_in_smp; ++ ++struct au_vdir_de { ++ ino_t de_ino; ++ unsigned char de_type; ++ /* caution: packed */ ++ struct au_vdir_destr de_str; ++} __packed; ++ ++struct au_vdir_wh { ++ struct hlist_node wh_hash; ++#ifdef CONFIG_AUFS_SHWH ++ ino_t wh_ino; ++ aufs_bindex_t wh_bindex; ++ unsigned char wh_type; ++#else ++ aufs_bindex_t wh_bindex; ++#endif ++ /* caution: packed */ ++ struct au_vdir_destr wh_str; ++} __packed; ++ ++union au_vdir_deblk_p { ++ unsigned char *deblk; ++ struct au_vdir_de *de; ++}; ++ ++struct au_vdir { ++ unsigned char **vd_deblk; ++ unsigned long vd_nblk; ++ struct { ++ unsigned long ul; ++ union au_vdir_deblk_p p; ++ } vd_last; ++ ++ u64 vd_version; ++ unsigned int vd_deblk_sz; ++ unsigned long vd_jiffy; ++ struct rcu_head rcu; ++} ____cacheline_aligned_in_smp; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dir.c */ ++extern const struct file_operations aufs_dir_fop; ++void au_add_nlink(struct inode *dir, struct inode *h_dir); ++void au_sub_nlink(struct inode *dir, struct inode *h_dir); ++loff_t au_dir_size(struct file *file, struct dentry *dentry); ++void au_dir_ts(struct inode *dir, aufs_bindex_t bsrc); ++int au_test_empty_lower(struct dentry *dentry); ++int au_test_empty(struct dentry *dentry, struct au_nhash *whlist); ++ ++/* vdir.c */ ++unsigned int au_rdhash_est(loff_t sz); ++int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp); ++void au_nhash_wh_free(struct au_nhash *whlist); ++int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt, ++ int limit); ++int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen); ++int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino, ++ unsigned int d_type, aufs_bindex_t bindex, ++ unsigned char shwh); ++void au_vdir_free(struct au_vdir *vdir); ++int au_vdir_init(struct file *file); ++int au_vdir_fill_de(struct file *file, struct dir_context *ctx); ++ ++/* ioctl.c */ ++long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg); ++ ++#ifdef CONFIG_AUFS_RDU ++/* rdu.c */ ++long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg); ++#ifdef CONFIG_COMPAT ++long au_rdu_compat_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg); ++#endif ++#else ++AuStub(long, au_rdu_ioctl, return -EINVAL, struct file *file, ++ unsigned int cmd, unsigned long arg) ++#ifdef CONFIG_COMPAT ++AuStub(long, au_rdu_compat_ioctl, return -EINVAL, struct file *file, ++ unsigned int cmd, unsigned long arg) ++#endif ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DIR_H__ */ +diff -Nurp linux-5.4/fs/aufs/dirren.c linux-5.4-aufs/fs/aufs/dirren.c +--- linux-5.4/fs/aufs/dirren.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/dirren.c 2019-11-28 01:25:59.064925618 +0200 +@@ -0,0 +1,1303 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2017-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * special handling in renaming a directory ++ * in order to support looking-up the before-renamed name on the lower readonly ++ * branches ++ */ ++ ++#include ++#include "aufs.h" ++ ++static void au_dr_hino_del(struct au_dr_br *dr, struct au_dr_hino *ent) ++{ ++ int idx; ++ ++ idx = au_dr_ihash(ent->dr_h_ino); ++ au_hbl_del(&ent->dr_hnode, dr->dr_h_ino + idx); ++} ++ ++static int au_dr_hino_test_empty(struct au_dr_br *dr) ++{ ++ int ret, i; ++ struct hlist_bl_head *hbl; ++ ++ ret = 1; ++ for (i = 0; ret && i < AuDirren_NHASH; i++) { ++ hbl = dr->dr_h_ino + i; ++ hlist_bl_lock(hbl); ++ ret &= hlist_bl_empty(hbl); ++ hlist_bl_unlock(hbl); ++ } ++ ++ return ret; ++} ++ ++static struct au_dr_hino *au_dr_hino_find(struct au_dr_br *dr, ino_t ino) ++{ ++ struct au_dr_hino *found, *ent; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ int idx; ++ ++ found = NULL; ++ idx = au_dr_ihash(ino); ++ hbl = dr->dr_h_ino + idx; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(ent, pos, hbl, dr_hnode) ++ if (ent->dr_h_ino == ino) { ++ found = ent; ++ break; ++ } ++ hlist_bl_unlock(hbl); ++ ++ return found; ++} ++ ++int au_dr_hino_test_add(struct au_dr_br *dr, ino_t ino, ++ struct au_dr_hino *add_ent) ++{ ++ int found, idx; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_dr_hino *ent; ++ ++ found = 0; ++ idx = au_dr_ihash(ino); ++ hbl = dr->dr_h_ino + idx; ++#if 0 ++ { ++ struct hlist_bl_node *tmp; ++ ++ hlist_bl_for_each_entry_safe(ent, pos, tmp, hbl, dr_hnode) ++ AuDbg("hi%llu\n", (unsigned long long)ent->dr_h_ino); ++ } ++#endif ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(ent, pos, hbl, dr_hnode) ++ if (ent->dr_h_ino == ino) { ++ found = 1; ++ break; ++ } ++ if (!found && add_ent) ++ hlist_bl_add_head(&add_ent->dr_hnode, hbl); ++ hlist_bl_unlock(hbl); ++ ++ if (!found && add_ent) ++ AuDbg("i%llu added\n", (unsigned long long)add_ent->dr_h_ino); ++ ++ return found; ++} ++ ++void au_dr_hino_free(struct au_dr_br *dr) ++{ ++ int i; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos, *tmp; ++ struct au_dr_hino *ent; ++ ++ /* SiMustWriteLock(sb); */ ++ ++ for (i = 0; i < AuDirren_NHASH; i++) { ++ hbl = dr->dr_h_ino + i; ++ /* no spinlock since sbinfo must be write-locked */ ++ hlist_bl_for_each_entry_safe(ent, pos, tmp, hbl, dr_hnode) ++ au_kfree_rcu(ent); ++ INIT_HLIST_BL_HEAD(hbl); ++ } ++} ++ ++/* returns the number of inodes or an error */ ++static int au_dr_hino_store(struct super_block *sb, struct au_branch *br, ++ struct file *hinofile) ++{ ++ int err, i; ++ ssize_t ssz; ++ loff_t pos, oldsize; ++ __be64 u64; ++ struct inode *hinoinode; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *n1, *n2; ++ struct au_dr_hino *ent; ++ ++ SiMustWriteLock(sb); ++ AuDebugOn(!au_br_writable(br->br_perm)); ++ ++ hinoinode = file_inode(hinofile); ++ oldsize = i_size_read(hinoinode); ++ ++ err = 0; ++ pos = 0; ++ hbl = br->br_dirren.dr_h_ino; ++ for (i = 0; !err && i < AuDirren_NHASH; i++, hbl++) { ++ /* no bit-lock since sbinfo must be write-locked */ ++ hlist_bl_for_each_entry_safe(ent, n1, n2, hbl, dr_hnode) { ++ AuDbg("hi%llu, %pD2\n", ++ (unsigned long long)ent->dr_h_ino, hinofile); ++ u64 = cpu_to_be64(ent->dr_h_ino); ++ ssz = vfsub_write_k(hinofile, &u64, sizeof(u64), &pos); ++ if (ssz == sizeof(u64)) ++ continue; ++ ++ /* write error */ ++ pr_err("ssz %zd, %pD2\n", ssz, hinofile); ++ err = -ENOSPC; ++ if (ssz < 0) ++ err = ssz; ++ break; ++ } ++ } ++ /* regardless the error */ ++ if (pos < oldsize) { ++ err = vfsub_trunc(&hinofile->f_path, pos, /*attr*/0, hinofile); ++ AuTraceErr(err); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_dr_hino_load(struct au_dr_br *dr, struct file *hinofile) ++{ ++ int err, hidx; ++ ssize_t ssz; ++ size_t sz, n; ++ loff_t pos; ++ uint64_t u64; ++ struct au_dr_hino *ent; ++ struct inode *hinoinode; ++ struct hlist_bl_head *hbl; ++ ++ err = 0; ++ pos = 0; ++ hbl = dr->dr_h_ino; ++ hinoinode = file_inode(hinofile); ++ sz = i_size_read(hinoinode); ++ AuDebugOn(sz % sizeof(u64)); ++ n = sz / sizeof(u64); ++ while (n--) { ++ ssz = vfsub_read_k(hinofile, &u64, sizeof(u64), &pos); ++ if (unlikely(ssz != sizeof(u64))) { ++ pr_err("ssz %zd, %pD2\n", ssz, hinofile); ++ err = -EINVAL; ++ if (ssz < 0) ++ err = ssz; ++ goto out_free; ++ } ++ ++ ent = kmalloc(sizeof(*ent), GFP_NOFS); ++ if (!ent) { ++ err = -ENOMEM; ++ AuTraceErr(err); ++ goto out_free; ++ } ++ ent->dr_h_ino = be64_to_cpu((__force __be64)u64); ++ AuDbg("hi%llu, %pD2\n", ++ (unsigned long long)ent->dr_h_ino, hinofile); ++ hidx = au_dr_ihash(ent->dr_h_ino); ++ au_hbl_add(&ent->dr_hnode, hbl + hidx); ++ } ++ goto out; /* success */ ++ ++out_free: ++ au_dr_hino_free(dr); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * @bindex/@br is a switch to distinguish whether suspending hnotify or not. ++ * @path is a switch to distinguish load and store. ++ */ ++static int au_dr_hino(struct super_block *sb, aufs_bindex_t bindex, ++ struct au_branch *br, const struct path *path) ++{ ++ int err, flags; ++ unsigned char load, suspend; ++ struct file *hinofile; ++ struct au_hinode *hdir; ++ struct inode *dir, *delegated; ++ struct path hinopath; ++ struct qstr hinoname = QSTR_INIT(AUFS_WH_DR_BRHINO, ++ sizeof(AUFS_WH_DR_BRHINO) - 1); ++ ++ AuDebugOn(bindex < 0 && !br); ++ AuDebugOn(bindex >= 0 && br); ++ ++ err = -EINVAL; ++ suspend = !br; ++ if (suspend) ++ br = au_sbr(sb, bindex); ++ load = !!path; ++ if (!load) { ++ path = &br->br_path; ++ AuDebugOn(!au_br_writable(br->br_perm)); ++ if (unlikely(!au_br_writable(br->br_perm))) ++ goto out; ++ } ++ ++ hdir = NULL; ++ if (suspend) { ++ dir = d_inode(sb->s_root); ++ hdir = au_hinode(au_ii(dir), bindex); ++ dir = hdir->hi_inode; ++ au_hn_inode_lock_nested(hdir, AuLsc_I_CHILD); ++ } else { ++ dir = d_inode(path->dentry); ++ inode_lock_nested(dir, AuLsc_I_CHILD); ++ } ++ hinopath.dentry = vfsub_lkup_one(&hinoname, path->dentry); ++ err = PTR_ERR(hinopath.dentry); ++ if (IS_ERR(hinopath.dentry)) ++ goto out_unlock; ++ ++ err = 0; ++ flags = O_RDONLY; ++ if (load) { ++ if (d_is_negative(hinopath.dentry)) ++ goto out_dput; /* success */ ++ } else { ++ if (au_dr_hino_test_empty(&br->br_dirren)) { ++ if (d_is_positive(hinopath.dentry)) { ++ delegated = NULL; ++ err = vfsub_unlink(dir, &hinopath, &delegated, ++ /*force*/0); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ pr_err("ignored err %d, %pd2\n", ++ err, hinopath.dentry); ++ if (unlikely(err == -EWOULDBLOCK)) ++ iput(delegated); ++ err = 0; ++ } ++ goto out_dput; ++ } else if (!d_is_positive(hinopath.dentry)) { ++ err = vfsub_create(dir, &hinopath, 0600, ++ /*want_excl*/false); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out_dput; ++ } ++ flags = O_WRONLY; ++ } ++ hinopath.mnt = path->mnt; ++ hinofile = vfsub_dentry_open(&hinopath, flags); ++ if (suspend) ++ au_hn_inode_unlock(hdir); ++ else ++ inode_unlock(dir); ++ dput(hinopath.dentry); ++ AuTraceErrPtr(hinofile); ++ if (IS_ERR(hinofile)) { ++ err = PTR_ERR(hinofile); ++ goto out; ++ } ++ ++ if (load) ++ err = au_dr_hino_load(&br->br_dirren, hinofile); ++ else ++ err = au_dr_hino_store(sb, br, hinofile); ++ fput(hinofile); ++ goto out; ++ ++out_dput: ++ dput(hinopath.dentry); ++out_unlock: ++ if (suspend) ++ au_hn_inode_unlock(hdir); ++ else ++ inode_unlock(dir); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_dr_brid_init(struct au_dr_brid *brid, const struct path *path) ++{ ++ int err; ++ struct kstatfs kstfs; ++ dev_t dev; ++ struct dentry *dentry; ++ struct super_block *sb; ++ ++ err = vfs_statfs((void *)path, &kstfs); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out; ++ ++ /* todo: support for UUID */ ++ ++ if (kstfs.f_fsid.val[0] || kstfs.f_fsid.val[1]) { ++ brid->type = AuBrid_FSID; ++ brid->fsid = kstfs.f_fsid; ++ } else { ++ dentry = path->dentry; ++ sb = dentry->d_sb; ++ dev = sb->s_dev; ++ if (dev) { ++ brid->type = AuBrid_DEV; ++ brid->dev = dev; ++ } ++ } ++ ++out: ++ return err; ++} ++ ++int au_dr_br_init(struct super_block *sb, struct au_branch *br, ++ const struct path *path) ++{ ++ int err, i; ++ struct au_dr_br *dr; ++ struct hlist_bl_head *hbl; ++ ++ dr = &br->br_dirren; ++ hbl = dr->dr_h_ino; ++ for (i = 0; i < AuDirren_NHASH; i++, hbl++) ++ INIT_HLIST_BL_HEAD(hbl); ++ ++ err = au_dr_brid_init(&dr->dr_brid, path); ++ if (unlikely(err)) ++ goto out; ++ ++ if (au_opt_test(au_mntflags(sb), DIRREN)) ++ err = au_dr_hino(sb, /*bindex*/-1, br, path); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_dr_br_fin(struct super_block *sb, struct au_branch *br) ++{ ++ int err; ++ ++ err = 0; ++ if (au_br_writable(br->br_perm)) ++ err = au_dr_hino(sb, /*bindex*/-1, br, /*path*/NULL); ++ if (!err) ++ au_dr_hino_free(&br->br_dirren); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_brid_str(struct au_dr_brid *brid, struct inode *h_inode, ++ char *buf, size_t sz) ++{ ++ int err; ++ unsigned int major, minor; ++ char *p; ++ ++ p = buf; ++ err = snprintf(p, sz, "%d_", brid->type); ++ AuDebugOn(err > sz); ++ p += err; ++ sz -= err; ++ switch (brid->type) { ++ case AuBrid_Unset: ++ return -EINVAL; ++ case AuBrid_UUID: ++ err = snprintf(p, sz, "%pU", brid->uuid.b); ++ break; ++ case AuBrid_FSID: ++ err = snprintf(p, sz, "%08x-%08x", ++ brid->fsid.val[0], brid->fsid.val[1]); ++ break; ++ case AuBrid_DEV: ++ major = MAJOR(brid->dev); ++ minor = MINOR(brid->dev); ++ if (major <= 0xff && minor <= 0xff) ++ err = snprintf(p, sz, "%02x%02x", major, minor); ++ else ++ err = snprintf(p, sz, "%03x:%05x", major, minor); ++ break; ++ } ++ AuDebugOn(err > sz); ++ p += err; ++ sz -= err; ++ err = snprintf(p, sz, "_%llu", (unsigned long long)h_inode->i_ino); ++ AuDebugOn(err > sz); ++ p += err; ++ sz -= err; ++ ++ return p - buf; ++} ++ ++static int au_drinfo_name(struct au_branch *br, char *name, int len) ++{ ++ int rlen; ++ struct dentry *br_dentry; ++ struct inode *br_inode; ++ ++ br_dentry = au_br_dentry(br); ++ br_inode = d_inode(br_dentry); ++ rlen = au_brid_str(&br->br_dirren.dr_brid, br_inode, name, len); ++ AuDebugOn(rlen >= AUFS_DIRREN_ENV_VAL_SZ); ++ AuDebugOn(rlen > len); ++ ++ return rlen; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * from the given @h_dentry, construct drinfo at @*fdata. ++ * when the size of @*fdata is not enough, reallocate and return new @fdata and ++ * @allocated. ++ */ ++static int au_drinfo_construct(struct au_drinfo_fdata **fdata, ++ struct dentry *h_dentry, ++ unsigned char *allocated) ++{ ++ int err, v; ++ struct au_drinfo_fdata *f, *p; ++ struct au_drinfo *drinfo; ++ struct inode *h_inode; ++ struct qstr *qname; ++ ++ err = 0; ++ f = *fdata; ++ h_inode = d_inode(h_dentry); ++ qname = &h_dentry->d_name; ++ drinfo = &f->drinfo; ++ drinfo->ino = (__force uint64_t)cpu_to_be64(h_inode->i_ino); ++ drinfo->oldnamelen = qname->len; ++ if (*allocated < sizeof(*f) + qname->len) { ++ v = roundup_pow_of_two(*allocated + qname->len); ++ p = au_krealloc(f, v, GFP_NOFS, /*may_shrink*/0); ++ if (unlikely(!p)) { ++ err = -ENOMEM; ++ AuTraceErr(err); ++ goto out; ++ } ++ f = p; ++ *fdata = f; ++ *allocated = v; ++ drinfo = &f->drinfo; ++ } ++ memcpy(drinfo->oldname, qname->name, qname->len); ++ AuDbg("i%llu, %.*s\n", ++ be64_to_cpu((__force __be64)drinfo->ino), drinfo->oldnamelen, ++ drinfo->oldname); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* callers have to free the return value */ ++static struct au_drinfo *au_drinfo_read_k(struct file *file, ino_t h_ino) ++{ ++ struct au_drinfo *ret, *drinfo; ++ struct au_drinfo_fdata fdata; ++ int len; ++ loff_t pos; ++ ssize_t ssz; ++ ++ ret = ERR_PTR(-EIO); ++ pos = 0; ++ ssz = vfsub_read_k(file, &fdata, sizeof(fdata), &pos); ++ if (unlikely(ssz != sizeof(fdata))) { ++ AuIOErr("ssz %zd, %u, %pD2\n", ++ ssz, (unsigned int)sizeof(fdata), file); ++ goto out; ++ } ++ ++ fdata.magic = ntohl((__force __be32)fdata.magic); ++ switch (fdata.magic) { ++ case AUFS_DRINFO_MAGIC_V1: ++ break; ++ default: ++ AuIOErr("magic-num 0x%x, 0x%x, %pD2\n", ++ fdata.magic, AUFS_DRINFO_MAGIC_V1, file); ++ goto out; ++ } ++ ++ drinfo = &fdata.drinfo; ++ len = drinfo->oldnamelen; ++ if (!len) { ++ AuIOErr("broken drinfo %pD2\n", file); ++ goto out; ++ } ++ ++ ret = NULL; ++ drinfo->ino = be64_to_cpu((__force __be64)drinfo->ino); ++ if (unlikely(h_ino && drinfo->ino != h_ino)) { ++ AuDbg("ignored i%llu, i%llu, %pD2\n", ++ (unsigned long long)drinfo->ino, ++ (unsigned long long)h_ino, file); ++ goto out; /* success */ ++ } ++ ++ ret = kmalloc(sizeof(*ret) + len, GFP_NOFS); ++ if (unlikely(!ret)) { ++ ret = ERR_PTR(-ENOMEM); ++ AuTraceErrPtr(ret); ++ goto out; ++ } ++ ++ *ret = *drinfo; ++ ssz = vfsub_read_k(file, (void *)ret->oldname, len, &pos); ++ if (unlikely(ssz != len)) { ++ au_kfree_rcu(ret); ++ ret = ERR_PTR(-EIO); ++ AuIOErr("ssz %zd, %u, %pD2\n", ssz, len, file); ++ goto out; ++ } ++ ++ AuDbg("oldname %.*s\n", ret->oldnamelen, ret->oldname); ++ ++out: ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* in order to be revertible */ ++struct au_drinfo_rev_elm { ++ int created; ++ struct dentry *info_dentry; ++ struct au_drinfo *info_last; ++}; ++ ++struct au_drinfo_rev { ++ unsigned char already; ++ aufs_bindex_t nelm; ++ struct au_drinfo_rev_elm elm[0]; ++}; ++ ++/* todo: isn't it too large? */ ++struct au_drinfo_store { ++ struct path h_ppath; ++ struct dentry *h_dentry; ++ struct au_drinfo_fdata *fdata; ++ char *infoname; /* inside of whname, just after PFX */ ++ char whname[sizeof(AUFS_WH_DR_INFO_PFX) + AUFS_DIRREN_ENV_VAL_SZ]; ++ aufs_bindex_t btgt, btail; ++ unsigned char no_sio, ++ allocated, /* current size of *fdata */ ++ infonamelen, /* room size for p */ ++ whnamelen, /* length of the generated name */ ++ renameback; /* renamed back */ ++}; ++ ++/* on rename(2) error, the caller should revert it using @elm */ ++static int au_drinfo_do_store(struct au_drinfo_store *w, ++ struct au_drinfo_rev_elm *elm) ++{ ++ int err, len; ++ ssize_t ssz; ++ loff_t pos; ++ struct path infopath = { ++ .mnt = w->h_ppath.mnt ++ }; ++ struct inode *h_dir, *h_inode, *delegated; ++ struct file *infofile; ++ struct qstr *qname; ++ ++ AuDebugOn(elm ++ && memcmp(elm, page_address(ZERO_PAGE(0)), sizeof(*elm))); ++ ++ infopath.dentry = vfsub_lookup_one_len(w->whname, w->h_ppath.dentry, ++ w->whnamelen); ++ AuTraceErrPtr(infopath.dentry); ++ if (IS_ERR(infopath.dentry)) { ++ err = PTR_ERR(infopath.dentry); ++ goto out; ++ } ++ ++ err = 0; ++ h_dir = d_inode(w->h_ppath.dentry); ++ if (elm && d_is_negative(infopath.dentry)) { ++ err = vfsub_create(h_dir, &infopath, 0600, /*want_excl*/true); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out_dput; ++ elm->created = 1; ++ elm->info_dentry = dget(infopath.dentry); ++ } ++ ++ infofile = vfsub_dentry_open(&infopath, O_RDWR); ++ AuTraceErrPtr(infofile); ++ if (IS_ERR(infofile)) { ++ err = PTR_ERR(infofile); ++ goto out_dput; ++ } ++ ++ h_inode = d_inode(infopath.dentry); ++ if (elm && i_size_read(h_inode)) { ++ h_inode = d_inode(w->h_dentry); ++ elm->info_last = au_drinfo_read_k(infofile, h_inode->i_ino); ++ AuTraceErrPtr(elm->info_last); ++ if (IS_ERR(elm->info_last)) { ++ err = PTR_ERR(elm->info_last); ++ elm->info_last = NULL; ++ AuDebugOn(elm->info_dentry); ++ goto out_fput; ++ } ++ } ++ ++ if (elm && w->renameback) { ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, &infopath, &delegated, /*force*/0); ++ AuTraceErr(err); ++ if (unlikely(err == -EWOULDBLOCK)) ++ iput(delegated); ++ goto out_fput; ++ } ++ ++ pos = 0; ++ qname = &w->h_dentry->d_name; ++ len = sizeof(*w->fdata) + qname->len; ++ if (!elm) ++ len = sizeof(*w->fdata) + w->fdata->drinfo.oldnamelen; ++ ssz = vfsub_write_k(infofile, w->fdata, len, &pos); ++ if (ssz == len) { ++ AuDbg("hi%llu, %.*s\n", w->fdata->drinfo.ino, ++ w->fdata->drinfo.oldnamelen, w->fdata->drinfo.oldname); ++ goto out_fput; /* success */ ++ } else { ++ err = -EIO; ++ if (ssz < 0) ++ err = ssz; ++ /* the caller should revert it using @elm */ ++ } ++ ++out_fput: ++ fput(infofile); ++out_dput: ++ dput(infopath.dentry); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++struct au_call_drinfo_do_store_args { ++ int *errp; ++ struct au_drinfo_store *w; ++ struct au_drinfo_rev_elm *elm; ++}; ++ ++static void au_call_drinfo_do_store(void *args) ++{ ++ struct au_call_drinfo_do_store_args *a = args; ++ ++ *a->errp = au_drinfo_do_store(a->w, a->elm); ++} ++ ++static int au_drinfo_store_sio(struct au_drinfo_store *w, ++ struct au_drinfo_rev_elm *elm) ++{ ++ int err, wkq_err; ++ ++ if (w->no_sio) ++ err = au_drinfo_do_store(w, elm); ++ else { ++ struct au_call_drinfo_do_store_args a = { ++ .errp = &err, ++ .w = w, ++ .elm = elm ++ }; ++ wkq_err = au_wkq_wait(au_call_drinfo_do_store, &a); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ AuTraceErr(err); ++ ++ return err; ++} ++ ++static int au_drinfo_store_work_init(struct au_drinfo_store *w, ++ aufs_bindex_t btgt) ++{ ++ int err; ++ ++ memset(w, 0, sizeof(*w)); ++ w->allocated = roundup_pow_of_two(sizeof(*w->fdata) + 40); ++ strcpy(w->whname, AUFS_WH_DR_INFO_PFX); ++ w->infoname = w->whname + sizeof(AUFS_WH_DR_INFO_PFX) - 1; ++ w->infonamelen = sizeof(w->whname) - sizeof(AUFS_WH_DR_INFO_PFX); ++ w->btgt = btgt; ++ w->no_sio = !!uid_eq(current_fsuid(), GLOBAL_ROOT_UID); ++ ++ err = -ENOMEM; ++ w->fdata = kcalloc(1, w->allocated, GFP_NOFS); ++ if (unlikely(!w->fdata)) { ++ AuTraceErr(err); ++ goto out; ++ } ++ w->fdata->magic = (__force uint32_t)htonl(AUFS_DRINFO_MAGIC_V1); ++ err = 0; ++ ++out: ++ return err; ++} ++ ++static void au_drinfo_store_work_fin(struct au_drinfo_store *w) ++{ ++ au_kfree_rcu(w->fdata); ++} ++ ++static void au_drinfo_store_rev(struct au_drinfo_rev *rev, ++ struct au_drinfo_store *w) ++{ ++ struct au_drinfo_rev_elm *elm; ++ struct inode *h_dir, *delegated; ++ int err, nelm; ++ struct path infopath = { ++ .mnt = w->h_ppath.mnt ++ }; ++ ++ h_dir = d_inode(w->h_ppath.dentry); ++ IMustLock(h_dir); ++ ++ err = 0; ++ elm = rev->elm; ++ for (nelm = rev->nelm; nelm > 0; nelm--, elm++) { ++ AuDebugOn(elm->created && elm->info_last); ++ if (elm->created) { ++ AuDbg("here\n"); ++ delegated = NULL; ++ infopath.dentry = elm->info_dentry; ++ err = vfsub_unlink(h_dir, &infopath, &delegated, ++ !w->no_sio); ++ AuTraceErr(err); ++ if (unlikely(err == -EWOULDBLOCK)) ++ iput(delegated); ++ dput(elm->info_dentry); ++ } else if (elm->info_last) { ++ AuDbg("here\n"); ++ w->fdata->drinfo = *elm->info_last; ++ memcpy(w->fdata->drinfo.oldname, ++ elm->info_last->oldname, ++ elm->info_last->oldnamelen); ++ err = au_drinfo_store_sio(w, /*elm*/NULL); ++ au_kfree_rcu(elm->info_last); ++ } ++ if (unlikely(err)) ++ AuIOErr("%d, %s\n", err, w->whname); ++ /* go on even if err */ ++ } ++} ++ ++/* caller has to call au_dr_rename_fin() later */ ++static int au_drinfo_store(struct dentry *dentry, aufs_bindex_t btgt, ++ struct qstr *dst_name, void *_rev) ++{ ++ int err, sz, nelm; ++ aufs_bindex_t bindex, btail; ++ struct au_drinfo_store work; ++ struct au_drinfo_rev *rev, **p; ++ struct au_drinfo_rev_elm *elm; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_hinode *hdir; ++ ++ err = au_drinfo_store_work_init(&work, btgt); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out; ++ ++ err = -ENOMEM; ++ btail = au_dbtaildir(dentry); ++ nelm = btail - btgt; ++ sz = sizeof(*rev) + sizeof(*elm) * nelm; ++ rev = kcalloc(1, sz, GFP_NOFS); ++ if (unlikely(!rev)) { ++ AuTraceErr(err); ++ goto out_args; ++ } ++ rev->nelm = nelm; ++ elm = rev->elm; ++ p = _rev; ++ *p = rev; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ work.h_ppath.dentry = au_h_dptr(dentry, btgt); ++ work.h_ppath.mnt = au_sbr_mnt(sb, btgt); ++ hdir = au_hi(d_inode(dentry), btgt); ++ au_hn_inode_lock_nested(hdir, AuLsc_I_CHILD); ++ for (bindex = btgt + 1; bindex <= btail; bindex++, elm++) { ++ work.h_dentry = au_h_dptr(dentry, bindex); ++ if (!work.h_dentry) ++ continue; ++ ++ err = au_drinfo_construct(&work.fdata, work.h_dentry, ++ &work.allocated); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ break; ++ ++ work.renameback = au_qstreq(&work.h_dentry->d_name, dst_name); ++ br = au_sbr(sb, bindex); ++ work.whnamelen = sizeof(AUFS_WH_DR_INFO_PFX) - 1; ++ work.whnamelen += au_drinfo_name(br, work.infoname, ++ work.infonamelen); ++ AuDbg("whname %.*s, i%llu, %.*s\n", ++ work.whnamelen, work.whname, ++ be64_to_cpu((__force __be64)work.fdata->drinfo.ino), ++ work.fdata->drinfo.oldnamelen, ++ work.fdata->drinfo.oldname); ++ ++ err = au_drinfo_store_sio(&work, elm); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ break; ++ } ++ if (unlikely(err)) { ++ /* revert all drinfo */ ++ au_drinfo_store_rev(rev, &work); ++ au_kfree_try_rcu(rev); ++ *p = NULL; ++ } ++ au_hn_inode_unlock(hdir); ++ ++out_args: ++ au_drinfo_store_work_fin(&work); ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_dr_rename(struct dentry *src, aufs_bindex_t bindex, ++ struct qstr *dst_name, void *_rev) ++{ ++ int err, already; ++ ino_t ino; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_dr_br *dr; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct au_dr_hino *ent; ++ struct au_drinfo_rev *rev, **p; ++ ++ AuDbg("bindex %d\n", bindex); ++ ++ err = -ENOMEM; ++ ent = kmalloc(sizeof(*ent), GFP_NOFS); ++ if (unlikely(!ent)) ++ goto out; ++ ++ sb = src->d_sb; ++ br = au_sbr(sb, bindex); ++ dr = &br->br_dirren; ++ h_dentry = au_h_dptr(src, bindex); ++ h_inode = d_inode(h_dentry); ++ ino = h_inode->i_ino; ++ ent->dr_h_ino = ino; ++ already = au_dr_hino_test_add(dr, ino, ent); ++ AuDbg("b%d, hi%llu, already %d\n", ++ bindex, (unsigned long long)ino, already); ++ ++ err = au_drinfo_store(src, bindex, dst_name, _rev); ++ AuTraceErr(err); ++ if (!err) { ++ p = _rev; ++ rev = *p; ++ rev->already = already; ++ goto out; /* success */ ++ } ++ ++ /* revert */ ++ if (!already) ++ au_dr_hino_del(dr, ent); ++ au_kfree_rcu(ent); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_dr_rename_fin(struct dentry *src, aufs_bindex_t btgt, void *_rev) ++{ ++ struct au_drinfo_rev *rev; ++ struct au_drinfo_rev_elm *elm; ++ int nelm; ++ ++ rev = _rev; ++ elm = rev->elm; ++ for (nelm = rev->nelm; nelm > 0; nelm--, elm++) { ++ dput(elm->info_dentry); ++ au_kfree_rcu(elm->info_last); ++ } ++ au_kfree_try_rcu(rev); ++} ++ ++void au_dr_rename_rev(struct dentry *src, aufs_bindex_t btgt, void *_rev) ++{ ++ int err; ++ struct au_drinfo_store work; ++ struct au_drinfo_rev *rev = _rev; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct inode *h_inode; ++ struct au_dr_br *dr; ++ struct au_dr_hino *ent; ++ ++ err = au_drinfo_store_work_init(&work, btgt); ++ if (unlikely(err)) ++ goto out; ++ ++ sb = src->d_sb; ++ br = au_sbr(sb, btgt); ++ work.h_ppath.dentry = au_h_dptr(src, btgt); ++ work.h_ppath.mnt = au_br_mnt(br); ++ au_drinfo_store_rev(rev, &work); ++ au_drinfo_store_work_fin(&work); ++ if (rev->already) ++ goto out; ++ ++ dr = &br->br_dirren; ++ h_inode = d_inode(work.h_ppath.dentry); ++ ent = au_dr_hino_find(dr, h_inode->i_ino); ++ BUG_ON(!ent); ++ au_dr_hino_del(dr, ent); ++ au_kfree_rcu(ent); ++ ++out: ++ au_kfree_try_rcu(rev); ++ if (unlikely(err)) ++ pr_err("failed to remove dirren info\n"); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct au_drinfo *au_drinfo_do_load(struct path *h_ppath, ++ char *whname, int whnamelen, ++ struct dentry **info_dentry) ++{ ++ struct au_drinfo *drinfo; ++ struct file *f; ++ struct inode *h_dir; ++ struct path infopath; ++ int unlocked; ++ ++ AuDbg("%pd/%.*s\n", h_ppath->dentry, whnamelen, whname); ++ ++ *info_dentry = NULL; ++ drinfo = NULL; ++ unlocked = 0; ++ h_dir = d_inode(h_ppath->dentry); ++ inode_lock_shared_nested(h_dir, AuLsc_I_PARENT); ++ infopath.dentry = vfsub_lookup_one_len(whname, h_ppath->dentry, ++ whnamelen); ++ if (IS_ERR(infopath.dentry)) { ++ drinfo = (void *)infopath.dentry; ++ goto out; ++ } ++ ++ if (d_is_negative(infopath.dentry)) ++ goto out_dput; /* success */ ++ ++ infopath.mnt = h_ppath->mnt; ++ f = vfsub_dentry_open(&infopath, O_RDONLY); ++ inode_unlock_shared(h_dir); ++ unlocked = 1; ++ if (IS_ERR(f)) { ++ drinfo = (void *)f; ++ goto out_dput; ++ } ++ ++ drinfo = au_drinfo_read_k(f, /*h_ino*/0); ++ if (IS_ERR_OR_NULL(drinfo)) ++ goto out_fput; ++ ++ AuDbg("oldname %.*s\n", drinfo->oldnamelen, drinfo->oldname); ++ *info_dentry = dget(infopath.dentry); /* keep it alive */ ++ ++out_fput: ++ fput(f); ++out_dput: ++ dput(infopath.dentry); ++out: ++ if (!unlocked) ++ inode_unlock_shared(h_dir); ++ AuTraceErrPtr(drinfo); ++ return drinfo; ++} ++ ++struct au_drinfo_do_load_args { ++ struct au_drinfo **drinfop; ++ struct path *h_ppath; ++ char *whname; ++ int whnamelen; ++ struct dentry **info_dentry; ++}; ++ ++static void au_call_drinfo_do_load(void *args) ++{ ++ struct au_drinfo_do_load_args *a = args; ++ ++ *a->drinfop = au_drinfo_do_load(a->h_ppath, a->whname, a->whnamelen, ++ a->info_dentry); ++} ++ ++struct au_drinfo_load { ++ struct path h_ppath; ++ struct qstr *qname; ++ unsigned char no_sio; ++ ++ aufs_bindex_t ninfo; ++ struct au_drinfo **drinfo; ++}; ++ ++static int au_drinfo_load(struct au_drinfo_load *w, aufs_bindex_t bindex, ++ struct au_branch *br) ++{ ++ int err, wkq_err, whnamelen, e; ++ char whname[sizeof(AUFS_WH_DR_INFO_PFX) + AUFS_DIRREN_ENV_VAL_SZ] ++ = AUFS_WH_DR_INFO_PFX; ++ struct au_drinfo *drinfo; ++ struct qstr oldname; ++ struct inode *h_dir, *delegated; ++ struct dentry *info_dentry; ++ struct path infopath; ++ ++ whnamelen = sizeof(AUFS_WH_DR_INFO_PFX) - 1; ++ whnamelen += au_drinfo_name(br, whname + whnamelen, ++ sizeof(whname) - whnamelen); ++ if (w->no_sio) ++ drinfo = au_drinfo_do_load(&w->h_ppath, whname, whnamelen, ++ &info_dentry); ++ else { ++ struct au_drinfo_do_load_args args = { ++ .drinfop = &drinfo, ++ .h_ppath = &w->h_ppath, ++ .whname = whname, ++ .whnamelen = whnamelen, ++ .info_dentry = &info_dentry ++ }; ++ wkq_err = au_wkq_wait(au_call_drinfo_do_load, &args); ++ if (unlikely(wkq_err)) ++ drinfo = ERR_PTR(wkq_err); ++ } ++ err = PTR_ERR(drinfo); ++ if (IS_ERR_OR_NULL(drinfo)) ++ goto out; ++ ++ err = 0; ++ oldname.len = drinfo->oldnamelen; ++ oldname.name = drinfo->oldname; ++ if (au_qstreq(w->qname, &oldname)) { ++ /* the name is renamed back */ ++ au_kfree_rcu(drinfo); ++ drinfo = NULL; ++ ++ infopath.dentry = info_dentry; ++ infopath.mnt = w->h_ppath.mnt; ++ h_dir = d_inode(w->h_ppath.dentry); ++ delegated = NULL; ++ inode_lock_nested(h_dir, AuLsc_I_PARENT); ++ e = vfsub_unlink(h_dir, &infopath, &delegated, !w->no_sio); ++ inode_unlock(h_dir); ++ if (unlikely(e)) ++ AuIOErr("ignored %d, %pd2\n", e, &infopath.dentry); ++ if (unlikely(e == -EWOULDBLOCK)) ++ iput(delegated); ++ } ++ au_kfree_rcu(w->drinfo[bindex]); ++ w->drinfo[bindex] = drinfo; ++ dput(info_dentry); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_dr_lkup_free(struct au_drinfo **drinfo, int n) ++{ ++ struct au_drinfo **p = drinfo; ++ ++ while (n-- > 0) ++ au_kfree_rcu(*drinfo++); ++ au_kfree_try_rcu(p); ++} ++ ++int au_dr_lkup(struct au_do_lookup_args *lkup, struct dentry *dentry, ++ aufs_bindex_t btgt) ++{ ++ int err, ninfo; ++ struct au_drinfo_load w; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ struct inode *h_dir; ++ struct au_dr_hino *ent; ++ struct super_block *sb; ++ ++ AuDbg("%.*s, name %.*s, whname %.*s, b%d\n", ++ AuLNPair(&dentry->d_name), AuLNPair(&lkup->dirren.dr_name), ++ AuLNPair(&lkup->whname), btgt); ++ ++ sb = dentry->d_sb; ++ bbot = au_sbbot(sb); ++ w.ninfo = bbot + 1; ++ if (!lkup->dirren.drinfo) { ++ lkup->dirren.drinfo = kcalloc(w.ninfo, ++ sizeof(*lkup->dirren.drinfo), ++ GFP_NOFS); ++ if (unlikely(!lkup->dirren.drinfo)) { ++ err = -ENOMEM; ++ goto out; ++ } ++ lkup->dirren.ninfo = w.ninfo; ++ } ++ w.drinfo = lkup->dirren.drinfo; ++ w.no_sio = !!uid_eq(current_fsuid(), GLOBAL_ROOT_UID); ++ w.h_ppath.dentry = au_h_dptr(dentry, btgt); ++ AuDebugOn(!w.h_ppath.dentry); ++ w.h_ppath.mnt = au_sbr_mnt(sb, btgt); ++ w.qname = &dentry->d_name; ++ ++ ninfo = 0; ++ for (bindex = btgt + 1; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ err = au_drinfo_load(&w, bindex, br); ++ if (unlikely(err)) ++ goto out_free; ++ if (w.drinfo[bindex]) ++ ninfo++; ++ } ++ if (!ninfo) { ++ br = au_sbr(sb, btgt); ++ h_dir = d_inode(w.h_ppath.dentry); ++ ent = au_dr_hino_find(&br->br_dirren, h_dir->i_ino); ++ AuDebugOn(!ent); ++ au_dr_hino_del(&br->br_dirren, ent); ++ au_kfree_rcu(ent); ++ } ++ goto out; /* success */ ++ ++out_free: ++ au_dr_lkup_free(lkup->dirren.drinfo, lkup->dirren.ninfo); ++ lkup->dirren.ninfo = 0; ++ lkup->dirren.drinfo = NULL; ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_dr_lkup_fin(struct au_do_lookup_args *lkup) ++{ ++ au_dr_lkup_free(lkup->dirren.drinfo, lkup->dirren.ninfo); ++} ++ ++int au_dr_lkup_name(struct au_do_lookup_args *lkup, aufs_bindex_t btgt) ++{ ++ int err; ++ struct au_drinfo *drinfo; ++ ++ err = 0; ++ if (!lkup->dirren.drinfo) ++ goto out; ++ AuDebugOn(lkup->dirren.ninfo < btgt + 1); ++ drinfo = lkup->dirren.drinfo[btgt + 1]; ++ if (!drinfo) ++ goto out; ++ ++ au_kfree_try_rcu(lkup->whname.name); ++ lkup->whname.name = NULL; ++ lkup->dirren.dr_name.len = drinfo->oldnamelen; ++ lkup->dirren.dr_name.name = drinfo->oldname; ++ lkup->name = &lkup->dirren.dr_name; ++ err = au_wh_name_alloc(&lkup->whname, lkup->name); ++ if (!err) ++ AuDbg("name %.*s, whname %.*s, b%d\n", ++ AuLNPair(lkup->name), AuLNPair(&lkup->whname), ++ btgt); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_dr_lkup_h_ino(struct au_do_lookup_args *lkup, aufs_bindex_t bindex, ++ ino_t h_ino) ++{ ++ int match; ++ struct au_drinfo *drinfo; ++ ++ match = 1; ++ if (!lkup->dirren.drinfo) ++ goto out; ++ AuDebugOn(lkup->dirren.ninfo < bindex + 1); ++ drinfo = lkup->dirren.drinfo[bindex + 1]; ++ if (!drinfo) ++ goto out; ++ ++ match = (drinfo->ino == h_ino); ++ AuDbg("match %d\n", match); ++ ++out: ++ return match; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_dr_opt_set(struct super_block *sb) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ err = 0; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; !err && bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ err = au_dr_hino(sb, bindex, /*br*/NULL, &br->br_path); ++ } ++ ++ return err; ++} ++ ++int au_dr_opt_flush(struct super_block *sb) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ err = 0; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; !err && bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_writable(br->br_perm)) ++ err = au_dr_hino(sb, bindex, /*br*/NULL, /*path*/NULL); ++ } ++ ++ return err; ++} ++ ++int au_dr_opt_clr(struct super_block *sb, int no_flush) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ err = 0; ++ if (!no_flush) { ++ err = au_dr_opt_flush(sb); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ au_dr_hino_free(&br->br_dirren); ++ } ++ ++out: ++ return err; ++} +diff -Nurp linux-5.4/fs/aufs/dirren.h linux-5.4-aufs/fs/aufs/dirren.h +--- linux-5.4/fs/aufs/dirren.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/dirren.h 2019-11-28 01:25:59.064925618 +0200 +@@ -0,0 +1,127 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2017-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * renamed dir info ++ */ ++ ++#ifndef __AUFS_DIRREN_H__ ++#define __AUFS_DIRREN_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include "hbl.h" ++ ++#define AuDirren_NHASH 100 ++ ++#ifdef CONFIG_AUFS_DIRREN ++enum au_brid_type { ++ AuBrid_Unset, ++ AuBrid_UUID, ++ AuBrid_FSID, ++ AuBrid_DEV ++}; ++ ++struct au_dr_brid { ++ enum au_brid_type type; ++ union { ++ uuid_t uuid; /* unimplemented yet */ ++ fsid_t fsid; ++ dev_t dev; ++ }; ++}; ++ ++/* 20 is the max digits length of ulong 64 */ ++/* brid-type "_" uuid "_" inum */ ++#define AUFS_DIRREN_FNAME_SZ (1 + 1 + UUID_STRING_LEN + 20) ++#define AUFS_DIRREN_ENV_VAL_SZ (AUFS_DIRREN_FNAME_SZ + 1 + 20) ++ ++struct au_dr_hino { ++ struct hlist_bl_node dr_hnode; ++ ino_t dr_h_ino; ++}; ++ ++struct au_dr_br { ++ struct hlist_bl_head dr_h_ino[AuDirren_NHASH]; ++ struct au_dr_brid dr_brid; ++}; ++ ++struct au_dr_lookup { ++ /* dr_name is pointed by struct au_do_lookup_args.name */ ++ struct qstr dr_name; /* subset of dr_info */ ++ aufs_bindex_t ninfo; ++ struct au_drinfo **drinfo; ++}; ++#else ++struct au_dr_hino; ++/* empty */ ++struct au_dr_br { }; ++struct au_dr_lookup { }; ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_branch; ++struct au_do_lookup_args; ++struct au_hinode; ++#ifdef CONFIG_AUFS_DIRREN ++int au_dr_hino_test_add(struct au_dr_br *dr, ino_t h_ino, ++ struct au_dr_hino *add_ent); ++void au_dr_hino_free(struct au_dr_br *dr); ++int au_dr_br_init(struct super_block *sb, struct au_branch *br, ++ const struct path *path); ++int au_dr_br_fin(struct super_block *sb, struct au_branch *br); ++int au_dr_rename(struct dentry *src, aufs_bindex_t bindex, ++ struct qstr *dst_name, void *_rev); ++void au_dr_rename_fin(struct dentry *src, aufs_bindex_t btgt, void *rev); ++void au_dr_rename_rev(struct dentry *src, aufs_bindex_t bindex, void *rev); ++int au_dr_lkup(struct au_do_lookup_args *lkup, struct dentry *dentry, ++ aufs_bindex_t bindex); ++int au_dr_lkup_name(struct au_do_lookup_args *lkup, aufs_bindex_t btgt); ++int au_dr_lkup_h_ino(struct au_do_lookup_args *lkup, aufs_bindex_t bindex, ++ ino_t h_ino); ++void au_dr_lkup_fin(struct au_do_lookup_args *lkup); ++int au_dr_opt_set(struct super_block *sb); ++int au_dr_opt_flush(struct super_block *sb); ++int au_dr_opt_clr(struct super_block *sb, int no_flush); ++#else ++AuStubInt0(au_dr_hino_test_add, struct au_dr_br *dr, ino_t h_ino, ++ struct au_dr_hino *add_ent); ++AuStubVoid(au_dr_hino_free, struct au_dr_br *dr); ++AuStubInt0(au_dr_br_init, struct super_block *sb, struct au_branch *br, ++ const struct path *path); ++AuStubInt0(au_dr_br_fin, struct super_block *sb, struct au_branch *br); ++AuStubInt0(au_dr_rename, struct dentry *src, aufs_bindex_t bindex, ++ struct qstr *dst_name, void *_rev); ++AuStubVoid(au_dr_rename_fin, struct dentry *src, aufs_bindex_t btgt, void *rev); ++AuStubVoid(au_dr_rename_rev, struct dentry *src, aufs_bindex_t bindex, ++ void *rev); ++AuStubInt0(au_dr_lkup, struct au_do_lookup_args *lkup, struct dentry *dentry, ++ aufs_bindex_t bindex); ++AuStubInt0(au_dr_lkup_name, struct au_do_lookup_args *lkup, aufs_bindex_t btgt); ++AuStubInt0(au_dr_lkup_h_ino, struct au_do_lookup_args *lkup, ++ aufs_bindex_t bindex, ino_t h_ino); ++AuStubVoid(au_dr_lkup_fin, struct au_do_lookup_args *lkup); ++AuStubInt0(au_dr_opt_set, struct super_block *sb); ++AuStubInt0(au_dr_opt_flush, struct super_block *sb); ++AuStubInt0(au_dr_opt_clr, struct super_block *sb, int no_flush); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_DIRREN ++static inline int au_dr_ihash(ino_t h_ino) ++{ ++ return h_ino % AuDirren_NHASH; ++} ++#else ++AuStubInt0(au_dr_ihash, ino_t h_ino); ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DIRREN_H__ */ +diff -Nurp linux-5.4/fs/aufs/dynop.c linux-5.4-aufs/fs/aufs/dynop.c +--- linux-5.4/fs/aufs/dynop.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/dynop.c 2019-11-28 01:25:59.064925618 +0200 +@@ -0,0 +1,354 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2010-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * dynamically customizable operations for regular files ++ */ ++ ++#include "aufs.h" ++ ++#define DyPrSym(key) AuDbgSym(key->dk_op.dy_hop) ++ ++/* ++ * How large will these lists be? ++ * Usually just a few elements, 20-30 at most for each, I guess. ++ */ ++static struct hlist_bl_head dynop[AuDyLast]; ++ ++static struct au_dykey *dy_gfind_get(struct hlist_bl_head *hbl, ++ const void *h_op) ++{ ++ struct au_dykey *key, *tmp; ++ struct hlist_bl_node *pos; ++ ++ key = NULL; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(tmp, pos, hbl, dk_hnode) ++ if (tmp->dk_op.dy_hop == h_op) { ++ if (kref_get_unless_zero(&tmp->dk_kref)) ++ key = tmp; ++ break; ++ } ++ hlist_bl_unlock(hbl); ++ ++ return key; ++} ++ ++static struct au_dykey *dy_bradd(struct au_branch *br, struct au_dykey *key) ++{ ++ struct au_dykey **k, *found; ++ const void *h_op = key->dk_op.dy_hop; ++ int i; ++ ++ found = NULL; ++ k = br->br_dykey; ++ for (i = 0; i < AuBrDynOp; i++) ++ if (k[i]) { ++ if (k[i]->dk_op.dy_hop == h_op) { ++ found = k[i]; ++ break; ++ } ++ } else ++ break; ++ if (!found) { ++ spin_lock(&br->br_dykey_lock); ++ for (; i < AuBrDynOp; i++) ++ if (k[i]) { ++ if (k[i]->dk_op.dy_hop == h_op) { ++ found = k[i]; ++ break; ++ } ++ } else { ++ k[i] = key; ++ break; ++ } ++ spin_unlock(&br->br_dykey_lock); ++ BUG_ON(i == AuBrDynOp); /* expand the array */ ++ } ++ ++ return found; ++} ++ ++/* kref_get() if @key is already added */ ++static struct au_dykey *dy_gadd(struct hlist_bl_head *hbl, struct au_dykey *key) ++{ ++ struct au_dykey *tmp, *found; ++ struct hlist_bl_node *pos; ++ const void *h_op = key->dk_op.dy_hop; ++ ++ found = NULL; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(tmp, pos, hbl, dk_hnode) ++ if (tmp->dk_op.dy_hop == h_op) { ++ if (kref_get_unless_zero(&tmp->dk_kref)) ++ found = tmp; ++ break; ++ } ++ if (!found) ++ hlist_bl_add_head(&key->dk_hnode, hbl); ++ hlist_bl_unlock(hbl); ++ ++ if (!found) ++ DyPrSym(key); ++ return found; ++} ++ ++static void dy_free_rcu(struct rcu_head *rcu) ++{ ++ struct au_dykey *key; ++ ++ key = container_of(rcu, struct au_dykey, dk_rcu); ++ DyPrSym(key); ++ kfree(key); ++} ++ ++static void dy_free(struct kref *kref) ++{ ++ struct au_dykey *key; ++ struct hlist_bl_head *hbl; ++ ++ key = container_of(kref, struct au_dykey, dk_kref); ++ hbl = dynop + key->dk_op.dy_type; ++ au_hbl_del(&key->dk_hnode, hbl); ++ call_rcu(&key->dk_rcu, dy_free_rcu); ++} ++ ++void au_dy_put(struct au_dykey *key) ++{ ++ kref_put(&key->dk_kref, dy_free); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define DyDbgSize(cnt, op) AuDebugOn(cnt != sizeof(op)/sizeof(void *)) ++ ++#ifdef CONFIG_AUFS_DEBUG ++#define DyDbgDeclare(cnt) unsigned int cnt = 0 ++#define DyDbgInc(cnt) do { cnt++; } while (0) ++#else ++#define DyDbgDeclare(cnt) do {} while (0) ++#define DyDbgInc(cnt) do {} while (0) ++#endif ++ ++#define DySet(func, dst, src, h_op, h_sb) do { \ ++ DyDbgInc(cnt); \ ++ if (h_op->func) { \ ++ if (src.func) \ ++ dst.func = src.func; \ ++ else \ ++ AuDbg("%s %s\n", au_sbtype(h_sb), #func); \ ++ } \ ++} while (0) ++ ++#define DySetForce(func, dst, src) do { \ ++ AuDebugOn(!src.func); \ ++ DyDbgInc(cnt); \ ++ dst.func = src.func; \ ++} while (0) ++ ++#define DySetAop(func) \ ++ DySet(func, dyaop->da_op, aufs_aop, h_aop, h_sb) ++#define DySetAopForce(func) \ ++ DySetForce(func, dyaop->da_op, aufs_aop) ++ ++static void dy_aop(struct au_dykey *key, const void *h_op, ++ struct super_block *h_sb __maybe_unused) ++{ ++ struct au_dyaop *dyaop = (void *)key; ++ const struct address_space_operations *h_aop = h_op; ++ DyDbgDeclare(cnt); ++ ++ AuDbg("%s\n", au_sbtype(h_sb)); ++ ++ DySetAop(writepage); ++ DySetAopForce(readpage); /* force */ ++ DySetAop(writepages); ++ DySetAop(set_page_dirty); ++ DySetAop(readpages); ++ DySetAop(write_begin); ++ DySetAop(write_end); ++ DySetAop(bmap); ++ DySetAop(invalidatepage); ++ DySetAop(releasepage); ++ DySetAop(freepage); ++ /* this one will be changed according to an aufs mount option */ ++ DySetAop(direct_IO); ++ DySetAop(migratepage); ++ DySetAop(isolate_page); ++ DySetAop(putback_page); ++ DySetAop(launder_page); ++ DySetAop(is_partially_uptodate); ++ DySetAop(is_dirty_writeback); ++ DySetAop(error_remove_page); ++ DySetAop(swap_activate); ++ DySetAop(swap_deactivate); ++ ++ DyDbgSize(cnt, *h_aop); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void dy_bug(struct kref *kref) ++{ ++ BUG(); ++} ++ ++static struct au_dykey *dy_get(struct au_dynop *op, struct au_branch *br) ++{ ++ struct au_dykey *key, *old; ++ struct hlist_bl_head *hbl; ++ struct op { ++ unsigned int sz; ++ void (*set)(struct au_dykey *key, const void *h_op, ++ struct super_block *h_sb __maybe_unused); ++ }; ++ static const struct op a[] = { ++ [AuDy_AOP] = { ++ .sz = sizeof(struct au_dyaop), ++ .set = dy_aop ++ } ++ }; ++ const struct op *p; ++ ++ hbl = dynop + op->dy_type; ++ key = dy_gfind_get(hbl, op->dy_hop); ++ if (key) ++ goto out_add; /* success */ ++ ++ p = a + op->dy_type; ++ key = kzalloc(p->sz, GFP_NOFS); ++ if (unlikely(!key)) { ++ key = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ ++ key->dk_op.dy_hop = op->dy_hop; ++ kref_init(&key->dk_kref); ++ p->set(key, op->dy_hop, au_br_sb(br)); ++ old = dy_gadd(hbl, key); ++ if (old) { ++ au_kfree_rcu(key); ++ key = old; ++ } ++ ++out_add: ++ old = dy_bradd(br, key); ++ if (old) ++ /* its ref-count should never be zero here */ ++ kref_put(&key->dk_kref, dy_bug); ++out: ++ return key; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * Aufs prohibits O_DIRECT by default even if the branch supports it. ++ * This behaviour is necessary to return an error from open(O_DIRECT) instead ++ * of the succeeding I/O. The dio mount option enables O_DIRECT and makes ++ * open(O_DIRECT) always succeed, but the succeeding I/O may return an error. ++ * See the aufs manual in detail. ++ */ ++static void dy_adx(struct au_dyaop *dyaop, int do_dx) ++{ ++ if (!do_dx) ++ dyaop->da_op.direct_IO = NULL; ++ else ++ dyaop->da_op.direct_IO = aufs_aop.direct_IO; ++} ++ ++static struct au_dyaop *dy_aget(struct au_branch *br, ++ const struct address_space_operations *h_aop, ++ int do_dx) ++{ ++ struct au_dyaop *dyaop; ++ struct au_dynop op; ++ ++ op.dy_type = AuDy_AOP; ++ op.dy_haop = h_aop; ++ dyaop = (void *)dy_get(&op, br); ++ if (IS_ERR(dyaop)) ++ goto out; ++ dy_adx(dyaop, do_dx); ++ ++out: ++ return dyaop; ++} ++ ++int au_dy_iaop(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode) ++{ ++ int err, do_dx; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_dyaop *dyaop; ++ ++ AuDebugOn(!S_ISREG(h_inode->i_mode)); ++ IiMustWriteLock(inode); ++ ++ sb = inode->i_sb; ++ br = au_sbr(sb, bindex); ++ do_dx = !!au_opt_test(au_mntflags(sb), DIO); ++ dyaop = dy_aget(br, h_inode->i_mapping->a_ops, do_dx); ++ err = PTR_ERR(dyaop); ++ if (IS_ERR(dyaop)) ++ /* unnecessary to call dy_fput() */ ++ goto out; ++ ++ err = 0; ++ inode->i_mapping->a_ops = &dyaop->da_op; ++ ++out: ++ return err; ++} ++ ++/* ++ * Is it safe to replace a_ops during the inode/file is in operation? ++ * Yes, I hope so. ++ */ ++int au_dy_irefresh(struct inode *inode) ++{ ++ int err; ++ aufs_bindex_t btop; ++ struct inode *h_inode; ++ ++ err = 0; ++ if (S_ISREG(inode->i_mode)) { ++ btop = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, btop); ++ err = au_dy_iaop(inode, btop, h_inode); ++ } ++ return err; ++} ++ ++void au_dy_arefresh(int do_dx) ++{ ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_dykey *key; ++ ++ hbl = dynop + AuDy_AOP; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(key, pos, hbl, dk_hnode) ++ dy_adx((void *)key, do_dx); ++ hlist_bl_unlock(hbl); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void __init au_dy_init(void) ++{ ++ int i; ++ ++ for (i = 0; i < AuDyLast; i++) ++ INIT_HLIST_BL_HEAD(dynop + i); ++} ++ ++void au_dy_fin(void) ++{ ++ int i; ++ ++ for (i = 0; i < AuDyLast; i++) ++ WARN_ON(!hlist_bl_empty(dynop + i)); ++} +diff -Nurp linux-5.4/fs/aufs/dynop.h linux-5.4-aufs/fs/aufs/dynop.h +--- linux-5.4/fs/aufs/dynop.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/dynop.h 2019-11-28 01:25:59.064925618 +0200 +@@ -0,0 +1,64 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2010-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * dynamically customizable operations (for regular files only) ++ */ ++ ++#ifndef __AUFS_DYNOP_H__ ++#define __AUFS_DYNOP_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++ ++enum {AuDy_AOP, AuDyLast}; ++ ++struct au_dynop { ++ int dy_type; ++ union { ++ const void *dy_hop; ++ const struct address_space_operations *dy_haop; ++ }; ++}; ++ ++struct au_dykey { ++ union { ++ struct hlist_bl_node dk_hnode; ++ struct rcu_head dk_rcu; ++ }; ++ struct au_dynop dk_op; ++ ++ /* ++ * during I am in the branch local array, kref is gotten. when the ++ * branch is removed, kref is put. ++ */ ++ struct kref dk_kref; ++}; ++ ++/* stop unioning since their sizes are very different from each other */ ++struct au_dyaop { ++ struct au_dykey da_key; ++ struct address_space_operations da_op; /* not const */ ++}; ++/* make sure that 'struct au_dykey *' can be any type */ ++static_assert(!offsetof(struct au_dyaop, da_key)); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dynop.c */ ++struct au_branch; ++void au_dy_put(struct au_dykey *key); ++int au_dy_iaop(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode); ++int au_dy_irefresh(struct inode *inode); ++void au_dy_arefresh(int do_dio); ++ ++void __init au_dy_init(void); ++void au_dy_fin(void); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DYNOP_H__ */ +diff -Nurp linux-5.4/fs/aufs/export.c linux-5.4-aufs/fs/aufs/export.c +--- linux-5.4/fs/aufs/export.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/export.c 2019-11-28 01:25:59.064925618 +0200 +@@ -0,0 +1,825 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * export via nfs ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++union conv { ++#ifdef CONFIG_AUFS_INO_T_64 ++ __u32 a[2]; ++#else ++ __u32 a[1]; ++#endif ++ ino_t ino; ++}; ++ ++static ino_t decode_ino(__u32 *a) ++{ ++ union conv u; ++ ++ BUILD_BUG_ON(sizeof(u.ino) != sizeof(u.a)); ++ u.a[0] = a[0]; ++#ifdef CONFIG_AUFS_INO_T_64 ++ u.a[1] = a[1]; ++#endif ++ return u.ino; ++} ++ ++static void encode_ino(__u32 *a, ino_t ino) ++{ ++ union conv u; ++ ++ u.ino = ino; ++ a[0] = u.a[0]; ++#ifdef CONFIG_AUFS_INO_T_64 ++ a[1] = u.a[1]; ++#endif ++} ++ ++/* NFS file handle */ ++enum { ++ Fh_br_id, ++ Fh_sigen, ++#ifdef CONFIG_AUFS_INO_T_64 ++ /* support 64bit inode number */ ++ Fh_ino1, ++ Fh_ino2, ++ Fh_dir_ino1, ++ Fh_dir_ino2, ++#else ++ Fh_ino1, ++ Fh_dir_ino1, ++#endif ++ Fh_igen, ++ Fh_h_type, ++ Fh_tail, ++ ++ Fh_ino = Fh_ino1, ++ Fh_dir_ino = Fh_dir_ino1 ++}; ++ ++static int au_test_anon(struct dentry *dentry) ++{ ++ /* note: read d_flags without d_lock */ ++ return !!(dentry->d_flags & DCACHE_DISCONNECTED); ++} ++ ++int au_test_nfsd(void) ++{ ++ int ret; ++ struct task_struct *tsk = current; ++ char comm[sizeof(tsk->comm)]; ++ ++ ret = 0; ++ if (tsk->flags & PF_KTHREAD) { ++ get_task_comm(comm, tsk); ++ ret = !strcmp(comm, "nfsd"); ++ } ++ ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* inode generation external table */ ++ ++void au_xigen_inc(struct inode *inode) ++{ ++ loff_t pos; ++ ssize_t sz; ++ __u32 igen; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++ sb = inode->i_sb; ++ AuDebugOn(!au_opt_test(au_mntflags(sb), XINO)); ++ ++ sbinfo = au_sbi(sb); ++ pos = inode->i_ino; ++ pos *= sizeof(igen); ++ igen = inode->i_generation + 1; ++ sz = xino_fwrite(sbinfo->si_xwrite, sbinfo->si_xigen, &igen, ++ sizeof(igen), &pos); ++ if (sz == sizeof(igen)) ++ return; /* success */ ++ ++ if (unlikely(sz >= 0)) ++ AuIOErr("xigen error (%zd)\n", sz); ++} ++ ++int au_xigen_new(struct inode *inode) ++{ ++ int err; ++ loff_t pos; ++ ssize_t sz; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ ++ err = 0; ++ /* todo: dirty, at mount time */ ++ if (inode->i_ino == AUFS_ROOT_INO) ++ goto out; ++ sb = inode->i_sb; ++ SiMustAnyLock(sb); ++ if (unlikely(!au_opt_test(au_mntflags(sb), XINO))) ++ goto out; ++ ++ err = -EFBIG; ++ pos = inode->i_ino; ++ if (unlikely(au_loff_max / sizeof(inode->i_generation) - 1 < pos)) { ++ AuIOErr1("too large i%lld\n", pos); ++ goto out; ++ } ++ pos *= sizeof(inode->i_generation); ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ file = sbinfo->si_xigen; ++ BUG_ON(!file); ++ ++ if (vfsub_f_size_read(file) ++ < pos + sizeof(inode->i_generation)) { ++ inode->i_generation = atomic_inc_return(&sbinfo->si_xigen_next); ++ sz = xino_fwrite(sbinfo->si_xwrite, file, &inode->i_generation, ++ sizeof(inode->i_generation), &pos); ++ } else ++ sz = xino_fread(sbinfo->si_xread, file, &inode->i_generation, ++ sizeof(inode->i_generation), &pos); ++ if (sz == sizeof(inode->i_generation)) ++ goto out; /* success */ ++ ++ err = sz; ++ if (unlikely(sz >= 0)) { ++ err = -EIO; ++ AuIOErr("xigen error (%zd)\n", sz); ++ } ++ ++out: ++ return err; ++} ++ ++int au_xigen_set(struct super_block *sb, struct path *path) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ file = au_xino_create2(sb, path, sbinfo->si_xigen); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ err = 0; ++ if (sbinfo->si_xigen) ++ fput(sbinfo->si_xigen); ++ sbinfo->si_xigen = file; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_xigen_clr(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ if (sbinfo->si_xigen) { ++ fput(sbinfo->si_xigen); ++ sbinfo->si_xigen = NULL; ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry *decode_by_ino(struct super_block *sb, ino_t ino, ++ ino_t dir_ino) ++{ ++ struct dentry *dentry, *d; ++ struct inode *inode; ++ unsigned int sigen; ++ ++ dentry = NULL; ++ inode = ilookup(sb, ino); ++ if (!inode) ++ goto out; ++ ++ dentry = ERR_PTR(-ESTALE); ++ sigen = au_sigen(sb); ++ if (unlikely(au_is_bad_inode(inode) ++ || IS_DEADDIR(inode) ++ || sigen != au_iigen(inode, NULL))) ++ goto out_iput; ++ ++ dentry = NULL; ++ if (!dir_ino || S_ISDIR(inode->i_mode)) ++ dentry = d_find_alias(inode); ++ else { ++ spin_lock(&inode->i_lock); ++ hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias) { ++ spin_lock(&d->d_lock); ++ if (!au_test_anon(d) ++ && d_inode(d->d_parent)->i_ino == dir_ino) { ++ dentry = dget_dlock(d); ++ spin_unlock(&d->d_lock); ++ break; ++ } ++ spin_unlock(&d->d_lock); ++ } ++ spin_unlock(&inode->i_lock); ++ } ++ if (unlikely(dentry && au_digen_test(dentry, sigen))) { ++ /* need to refresh */ ++ dput(dentry); ++ dentry = NULL; ++ } ++ ++out_iput: ++ iput(inode); ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* todo: dirty? */ ++/* if exportfs_decode_fh() passed vfsmount*, we could be happy */ ++ ++struct au_compare_mnt_args { ++ /* input */ ++ struct super_block *sb; ++ ++ /* output */ ++ struct vfsmount *mnt; ++}; ++ ++static int au_compare_mnt(struct vfsmount *mnt, void *arg) ++{ ++ struct au_compare_mnt_args *a = arg; ++ ++ if (mnt->mnt_sb != a->sb) ++ return 0; ++ a->mnt = mntget(mnt); ++ return 1; ++} ++ ++static struct vfsmount *au_mnt_get(struct super_block *sb) ++{ ++ int err; ++ struct path root; ++ struct au_compare_mnt_args args = { ++ .sb = sb ++ }; ++ ++ get_fs_root(current->fs, &root); ++ rcu_read_lock(); ++ err = iterate_mounts(au_compare_mnt, &args, root.mnt); ++ rcu_read_unlock(); ++ path_put(&root); ++ AuDebugOn(!err); ++ AuDebugOn(!args.mnt); ++ return args.mnt; ++} ++ ++struct au_nfsd_si_lock { ++ unsigned int sigen; ++ aufs_bindex_t bindex, br_id; ++ unsigned char force_lock; ++}; ++ ++static int si_nfsd_read_lock(struct super_block *sb, ++ struct au_nfsd_si_lock *nsi_lock) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ ++ si_read_lock(sb, AuLock_FLUSH); ++ ++ /* branch id may be wrapped around */ ++ err = 0; ++ bindex = au_br_index(sb, nsi_lock->br_id); ++ if (bindex >= 0 && nsi_lock->sigen + AUFS_BRANCH_MAX > au_sigen(sb)) ++ goto out; /* success */ ++ ++ err = -ESTALE; ++ bindex = -1; ++ if (!nsi_lock->force_lock) ++ si_read_unlock(sb); ++ ++out: ++ nsi_lock->bindex = bindex; ++ return err; ++} ++ ++struct find_name_by_ino { ++ struct dir_context ctx; ++ int called, found; ++ ino_t ino; ++ char *name; ++ int namelen; ++}; ++ ++static int ++find_name_by_ino(struct dir_context *ctx, const char *name, int namelen, ++ loff_t offset, u64 ino, unsigned int d_type) ++{ ++ struct find_name_by_ino *a = container_of(ctx, struct find_name_by_ino, ++ ctx); ++ ++ a->called++; ++ if (a->ino != ino) ++ return 0; ++ ++ memcpy(a->name, name, namelen); ++ a->namelen = namelen; ++ a->found = 1; ++ return 1; ++} ++ ++static struct dentry *au_lkup_by_ino(struct path *path, ino_t ino, ++ struct au_nfsd_si_lock *nsi_lock) ++{ ++ struct dentry *dentry, *parent; ++ struct file *file; ++ struct inode *dir; ++ struct find_name_by_ino arg = { ++ .ctx = { ++ .actor = find_name_by_ino ++ } ++ }; ++ int err; ++ ++ parent = path->dentry; ++ if (nsi_lock) ++ si_read_unlock(parent->d_sb); ++ file = vfsub_dentry_open(path, au_dir_roflags); ++ dentry = (void *)file; ++ if (IS_ERR(file)) ++ goto out; ++ ++ dentry = ERR_PTR(-ENOMEM); ++ arg.name = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!arg.name)) ++ goto out_file; ++ arg.ino = ino; ++ arg.found = 0; ++ do { ++ arg.called = 0; ++ /* smp_mb(); */ ++ err = vfsub_iterate_dir(file, &arg.ctx); ++ } while (!err && !arg.found && arg.called); ++ dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_name; ++ /* instead of ENOENT */ ++ dentry = ERR_PTR(-ESTALE); ++ if (!arg.found) ++ goto out_name; ++ ++ /* do not call vfsub_lkup_one() */ ++ dir = d_inode(parent); ++ dentry = vfsub_lookup_one_len_unlocked(arg.name, parent, arg.namelen); ++ AuTraceErrPtr(dentry); ++ if (IS_ERR(dentry)) ++ goto out_name; ++ AuDebugOn(au_test_anon(dentry)); ++ if (unlikely(d_really_is_negative(dentry))) { ++ dput(dentry); ++ dentry = ERR_PTR(-ENOENT); ++ } ++ ++out_name: ++ free_page((unsigned long)arg.name); ++out_file: ++ fput(file); ++out: ++ if (unlikely(nsi_lock ++ && si_nfsd_read_lock(parent->d_sb, nsi_lock) < 0)) ++ if (!IS_ERR(dentry)) { ++ dput(dentry); ++ dentry = ERR_PTR(-ESTALE); ++ } ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++static struct dentry *decode_by_dir_ino(struct super_block *sb, ino_t ino, ++ ino_t dir_ino, ++ struct au_nfsd_si_lock *nsi_lock) ++{ ++ struct dentry *dentry; ++ struct path path; ++ ++ if (dir_ino != AUFS_ROOT_INO) { ++ path.dentry = decode_by_ino(sb, dir_ino, 0); ++ dentry = path.dentry; ++ if (!path.dentry || IS_ERR(path.dentry)) ++ goto out; ++ AuDebugOn(au_test_anon(path.dentry)); ++ } else ++ path.dentry = dget(sb->s_root); ++ ++ path.mnt = au_mnt_get(sb); ++ dentry = au_lkup_by_ino(&path, ino, nsi_lock); ++ path_put(&path); ++ ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int h_acceptable(void *expv, struct dentry *dentry) ++{ ++ return 1; ++} ++ ++static char *au_build_path(struct dentry *h_parent, struct path *h_rootpath, ++ char *buf, int len, struct super_block *sb) ++{ ++ char *p; ++ int n; ++ struct path path; ++ ++ p = d_path(h_rootpath, buf, len); ++ if (IS_ERR(p)) ++ goto out; ++ n = strlen(p); ++ ++ path.mnt = h_rootpath->mnt; ++ path.dentry = h_parent; ++ p = d_path(&path, buf, len); ++ if (IS_ERR(p)) ++ goto out; ++ if (n != 1) ++ p += n; ++ ++ path.mnt = au_mnt_get(sb); ++ path.dentry = sb->s_root; ++ p = d_path(&path, buf, len - strlen(p)); ++ mntput(path.mnt); ++ if (IS_ERR(p)) ++ goto out; ++ if (n != 1) ++ p[strlen(p)] = '/'; ++ ++out: ++ AuTraceErrPtr(p); ++ return p; ++} ++ ++static ++struct dentry *decode_by_path(struct super_block *sb, ino_t ino, __u32 *fh, ++ int fh_len, struct au_nfsd_si_lock *nsi_lock) ++{ ++ struct dentry *dentry, *h_parent, *root; ++ struct super_block *h_sb; ++ char *pathname, *p; ++ struct vfsmount *h_mnt; ++ struct au_branch *br; ++ int err; ++ struct path path; ++ ++ br = au_sbr(sb, nsi_lock->bindex); ++ h_mnt = au_br_mnt(br); ++ h_sb = h_mnt->mnt_sb; ++ /* todo: call lower fh_to_dentry()? fh_to_parent()? */ ++ lockdep_off(); ++ h_parent = exportfs_decode_fh(h_mnt, (void *)(fh + Fh_tail), ++ fh_len - Fh_tail, fh[Fh_h_type], ++ h_acceptable, /*context*/NULL); ++ lockdep_on(); ++ dentry = h_parent; ++ if (unlikely(!h_parent || IS_ERR(h_parent))) { ++ AuWarn1("%s decode_fh failed, %ld\n", ++ au_sbtype(h_sb), PTR_ERR(h_parent)); ++ goto out; ++ } ++ dentry = NULL; ++ if (unlikely(au_test_anon(h_parent))) { ++ AuWarn1("%s decode_fh returned a disconnected dentry\n", ++ au_sbtype(h_sb)); ++ goto out_h_parent; ++ } ++ ++ dentry = ERR_PTR(-ENOMEM); ++ pathname = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!pathname)) ++ goto out_h_parent; ++ ++ root = sb->s_root; ++ path.mnt = h_mnt; ++ di_read_lock_parent(root, !AuLock_IR); ++ path.dentry = au_h_dptr(root, nsi_lock->bindex); ++ di_read_unlock(root, !AuLock_IR); ++ p = au_build_path(h_parent, &path, pathname, PAGE_SIZE, sb); ++ dentry = (void *)p; ++ if (IS_ERR(p)) ++ goto out_pathname; ++ ++ si_read_unlock(sb); ++ err = vfsub_kern_path(p, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); ++ dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_relock; ++ ++ dentry = ERR_PTR(-ENOENT); ++ AuDebugOn(au_test_anon(path.dentry)); ++ if (unlikely(d_really_is_negative(path.dentry))) ++ goto out_path; ++ ++ if (ino != d_inode(path.dentry)->i_ino) ++ dentry = au_lkup_by_ino(&path, ino, /*nsi_lock*/NULL); ++ else ++ dentry = dget(path.dentry); ++ ++out_path: ++ path_put(&path); ++out_relock: ++ if (unlikely(si_nfsd_read_lock(sb, nsi_lock) < 0)) ++ if (!IS_ERR(dentry)) { ++ dput(dentry); ++ dentry = ERR_PTR(-ESTALE); ++ } ++out_pathname: ++ free_page((unsigned long)pathname); ++out_h_parent: ++ dput(h_parent); ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry * ++aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, ++ int fh_type) ++{ ++ struct dentry *dentry; ++ __u32 *fh = fid->raw; ++ struct au_branch *br; ++ ino_t ino, dir_ino; ++ struct au_nfsd_si_lock nsi_lock = { ++ .force_lock = 0 ++ }; ++ ++ dentry = ERR_PTR(-ESTALE); ++ /* it should never happen, but the file handle is unreliable */ ++ if (unlikely(fh_len < Fh_tail)) ++ goto out; ++ nsi_lock.sigen = fh[Fh_sigen]; ++ nsi_lock.br_id = fh[Fh_br_id]; ++ ++ /* branch id may be wrapped around */ ++ br = NULL; ++ if (unlikely(si_nfsd_read_lock(sb, &nsi_lock))) ++ goto out; ++ nsi_lock.force_lock = 1; ++ ++ /* is this inode still cached? */ ++ ino = decode_ino(fh + Fh_ino); ++ /* it should never happen */ ++ if (unlikely(ino == AUFS_ROOT_INO)) ++ goto out_unlock; ++ ++ dir_ino = decode_ino(fh + Fh_dir_ino); ++ dentry = decode_by_ino(sb, ino, dir_ino); ++ if (IS_ERR(dentry)) ++ goto out_unlock; ++ if (dentry) ++ goto accept; ++ ++ /* is the parent dir cached? */ ++ br = au_sbr(sb, nsi_lock.bindex); ++ au_lcnt_inc(&br->br_nfiles); ++ dentry = decode_by_dir_ino(sb, ino, dir_ino, &nsi_lock); ++ if (IS_ERR(dentry)) ++ goto out_unlock; ++ if (dentry) ++ goto accept; ++ ++ /* lookup path */ ++ dentry = decode_by_path(sb, ino, fh, fh_len, &nsi_lock); ++ if (IS_ERR(dentry)) ++ goto out_unlock; ++ if (unlikely(!dentry)) ++ /* todo?: make it ESTALE */ ++ goto out_unlock; ++ ++accept: ++ if (!au_digen_test(dentry, au_sigen(sb)) ++ && d_inode(dentry)->i_generation == fh[Fh_igen]) ++ goto out_unlock; /* success */ ++ ++ dput(dentry); ++ dentry = ERR_PTR(-ESTALE); ++out_unlock: ++ if (br) ++ au_lcnt_dec(&br->br_nfiles); ++ si_read_unlock(sb); ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++#if 0 /* reserved for future use */ ++/* support subtreecheck option */ ++static struct dentry *aufs_fh_to_parent(struct super_block *sb, struct fid *fid, ++ int fh_len, int fh_type) ++{ ++ struct dentry *parent; ++ __u32 *fh = fid->raw; ++ ino_t dir_ino; ++ ++ dir_ino = decode_ino(fh + Fh_dir_ino); ++ parent = decode_by_ino(sb, dir_ino, 0); ++ if (IS_ERR(parent)) ++ goto out; ++ if (!parent) ++ parent = decode_by_path(sb, au_br_index(sb, fh[Fh_br_id]), ++ dir_ino, fh, fh_len); ++ ++out: ++ AuTraceErrPtr(parent); ++ return parent; ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_encode_fh(struct inode *inode, __u32 *fh, int *max_len, ++ struct inode *dir) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct super_block *sb, *h_sb; ++ struct dentry *dentry, *parent, *h_parent; ++ struct inode *h_dir; ++ struct au_branch *br; ++ ++ err = -ENOSPC; ++ if (unlikely(*max_len <= Fh_tail)) { ++ AuWarn1("NFSv2 client (max_len %d)?\n", *max_len); ++ goto out; ++ } ++ ++ err = FILEID_ROOT; ++ if (inode->i_ino == AUFS_ROOT_INO) { ++ AuDebugOn(inode->i_ino != AUFS_ROOT_INO); ++ goto out; ++ } ++ ++ h_parent = NULL; ++ sb = inode->i_sb; ++ err = si_read_lock(sb, AuLock_FLUSH); ++ if (unlikely(err)) ++ goto out; ++ ++#ifdef CONFIG_AUFS_DEBUG ++ if (unlikely(!au_opt_test(au_mntflags(sb), XINO))) ++ AuWarn1("NFS-exporting requires xino\n"); ++#endif ++ err = -EIO; ++ parent = NULL; ++ ii_read_lock_child(inode); ++ bindex = au_ibtop(inode); ++ if (!dir) { ++ dentry = d_find_any_alias(inode); ++ if (unlikely(!dentry)) ++ goto out_unlock; ++ AuDebugOn(au_test_anon(dentry)); ++ parent = dget_parent(dentry); ++ dput(dentry); ++ if (unlikely(!parent)) ++ goto out_unlock; ++ if (d_really_is_positive(parent)) ++ dir = d_inode(parent); ++ } ++ ++ ii_read_lock_parent(dir); ++ h_dir = au_h_iptr(dir, bindex); ++ ii_read_unlock(dir); ++ if (unlikely(!h_dir)) ++ goto out_parent; ++ h_parent = d_find_any_alias(h_dir); ++ if (unlikely(!h_parent)) ++ goto out_hparent; ++ ++ err = -EPERM; ++ br = au_sbr(sb, bindex); ++ h_sb = au_br_sb(br); ++ if (unlikely(!h_sb->s_export_op)) { ++ AuErr1("%s branch is not exportable\n", au_sbtype(h_sb)); ++ goto out_hparent; ++ } ++ ++ fh[Fh_br_id] = br->br_id; ++ fh[Fh_sigen] = au_sigen(sb); ++ encode_ino(fh + Fh_ino, inode->i_ino); ++ encode_ino(fh + Fh_dir_ino, dir->i_ino); ++ fh[Fh_igen] = inode->i_generation; ++ ++ *max_len -= Fh_tail; ++ fh[Fh_h_type] = exportfs_encode_fh(h_parent, (void *)(fh + Fh_tail), ++ max_len, ++ /*connectable or subtreecheck*/0); ++ err = fh[Fh_h_type]; ++ *max_len += Fh_tail; ++ /* todo: macros? */ ++ if (err != FILEID_INVALID) ++ err = 99; ++ else ++ AuWarn1("%s encode_fh failed\n", au_sbtype(h_sb)); ++ ++out_hparent: ++ dput(h_parent); ++out_parent: ++ dput(parent); ++out_unlock: ++ ii_read_unlock(inode); ++ si_read_unlock(sb); ++out: ++ if (unlikely(err < 0)) ++ err = FILEID_INVALID; ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_commit_metadata(struct inode *inode) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct super_block *sb; ++ struct inode *h_inode; ++ int (*f)(struct inode *inode); ++ ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ii_write_lock_child(inode); ++ bindex = au_ibtop(inode); ++ AuDebugOn(bindex < 0); ++ h_inode = au_h_iptr(inode, bindex); ++ ++ f = h_inode->i_sb->s_export_op->commit_metadata; ++ if (f) ++ err = f(h_inode); ++ else { ++ struct writeback_control wbc = { ++ .sync_mode = WB_SYNC_ALL, ++ .nr_to_write = 0 /* metadata only */ ++ }; ++ ++ err = sync_inode(h_inode, &wbc); ++ } ++ ++ au_cpup_attr_timesizes(inode); ++ ii_write_unlock(inode); ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct export_operations aufs_export_op = { ++ .fh_to_dentry = aufs_fh_to_dentry, ++ /* .fh_to_parent = aufs_fh_to_parent, */ ++ .encode_fh = aufs_encode_fh, ++ .commit_metadata = aufs_commit_metadata ++}; ++ ++void au_export_init(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ __u32 u; ++ ++ BUILD_BUG_ON_MSG(IS_BUILTIN(CONFIG_AUFS_FS) ++ && IS_MODULE(CONFIG_EXPORTFS), ++ AUFS_NAME ": unsupported configuration " ++ "CONFIG_EXPORTFS=m and CONFIG_AUFS_FS=y"); ++ ++ sb->s_export_op = &aufs_export_op; ++ sbinfo = au_sbi(sb); ++ sbinfo->si_xigen = NULL; ++ get_random_bytes(&u, sizeof(u)); ++ BUILD_BUG_ON(sizeof(u) != sizeof(int)); ++ atomic_set(&sbinfo->si_xigen_next, u); ++} +diff -Nurp linux-5.4/fs/aufs/fhsm.c linux-5.4-aufs/fs/aufs/fhsm.c +--- linux-5.4/fs/aufs/fhsm.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/fhsm.c 2019-11-28 01:25:59.064925618 +0200 +@@ -0,0 +1,413 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2011-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * File-based Hierarchy Storage Management ++ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++static aufs_bindex_t au_fhsm_bottom(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ AuDebugOn(!fhsm); ++ return fhsm->fhsm_bottom; ++} ++ ++void au_fhsm_set_bottom(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ AuDebugOn(!fhsm); ++ fhsm->fhsm_bottom = bindex; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_fhsm_test_jiffy(struct au_sbinfo *sbinfo, struct au_branch *br) ++{ ++ struct au_br_fhsm *bf; ++ ++ bf = br->br_fhsm; ++ MtxMustLock(&bf->bf_lock); ++ ++ return !bf->bf_readable ++ || time_after(jiffies, ++ bf->bf_jiffy + sbinfo->si_fhsm.fhsm_expire); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_fhsm_notify(struct super_block *sb, int val) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ if (au_fhsm_pid(fhsm) ++ && atomic_read(&fhsm->fhsm_readable) != -1) { ++ atomic_set(&fhsm->fhsm_readable, val); ++ if (val) ++ wake_up(&fhsm->fhsm_wqh); ++ } ++} ++ ++static int au_fhsm_stfs(struct super_block *sb, aufs_bindex_t bindex, ++ struct aufs_stfs *rstfs, int do_lock, int do_notify) ++{ ++ int err; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ br = au_sbr(sb, bindex); ++ AuDebugOn(au_br_rdonly(br)); ++ bf = br->br_fhsm; ++ AuDebugOn(!bf); ++ ++ if (do_lock) ++ mutex_lock(&bf->bf_lock); ++ else ++ MtxMustLock(&bf->bf_lock); ++ ++ /* sb->s_root for NFS is unreliable */ ++ err = au_br_stfs(br, &bf->bf_stfs); ++ if (unlikely(err)) { ++ AuErr1("FHSM failed (%d), b%d, ignored.\n", bindex, err); ++ goto out; ++ } ++ ++ bf->bf_jiffy = jiffies; ++ bf->bf_readable = 1; ++ if (do_notify) ++ au_fhsm_notify(sb, /*val*/1); ++ if (rstfs) ++ *rstfs = bf->bf_stfs; ++ ++out: ++ if (do_lock) ++ mutex_unlock(&bf->bf_lock); ++ au_fhsm_notify(sb, /*val*/1); ++ ++ return err; ++} ++ ++void au_fhsm_wrote(struct super_block *sb, aufs_bindex_t bindex, int force) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ AuDbg("b%d, force %d\n", bindex, force); ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ if (!au_ftest_si(sbinfo, FHSM) ++ || fhsm->fhsm_bottom == bindex) ++ return; ++ ++ br = au_sbr(sb, bindex); ++ bf = br->br_fhsm; ++ AuDebugOn(!bf); ++ mutex_lock(&bf->bf_lock); ++ if (force ++ || au_fhsm_pid(fhsm) ++ || au_fhsm_test_jiffy(sbinfo, br)) ++ err = au_fhsm_stfs(sb, bindex, /*rstfs*/NULL, /*do_lock*/0, ++ /*do_notify*/1); ++ mutex_unlock(&bf->bf_lock); ++} ++ ++void au_fhsm_wrote_all(struct super_block *sb, int force) ++{ ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ /* exclude the bottom */ ++ bbot = au_fhsm_bottom(sb); ++ for (bindex = 0; bindex < bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm)) ++ au_fhsm_wrote(sb, bindex, force); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static __poll_t au_fhsm_poll(struct file *file, struct poll_table_struct *wait) ++{ ++ __poll_t mask; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ mask = 0; ++ sbinfo = file->private_data; ++ fhsm = &sbinfo->si_fhsm; ++ poll_wait(file, &fhsm->fhsm_wqh, wait); ++ if (atomic_read(&fhsm->fhsm_readable)) ++ mask = EPOLLIN /* | EPOLLRDNORM */; ++ ++ if (!mask) ++ AuDbg("mask 0x%x\n", mask); ++ return mask; ++} ++ ++static int au_fhsm_do_read_one(struct aufs_stbr __user *stbr, ++ struct aufs_stfs *stfs, __s16 brid) ++{ ++ int err; ++ ++ err = copy_to_user(&stbr->stfs, stfs, sizeof(*stfs)); ++ if (!err) ++ err = __put_user(brid, &stbr->brid); ++ if (unlikely(err)) ++ err = -EFAULT; ++ ++ return err; ++} ++ ++static ssize_t au_fhsm_do_read(struct super_block *sb, ++ struct aufs_stbr __user *stbr, size_t count) ++{ ++ ssize_t err; ++ int nstbr; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ struct au_br_fhsm *bf; ++ ++ /* except the bottom branch */ ++ err = 0; ++ nstbr = 0; ++ bbot = au_fhsm_bottom(sb); ++ for (bindex = 0; !err && bindex < bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!au_br_fhsm(br->br_perm)) ++ continue; ++ ++ bf = br->br_fhsm; ++ mutex_lock(&bf->bf_lock); ++ if (bf->bf_readable) { ++ err = -EFAULT; ++ if (count >= sizeof(*stbr)) ++ err = au_fhsm_do_read_one(stbr++, &bf->bf_stfs, ++ br->br_id); ++ if (!err) { ++ bf->bf_readable = 0; ++ count -= sizeof(*stbr); ++ nstbr++; ++ } ++ } ++ mutex_unlock(&bf->bf_lock); ++ } ++ if (!err) ++ err = sizeof(*stbr) * nstbr; ++ ++ return err; ++} ++ ++static ssize_t au_fhsm_read(struct file *file, char __user *buf, size_t count, ++ loff_t *pos) ++{ ++ ssize_t err; ++ int readable; ++ aufs_bindex_t nfhsm, bindex, bbot; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ struct au_branch *br; ++ struct super_block *sb; ++ ++ err = 0; ++ sbinfo = file->private_data; ++ fhsm = &sbinfo->si_fhsm; ++need_data: ++ spin_lock_irq(&fhsm->fhsm_wqh.lock); ++ if (!atomic_read(&fhsm->fhsm_readable)) { ++ if (vfsub_file_flags(file) & O_NONBLOCK) ++ err = -EAGAIN; ++ else ++ err = wait_event_interruptible_locked_irq ++ (fhsm->fhsm_wqh, ++ atomic_read(&fhsm->fhsm_readable)); ++ } ++ spin_unlock_irq(&fhsm->fhsm_wqh.lock); ++ if (unlikely(err)) ++ goto out; ++ ++ /* sb may already be dead */ ++ au_rw_read_lock(&sbinfo->si_rwsem); ++ readable = atomic_read(&fhsm->fhsm_readable); ++ if (readable > 0) { ++ sb = sbinfo->si_sb; ++ AuDebugOn(!sb); ++ /* exclude the bottom branch */ ++ nfhsm = 0; ++ bbot = au_fhsm_bottom(sb); ++ for (bindex = 0; bindex < bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm)) ++ nfhsm++; ++ } ++ err = -EMSGSIZE; ++ if (nfhsm * sizeof(struct aufs_stbr) <= count) { ++ atomic_set(&fhsm->fhsm_readable, 0); ++ err = au_fhsm_do_read(sbinfo->si_sb, (void __user *)buf, ++ count); ++ } ++ } ++ au_rw_read_unlock(&sbinfo->si_rwsem); ++ if (!readable) ++ goto need_data; ++ ++out: ++ return err; ++} ++ ++static int au_fhsm_release(struct inode *inode, struct file *file) ++{ ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ /* sb may already be dead */ ++ sbinfo = file->private_data; ++ fhsm = &sbinfo->si_fhsm; ++ spin_lock(&fhsm->fhsm_spin); ++ fhsm->fhsm_pid = 0; ++ spin_unlock(&fhsm->fhsm_spin); ++ kobject_put(&sbinfo->si_kobj); ++ ++ return 0; ++} ++ ++static const struct file_operations au_fhsm_fops = { ++ .owner = THIS_MODULE, ++ .llseek = noop_llseek, ++ .read = au_fhsm_read, ++ .poll = au_fhsm_poll, ++ .release = au_fhsm_release ++}; ++ ++int au_fhsm_fd(struct super_block *sb, int oflags) ++{ ++ int err, fd; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ ++ err = -EPERM; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = -EINVAL; ++ if (unlikely(oflags & ~(O_CLOEXEC | O_NONBLOCK))) ++ goto out; ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ spin_lock(&fhsm->fhsm_spin); ++ if (!fhsm->fhsm_pid) ++ fhsm->fhsm_pid = current->pid; ++ else ++ err = -EBUSY; ++ spin_unlock(&fhsm->fhsm_spin); ++ if (unlikely(err)) ++ goto out; ++ ++ oflags |= O_RDONLY; ++ /* oflags |= FMODE_NONOTIFY; */ ++ fd = anon_inode_getfd("[aufs_fhsm]", &au_fhsm_fops, sbinfo, oflags); ++ err = fd; ++ if (unlikely(fd < 0)) ++ goto out_pid; ++ ++ /* succeed regardless 'fhsm' status */ ++ kobject_get(&sbinfo->si_kobj); ++ si_noflush_read_lock(sb); ++ if (au_ftest_si(sbinfo, FHSM)) ++ au_fhsm_wrote_all(sb, /*force*/0); ++ si_read_unlock(sb); ++ goto out; /* success */ ++ ++out_pid: ++ spin_lock(&fhsm->fhsm_spin); ++ fhsm->fhsm_pid = 0; ++ spin_unlock(&fhsm->fhsm_spin); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_fhsm_br_alloc(struct au_branch *br) ++{ ++ int err; ++ ++ err = 0; ++ br->br_fhsm = kmalloc(sizeof(*br->br_fhsm), GFP_NOFS); ++ if (br->br_fhsm) ++ au_br_fhsm_init(br->br_fhsm); ++ else ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_fhsm_fin(struct super_block *sb) ++{ ++ au_fhsm_notify(sb, /*val*/-1); ++} ++ ++void au_fhsm_init(struct au_sbinfo *sbinfo) ++{ ++ struct au_fhsm *fhsm; ++ ++ fhsm = &sbinfo->si_fhsm; ++ spin_lock_init(&fhsm->fhsm_spin); ++ init_waitqueue_head(&fhsm->fhsm_wqh); ++ atomic_set(&fhsm->fhsm_readable, 0); ++ fhsm->fhsm_expire ++ = msecs_to_jiffies(AUFS_FHSM_CACHE_DEF_SEC * MSEC_PER_SEC); ++ fhsm->fhsm_bottom = -1; ++} ++ ++void au_fhsm_set(struct au_sbinfo *sbinfo, unsigned int sec) ++{ ++ sbinfo->si_fhsm.fhsm_expire ++ = msecs_to_jiffies(sec * MSEC_PER_SEC); ++} ++ ++void au_fhsm_show(struct seq_file *seq, struct au_sbinfo *sbinfo) ++{ ++ unsigned int u; ++ ++ if (!au_ftest_si(sbinfo, FHSM)) ++ return; ++ ++ u = jiffies_to_msecs(sbinfo->si_fhsm.fhsm_expire) / MSEC_PER_SEC; ++ if (u != AUFS_FHSM_CACHE_DEF_SEC) ++ seq_printf(seq, ",fhsm_sec=%u", u); ++} +diff -Nurp linux-5.4/fs/aufs/file.c linux-5.4-aufs/fs/aufs/file.c +--- linux-5.4/fs/aufs/file.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/file.c 2019-11-28 01:25:59.065925618 +0200 +@@ -0,0 +1,850 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * handling file/dir, and address_space operation ++ */ ++ ++#ifdef CONFIG_AUFS_DEBUG ++#include ++#endif ++#include ++#include "aufs.h" ++ ++/* drop flags for writing */ ++unsigned int au_file_roflags(unsigned int flags) ++{ ++ flags &= ~(O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_TRUNC); ++ flags |= O_RDONLY | O_NOATIME; ++ return flags; ++} ++ ++/* common functions to regular file and dir */ ++struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, ++ struct file *file, int force_wr) ++{ ++ struct file *h_file; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct path h_path; ++ int err; ++ ++ /* a race condition can happen between open and unlink/rmdir */ ++ h_file = ERR_PTR(-ENOENT); ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (au_test_nfsd() && (!h_dentry || d_is_negative(h_dentry))) ++ goto out; ++ h_inode = d_inode(h_dentry); ++ spin_lock(&h_dentry->d_lock); ++ err = (!d_unhashed(dentry) && d_unlinked(h_dentry)) ++ /* || !d_inode(dentry)->i_nlink */ ++ ; ++ spin_unlock(&h_dentry->d_lock); ++ if (unlikely(err)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, bindex); ++ err = au_br_test_oflag(flags, br); ++ h_file = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ /* drop flags for writing */ ++ if (au_test_ro(sb, bindex, d_inode(dentry))) { ++ if (force_wr && !(flags & O_WRONLY)) ++ force_wr = 0; ++ flags = au_file_roflags(flags); ++ if (force_wr) { ++ h_file = ERR_PTR(-EROFS); ++ flags = au_file_roflags(flags); ++ if (unlikely(vfsub_native_ro(h_inode) ++ || IS_APPEND(h_inode))) ++ goto out; ++ flags &= ~O_ACCMODE; ++ flags |= O_WRONLY; ++ } ++ } ++ flags &= ~O_CREAT; ++ au_lcnt_inc(&br->br_nfiles); ++ h_path.dentry = h_dentry; ++ h_path.mnt = au_br_mnt(br); ++ h_file = vfsub_dentry_open(&h_path, flags); ++ if (IS_ERR(h_file)) ++ goto out_br; ++ ++ if (flags & __FMODE_EXEC) { ++ err = deny_write_access(h_file); ++ if (unlikely(err)) { ++ fput(h_file); ++ h_file = ERR_PTR(err); ++ goto out_br; ++ } ++ } ++ fsnotify_open(h_file); ++ goto out; /* success */ ++ ++out_br: ++ au_lcnt_dec(&br->br_nfiles); ++out: ++ return h_file; ++} ++ ++static int au_cmoo(struct dentry *dentry) ++{ ++ int err, cmoo, matched; ++ unsigned int udba; ++ struct path h_path; ++ struct au_pin pin; ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = -1, ++ .bsrc = -1, ++ .len = -1, ++ .pin = &pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ struct inode *delegated; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct au_fhsm *fhsm; ++ pid_t pid; ++ struct au_branch *br; ++ struct dentry *parent; ++ struct au_hinode *hdir; ++ ++ DiMustWriteLock(dentry); ++ IiMustWriteLock(d_inode(dentry)); ++ ++ err = 0; ++ if (IS_ROOT(dentry)) ++ goto out; ++ cpg.bsrc = au_dbtop(dentry); ++ if (!cpg.bsrc) ++ goto out; ++ ++ sb = dentry->d_sb; ++ sbinfo = au_sbi(sb); ++ fhsm = &sbinfo->si_fhsm; ++ pid = au_fhsm_pid(fhsm); ++ rcu_read_lock(); ++ matched = (pid ++ && (current->pid == pid ++ || rcu_dereference(current->real_parent)->pid == pid)); ++ rcu_read_unlock(); ++ if (matched) ++ goto out; ++ ++ br = au_sbr(sb, cpg.bsrc); ++ cmoo = au_br_cmoo(br->br_perm); ++ if (!cmoo) ++ goto out; ++ if (!d_is_reg(dentry)) ++ cmoo &= AuBrAttr_COO_ALL; ++ if (!cmoo) ++ goto out; ++ ++ parent = dget_parent(dentry); ++ di_write_lock_parent(parent); ++ err = au_wbr_do_copyup_bu(dentry, cpg.bsrc - 1); ++ cpg.bdst = err; ++ if (unlikely(err < 0)) { ++ err = 0; /* there is no upper writable branch */ ++ goto out_dgrade; ++ } ++ AuDbg("bsrc %d, bdst %d\n", cpg.bsrc, cpg.bdst); ++ ++ /* do not respect the coo attrib for the target branch */ ++ err = au_cpup_dirs(dentry, cpg.bdst); ++ if (unlikely(err)) ++ goto out_dgrade; ++ ++ di_downgrade_lock(parent, AuLock_IR); ++ udba = au_opt_udba(sb); ++ err = au_pin(&pin, dentry, cpg.bdst, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&pin); ++ if (unlikely(err)) ++ goto out_parent; ++ if (!(cmoo & AuBrWAttr_MOO)) ++ goto out_parent; /* success */ ++ ++ err = au_pin(&pin, dentry, cpg.bsrc, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ h_path.mnt = au_br_mnt(br); ++ h_path.dentry = au_h_dptr(dentry, cpg.bsrc); ++ hdir = au_hi(d_inode(parent), cpg.bsrc); ++ delegated = NULL; ++ err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated, /*force*/1); ++ au_unpin(&pin); ++ /* todo: keep h_dentry or not? */ ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) { ++ pr_err("unlink %pd after coo failed (%d), ignored\n", ++ dentry, err); ++ err = 0; ++ } ++ goto out_parent; /* success */ ++ ++out_dgrade: ++ di_downgrade_lock(parent, AuLock_IR); ++out_parent: ++ di_read_unlock(parent, AuLock_IR); ++ dput(parent); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_do_open(struct file *file, struct au_do_open_args *args) ++{ ++ int err, aopen = args->aopen; ++ struct dentry *dentry; ++ struct au_finfo *finfo; ++ ++ if (!aopen) ++ err = au_finfo_init(file, args->fidir); ++ else { ++ lockdep_off(); ++ err = au_finfo_init(file, args->fidir); ++ lockdep_on(); ++ } ++ if (unlikely(err)) ++ goto out; ++ ++ dentry = file->f_path.dentry; ++ AuDebugOn(IS_ERR_OR_NULL(dentry)); ++ di_write_lock_child(dentry); ++ err = au_cmoo(dentry); ++ di_downgrade_lock(dentry, AuLock_IR); ++ if (!err) { ++ if (!aopen) ++ err = args->open(file, vfsub_file_flags(file), NULL); ++ else { ++ lockdep_off(); ++ err = args->open(file, vfsub_file_flags(file), ++ args->h_file); ++ lockdep_on(); ++ } ++ } ++ di_read_unlock(dentry, AuLock_IR); ++ ++ finfo = au_fi(file); ++ if (!err) { ++ finfo->fi_file = file; ++ au_hbl_add(&finfo->fi_hlist, ++ &au_sbi(file->f_path.dentry->d_sb)->si_files); ++ } ++ if (!aopen) ++ fi_write_unlock(file); ++ else { ++ lockdep_off(); ++ fi_write_unlock(file); ++ lockdep_on(); ++ } ++ if (unlikely(err)) { ++ finfo->fi_hdir = NULL; ++ au_finfo_fin(file); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_reopen_nondir(struct file *file) ++{ ++ int err; ++ aufs_bindex_t btop; ++ struct dentry *dentry; ++ struct au_branch *br; ++ struct file *h_file, *h_file_tmp; ++ ++ dentry = file->f_path.dentry; ++ btop = au_dbtop(dentry); ++ br = au_sbr(dentry->d_sb, btop); ++ h_file_tmp = NULL; ++ if (au_fbtop(file) == btop) { ++ h_file = au_hf_top(file); ++ if (file->f_mode == h_file->f_mode) ++ return 0; /* success */ ++ h_file_tmp = h_file; ++ get_file(h_file_tmp); ++ au_lcnt_inc(&br->br_nfiles); ++ au_set_h_fptr(file, btop, NULL); ++ } ++ AuDebugOn(au_fi(file)->fi_hdir); ++ /* ++ * it can happen ++ * file exists on both of rw and ro ++ * open --> dbtop and fbtop are both 0 ++ * prepend a branch as rw, "rw" become ro ++ * remove rw/file ++ * delete the top branch, "rw" becomes rw again ++ * --> dbtop is 1, fbtop is still 0 ++ * write --> fbtop is 0 but dbtop is 1 ++ */ ++ /* AuDebugOn(au_fbtop(file) < btop); */ ++ ++ h_file = au_h_open(dentry, btop, vfsub_file_flags(file) & ~O_TRUNC, ++ file, /*force_wr*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) { ++ if (h_file_tmp) { ++ /* revert */ ++ au_set_h_fptr(file, btop, h_file_tmp); ++ h_file_tmp = NULL; ++ } ++ goto out; /* todo: close all? */ ++ } ++ ++ err = 0; ++ au_set_fbtop(file, btop); ++ au_set_h_fptr(file, btop, h_file); ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ ++out: ++ if (h_file_tmp) { ++ fput(h_file_tmp); ++ au_lcnt_dec(&br->br_nfiles); ++ } ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_reopen_wh(struct file *file, aufs_bindex_t btgt, ++ struct dentry *hi_wh) ++{ ++ int err; ++ aufs_bindex_t btop; ++ struct au_dinfo *dinfo; ++ struct dentry *h_dentry; ++ struct au_hdentry *hdp; ++ ++ dinfo = au_di(file->f_path.dentry); ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ btop = dinfo->di_btop; ++ dinfo->di_btop = btgt; ++ hdp = au_hdentry(dinfo, btgt); ++ h_dentry = hdp->hd_dentry; ++ hdp->hd_dentry = hi_wh; ++ err = au_reopen_nondir(file); ++ hdp->hd_dentry = h_dentry; ++ dinfo->di_btop = btop; ++ ++ return err; ++} ++ ++static int au_ready_to_write_wh(struct file *file, loff_t len, ++ aufs_bindex_t bcpup, struct au_pin *pin) ++{ ++ int err; ++ struct inode *inode, *h_inode; ++ struct dentry *h_dentry, *hi_wh; ++ struct au_cp_generic cpg = { ++ .dentry = file->f_path.dentry, ++ .bdst = bcpup, ++ .bsrc = -1, ++ .len = len, ++ .pin = pin ++ }; ++ ++ au_update_dbtop(cpg.dentry); ++ inode = d_inode(cpg.dentry); ++ h_inode = NULL; ++ if (au_dbtop(cpg.dentry) <= bcpup ++ && au_dbbot(cpg.dentry) >= bcpup) { ++ h_dentry = au_h_dptr(cpg.dentry, bcpup); ++ if (h_dentry && d_is_positive(h_dentry)) ++ h_inode = d_inode(h_dentry); ++ } ++ hi_wh = au_hi_wh(inode, bcpup); ++ if (!hi_wh && !h_inode) ++ err = au_sio_cpup_wh(&cpg, file); ++ else ++ /* already copied-up after unlink */ ++ err = au_reopen_wh(file, bcpup, hi_wh); ++ ++ if (!err ++ && (inode->i_nlink > 1 ++ || (inode->i_state & I_LINKABLE)) ++ && au_opt_test(au_mntflags(cpg.dentry->d_sb), PLINK)) ++ au_plink_append(inode, bcpup, au_h_dptr(cpg.dentry, bcpup)); ++ ++ return err; ++} ++ ++/* ++ * prepare the @file for writing. ++ */ ++int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin) ++{ ++ int err; ++ aufs_bindex_t dbtop; ++ struct dentry *parent; ++ struct inode *inode; ++ struct super_block *sb; ++ struct file *h_file; ++ struct au_cp_generic cpg = { ++ .dentry = file->f_path.dentry, ++ .bdst = -1, ++ .bsrc = -1, ++ .len = len, ++ .pin = pin, ++ .flags = AuCpup_DTIME ++ }; ++ ++ sb = cpg.dentry->d_sb; ++ inode = d_inode(cpg.dentry); ++ cpg.bsrc = au_fbtop(file); ++ err = au_test_ro(sb, cpg.bsrc, inode); ++ if (!err && (au_hf_top(file)->f_mode & FMODE_WRITE)) { ++ err = au_pin(pin, cpg.dentry, cpg.bsrc, AuOpt_UDBA_NONE, ++ /*flags*/0); ++ goto out; ++ } ++ ++ /* need to cpup or reopen */ ++ parent = dget_parent(cpg.dentry); ++ di_write_lock_parent(parent); ++ err = AuWbrCopyup(au_sbi(sb), cpg.dentry); ++ cpg.bdst = err; ++ if (unlikely(err < 0)) ++ goto out_dgrade; ++ err = 0; ++ ++ if (!d_unhashed(cpg.dentry) && !au_h_dptr(parent, cpg.bdst)) { ++ err = au_cpup_dirs(cpg.dentry, cpg.bdst); ++ if (unlikely(err)) ++ goto out_dgrade; ++ } ++ ++ err = au_pin(pin, cpg.dentry, cpg.bdst, AuOpt_UDBA_NONE, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_dgrade; ++ ++ dbtop = au_dbtop(cpg.dentry); ++ if (dbtop <= cpg.bdst) ++ cpg.bsrc = cpg.bdst; ++ ++ if (dbtop <= cpg.bdst /* just reopen */ ++ || !d_unhashed(cpg.dentry) /* copyup and reopen */ ++ ) { ++ h_file = au_h_open_pre(cpg.dentry, cpg.bsrc, /*force_wr*/0); ++ if (IS_ERR(h_file)) ++ err = PTR_ERR(h_file); ++ else { ++ di_downgrade_lock(parent, AuLock_IR); ++ if (dbtop > cpg.bdst) ++ err = au_sio_cpup_simple(&cpg); ++ if (!err) ++ err = au_reopen_nondir(file); ++ au_h_open_post(cpg.dentry, cpg.bsrc, h_file); ++ } ++ } else { /* copyup as wh and reopen */ ++ /* ++ * since writable hfsplus branch is not supported, ++ * h_open_pre/post() are unnecessary. ++ */ ++ err = au_ready_to_write_wh(file, len, cpg.bdst, pin); ++ di_downgrade_lock(parent, AuLock_IR); ++ } ++ ++ if (!err) { ++ au_pin_set_parent_lflag(pin, /*lflag*/0); ++ goto out_dput; /* success */ ++ } ++ au_unpin(pin); ++ goto out_unlock; ++ ++out_dgrade: ++ di_downgrade_lock(parent, AuLock_IR); ++out_unlock: ++ di_read_unlock(parent, AuLock_IR); ++out_dput: ++ dput(parent); ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_do_flush(struct file *file, fl_owner_t id, ++ int (*flush)(struct file *file, fl_owner_t id)) ++{ ++ int err; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ si_noflush_read_lock(sb); ++ fi_read_lock(file); ++ ii_read_lock_child(inode); ++ ++ err = flush(file, id); ++ au_cpup_attr_timesizes(inode); ++ ++ ii_read_unlock(inode); ++ fi_read_unlock(file); ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_file_refresh_by_inode(struct file *file, int *need_reopen) ++{ ++ int err; ++ struct au_pin pin; ++ struct au_finfo *finfo; ++ struct dentry *parent, *hi_wh; ++ struct inode *inode; ++ struct super_block *sb; ++ struct au_cp_generic cpg = { ++ .dentry = file->f_path.dentry, ++ .bdst = -1, ++ .bsrc = -1, ++ .len = -1, ++ .pin = &pin, ++ .flags = AuCpup_DTIME ++ }; ++ ++ FiMustWriteLock(file); ++ ++ err = 0; ++ finfo = au_fi(file); ++ sb = cpg.dentry->d_sb; ++ inode = d_inode(cpg.dentry); ++ cpg.bdst = au_ibtop(inode); ++ if (cpg.bdst == finfo->fi_btop || IS_ROOT(cpg.dentry)) ++ goto out; ++ ++ parent = dget_parent(cpg.dentry); ++ if (au_test_ro(sb, cpg.bdst, inode)) { ++ di_read_lock_parent(parent, !AuLock_IR); ++ err = AuWbrCopyup(au_sbi(sb), cpg.dentry); ++ cpg.bdst = err; ++ di_read_unlock(parent, !AuLock_IR); ++ if (unlikely(err < 0)) ++ goto out_parent; ++ err = 0; ++ } ++ ++ di_read_lock_parent(parent, AuLock_IR); ++ hi_wh = au_hi_wh(inode, cpg.bdst); ++ if (!S_ISDIR(inode->i_mode) ++ && au_opt_test(au_mntflags(sb), PLINK) ++ && au_plink_test(inode) ++ && !d_unhashed(cpg.dentry) ++ && cpg.bdst < au_dbtop(cpg.dentry)) { ++ err = au_test_and_cpup_dirs(cpg.dentry, cpg.bdst); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ /* always superio. */ ++ err = au_pin(&pin, cpg.dentry, cpg.bdst, AuOpt_UDBA_NONE, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (!err) { ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&pin); ++ } ++ } else if (hi_wh) { ++ /* already copied-up after unlink */ ++ err = au_reopen_wh(file, cpg.bdst, hi_wh); ++ *need_reopen = 0; ++ } ++ ++out_unlock: ++ di_read_unlock(parent, AuLock_IR); ++out_parent: ++ dput(parent); ++out: ++ return err; ++} ++ ++static void au_do_refresh_dir(struct file *file) ++{ ++ aufs_bindex_t bindex, bbot, new_bindex, brid; ++ struct au_hfile *p, tmp, *q; ++ struct au_finfo *finfo; ++ struct super_block *sb; ++ struct au_fidir *fidir; ++ ++ FiMustWriteLock(file); ++ ++ sb = file->f_path.dentry->d_sb; ++ finfo = au_fi(file); ++ fidir = finfo->fi_hdir; ++ AuDebugOn(!fidir); ++ p = fidir->fd_hfile + finfo->fi_btop; ++ brid = p->hf_br->br_id; ++ bbot = fidir->fd_bbot; ++ for (bindex = finfo->fi_btop; bindex <= bbot; bindex++, p++) { ++ if (!p->hf_file) ++ continue; ++ ++ new_bindex = au_br_index(sb, p->hf_br->br_id); ++ if (new_bindex == bindex) ++ continue; ++ if (new_bindex < 0) { ++ au_set_h_fptr(file, bindex, NULL); ++ continue; ++ } ++ ++ /* swap two lower inode, and loop again */ ++ q = fidir->fd_hfile + new_bindex; ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hf_file) { ++ bindex--; ++ p--; ++ } ++ } ++ ++ p = fidir->fd_hfile; ++ if (!au_test_mmapped(file) && !d_unlinked(file->f_path.dentry)) { ++ bbot = au_sbbot(sb); ++ for (finfo->fi_btop = 0; finfo->fi_btop <= bbot; ++ finfo->fi_btop++, p++) ++ if (p->hf_file) { ++ if (file_inode(p->hf_file)) ++ break; ++ au_hfput(p, /*execed*/0); ++ } ++ } else { ++ bbot = au_br_index(sb, brid); ++ for (finfo->fi_btop = 0; finfo->fi_btop < bbot; ++ finfo->fi_btop++, p++) ++ if (p->hf_file) ++ au_hfput(p, /*execed*/0); ++ bbot = au_sbbot(sb); ++ } ++ ++ p = fidir->fd_hfile + bbot; ++ for (fidir->fd_bbot = bbot; fidir->fd_bbot >= finfo->fi_btop; ++ fidir->fd_bbot--, p--) ++ if (p->hf_file) { ++ if (file_inode(p->hf_file)) ++ break; ++ au_hfput(p, /*execed*/0); ++ } ++ AuDebugOn(fidir->fd_bbot < finfo->fi_btop); ++} ++ ++/* ++ * after branch manipulating, refresh the file. ++ */ ++static int refresh_file(struct file *file, int (*reopen)(struct file *file)) ++{ ++ int err, need_reopen, nbr; ++ aufs_bindex_t bbot, bindex; ++ struct dentry *dentry; ++ struct super_block *sb; ++ struct au_finfo *finfo; ++ struct au_hfile *hfile; ++ ++ dentry = file->f_path.dentry; ++ sb = dentry->d_sb; ++ nbr = au_sbbot(sb) + 1; ++ finfo = au_fi(file); ++ if (!finfo->fi_hdir) { ++ hfile = &finfo->fi_htop; ++ AuDebugOn(!hfile->hf_file); ++ bindex = au_br_index(sb, hfile->hf_br->br_id); ++ AuDebugOn(bindex < 0); ++ if (bindex != finfo->fi_btop) ++ au_set_fbtop(file, bindex); ++ } else { ++ err = au_fidir_realloc(finfo, nbr, /*may_shrink*/0); ++ if (unlikely(err)) ++ goto out; ++ au_do_refresh_dir(file); ++ } ++ ++ err = 0; ++ need_reopen = 1; ++ if (!au_test_mmapped(file)) ++ err = au_file_refresh_by_inode(file, &need_reopen); ++ if (finfo->fi_hdir) ++ /* harmless if err */ ++ au_fidir_realloc(finfo, nbr, /*may_shrink*/1); ++ if (!err && need_reopen && !d_unlinked(dentry)) ++ err = reopen(file); ++ if (!err) { ++ au_update_figen(file); ++ goto out; /* success */ ++ } ++ ++ /* error, close all lower files */ ++ if (finfo->fi_hdir) { ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); bindex <= bbot; bindex++) ++ au_set_h_fptr(file, bindex, NULL); ++ } ++ ++out: ++ return err; ++} ++ ++/* common function to regular file and dir */ ++int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file), ++ int wlock, unsigned int fi_lsc) ++{ ++ int err; ++ unsigned int sigen, figen; ++ aufs_bindex_t btop; ++ unsigned char pseudo_link; ++ struct dentry *dentry; ++ struct inode *inode; ++ ++ err = 0; ++ dentry = file->f_path.dentry; ++ inode = d_inode(dentry); ++ sigen = au_sigen(dentry->d_sb); ++ fi_write_lock_nested(file, fi_lsc); ++ figen = au_figen(file); ++ if (!fi_lsc) ++ di_write_lock_child(dentry); ++ else ++ di_write_lock_child2(dentry); ++ btop = au_dbtop(dentry); ++ pseudo_link = (btop != au_ibtop(inode)); ++ if (sigen == figen && !pseudo_link && au_fbtop(file) == btop) { ++ if (!wlock) { ++ di_downgrade_lock(dentry, AuLock_IR); ++ fi_downgrade_lock(file); ++ } ++ goto out; /* success */ ++ } ++ ++ AuDbg("sigen %d, figen %d\n", sigen, figen); ++ if (au_digen_test(dentry, sigen)) { ++ err = au_reval_dpath(dentry, sigen); ++ AuDebugOn(!err && au_digen_test(dentry, sigen)); ++ } ++ ++ if (!err) ++ err = refresh_file(file, reopen); ++ if (!err) { ++ if (!wlock) { ++ di_downgrade_lock(dentry, AuLock_IR); ++ fi_downgrade_lock(file); ++ } ++ } else { ++ di_write_unlock(dentry); ++ fi_write_unlock(file); ++ } ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* cf. aufs_nopage() */ ++/* for madvise(2) */ ++static int aufs_readpage(struct file *file __maybe_unused, struct page *page) ++{ ++ unlock_page(page); ++ return 0; ++} ++ ++/* it will never be called, but necessary to support O_DIRECT */ ++static ssize_t aufs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) ++{ BUG(); return 0; } ++ ++/* they will never be called. */ ++#ifdef CONFIG_AUFS_DEBUG ++static int aufs_write_begin(struct file *file, struct address_space *mapping, ++ loff_t pos, unsigned len, unsigned flags, ++ struct page **pagep, void **fsdata) ++{ AuUnsupport(); return 0; } ++static int aufs_write_end(struct file *file, struct address_space *mapping, ++ loff_t pos, unsigned len, unsigned copied, ++ struct page *page, void *fsdata) ++{ AuUnsupport(); return 0; } ++static int aufs_writepage(struct page *page, struct writeback_control *wbc) ++{ AuUnsupport(); return 0; } ++ ++static int aufs_set_page_dirty(struct page *page) ++{ AuUnsupport(); return 0; } ++static void aufs_invalidatepage(struct page *page, unsigned int offset, ++ unsigned int length) ++{ AuUnsupport(); } ++static int aufs_releasepage(struct page *page, gfp_t gfp) ++{ AuUnsupport(); return 0; } ++#if 0 /* called by memory compaction regardless file */ ++static int aufs_migratepage(struct address_space *mapping, struct page *newpage, ++ struct page *page, enum migrate_mode mode) ++{ AuUnsupport(); return 0; } ++#endif ++static bool aufs_isolate_page(struct page *page, isolate_mode_t mode) ++{ AuUnsupport(); return true; } ++static void aufs_putback_page(struct page *page) ++{ AuUnsupport(); } ++static int aufs_launder_page(struct page *page) ++{ AuUnsupport(); return 0; } ++static int aufs_is_partially_uptodate(struct page *page, ++ unsigned long from, ++ unsigned long count) ++{ AuUnsupport(); return 0; } ++static void aufs_is_dirty_writeback(struct page *page, bool *dirty, ++ bool *writeback) ++{ AuUnsupport(); } ++static int aufs_error_remove_page(struct address_space *mapping, ++ struct page *page) ++{ AuUnsupport(); return 0; } ++static int aufs_swap_activate(struct swap_info_struct *sis, struct file *file, ++ sector_t *span) ++{ AuUnsupport(); return 0; } ++static void aufs_swap_deactivate(struct file *file) ++{ AuUnsupport(); } ++#endif /* CONFIG_AUFS_DEBUG */ ++ ++const struct address_space_operations aufs_aop = { ++ .readpage = aufs_readpage, ++ .direct_IO = aufs_direct_IO, ++#ifdef CONFIG_AUFS_DEBUG ++ .writepage = aufs_writepage, ++ /* no writepages, because of writepage */ ++ .set_page_dirty = aufs_set_page_dirty, ++ /* no readpages, because of readpage */ ++ .write_begin = aufs_write_begin, ++ .write_end = aufs_write_end, ++ /* no bmap, no block device */ ++ .invalidatepage = aufs_invalidatepage, ++ .releasepage = aufs_releasepage, ++ /* is fallback_migrate_page ok? */ ++ /* .migratepage = aufs_migratepage, */ ++ .isolate_page = aufs_isolate_page, ++ .putback_page = aufs_putback_page, ++ .launder_page = aufs_launder_page, ++ .is_partially_uptodate = aufs_is_partially_uptodate, ++ .is_dirty_writeback = aufs_is_dirty_writeback, ++ .error_remove_page = aufs_error_remove_page, ++ .swap_activate = aufs_swap_activate, ++ .swap_deactivate = aufs_swap_deactivate ++#endif /* CONFIG_AUFS_DEBUG */ ++}; +diff -Nurp linux-5.4/fs/aufs/file.h linux-5.4-aufs/fs/aufs/file.h +--- linux-5.4/fs/aufs/file.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/file.h 2019-11-28 01:25:59.065925618 +0200 +@@ -0,0 +1,329 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * file operations ++ */ ++ ++#ifndef __AUFS_FILE_H__ ++#define __AUFS_FILE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++#include "rwsem.h" ++ ++struct au_branch; ++struct au_hfile { ++ struct file *hf_file; ++ struct au_branch *hf_br; ++}; ++ ++struct au_vdir; ++struct au_fidir { ++ aufs_bindex_t fd_bbot; ++ aufs_bindex_t fd_nent; ++ struct au_vdir *fd_vdir_cache; ++ struct au_hfile fd_hfile[]; ++}; ++ ++static inline int au_fidir_sz(int nent) ++{ ++ AuDebugOn(nent < 0); ++ return sizeof(struct au_fidir) + sizeof(struct au_hfile) * nent; ++} ++ ++struct au_finfo { ++ atomic_t fi_generation; ++ ++ struct au_rwsem fi_rwsem; ++ aufs_bindex_t fi_btop; ++ ++ /* do not union them */ ++ struct { /* for non-dir */ ++ struct au_hfile fi_htop; ++ atomic_t fi_mmapped; ++ }; ++ struct au_fidir *fi_hdir; /* for dir only */ ++ ++ struct hlist_bl_node fi_hlist; ++ struct file *fi_file; /* very ugly */ ++ struct rcu_head rcu; ++} ____cacheline_aligned_in_smp; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* file.c */ ++extern const struct address_space_operations aufs_aop; ++unsigned int au_file_roflags(unsigned int flags); ++struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, ++ struct file *file, int force_wr); ++struct au_do_open_args { ++ int aopen; ++ int (*open)(struct file *file, int flags, ++ struct file *h_file); ++ struct au_fidir *fidir; ++ struct file *h_file; ++}; ++int au_do_open(struct file *file, struct au_do_open_args *args); ++int au_reopen_nondir(struct file *file); ++struct au_pin; ++int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin); ++int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file), ++ int wlock, unsigned int fi_lsc); ++int au_do_flush(struct file *file, fl_owner_t id, ++ int (*flush)(struct file *file, fl_owner_t id)); ++ ++/* poll.c */ ++#ifdef CONFIG_AUFS_POLL ++__poll_t aufs_poll(struct file *file, struct poll_table_struct *pt); ++#endif ++ ++#ifdef CONFIG_AUFS_BR_HFSPLUS ++/* hfsplus.c */ ++struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex, ++ int force_wr); ++void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex, ++ struct file *h_file); ++#else ++AuStub(struct file *, au_h_open_pre, return NULL, struct dentry *dentry, ++ aufs_bindex_t bindex, int force_wr) ++AuStubVoid(au_h_open_post, struct dentry *dentry, aufs_bindex_t bindex, ++ struct file *h_file); ++#endif ++ ++/* f_op.c */ ++extern const struct file_operations aufs_file_fop; ++int au_do_open_nondir(struct file *file, int flags, struct file *h_file); ++int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file); ++struct file *au_read_pre(struct file *file, int keep_fi, unsigned int lsc); ++ ++/* finfo.c */ ++void au_hfput(struct au_hfile *hf, int execed); ++void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, ++ struct file *h_file); ++ ++void au_update_figen(struct file *file); ++struct au_fidir *au_fidir_alloc(struct super_block *sb); ++int au_fidir_realloc(struct au_finfo *finfo, int nbr, int may_shrink); ++ ++void au_fi_init_once(void *_fi); ++void au_finfo_fin(struct file *file); ++int au_finfo_init(struct file *file, struct au_fidir *fidir); ++ ++/* ioctl.c */ ++long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg); ++#ifdef CONFIG_COMPAT ++long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd, ++ unsigned long arg); ++long aufs_compat_ioctl_nondir(struct file *file, unsigned int cmd, ++ unsigned long arg); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_finfo *au_fi(struct file *file) ++{ ++ return file->private_data; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define fi_read_lock(f) au_rw_read_lock(&au_fi(f)->fi_rwsem) ++#define fi_write_lock(f) au_rw_write_lock(&au_fi(f)->fi_rwsem) ++#define fi_read_trylock(f) au_rw_read_trylock(&au_fi(f)->fi_rwsem) ++#define fi_write_trylock(f) au_rw_write_trylock(&au_fi(f)->fi_rwsem) ++/* ++#define fi_read_trylock_nested(f) \ ++ au_rw_read_trylock_nested(&au_fi(f)->fi_rwsem) ++#define fi_write_trylock_nested(f) \ ++ au_rw_write_trylock_nested(&au_fi(f)->fi_rwsem) ++*/ ++ ++#define fi_read_unlock(f) au_rw_read_unlock(&au_fi(f)->fi_rwsem) ++#define fi_write_unlock(f) au_rw_write_unlock(&au_fi(f)->fi_rwsem) ++#define fi_downgrade_lock(f) au_rw_dgrade_lock(&au_fi(f)->fi_rwsem) ++ ++/* lock subclass for finfo */ ++enum { ++ AuLsc_FI_1, ++ AuLsc_FI_2 ++}; ++ ++static inline void fi_read_lock_nested(struct file *f, unsigned int lsc) ++{ ++ au_rw_read_lock_nested(&au_fi(f)->fi_rwsem, lsc); ++} ++ ++static inline void fi_write_lock_nested(struct file *f, unsigned int lsc) ++{ ++ au_rw_write_lock_nested(&au_fi(f)->fi_rwsem, lsc); ++} ++ ++/* ++ * fi_read_lock_1, fi_write_lock_1, ++ * fi_read_lock_2, fi_write_lock_2 ++ */ ++#define AuReadLockFunc(name) \ ++static inline void fi_read_lock_##name(struct file *f) \ ++{ fi_read_lock_nested(f, AuLsc_FI_##name); } ++ ++#define AuWriteLockFunc(name) \ ++static inline void fi_write_lock_##name(struct file *f) \ ++{ fi_write_lock_nested(f, AuLsc_FI_##name); } ++ ++#define AuRWLockFuncs(name) \ ++ AuReadLockFunc(name) \ ++ AuWriteLockFunc(name) ++ ++AuRWLockFuncs(1); ++AuRWLockFuncs(2); ++ ++#undef AuReadLockFunc ++#undef AuWriteLockFunc ++#undef AuRWLockFuncs ++ ++#define FiMustNoWaiters(f) AuRwMustNoWaiters(&au_fi(f)->fi_rwsem) ++#define FiMustAnyLock(f) AuRwMustAnyLock(&au_fi(f)->fi_rwsem) ++#define FiMustWriteLock(f) AuRwMustWriteLock(&au_fi(f)->fi_rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* todo: hard/soft set? */ ++static inline aufs_bindex_t au_fbtop(struct file *file) ++{ ++ FiMustAnyLock(file); ++ return au_fi(file)->fi_btop; ++} ++ ++static inline aufs_bindex_t au_fbbot_dir(struct file *file) ++{ ++ FiMustAnyLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ return au_fi(file)->fi_hdir->fd_bbot; ++} ++ ++static inline struct au_vdir *au_fvdir_cache(struct file *file) ++{ ++ FiMustAnyLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ return au_fi(file)->fi_hdir->fd_vdir_cache; ++} ++ ++static inline void au_set_fbtop(struct file *file, aufs_bindex_t bindex) ++{ ++ FiMustWriteLock(file); ++ au_fi(file)->fi_btop = bindex; ++} ++ ++static inline void au_set_fbbot_dir(struct file *file, aufs_bindex_t bindex) ++{ ++ FiMustWriteLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ au_fi(file)->fi_hdir->fd_bbot = bindex; ++} ++ ++static inline void au_set_fvdir_cache(struct file *file, ++ struct au_vdir *vdir_cache) ++{ ++ FiMustWriteLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ au_fi(file)->fi_hdir->fd_vdir_cache = vdir_cache; ++} ++ ++static inline struct file *au_hf_top(struct file *file) ++{ ++ FiMustAnyLock(file); ++ AuDebugOn(au_fi(file)->fi_hdir); ++ return au_fi(file)->fi_htop.hf_file; ++} ++ ++static inline struct file *au_hf_dir(struct file *file, aufs_bindex_t bindex) ++{ ++ FiMustAnyLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ return au_fi(file)->fi_hdir->fd_hfile[0 + bindex].hf_file; ++} ++ ++/* todo: memory barrier? */ ++static inline unsigned int au_figen(struct file *f) ++{ ++ return atomic_read(&au_fi(f)->fi_generation); ++} ++ ++static inline void au_set_mmapped(struct file *f) ++{ ++ if (atomic_inc_return(&au_fi(f)->fi_mmapped)) ++ return; ++ pr_warn("fi_mmapped wrapped around\n"); ++ while (!atomic_inc_return(&au_fi(f)->fi_mmapped)) ++ ; ++} ++ ++static inline void au_unset_mmapped(struct file *f) ++{ ++ atomic_dec(&au_fi(f)->fi_mmapped); ++} ++ ++static inline int au_test_mmapped(struct file *f) ++{ ++ return atomic_read(&au_fi(f)->fi_mmapped); ++} ++ ++/* customize vma->vm_file */ ++ ++static inline void au_do_vm_file_reset(struct vm_area_struct *vma, ++ struct file *file) ++{ ++ struct file *f; ++ ++ f = vma->vm_file; ++ get_file(file); ++ vma->vm_file = file; ++ fput(f); ++} ++ ++#ifdef CONFIG_MMU ++#define AuDbgVmRegion(file, vma) do {} while (0) ++ ++static inline void au_vm_file_reset(struct vm_area_struct *vma, ++ struct file *file) ++{ ++ au_do_vm_file_reset(vma, file); ++} ++#else ++#define AuDbgVmRegion(file, vma) \ ++ AuDebugOn((vma)->vm_region && (vma)->vm_region->vm_file != (file)) ++ ++static inline void au_vm_file_reset(struct vm_area_struct *vma, ++ struct file *file) ++{ ++ struct file *f; ++ ++ au_do_vm_file_reset(vma, file); ++ f = vma->vm_region->vm_file; ++ get_file(file); ++ vma->vm_region->vm_file = file; ++ fput(f); ++} ++#endif /* CONFIG_MMU */ ++ ++/* handle vma->vm_prfile */ ++static inline void au_vm_prfile_set(struct vm_area_struct *vma, ++ struct file *file) ++{ ++ get_file(file); ++ vma->vm_prfile = file; ++#ifndef CONFIG_MMU ++ get_file(file); ++ vma->vm_region->vm_prfile = file; ++#endif ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_FILE_H__ */ +diff -Nurp linux-5.4/fs/aufs/finfo.c linux-5.4-aufs/fs/aufs/finfo.c +--- linux-5.4/fs/aufs/finfo.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/finfo.c 2019-11-28 01:25:59.065925618 +0200 +@@ -0,0 +1,136 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * file private data ++ */ ++ ++#include "aufs.h" ++ ++void au_hfput(struct au_hfile *hf, int execed) ++{ ++ if (execed) ++ allow_write_access(hf->hf_file); ++ fput(hf->hf_file); ++ hf->hf_file = NULL; ++ au_lcnt_dec(&hf->hf_br->br_nfiles); ++ hf->hf_br = NULL; ++} ++ ++void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, struct file *val) ++{ ++ struct au_finfo *finfo = au_fi(file); ++ struct au_hfile *hf; ++ struct au_fidir *fidir; ++ ++ fidir = finfo->fi_hdir; ++ if (!fidir) { ++ AuDebugOn(finfo->fi_btop != bindex); ++ hf = &finfo->fi_htop; ++ } else ++ hf = fidir->fd_hfile + bindex; ++ ++ if (hf && hf->hf_file) ++ au_hfput(hf, vfsub_file_execed(file)); ++ if (val) { ++ FiMustWriteLock(file); ++ AuDebugOn(IS_ERR_OR_NULL(file->f_path.dentry)); ++ hf->hf_file = val; ++ hf->hf_br = au_sbr(file->f_path.dentry->d_sb, bindex); ++ } ++} ++ ++void au_update_figen(struct file *file) ++{ ++ atomic_set(&au_fi(file)->fi_generation, au_digen(file->f_path.dentry)); ++ /* smp_mb(); */ /* atomic_set */ ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_fidir *au_fidir_alloc(struct super_block *sb) ++{ ++ struct au_fidir *fidir; ++ int nbr; ++ ++ nbr = au_sbbot(sb) + 1; ++ if (nbr < 2) ++ nbr = 2; /* initial allocate for 2 branches */ ++ fidir = kzalloc(au_fidir_sz(nbr), GFP_NOFS); ++ if (fidir) { ++ fidir->fd_bbot = -1; ++ fidir->fd_nent = nbr; ++ } ++ ++ return fidir; ++} ++ ++int au_fidir_realloc(struct au_finfo *finfo, int nbr, int may_shrink) ++{ ++ int err; ++ struct au_fidir *fidir, *p; ++ ++ AuRwMustWriteLock(&finfo->fi_rwsem); ++ fidir = finfo->fi_hdir; ++ AuDebugOn(!fidir); ++ ++ err = -ENOMEM; ++ p = au_kzrealloc(fidir, au_fidir_sz(fidir->fd_nent), au_fidir_sz(nbr), ++ GFP_NOFS, may_shrink); ++ if (p) { ++ p->fd_nent = nbr; ++ finfo->fi_hdir = p; ++ err = 0; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_finfo_fin(struct file *file) ++{ ++ struct au_finfo *finfo; ++ ++ au_lcnt_dec(&au_sbi(file->f_path.dentry->d_sb)->si_nfiles); ++ ++ finfo = au_fi(file); ++ AuDebugOn(finfo->fi_hdir); ++ AuRwDestroy(&finfo->fi_rwsem); ++ au_cache_free_finfo(finfo); ++} ++ ++void au_fi_init_once(void *_finfo) ++{ ++ struct au_finfo *finfo = _finfo; ++ ++ au_rw_init(&finfo->fi_rwsem); ++} ++ ++int au_finfo_init(struct file *file, struct au_fidir *fidir) ++{ ++ int err; ++ struct au_finfo *finfo; ++ struct dentry *dentry; ++ ++ err = -ENOMEM; ++ dentry = file->f_path.dentry; ++ finfo = au_cache_alloc_finfo(); ++ if (unlikely(!finfo)) ++ goto out; ++ ++ err = 0; ++ au_lcnt_inc(&au_sbi(dentry->d_sb)->si_nfiles); ++ au_rw_write_lock(&finfo->fi_rwsem); ++ finfo->fi_btop = -1; ++ finfo->fi_hdir = fidir; ++ atomic_set(&finfo->fi_generation, au_digen(dentry)); ++ /* smp_mb(); */ /* atomic_set */ ++ ++ file->private_data = finfo; ++ ++out: ++ return err; ++} +diff -Nurp linux-5.4/fs/aufs/f_op.c linux-5.4-aufs/fs/aufs/f_op.c +--- linux-5.4/fs/aufs/f_op.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/f_op.c 2019-11-28 01:25:59.064925618 +0200 +@@ -0,0 +1,806 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * file and vm operations ++ */ ++ ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++int au_do_open_nondir(struct file *file, int flags, struct file *h_file) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct dentry *dentry, *h_dentry; ++ struct au_finfo *finfo; ++ struct inode *h_inode; ++ ++ FiMustWriteLock(file); ++ ++ err = 0; ++ dentry = file->f_path.dentry; ++ AuDebugOn(IS_ERR_OR_NULL(dentry)); ++ finfo = au_fi(file); ++ memset(&finfo->fi_htop, 0, sizeof(finfo->fi_htop)); ++ atomic_set(&finfo->fi_mmapped, 0); ++ bindex = au_dbtop(dentry); ++ if (!h_file) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ err = vfsub_test_mntns(file->f_path.mnt, h_dentry->d_sb); ++ if (unlikely(err)) ++ goto out; ++ h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); ++ if (IS_ERR(h_file)) { ++ err = PTR_ERR(h_file); ++ goto out; ++ } ++ } else { ++ h_dentry = h_file->f_path.dentry; ++ err = vfsub_test_mntns(file->f_path.mnt, h_dentry->d_sb); ++ if (unlikely(err)) ++ goto out; ++ /* br ref is already inc-ed */ ++ } ++ ++ if ((flags & __O_TMPFILE) ++ && !(flags & O_EXCL)) { ++ h_inode = file_inode(h_file); ++ spin_lock(&h_inode->i_lock); ++ h_inode->i_state |= I_LINKABLE; ++ spin_unlock(&h_inode->i_lock); ++ } ++ au_set_fbtop(file, bindex); ++ au_set_h_fptr(file, bindex, h_file); ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ ++out: ++ return err; ++} ++ ++static int aufs_open_nondir(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ int err; ++ struct super_block *sb; ++ struct au_do_open_args args = { ++ .open = au_do_open_nondir ++ }; ++ ++ AuDbg("%pD, f_flags 0x%x, f_mode 0x%x\n", ++ file, vfsub_file_flags(file), file->f_mode); ++ ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ err = au_do_open(file, &args); ++ si_read_unlock(sb); ++ return err; ++} ++ ++int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file) ++{ ++ struct au_finfo *finfo; ++ aufs_bindex_t bindex; ++ ++ finfo = au_fi(file); ++ au_hbl_del(&finfo->fi_hlist, ++ &au_sbi(file->f_path.dentry->d_sb)->si_files); ++ bindex = finfo->fi_btop; ++ if (bindex >= 0) ++ au_set_h_fptr(file, bindex, NULL); ++ ++ au_finfo_fin(file); ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_flush_nondir(struct file *file, fl_owner_t id) ++{ ++ int err; ++ struct file *h_file; ++ ++ err = 0; ++ h_file = au_hf_top(file); ++ if (h_file) ++ err = vfsub_flush(h_file, id); ++ return err; ++} ++ ++static int aufs_flush_nondir(struct file *file, fl_owner_t id) ++{ ++ return au_do_flush(file, id, au_do_flush_nondir); ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * read and write functions acquire [fdi]_rwsem once, but release before ++ * mmap_sem. This is because to stop a race condition between mmap(2). ++ * Releasing these aufs-rwsem should be safe, no branch-management (by keeping ++ * si_rwsem), no harmful copy-up should happen. Actually copy-up may happen in ++ * read functions after [fdi]_rwsem are released, but it should be harmless. ++ */ ++ ++/* Callers should call au_read_post() or fput() in the end */ ++struct file *au_read_pre(struct file *file, int keep_fi, unsigned int lsc) ++{ ++ struct file *h_file; ++ int err; ++ ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/0, lsc); ++ if (!err) { ++ di_read_unlock(file->f_path.dentry, AuLock_IR); ++ h_file = au_hf_top(file); ++ get_file(h_file); ++ if (!keep_fi) ++ fi_read_unlock(file); ++ } else ++ h_file = ERR_PTR(err); ++ ++ return h_file; ++} ++ ++static void au_read_post(struct inode *inode, struct file *h_file) ++{ ++ /* update without lock, I don't think it a problem */ ++ fsstack_copy_attr_atime(inode, file_inode(h_file)); ++ fput(h_file); ++} ++ ++struct au_write_pre { ++ /* input */ ++ unsigned int lsc; ++ ++ /* output */ ++ blkcnt_t blks; ++ aufs_bindex_t btop; ++}; ++ ++/* ++ * return with iinfo is write-locked ++ * callers should call au_write_post() or iinfo_write_unlock() + fput() in the ++ * end ++ */ ++static struct file *au_write_pre(struct file *file, int do_ready, ++ struct au_write_pre *wpre) ++{ ++ struct file *h_file; ++ struct dentry *dentry; ++ int err; ++ unsigned int lsc; ++ struct au_pin pin; ++ ++ lsc = 0; ++ if (wpre) ++ lsc = wpre->lsc; ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1, lsc); ++ h_file = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ dentry = file->f_path.dentry; ++ if (do_ready) { ++ err = au_ready_to_write(file, -1, &pin); ++ if (unlikely(err)) { ++ h_file = ERR_PTR(err); ++ di_write_unlock(dentry); ++ goto out_fi; ++ } ++ } ++ ++ di_downgrade_lock(dentry, /*flags*/0); ++ if (wpre) ++ wpre->btop = au_fbtop(file); ++ h_file = au_hf_top(file); ++ get_file(h_file); ++ if (wpre) ++ wpre->blks = file_inode(h_file)->i_blocks; ++ if (do_ready) ++ au_unpin(&pin); ++ di_read_unlock(dentry, /*flags*/0); ++ ++out_fi: ++ fi_write_unlock(file); ++out: ++ return h_file; ++} ++ ++static void au_write_post(struct inode *inode, struct file *h_file, ++ struct au_write_pre *wpre, ssize_t written) ++{ ++ struct inode *h_inode; ++ ++ au_cpup_attr_timesizes(inode); ++ AuDebugOn(au_ibtop(inode) != wpre->btop); ++ h_inode = file_inode(h_file); ++ inode->i_mode = h_inode->i_mode; ++ ii_write_unlock(inode); ++ /* AuDbg("blks %llu, %llu\n", (u64)blks, (u64)h_inode->i_blocks); */ ++ if (written > 0) ++ au_fhsm_wrote(inode->i_sb, wpre->btop, ++ /*force*/h_inode->i_blocks > wpre->blks); ++ fput(h_file); ++} ++ ++static ssize_t aufs_read(struct file *file, char __user *buf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ struct inode *inode; ++ struct file *h_file; ++ struct super_block *sb; ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/0, /*lsc*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ /* filedata may be obsoleted by concurrent copyup, but no problem */ ++ err = vfsub_read_u(h_file, buf, count, ppos); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ au_read_post(inode, h_file); ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ++ * todo: very ugly ++ * it locks both of i_mutex and si_rwsem for read in safe. ++ * if the plink maintenance mode continues forever (that is the problem), ++ * may loop forever. ++ */ ++static void au_mtx_and_read_lock(struct inode *inode) ++{ ++ int err; ++ struct super_block *sb = inode->i_sb; ++ ++ while (1) { ++ inode_lock(inode); ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (!err) ++ break; ++ inode_unlock(inode); ++ si_read_lock(sb, AuLock_NOPLMW); ++ si_read_unlock(sb); ++ } ++} ++ ++static ssize_t aufs_write(struct file *file, const char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ ssize_t err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *h_file; ++ char __user *buf = (char __user *)ubuf; ++ ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ wpre.lsc = 0; ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = vfsub_write_u(h_file, buf, count, ppos); ++ au_write_post(inode, h_file, &wpre, err); ++ ++out: ++ si_read_unlock(inode->i_sb); ++ inode_unlock(inode); ++ return err; ++} ++ ++static ssize_t au_do_iter(struct file *h_file, int rw, struct kiocb *kio, ++ struct iov_iter *iov_iter) ++{ ++ ssize_t err; ++ struct file *file; ++ ssize_t (*iter)(struct kiocb *, struct iov_iter *); ++ ++ err = security_file_permission(h_file, rw); ++ if (unlikely(err)) ++ goto out; ++ ++ err = -ENOSYS; ++ iter = NULL; ++ if (rw == MAY_READ) ++ iter = h_file->f_op->read_iter; ++ else if (rw == MAY_WRITE) ++ iter = h_file->f_op->write_iter; ++ ++ file = kio->ki_filp; ++ kio->ki_filp = h_file; ++ if (iter) { ++ lockdep_off(); ++ err = iter(kio, iov_iter); ++ lockdep_on(); ++ } else ++ /* currently there is no such fs */ ++ WARN_ON_ONCE(1); ++ kio->ki_filp = file; ++ ++out: ++ return err; ++} ++ ++static ssize_t aufs_read_iter(struct kiocb *kio, struct iov_iter *iov_iter) ++{ ++ ssize_t err; ++ struct file *file, *h_file; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ file = kio->ki_filp; ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/1, /*lsc*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ if (au_test_loopback_kthread()) { ++ au_warn_loopback(h_file->f_path.dentry->d_sb); ++ if (file->f_mapping != h_file->f_mapping) { ++ file->f_mapping = h_file->f_mapping; ++ smp_mb(); /* unnecessary? */ ++ } ++ } ++ fi_read_unlock(file); ++ ++ err = au_do_iter(h_file, MAY_READ, kio, iov_iter); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ au_read_post(inode, h_file); ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++static ssize_t aufs_write_iter(struct kiocb *kio, struct iov_iter *iov_iter) ++{ ++ ssize_t err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *file, *h_file; ++ ++ file = kio->ki_filp; ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ wpre.lsc = 0; ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = au_do_iter(h_file, MAY_WRITE, kio, iov_iter); ++ au_write_post(inode, h_file, &wpre, err); ++ ++out: ++ si_read_unlock(inode->i_sb); ++ inode_unlock(inode); ++ return err; ++} ++ ++static ssize_t aufs_splice_read(struct file *file, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags) ++{ ++ ssize_t err; ++ struct file *h_file; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/0, /*lsc*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = vfsub_splice_to(h_file, ppos, pipe, len, flags); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ au_read_post(inode, h_file); ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++static ssize_t ++aufs_splice_write(struct pipe_inode_info *pipe, struct file *file, loff_t *ppos, ++ size_t len, unsigned int flags) ++{ ++ ssize_t err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *h_file; ++ ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ wpre.lsc = 0; ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = vfsub_splice_from(pipe, h_file, ppos, len, flags); ++ au_write_post(inode, h_file, &wpre, err); ++ ++out: ++ si_read_unlock(inode->i_sb); ++ inode_unlock(inode); ++ return err; ++} ++ ++static long aufs_fallocate(struct file *file, int mode, loff_t offset, ++ loff_t len) ++{ ++ long err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *h_file; ++ ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ wpre.lsc = 0; ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ lockdep_off(); ++ err = vfs_fallocate(h_file, mode, offset, len); ++ lockdep_on(); ++ au_write_post(inode, h_file, &wpre, /*written*/1); ++ ++out: ++ si_read_unlock(inode->i_sb); ++ inode_unlock(inode); ++ return err; ++} ++ ++static ssize_t aufs_copy_file_range(struct file *src, loff_t src_pos, ++ struct file *dst, loff_t dst_pos, ++ size_t len, unsigned int flags) ++{ ++ ssize_t err; ++ struct au_write_pre wpre; ++ enum { SRC, DST }; ++ struct { ++ struct inode *inode; ++ struct file *h_file; ++ struct super_block *h_sb; ++ } a[2]; ++#define a_src a[SRC] ++#define a_dst a[DST] ++ ++ err = -EINVAL; ++ a_src.inode = file_inode(src); ++ if (unlikely(!S_ISREG(a_src.inode->i_mode))) ++ goto out; ++ a_dst.inode = file_inode(dst); ++ if (unlikely(!S_ISREG(a_dst.inode->i_mode))) ++ goto out; ++ ++ au_mtx_and_read_lock(a_dst.inode); ++ /* ++ * in order to match the order in di_write_lock2_{child,parent}(), ++ * use f_path.dentry for this comparison. ++ */ ++ if (src->f_path.dentry < dst->f_path.dentry) { ++ a_src.h_file = au_read_pre(src, /*keep_fi*/1, AuLsc_FI_1); ++ err = PTR_ERR(a_src.h_file); ++ if (IS_ERR(a_src.h_file)) ++ goto out_si; ++ ++ wpre.lsc = AuLsc_FI_2; ++ a_dst.h_file = au_write_pre(dst, /*do_ready*/1, &wpre); ++ err = PTR_ERR(a_dst.h_file); ++ if (IS_ERR(a_dst.h_file)) { ++ au_read_post(a_src.inode, a_src.h_file); ++ goto out_si; ++ } ++ } else { ++ wpre.lsc = AuLsc_FI_1; ++ a_dst.h_file = au_write_pre(dst, /*do_ready*/1, &wpre); ++ err = PTR_ERR(a_dst.h_file); ++ if (IS_ERR(a_dst.h_file)) ++ goto out_si; ++ ++ a_src.h_file = au_read_pre(src, /*keep_fi*/1, AuLsc_FI_2); ++ err = PTR_ERR(a_src.h_file); ++ if (IS_ERR(a_src.h_file)) { ++ au_write_post(a_dst.inode, a_dst.h_file, &wpre, ++ /*written*/0); ++ goto out_si; ++ } ++ } ++ ++ err = -EXDEV; ++ a_src.h_sb = file_inode(a_src.h_file)->i_sb; ++ a_dst.h_sb = file_inode(a_dst.h_file)->i_sb; ++ if (unlikely(a_src.h_sb != a_dst.h_sb)) { ++ AuDbgFile(src); ++ AuDbgFile(dst); ++ goto out_file; ++ } ++ ++ err = vfsub_copy_file_range(a_src.h_file, src_pos, a_dst.h_file, ++ dst_pos, len, flags); ++ ++out_file: ++ au_write_post(a_dst.inode, a_dst.h_file, &wpre, err); ++ fi_read_unlock(src); ++ au_read_post(a_src.inode, a_src.h_file); ++out_si: ++ si_read_unlock(a_dst.inode->i_sb); ++ inode_unlock(a_dst.inode); ++out: ++ return err; ++#undef a_src ++#undef a_dst ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * The locking order around current->mmap_sem. ++ * - in most and regular cases ++ * file I/O syscall -- aufs_read() or something ++ * -- si_rwsem for read -- mmap_sem ++ * (Note that [fdi]i_rwsem are released before mmap_sem). ++ * - in mmap case ++ * mmap(2) -- mmap_sem -- aufs_mmap() -- si_rwsem for read -- [fdi]i_rwsem ++ * This AB-BA order is definitely bad, but is not a problem since "si_rwsem for ++ * read" allows multiple processes to acquire it and [fdi]i_rwsem are not held ++ * in file I/O. Aufs needs to stop lockdep in aufs_mmap() though. ++ * It means that when aufs acquires si_rwsem for write, the process should never ++ * acquire mmap_sem. ++ * ++ * Actually aufs_iterate() holds [fdi]i_rwsem before mmap_sem, but this is not a ++ * problem either since any directory is not able to be mmap-ed. ++ * The similar scenario is applied to aufs_readlink() too. ++ */ ++ ++#if 0 /* stop calling security_file_mmap() */ ++/* cf. linux/include/linux/mman.h: calc_vm_prot_bits() */ ++#define AuConv_VM_PROT(f, b) _calc_vm_trans(f, VM_##b, PROT_##b) ++ ++static unsigned long au_arch_prot_conv(unsigned long flags) ++{ ++ /* currently ppc64 only */ ++#ifdef CONFIG_PPC64 ++ /* cf. linux/arch/powerpc/include/asm/mman.h */ ++ AuDebugOn(arch_calc_vm_prot_bits(-1) != VM_SAO); ++ return AuConv_VM_PROT(flags, SAO); ++#else ++ AuDebugOn(arch_calc_vm_prot_bits(-1)); ++ return 0; ++#endif ++} ++ ++static unsigned long au_prot_conv(unsigned long flags) ++{ ++ return AuConv_VM_PROT(flags, READ) ++ | AuConv_VM_PROT(flags, WRITE) ++ | AuConv_VM_PROT(flags, EXEC) ++ | au_arch_prot_conv(flags); ++} ++ ++/* cf. linux/include/linux/mman.h: calc_vm_flag_bits() */ ++#define AuConv_VM_MAP(f, b) _calc_vm_trans(f, VM_##b, MAP_##b) ++ ++static unsigned long au_flag_conv(unsigned long flags) ++{ ++ return AuConv_VM_MAP(flags, GROWSDOWN) ++ | AuConv_VM_MAP(flags, DENYWRITE) ++ | AuConv_VM_MAP(flags, LOCKED); ++} ++#endif ++ ++static int aufs_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ int err; ++ const unsigned char wlock ++ = (file->f_mode & FMODE_WRITE) && (vma->vm_flags & VM_SHARED); ++ struct super_block *sb; ++ struct file *h_file; ++ struct inode *inode; ++ ++ AuDbgVmRegion(file, vma); ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ lockdep_off(); ++ si_read_lock(sb, AuLock_NOPLMW); ++ ++ h_file = au_write_pre(file, wlock, /*wpre*/NULL); ++ lockdep_on(); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = 0; ++ au_set_mmapped(file); ++ au_vm_file_reset(vma, h_file); ++ /* ++ * we cannot call security_mmap_file() here since it may acquire ++ * mmap_sem or i_mutex. ++ * ++ * err = security_mmap_file(h_file, au_prot_conv(vma->vm_flags), ++ * au_flag_conv(vma->vm_flags)); ++ */ ++ if (!err) ++ err = call_mmap(h_file, vma); ++ if (!err) { ++ au_vm_prfile_set(vma, file); ++ fsstack_copy_attr_atime(inode, file_inode(h_file)); ++ goto out_fput; /* success */ ++ } ++ au_unset_mmapped(file); ++ au_vm_file_reset(vma, file); ++ ++out_fput: ++ lockdep_off(); ++ ii_write_unlock(inode); ++ lockdep_on(); ++ fput(h_file); ++out: ++ lockdep_off(); ++ si_read_unlock(sb); ++ lockdep_on(); ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_fsync_nondir(struct file *file, loff_t start, loff_t end, ++ int datasync) ++{ ++ int err; ++ struct au_write_pre wpre; ++ struct inode *inode; ++ struct file *h_file; ++ ++ err = 0; /* -EBADF; */ /* posix? */ ++ if (unlikely(!(file->f_mode & FMODE_WRITE))) ++ goto out; ++ ++ inode = file_inode(file); ++ au_mtx_and_read_lock(inode); ++ ++ wpre.lsc = 0; ++ h_file = au_write_pre(file, /*do_ready*/1, &wpre); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out_unlock; ++ ++ err = vfsub_fsync(h_file, &h_file->f_path, datasync); ++ au_write_post(inode, h_file, &wpre, /*written*/0); ++ ++out_unlock: ++ si_read_unlock(inode->i_sb); ++ inode_unlock(inode); ++out: ++ return err; ++} ++ ++static int aufs_fasync(int fd, struct file *file, int flag) ++{ ++ int err; ++ struct file *h_file; ++ struct super_block *sb; ++ ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/0, /*lsc*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ if (h_file->f_op->fasync) ++ err = h_file->f_op->fasync(fd, h_file, flag); ++ fput(h_file); /* instead of au_read_post() */ ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++static int aufs_setfl(struct file *file, unsigned long arg) ++{ ++ int err; ++ struct file *h_file; ++ struct super_block *sb; ++ ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/0, /*lsc*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ /* stop calling h_file->fasync */ ++ arg |= vfsub_file_flags(file) & FASYNC; ++ err = setfl(/*unused fd*/-1, h_file, arg); ++ fput(h_file); /* instead of au_read_post() */ ++ ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* no one supports this operation, currently */ ++#if 0 ++static ssize_t aufs_sendpage(struct file *file, struct page *page, int offset, ++ size_t len, loff_t *pos, int more) ++{ ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++const struct file_operations aufs_file_fop = { ++ .owner = THIS_MODULE, ++ ++ .llseek = default_llseek, ++ ++ .read = aufs_read, ++ .write = aufs_write, ++ .read_iter = aufs_read_iter, ++ .write_iter = aufs_write_iter, ++ ++#ifdef CONFIG_AUFS_POLL ++ .poll = aufs_poll, ++#endif ++ .unlocked_ioctl = aufs_ioctl_nondir, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = aufs_compat_ioctl_nondir, ++#endif ++ .mmap = aufs_mmap, ++ .open = aufs_open_nondir, ++ .flush = aufs_flush_nondir, ++ .release = aufs_release_nondir, ++ .fsync = aufs_fsync_nondir, ++ .fasync = aufs_fasync, ++ /* .sendpage = aufs_sendpage, */ ++ .setfl = aufs_setfl, ++ .splice_write = aufs_splice_write, ++ .splice_read = aufs_splice_read, ++#if 0 ++ .aio_splice_write = aufs_aio_splice_write, ++ .aio_splice_read = aufs_aio_splice_read, ++#endif ++ .fallocate = aufs_fallocate, ++ .copy_file_range = aufs_copy_file_range ++}; +diff -Nurp linux-5.4/fs/aufs/fstype.h linux-5.4-aufs/fs/aufs/fstype.h +--- linux-5.4/fs/aufs/fstype.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/fstype.h 2019-11-28 01:25:59.065925618 +0200 +@@ -0,0 +1,388 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * judging filesystem type ++ */ ++ ++#ifndef __AUFS_FSTYPE_H__ ++#define __AUFS_FSTYPE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++ ++static inline int au_test_aufs(struct super_block *sb) ++{ ++ return sb->s_magic == AUFS_SUPER_MAGIC; ++} ++ ++static inline const char *au_sbtype(struct super_block *sb) ++{ ++ return sb->s_type->name; ++} ++ ++static inline int au_test_iso9660(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_ISO9660_FS) ++ return sb->s_magic == ISOFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_romfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_ROMFS_FS) ++ return sb->s_magic == ROMFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_cramfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_CRAMFS) ++ return sb->s_magic == CRAMFS_MAGIC; ++#endif ++ return 0; ++} ++ ++static inline int au_test_nfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_NFS_FS) ++ return sb->s_magic == NFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_fuse(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_FUSE_FS) ++ return sb->s_magic == FUSE_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_xfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_XFS_FS) ++ return sb->s_magic == XFS_SB_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_tmpfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_TMPFS ++ return sb->s_magic == TMPFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_ecryptfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_ECRYPT_FS) ++ return !strcmp(au_sbtype(sb), "ecryptfs"); ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_ramfs(struct super_block *sb) ++{ ++ return sb->s_magic == RAMFS_MAGIC; ++} ++ ++static inline int au_test_ubifs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_UBIFS_FS) ++ return sb->s_magic == UBIFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_procfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_PROC_FS ++ return sb->s_magic == PROC_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_sysfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_SYSFS ++ return sb->s_magic == SYSFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_configfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_CONFIGFS_FS) ++ return sb->s_magic == CONFIGFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_minix(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_MINIX_FS) ++ return sb->s_magic == MINIX3_SUPER_MAGIC ++ || sb->s_magic == MINIX2_SUPER_MAGIC ++ || sb->s_magic == MINIX2_SUPER_MAGIC2 ++ || sb->s_magic == MINIX_SUPER_MAGIC ++ || sb->s_magic == MINIX_SUPER_MAGIC2; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_fat(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_FAT_FS) ++ return sb->s_magic == MSDOS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_msdos(struct super_block *sb) ++{ ++ return au_test_fat(sb); ++} ++ ++static inline int au_test_vfat(struct super_block *sb) ++{ ++ return au_test_fat(sb); ++} ++ ++static inline int au_test_securityfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_SECURITYFS ++ return sb->s_magic == SECURITYFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_squashfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_SQUASHFS) ++ return sb->s_magic == SQUASHFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_btrfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_BTRFS_FS) ++ return sb->s_magic == BTRFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_xenfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_XENFS) ++ return sb->s_magic == XENFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_debugfs(struct super_block *sb __maybe_unused) ++{ ++#ifdef CONFIG_DEBUG_FS ++ return sb->s_magic == DEBUGFS_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_nilfs(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_NILFS) ++ return sb->s_magic == NILFS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_test_hfsplus(struct super_block *sb __maybe_unused) ++{ ++#if IS_ENABLED(CONFIG_HFSPLUS_FS) ++ return sb->s_magic == HFSPLUS_SUPER_MAGIC; ++#else ++ return 0; ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * they can't be an aufs branch. ++ */ ++static inline int au_test_fs_unsuppoted(struct super_block *sb) ++{ ++ return ++#ifndef CONFIG_AUFS_BR_RAMFS ++ au_test_ramfs(sb) || ++#endif ++ au_test_procfs(sb) ++ || au_test_sysfs(sb) ++ || au_test_configfs(sb) ++ || au_test_debugfs(sb) ++ || au_test_securityfs(sb) ++ || au_test_xenfs(sb) ++ || au_test_ecryptfs(sb) ++ /* || !strcmp(au_sbtype(sb), "unionfs") */ ++ || au_test_aufs(sb); /* will be supported in next version */ ++} ++ ++static inline int au_test_fs_remote(struct super_block *sb) ++{ ++ return !au_test_tmpfs(sb) ++#ifdef CONFIG_AUFS_BR_RAMFS ++ && !au_test_ramfs(sb) ++#endif ++ && !(sb->s_type->fs_flags & FS_REQUIRES_DEV); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * Note: these functions (below) are created after reading ->getattr() in all ++ * filesystems under linux/fs. it means we have to do so in every update... ++ */ ++ ++/* ++ * some filesystems require getattr to refresh the inode attributes before ++ * referencing. ++ * in most cases, we can rely on the inode attribute in NFS (or every remote fs) ++ * and leave the work for d_revalidate() ++ */ ++static inline int au_test_fs_refresh_iattr(struct super_block *sb) ++{ ++ return au_test_nfs(sb) ++ || au_test_fuse(sb) ++ /* || au_test_btrfs(sb) */ /* untested */ ++ ; ++} ++ ++/* ++ * filesystems which don't maintain i_size or i_blocks. ++ */ ++static inline int au_test_fs_bad_iattr_size(struct super_block *sb) ++{ ++ return au_test_xfs(sb) ++ || au_test_btrfs(sb) ++ || au_test_ubifs(sb) ++ || au_test_hfsplus(sb) /* maintained, but incorrect */ ++ /* || au_test_minix(sb) */ /* untested */ ++ ; ++} ++ ++/* ++ * filesystems which don't store the correct value in some of their inode ++ * attributes. ++ */ ++static inline int au_test_fs_bad_iattr(struct super_block *sb) ++{ ++ return au_test_fs_bad_iattr_size(sb) ++ || au_test_fat(sb) ++ || au_test_msdos(sb) ++ || au_test_vfat(sb); ++} ++ ++/* they don't check i_nlink in link(2) */ ++static inline int au_test_fs_no_limit_nlink(struct super_block *sb) ++{ ++ return au_test_tmpfs(sb) ++#ifdef CONFIG_AUFS_BR_RAMFS ++ || au_test_ramfs(sb) ++#endif ++ || au_test_ubifs(sb) ++ || au_test_hfsplus(sb); ++} ++ ++/* ++ * filesystems which sets S_NOATIME and S_NOCMTIME. ++ */ ++static inline int au_test_fs_notime(struct super_block *sb) ++{ ++ return au_test_nfs(sb) ++ || au_test_fuse(sb) ++ || au_test_ubifs(sb) ++ ; ++} ++ ++/* temporary support for i#1 in cramfs */ ++static inline int au_test_fs_unique_ino(struct inode *inode) ++{ ++ if (au_test_cramfs(inode->i_sb)) ++ return inode->i_ino != 1; ++ return 1; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * the filesystem where the xino files placed must support i/o after unlink and ++ * maintain i_size and i_blocks. ++ */ ++static inline int au_test_fs_bad_xino(struct super_block *sb) ++{ ++ return au_test_fs_remote(sb) ++ || au_test_fs_bad_iattr_size(sb) ++ /* don't want unnecessary work for xino */ ++ || au_test_aufs(sb) ++ || au_test_ecryptfs(sb) ++ || au_test_nilfs(sb); ++} ++ ++static inline int au_test_fs_trunc_xino(struct super_block *sb) ++{ ++ return au_test_tmpfs(sb) ++ || au_test_ramfs(sb); ++} ++ ++/* ++ * test if the @sb is real-readonly. ++ */ ++static inline int au_test_fs_rr(struct super_block *sb) ++{ ++ return au_test_squashfs(sb) ++ || au_test_iso9660(sb) ++ || au_test_cramfs(sb) ++ || au_test_romfs(sb); ++} ++ ++/* ++ * test if the @inode is nfs with 'noacl' option ++ * NFS always sets SB_POSIXACL regardless its mount option 'noacl.' ++ */ ++static inline int au_test_nfs_noacl(struct inode *inode) ++{ ++ return au_test_nfs(inode->i_sb) ++ /* && IS_POSIXACL(inode) */ ++ && !nfs_server_capable(inode, NFS_CAP_ACLS); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_FSTYPE_H__ */ +diff -Nurp linux-5.4/fs/aufs/hbl.h linux-5.4-aufs/fs/aufs/hbl.h +--- linux-5.4/fs/aufs/hbl.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/hbl.h 2019-11-28 01:25:59.065925618 +0200 +@@ -0,0 +1,52 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2017-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * helpers for hlist_bl.h ++ */ ++ ++#ifndef __AUFS_HBL_H__ ++#define __AUFS_HBL_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++static inline void au_hbl_add(struct hlist_bl_node *node, ++ struct hlist_bl_head *hbl) ++{ ++ hlist_bl_lock(hbl); ++ hlist_bl_add_head(node, hbl); ++ hlist_bl_unlock(hbl); ++} ++ ++static inline void au_hbl_del(struct hlist_bl_node *node, ++ struct hlist_bl_head *hbl) ++{ ++ hlist_bl_lock(hbl); ++ hlist_bl_del(node); ++ hlist_bl_unlock(hbl); ++} ++ ++#define au_hbl_for_each(pos, head) \ ++ for (pos = hlist_bl_first(head); \ ++ pos; \ ++ pos = pos->next) ++ ++static inline unsigned long au_hbl_count(struct hlist_bl_head *hbl) ++{ ++ unsigned long cnt; ++ struct hlist_bl_node *pos; ++ ++ cnt = 0; ++ hlist_bl_lock(hbl); ++ au_hbl_for_each(pos, hbl) ++ cnt++; ++ hlist_bl_unlock(hbl); ++ return cnt; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_HBL_H__ */ +diff -Nurp linux-5.4/fs/aufs/hfsnotify.c linux-5.4-aufs/fs/aufs/hfsnotify.c +--- linux-5.4/fs/aufs/hfsnotify.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/hfsnotify.c 2019-11-28 01:25:59.065925618 +0200 +@@ -0,0 +1,275 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * fsnotify for the lower directories ++ */ ++ ++#include "aufs.h" ++ ++/* FS_IN_IGNORED is unnecessary */ ++static const __u32 AuHfsnMask = (FS_MOVED_TO | FS_MOVED_FROM | FS_DELETE ++ | FS_CREATE | FS_EVENT_ON_CHILD); ++static DECLARE_WAIT_QUEUE_HEAD(au_hfsn_wq); ++static __cacheline_aligned_in_smp atomic64_t au_hfsn_ifree = ATOMIC64_INIT(0); ++ ++static void au_hfsn_free_mark(struct fsnotify_mark *mark) ++{ ++ struct au_hnotify *hn = container_of(mark, struct au_hnotify, ++ hn_mark); ++ /* AuDbg("here\n"); */ ++ au_cache_free_hnotify(hn); ++ smp_mb__before_atomic(); /* for atomic64_dec */ ++ if (atomic64_dec_and_test(&au_hfsn_ifree)) ++ wake_up(&au_hfsn_wq); ++} ++ ++static int au_hfsn_alloc(struct au_hinode *hinode) ++{ ++ int err; ++ struct au_hnotify *hn; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct fsnotify_mark *mark; ++ aufs_bindex_t bindex; ++ ++ hn = hinode->hi_notify; ++ sb = hn->hn_aufs_inode->i_sb; ++ bindex = au_br_index(sb, hinode->hi_id); ++ br = au_sbr(sb, bindex); ++ AuDebugOn(!br->br_hfsn); ++ ++ mark = &hn->hn_mark; ++ fsnotify_init_mark(mark, br->br_hfsn->hfsn_group); ++ mark->mask = AuHfsnMask; ++ /* ++ * by udba rename or rmdir, aufs assign a new inode to the known ++ * h_inode, so specify 1 to allow dups. ++ */ ++ lockdep_off(); ++ err = fsnotify_add_inode_mark(mark, hinode->hi_inode, /*allow_dups*/1); ++ lockdep_on(); ++ ++ return err; ++} ++ ++static int au_hfsn_free(struct au_hinode *hinode, struct au_hnotify *hn) ++{ ++ struct fsnotify_mark *mark; ++ unsigned long long ull; ++ struct fsnotify_group *group; ++ ++ ull = atomic64_inc_return(&au_hfsn_ifree); ++ BUG_ON(!ull); ++ ++ mark = &hn->hn_mark; ++ spin_lock(&mark->lock); ++ group = mark->group; ++ fsnotify_get_group(group); ++ spin_unlock(&mark->lock); ++ lockdep_off(); ++ fsnotify_destroy_mark(mark, group); ++ fsnotify_put_mark(mark); ++ fsnotify_put_group(group); ++ lockdep_on(); ++ ++ /* free hn by myself */ ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hfsn_ctl(struct au_hinode *hinode, int do_set) ++{ ++ struct fsnotify_mark *mark; ++ ++ mark = &hinode->hi_notify->hn_mark; ++ spin_lock(&mark->lock); ++ if (do_set) { ++ AuDebugOn(mark->mask & AuHfsnMask); ++ mark->mask |= AuHfsnMask; ++ } else { ++ AuDebugOn(!(mark->mask & AuHfsnMask)); ++ mark->mask &= ~AuHfsnMask; ++ } ++ spin_unlock(&mark->lock); ++ /* fsnotify_recalc_inode_mask(hinode->hi_inode); */ ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* #define AuDbgHnotify */ ++#ifdef AuDbgHnotify ++static char *au_hfsn_name(u32 mask) ++{ ++#ifdef CONFIG_AUFS_DEBUG ++#define test_ret(flag) \ ++ do { \ ++ if (mask & flag) \ ++ return #flag; \ ++ } while (0) ++ test_ret(FS_ACCESS); ++ test_ret(FS_MODIFY); ++ test_ret(FS_ATTRIB); ++ test_ret(FS_CLOSE_WRITE); ++ test_ret(FS_CLOSE_NOWRITE); ++ test_ret(FS_OPEN); ++ test_ret(FS_MOVED_FROM); ++ test_ret(FS_MOVED_TO); ++ test_ret(FS_CREATE); ++ test_ret(FS_DELETE); ++ test_ret(FS_DELETE_SELF); ++ test_ret(FS_MOVE_SELF); ++ test_ret(FS_UNMOUNT); ++ test_ret(FS_Q_OVERFLOW); ++ test_ret(FS_IN_IGNORED); ++ test_ret(FS_ISDIR); ++ test_ret(FS_IN_ONESHOT); ++ test_ret(FS_EVENT_ON_CHILD); ++ return ""; ++#undef test_ret ++#else ++ return "??"; ++#endif ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hfsn_free_group(struct fsnotify_group *group) ++{ ++ struct au_br_hfsnotify *hfsn = group->private; ++ ++ /* AuDbg("here\n"); */ ++ au_kfree_try_rcu(hfsn); ++} ++ ++static int au_hfsn_handle_event(struct fsnotify_group *group, ++ struct inode *inode, ++ u32 mask, const void *data, int data_type, ++ const struct qstr *file_name, u32 cookie, ++ struct fsnotify_iter_info *iter_info) ++{ ++ int err; ++ struct au_hnotify *hnotify; ++ struct inode *h_dir, *h_inode; ++ struct fsnotify_mark *inode_mark; ++ ++ AuDebugOn(data_type != FSNOTIFY_EVENT_INODE); ++ ++ err = 0; ++ /* if FS_UNMOUNT happens, there must be another bug */ ++ AuDebugOn(mask & FS_UNMOUNT); ++ if (mask & (FS_IN_IGNORED | FS_UNMOUNT)) ++ goto out; ++ ++ h_dir = inode; ++ h_inode = NULL; ++#ifdef AuDbgHnotify ++ au_debug_on(); ++ if (1 || h_child_qstr.len != sizeof(AUFS_XINO_FNAME) - 1 ++ || strncmp(h_child_qstr.name, AUFS_XINO_FNAME, h_child_qstr.len)) { ++ AuDbg("i%lu, mask 0x%x %s, hcname %.*s, hi%lu\n", ++ h_dir->i_ino, mask, au_hfsn_name(mask), ++ AuLNPair(&h_child_qstr), h_inode ? h_inode->i_ino : 0); ++ /* WARN_ON(1); */ ++ } ++ au_debug_off(); ++#endif ++ ++ inode_mark = fsnotify_iter_inode_mark(iter_info); ++ AuDebugOn(!inode_mark); ++ hnotify = container_of(inode_mark, struct au_hnotify, hn_mark); ++ err = au_hnotify(h_dir, hnotify, mask, file_name, h_inode); ++ ++out: ++ return err; ++} ++ ++static struct fsnotify_ops au_hfsn_ops = { ++ .handle_event = au_hfsn_handle_event, ++ .free_group_priv = au_hfsn_free_group, ++ .free_mark = au_hfsn_free_mark ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hfsn_fin_br(struct au_branch *br) ++{ ++ struct au_br_hfsnotify *hfsn; ++ ++ hfsn = br->br_hfsn; ++ if (hfsn) { ++ lockdep_off(); ++ fsnotify_put_group(hfsn->hfsn_group); ++ lockdep_on(); ++ } ++} ++ ++static int au_hfsn_init_br(struct au_branch *br, int perm) ++{ ++ int err; ++ struct fsnotify_group *group; ++ struct au_br_hfsnotify *hfsn; ++ ++ err = 0; ++ br->br_hfsn = NULL; ++ if (!au_br_hnotifyable(perm)) ++ goto out; ++ ++ err = -ENOMEM; ++ hfsn = kmalloc(sizeof(*hfsn), GFP_NOFS); ++ if (unlikely(!hfsn)) ++ goto out; ++ ++ err = 0; ++ group = fsnotify_alloc_group(&au_hfsn_ops); ++ if (IS_ERR(group)) { ++ err = PTR_ERR(group); ++ pr_err("fsnotify_alloc_group() failed, %d\n", err); ++ goto out_hfsn; ++ } ++ ++ group->private = hfsn; ++ hfsn->hfsn_group = group; ++ br->br_hfsn = hfsn; ++ goto out; /* success */ ++ ++out_hfsn: ++ au_kfree_try_rcu(hfsn); ++out: ++ return err; ++} ++ ++static int au_hfsn_reset_br(unsigned int udba, struct au_branch *br, int perm) ++{ ++ int err; ++ ++ err = 0; ++ if (!br->br_hfsn) ++ err = au_hfsn_init_br(br, perm); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hfsn_fin(void) ++{ ++ AuDbg("au_hfsn_ifree %lld\n", (long long)atomic64_read(&au_hfsn_ifree)); ++ wait_event(au_hfsn_wq, !atomic64_read(&au_hfsn_ifree)); ++} ++ ++const struct au_hnotify_op au_hnotify_op = { ++ .ctl = au_hfsn_ctl, ++ .alloc = au_hfsn_alloc, ++ .free = au_hfsn_free, ++ ++ .fin = au_hfsn_fin, ++ ++ .reset_br = au_hfsn_reset_br, ++ .fin_br = au_hfsn_fin_br, ++ .init_br = au_hfsn_init_br ++}; +diff -Nurp linux-5.4/fs/aufs/hfsplus.c linux-5.4-aufs/fs/aufs/hfsplus.c +--- linux-5.4/fs/aufs/hfsplus.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/hfsplus.c 2019-11-28 01:25:59.065925618 +0200 +@@ -0,0 +1,47 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2010-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * special support for filesystems which acquires an inode mutex ++ * at final closing a file, eg, hfsplus. ++ * ++ * This trick is very simple and stupid, just to open the file before really ++ * necessary open to tell hfsplus that this is not the final closing. ++ * The caller should call au_h_open_pre() after acquiring the inode mutex, ++ * and au_h_open_post() after releasing it. ++ */ ++ ++#include "aufs.h" ++ ++struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex, ++ int force_wr) ++{ ++ struct file *h_file; ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ AuDebugOn(!h_dentry); ++ AuDebugOn(d_is_negative(h_dentry)); ++ ++ h_file = NULL; ++ if (au_test_hfsplus(h_dentry->d_sb) ++ && d_is_reg(h_dentry)) ++ h_file = au_h_open(dentry, bindex, ++ O_RDONLY | O_NOATIME | O_LARGEFILE, ++ /*file*/NULL, force_wr); ++ return h_file; ++} ++ ++void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex, ++ struct file *h_file) ++{ ++ struct au_branch *br; ++ ++ if (h_file) { ++ fput(h_file); ++ br = au_sbr(dentry->d_sb, bindex); ++ au_lcnt_dec(&br->br_nfiles); ++ } ++} +diff -Nurp linux-5.4/fs/aufs/hnotify.c linux-5.4-aufs/fs/aufs/hnotify.c +--- linux-5.4/fs/aufs/hnotify.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/hnotify.c 2019-11-28 01:25:59.065925618 +0200 +@@ -0,0 +1,708 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * abstraction to notify the direct changes on lower directories ++ */ ++ ++/* #include */ ++#include "aufs.h" ++ ++int au_hn_alloc(struct au_hinode *hinode, struct inode *inode) ++{ ++ int err; ++ struct au_hnotify *hn; ++ ++ err = -ENOMEM; ++ hn = au_cache_alloc_hnotify(); ++ if (hn) { ++ hn->hn_aufs_inode = inode; ++ hinode->hi_notify = hn; ++ err = au_hnotify_op.alloc(hinode); ++ AuTraceErr(err); ++ if (unlikely(err)) { ++ hinode->hi_notify = NULL; ++ au_cache_free_hnotify(hn); ++ /* ++ * The upper dir was removed by udba, but the same named ++ * dir left. In this case, aufs assigns a new inode ++ * number and set the monitor again. ++ * For the lower dir, the old monitor is still left. ++ */ ++ if (err == -EEXIST) ++ err = 0; ++ } ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_hn_free(struct au_hinode *hinode) ++{ ++ struct au_hnotify *hn; ++ ++ hn = hinode->hi_notify; ++ if (hn) { ++ hinode->hi_notify = NULL; ++ if (au_hnotify_op.free(hinode, hn)) ++ au_cache_free_hnotify(hn); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_hn_ctl(struct au_hinode *hinode, int do_set) ++{ ++ if (hinode->hi_notify) ++ au_hnotify_op.ctl(hinode, do_set); ++} ++ ++void au_hn_reset(struct inode *inode, unsigned int flags) ++{ ++ aufs_bindex_t bindex, bbot; ++ struct inode *hi; ++ struct dentry *iwhdentry; ++ ++ bbot = au_ibbot(inode); ++ for (bindex = au_ibtop(inode); bindex <= bbot; bindex++) { ++ hi = au_h_iptr(inode, bindex); ++ if (!hi) ++ continue; ++ ++ /* inode_lock_nested(hi, AuLsc_I_CHILD); */ ++ iwhdentry = au_hi_wh(inode, bindex); ++ if (iwhdentry) ++ dget(iwhdentry); ++ au_igrab(hi); ++ au_set_h_iptr(inode, bindex, NULL, 0); ++ au_set_h_iptr(inode, bindex, au_igrab(hi), ++ flags & ~AuHi_XINO); ++ iput(hi); ++ dput(iwhdentry); ++ /* inode_unlock(hi); */ ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int hn_xino(struct inode *inode, struct inode *h_inode) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot, bfound, btop; ++ struct inode *h_i; ++ ++ err = 0; ++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { ++ pr_warn("branch root dir was changed\n"); ++ goto out; ++ } ++ ++ bfound = -1; ++ bbot = au_ibbot(inode); ++ btop = au_ibtop(inode); ++#if 0 /* reserved for future use */ ++ if (bindex == bbot) { ++ /* keep this ino in rename case */ ++ goto out; ++ } ++#endif ++ for (bindex = btop; bindex <= bbot; bindex++) ++ if (au_h_iptr(inode, bindex) == h_inode) { ++ bfound = bindex; ++ break; ++ } ++ if (bfound < 0) ++ goto out; ++ ++ for (bindex = btop; bindex <= bbot; bindex++) { ++ h_i = au_h_iptr(inode, bindex); ++ if (!h_i) ++ continue; ++ ++ err = au_xino_write(inode->i_sb, bindex, h_i->i_ino, /*ino*/0); ++ /* ignore this error */ ++ /* bad action? */ ++ } ++ ++ /* children inode number will be broken */ ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int hn_gen_tree(struct dentry *dentry) ++{ ++ int err, i, j, ndentry; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, dentry, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ for (i = 0; i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ ndentry = dpage->ndentry; ++ for (j = 0; j < ndentry; j++) { ++ struct dentry *d; ++ ++ d = dentries[j]; ++ if (IS_ROOT(d)) ++ continue; ++ ++ au_digen_dec(d); ++ if (d_really_is_positive(d)) ++ /* todo: reset children xino? ++ cached children only? */ ++ au_iigen_dec(d_inode(d)); ++ } ++ } ++ ++out_dpages: ++ au_dpages_free(&dpages); ++ ++#if 0 ++ /* discard children */ ++ dentry_unhash(dentry); ++ dput(dentry); ++#endif ++out: ++ return err; ++} ++ ++/* ++ * return 0 if processed. ++ */ ++static int hn_gen_by_inode(char *name, unsigned int nlen, struct inode *inode, ++ const unsigned int isdir) ++{ ++ int err; ++ struct dentry *d; ++ struct qstr *dname; ++ ++ err = 1; ++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { ++ pr_warn("branch root dir was changed\n"); ++ err = 0; ++ goto out; ++ } ++ ++ if (!isdir) { ++ AuDebugOn(!name); ++ au_iigen_dec(inode); ++ spin_lock(&inode->i_lock); ++ hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias) { ++ spin_lock(&d->d_lock); ++ dname = &d->d_name; ++ if (dname->len != nlen ++ && memcmp(dname->name, name, nlen)) { ++ spin_unlock(&d->d_lock); ++ continue; ++ } ++ err = 0; ++ au_digen_dec(d); ++ spin_unlock(&d->d_lock); ++ break; ++ } ++ spin_unlock(&inode->i_lock); ++ } else { ++ au_fset_si(au_sbi(inode->i_sb), FAILED_REFRESH_DIR); ++ d = d_find_any_alias(inode); ++ if (!d) { ++ au_iigen_dec(inode); ++ goto out; ++ } ++ ++ spin_lock(&d->d_lock); ++ dname = &d->d_name; ++ if (dname->len == nlen && !memcmp(dname->name, name, nlen)) { ++ spin_unlock(&d->d_lock); ++ err = hn_gen_tree(d); ++ spin_lock(&d->d_lock); ++ } ++ spin_unlock(&d->d_lock); ++ dput(d); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int hn_gen_by_name(struct dentry *dentry, const unsigned int isdir) ++{ ++ int err; ++ ++ if (IS_ROOT(dentry)) { ++ pr_warn("branch root dir was changed\n"); ++ return 0; ++ } ++ ++ err = 0; ++ if (!isdir) { ++ au_digen_dec(dentry); ++ if (d_really_is_positive(dentry)) ++ au_iigen_dec(d_inode(dentry)); ++ } else { ++ au_fset_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR); ++ if (d_really_is_positive(dentry)) ++ err = hn_gen_tree(dentry); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* hnotify job flags */ ++#define AuHnJob_XINO0 1 ++#define AuHnJob_GEN (1 << 1) ++#define AuHnJob_DIRENT (1 << 2) ++#define AuHnJob_ISDIR (1 << 3) ++#define AuHnJob_TRYXINO0 (1 << 4) ++#define AuHnJob_MNTPNT (1 << 5) ++#define au_ftest_hnjob(flags, name) ((flags) & AuHnJob_##name) ++#define au_fset_hnjob(flags, name) \ ++ do { (flags) |= AuHnJob_##name; } while (0) ++#define au_fclr_hnjob(flags, name) \ ++ do { (flags) &= ~AuHnJob_##name; } while (0) ++ ++enum { ++ AuHn_CHILD, ++ AuHn_PARENT, ++ AuHnLast ++}; ++ ++struct au_hnotify_args { ++ struct inode *h_dir, *dir, *h_child_inode; ++ u32 mask; ++ unsigned int flags[AuHnLast]; ++ unsigned int h_child_nlen; ++ char h_child_name[]; ++}; ++ ++struct hn_job_args { ++ unsigned int flags; ++ struct inode *inode, *h_inode, *dir, *h_dir; ++ struct dentry *dentry; ++ char *h_name; ++ int h_nlen; ++}; ++ ++static int hn_job(struct hn_job_args *a) ++{ ++ const unsigned int isdir = au_ftest_hnjob(a->flags, ISDIR); ++ int e; ++ ++ /* reset xino */ ++ if (au_ftest_hnjob(a->flags, XINO0) && a->inode) ++ hn_xino(a->inode, a->h_inode); /* ignore this error */ ++ ++ if (au_ftest_hnjob(a->flags, TRYXINO0) ++ && a->inode ++ && a->h_inode) { ++ inode_lock_shared_nested(a->h_inode, AuLsc_I_CHILD); ++ if (!a->h_inode->i_nlink ++ && !(a->h_inode->i_state & I_LINKABLE)) ++ hn_xino(a->inode, a->h_inode); /* ignore this error */ ++ inode_unlock_shared(a->h_inode); ++ } ++ ++ /* make the generation obsolete */ ++ if (au_ftest_hnjob(a->flags, GEN)) { ++ e = -1; ++ if (a->inode) ++ e = hn_gen_by_inode(a->h_name, a->h_nlen, a->inode, ++ isdir); ++ if (e && a->dentry) ++ hn_gen_by_name(a->dentry, isdir); ++ /* ignore this error */ ++ } ++ ++ /* make dir entries obsolete */ ++ if (au_ftest_hnjob(a->flags, DIRENT) && a->inode) { ++ struct au_vdir *vdir; ++ ++ vdir = au_ivdir(a->inode); ++ if (vdir) ++ vdir->vd_jiffy = 0; ++ /* IMustLock(a->inode); */ ++ /* inode_inc_iversion(a->inode); */ ++ } ++ ++ /* can do nothing but warn */ ++ if (au_ftest_hnjob(a->flags, MNTPNT) ++ && a->dentry ++ && d_mountpoint(a->dentry)) ++ pr_warn("mount-point %pd is removed or renamed\n", a->dentry); ++ ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry *lookup_wlock_by_name(char *name, unsigned int nlen, ++ struct inode *dir) ++{ ++ struct dentry *dentry, *d, *parent; ++ struct qstr *dname; ++ ++ parent = d_find_any_alias(dir); ++ if (!parent) ++ return NULL; ++ ++ dentry = NULL; ++ spin_lock(&parent->d_lock); ++ list_for_each_entry(d, &parent->d_subdirs, d_child) { ++ /* AuDbg("%pd\n", d); */ ++ spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED); ++ dname = &d->d_name; ++ if (dname->len != nlen || memcmp(dname->name, name, nlen)) ++ goto cont_unlock; ++ if (au_di(d)) ++ au_digen_dec(d); ++ else ++ goto cont_unlock; ++ if (au_dcount(d) > 0) { ++ dentry = dget_dlock(d); ++ spin_unlock(&d->d_lock); ++ break; ++ } ++ ++cont_unlock: ++ spin_unlock(&d->d_lock); ++ } ++ spin_unlock(&parent->d_lock); ++ dput(parent); ++ ++ if (dentry) ++ di_write_lock_child(dentry); ++ ++ return dentry; ++} ++ ++static struct inode *lookup_wlock_by_ino(struct super_block *sb, ++ aufs_bindex_t bindex, ino_t h_ino) ++{ ++ struct inode *inode; ++ ino_t ino; ++ int err; ++ ++ inode = NULL; ++ err = au_xino_read(sb, bindex, h_ino, &ino); ++ if (!err && ino) ++ inode = ilookup(sb, ino); ++ if (!inode) ++ goto out; ++ ++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { ++ pr_warn("wrong root branch\n"); ++ iput(inode); ++ inode = NULL; ++ goto out; ++ } ++ ++ ii_write_lock_child(inode); ++ ++out: ++ return inode; ++} ++ ++static void au_hn_bh(void *_args) ++{ ++ struct au_hnotify_args *a = _args; ++ struct super_block *sb; ++ aufs_bindex_t bindex, bbot, bfound; ++ unsigned char xino, try_iput; ++ int err; ++ struct inode *inode; ++ ino_t h_ino; ++ struct hn_job_args args; ++ struct dentry *dentry; ++ struct au_sbinfo *sbinfo; ++ ++ AuDebugOn(!_args); ++ AuDebugOn(!a->h_dir); ++ AuDebugOn(!a->dir); ++ AuDebugOn(!a->mask); ++ AuDbg("mask 0x%x, i%lu, hi%lu, hci%lu\n", ++ a->mask, a->dir->i_ino, a->h_dir->i_ino, ++ a->h_child_inode ? a->h_child_inode->i_ino : 0); ++ ++ inode = NULL; ++ dentry = NULL; ++ /* ++ * do not lock a->dir->i_mutex here ++ * because of d_revalidate() may cause a deadlock. ++ */ ++ sb = a->dir->i_sb; ++ AuDebugOn(!sb); ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!sbinfo); ++ si_write_lock(sb, AuLock_NOPLMW); ++ ++ if (au_opt_test(sbinfo->si_mntflags, DIRREN)) ++ switch (a->mask & FS_EVENTS_POSS_ON_CHILD) { ++ case FS_MOVED_FROM: ++ case FS_MOVED_TO: ++ AuWarn1("DIRREN with UDBA may not work correctly " ++ "for the direct rename(2)\n"); ++ } ++ ++ ii_read_lock_parent(a->dir); ++ bfound = -1; ++ bbot = au_ibbot(a->dir); ++ for (bindex = au_ibtop(a->dir); bindex <= bbot; bindex++) ++ if (au_h_iptr(a->dir, bindex) == a->h_dir) { ++ bfound = bindex; ++ break; ++ } ++ ii_read_unlock(a->dir); ++ if (unlikely(bfound < 0)) ++ goto out; ++ ++ xino = !!au_opt_test(au_mntflags(sb), XINO); ++ h_ino = 0; ++ if (a->h_child_inode) ++ h_ino = a->h_child_inode->i_ino; ++ ++ if (a->h_child_nlen ++ && (au_ftest_hnjob(a->flags[AuHn_CHILD], GEN) ++ || au_ftest_hnjob(a->flags[AuHn_CHILD], MNTPNT))) ++ dentry = lookup_wlock_by_name(a->h_child_name, a->h_child_nlen, ++ a->dir); ++ try_iput = 0; ++ if (dentry && d_really_is_positive(dentry)) ++ inode = d_inode(dentry); ++ if (xino && !inode && h_ino ++ && (au_ftest_hnjob(a->flags[AuHn_CHILD], XINO0) ++ || au_ftest_hnjob(a->flags[AuHn_CHILD], TRYXINO0) ++ || au_ftest_hnjob(a->flags[AuHn_CHILD], GEN))) { ++ inode = lookup_wlock_by_ino(sb, bfound, h_ino); ++ try_iput = 1; ++ } ++ ++ args.flags = a->flags[AuHn_CHILD]; ++ args.dentry = dentry; ++ args.inode = inode; ++ args.h_inode = a->h_child_inode; ++ args.dir = a->dir; ++ args.h_dir = a->h_dir; ++ args.h_name = a->h_child_name; ++ args.h_nlen = a->h_child_nlen; ++ err = hn_job(&args); ++ if (dentry) { ++ if (au_di(dentry)) ++ di_write_unlock(dentry); ++ dput(dentry); ++ } ++ if (inode && try_iput) { ++ ii_write_unlock(inode); ++ iput(inode); ++ } ++ ++ ii_write_lock_parent(a->dir); ++ args.flags = a->flags[AuHn_PARENT]; ++ args.dentry = NULL; ++ args.inode = a->dir; ++ args.h_inode = a->h_dir; ++ args.dir = NULL; ++ args.h_dir = NULL; ++ args.h_name = NULL; ++ args.h_nlen = 0; ++ err = hn_job(&args); ++ ii_write_unlock(a->dir); ++ ++out: ++ iput(a->h_child_inode); ++ iput(a->h_dir); ++ iput(a->dir); ++ si_write_unlock(sb); ++ au_nwt_done(&sbinfo->si_nowait); ++ au_kfree_rcu(a); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask, ++ const struct qstr *h_child_qstr, struct inode *h_child_inode) ++{ ++ int err, len; ++ unsigned int flags[AuHnLast], f; ++ unsigned char isdir, isroot, wh; ++ struct inode *dir; ++ struct au_hnotify_args *args; ++ char *p, *h_child_name; ++ ++ err = 0; ++ AuDebugOn(!hnotify || !hnotify->hn_aufs_inode); ++ dir = igrab(hnotify->hn_aufs_inode); ++ if (!dir) ++ goto out; ++ ++ isroot = (dir->i_ino == AUFS_ROOT_INO); ++ wh = 0; ++ h_child_name = (void *)h_child_qstr->name; ++ len = h_child_qstr->len; ++ if (h_child_name) { ++ if (len > AUFS_WH_PFX_LEN ++ && !memcmp(h_child_name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { ++ h_child_name += AUFS_WH_PFX_LEN; ++ len -= AUFS_WH_PFX_LEN; ++ wh = 1; ++ } ++ } ++ ++ isdir = 0; ++ if (h_child_inode) ++ isdir = !!S_ISDIR(h_child_inode->i_mode); ++ flags[AuHn_PARENT] = AuHnJob_ISDIR; ++ flags[AuHn_CHILD] = 0; ++ if (isdir) ++ flags[AuHn_CHILD] = AuHnJob_ISDIR; ++ au_fset_hnjob(flags[AuHn_PARENT], DIRENT); ++ au_fset_hnjob(flags[AuHn_CHILD], GEN); ++ switch (mask & ALL_FSNOTIFY_DIRENT_EVENTS) { ++ case FS_MOVED_FROM: ++ case FS_MOVED_TO: ++ au_fset_hnjob(flags[AuHn_CHILD], XINO0); ++ au_fset_hnjob(flags[AuHn_CHILD], MNTPNT); ++ /*FALLTHROUGH*/ ++ case FS_CREATE: ++ AuDebugOn(!h_child_name); ++ break; ++ ++ case FS_DELETE: ++ /* ++ * aufs never be able to get this child inode. ++ * revalidation should be in d_revalidate() ++ * by checking i_nlink, i_generation or d_unhashed(). ++ */ ++ AuDebugOn(!h_child_name); ++ au_fset_hnjob(flags[AuHn_CHILD], TRYXINO0); ++ au_fset_hnjob(flags[AuHn_CHILD], MNTPNT); ++ break; ++ ++ default: ++ AuDebugOn(1); ++ } ++ ++ if (wh) ++ h_child_inode = NULL; ++ ++ err = -ENOMEM; ++ /* iput() and kfree() will be called in au_hnotify() */ ++ args = kmalloc(sizeof(*args) + len + 1, GFP_NOFS); ++ if (unlikely(!args)) { ++ AuErr1("no memory\n"); ++ iput(dir); ++ goto out; ++ } ++ args->flags[AuHn_PARENT] = flags[AuHn_PARENT]; ++ args->flags[AuHn_CHILD] = flags[AuHn_CHILD]; ++ args->mask = mask; ++ args->dir = dir; ++ args->h_dir = igrab(h_dir); ++ if (h_child_inode) ++ h_child_inode = igrab(h_child_inode); /* can be NULL */ ++ args->h_child_inode = h_child_inode; ++ args->h_child_nlen = len; ++ if (len) { ++ p = (void *)args; ++ p += sizeof(*args); ++ memcpy(p, h_child_name, len); ++ p[len] = 0; ++ } ++ ++ /* NFS fires the event for silly-renamed one from kworker */ ++ f = 0; ++ if (!dir->i_nlink ++ || (au_test_nfs(h_dir->i_sb) && (mask & FS_DELETE))) ++ f = AuWkq_NEST; ++ err = au_wkq_nowait(au_hn_bh, args, dir->i_sb, f); ++ if (unlikely(err)) { ++ pr_err("wkq %d\n", err); ++ iput(args->h_child_inode); ++ iput(args->h_dir); ++ iput(args->dir); ++ au_kfree_rcu(args); ++ } ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm) ++{ ++ int err; ++ ++ AuDebugOn(!(udba & AuOptMask_UDBA)); ++ ++ err = 0; ++ if (au_hnotify_op.reset_br) ++ err = au_hnotify_op.reset_br(udba, br, perm); ++ ++ return err; ++} ++ ++int au_hnotify_init_br(struct au_branch *br, int perm) ++{ ++ int err; ++ ++ err = 0; ++ if (au_hnotify_op.init_br) ++ err = au_hnotify_op.init_br(br, perm); ++ ++ return err; ++} ++ ++void au_hnotify_fin_br(struct au_branch *br) ++{ ++ if (au_hnotify_op.fin_br) ++ au_hnotify_op.fin_br(br); ++} ++ ++static void au_hn_destroy_cache(void) ++{ ++ kmem_cache_destroy(au_cache[AuCache_HNOTIFY]); ++ au_cache[AuCache_HNOTIFY] = NULL; ++} ++ ++int __init au_hnotify_init(void) ++{ ++ int err; ++ ++ err = -ENOMEM; ++ au_cache[AuCache_HNOTIFY] = AuCache(au_hnotify); ++ if (au_cache[AuCache_HNOTIFY]) { ++ err = 0; ++ if (au_hnotify_op.init) ++ err = au_hnotify_op.init(); ++ if (unlikely(err)) ++ au_hn_destroy_cache(); ++ } ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_hnotify_fin(void) ++{ ++ if (au_hnotify_op.fin) ++ au_hnotify_op.fin(); ++ ++ /* cf. au_cache_fin() */ ++ if (au_cache[AuCache_HNOTIFY]) ++ au_hn_destroy_cache(); ++} +diff -Nurp linux-5.4/fs/aufs/iinfo.c linux-5.4-aufs/fs/aufs/iinfo.c +--- linux-5.4/fs/aufs/iinfo.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/iinfo.c 2019-11-28 01:25:59.066925618 +0200 +@@ -0,0 +1,273 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode private data ++ */ ++ ++#include "aufs.h" ++ ++struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex) ++{ ++ struct inode *h_inode; ++ struct au_hinode *hinode; ++ ++ IiMustAnyLock(inode); ++ ++ hinode = au_hinode(au_ii(inode), bindex); ++ h_inode = hinode->hi_inode; ++ AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0); ++ return h_inode; ++} ++ ++/* todo: hard/soft set? */ ++void au_hiput(struct au_hinode *hinode) ++{ ++ au_hn_free(hinode); ++ dput(hinode->hi_whdentry); ++ iput(hinode->hi_inode); ++} ++ ++unsigned int au_hi_flags(struct inode *inode, int isdir) ++{ ++ unsigned int flags; ++ const unsigned int mnt_flags = au_mntflags(inode->i_sb); ++ ++ flags = 0; ++ if (au_opt_test(mnt_flags, XINO)) ++ au_fset_hi(flags, XINO); ++ if (isdir && au_opt_test(mnt_flags, UDBA_HNOTIFY)) ++ au_fset_hi(flags, HNOTIFY); ++ return flags; ++} ++ ++void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode, unsigned int flags) ++{ ++ struct au_hinode *hinode; ++ struct inode *hi; ++ struct au_iinfo *iinfo = au_ii(inode); ++ ++ IiMustWriteLock(inode); ++ ++ hinode = au_hinode(iinfo, bindex); ++ hi = hinode->hi_inode; ++ AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0); ++ ++ if (hi) ++ au_hiput(hinode); ++ hinode->hi_inode = h_inode; ++ if (h_inode) { ++ int err; ++ struct super_block *sb = inode->i_sb; ++ struct au_branch *br; ++ ++ AuDebugOn(inode->i_mode ++ && (h_inode->i_mode & S_IFMT) ++ != (inode->i_mode & S_IFMT)); ++ if (bindex == iinfo->ii_btop) ++ au_cpup_igen(inode, h_inode); ++ br = au_sbr(sb, bindex); ++ hinode->hi_id = br->br_id; ++ if (au_ftest_hi(flags, XINO)) { ++ err = au_xino_write(sb, bindex, h_inode->i_ino, ++ inode->i_ino); ++ if (unlikely(err)) ++ AuIOErr1("failed au_xino_write() %d\n", err); ++ } ++ ++ if (au_ftest_hi(flags, HNOTIFY) ++ && au_br_hnotifyable(br->br_perm)) { ++ err = au_hn_alloc(hinode, inode); ++ if (unlikely(err)) ++ AuIOErr1("au_hn_alloc() %d\n", err); ++ } ++ } ++} ++ ++void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_wh) ++{ ++ struct au_hinode *hinode; ++ ++ IiMustWriteLock(inode); ++ ++ hinode = au_hinode(au_ii(inode), bindex); ++ AuDebugOn(hinode->hi_whdentry); ++ hinode->hi_whdentry = h_wh; ++} ++ ++void au_update_iigen(struct inode *inode, int half) ++{ ++ struct au_iinfo *iinfo; ++ struct au_iigen *iigen; ++ unsigned int sigen; ++ ++ sigen = au_sigen(inode->i_sb); ++ iinfo = au_ii(inode); ++ iigen = &iinfo->ii_generation; ++ spin_lock(&iigen->ig_spin); ++ iigen->ig_generation = sigen; ++ if (half) ++ au_ig_fset(iigen->ig_flags, HALF_REFRESHED); ++ else ++ au_ig_fclr(iigen->ig_flags, HALF_REFRESHED); ++ spin_unlock(&iigen->ig_spin); ++} ++ ++/* it may be called at remount time, too */ ++void au_update_ibrange(struct inode *inode, int do_put_zero) ++{ ++ struct au_iinfo *iinfo; ++ aufs_bindex_t bindex, bbot; ++ ++ AuDebugOn(au_is_bad_inode(inode)); ++ IiMustWriteLock(inode); ++ ++ iinfo = au_ii(inode); ++ if (do_put_zero && iinfo->ii_btop >= 0) { ++ for (bindex = iinfo->ii_btop; bindex <= iinfo->ii_bbot; ++ bindex++) { ++ struct inode *h_i; ++ ++ h_i = au_hinode(iinfo, bindex)->hi_inode; ++ if (h_i ++ && !h_i->i_nlink ++ && !(h_i->i_state & I_LINKABLE)) ++ au_set_h_iptr(inode, bindex, NULL, 0); ++ } ++ } ++ ++ iinfo->ii_btop = -1; ++ iinfo->ii_bbot = -1; ++ bbot = au_sbbot(inode->i_sb); ++ for (bindex = 0; bindex <= bbot; bindex++) ++ if (au_hinode(iinfo, bindex)->hi_inode) { ++ iinfo->ii_btop = bindex; ++ break; ++ } ++ if (iinfo->ii_btop >= 0) ++ for (bindex = bbot; bindex >= iinfo->ii_btop; bindex--) ++ if (au_hinode(iinfo, bindex)->hi_inode) { ++ iinfo->ii_bbot = bindex; ++ break; ++ } ++ AuDebugOn(iinfo->ii_btop > iinfo->ii_bbot); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_icntnr_init_once(void *_c) ++{ ++ struct au_icntnr *c = _c; ++ struct au_iinfo *iinfo = &c->iinfo; ++ ++ spin_lock_init(&iinfo->ii_generation.ig_spin); ++ au_rw_init(&iinfo->ii_rwsem); ++ inode_init_once(&c->vfs_inode); ++} ++ ++void au_hinode_init(struct au_hinode *hinode) ++{ ++ hinode->hi_inode = NULL; ++ hinode->hi_id = -1; ++ au_hn_init(hinode); ++ hinode->hi_whdentry = NULL; ++} ++ ++int au_iinfo_init(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct super_block *sb; ++ struct au_hinode *hi; ++ int nbr, i; ++ ++ sb = inode->i_sb; ++ iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); ++ nbr = au_sbbot(sb) + 1; ++ if (unlikely(nbr <= 0)) ++ nbr = 1; ++ hi = kmalloc_array(nbr, sizeof(*iinfo->ii_hinode), GFP_NOFS); ++ if (hi) { ++ au_lcnt_inc(&au_sbi(sb)->si_ninodes); ++ ++ iinfo->ii_hinode = hi; ++ for (i = 0; i < nbr; i++, hi++) ++ au_hinode_init(hi); ++ ++ iinfo->ii_generation.ig_generation = au_sigen(sb); ++ iinfo->ii_btop = -1; ++ iinfo->ii_bbot = -1; ++ iinfo->ii_vdir = NULL; ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++int au_hinode_realloc(struct au_iinfo *iinfo, int nbr, int may_shrink) ++{ ++ int err, i; ++ struct au_hinode *hip; ++ ++ AuRwMustWriteLock(&iinfo->ii_rwsem); ++ ++ err = -ENOMEM; ++ hip = au_krealloc(iinfo->ii_hinode, sizeof(*hip) * nbr, GFP_NOFS, ++ may_shrink); ++ if (hip) { ++ iinfo->ii_hinode = hip; ++ i = iinfo->ii_bbot + 1; ++ hip += i; ++ for (; i < nbr; i++, hip++) ++ au_hinode_init(hip); ++ err = 0; ++ } ++ ++ return err; ++} ++ ++void au_iinfo_fin(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct au_hinode *hi; ++ struct super_block *sb; ++ aufs_bindex_t bindex, bbot; ++ const unsigned char unlinked = !inode->i_nlink; ++ ++ AuDebugOn(au_is_bad_inode(inode)); ++ ++ sb = inode->i_sb; ++ au_lcnt_dec(&au_sbi(sb)->si_ninodes); ++ if (si_pid_test(sb)) ++ au_xino_delete_inode(inode, unlinked); ++ else { ++ /* ++ * it is safe to hide the dependency between sbinfo and ++ * sb->s_umount. ++ */ ++ lockdep_off(); ++ si_noflush_read_lock(sb); ++ au_xino_delete_inode(inode, unlinked); ++ si_read_unlock(sb); ++ lockdep_on(); ++ } ++ ++ iinfo = au_ii(inode); ++ if (iinfo->ii_vdir) ++ au_vdir_free(iinfo->ii_vdir); ++ ++ bindex = iinfo->ii_btop; ++ if (bindex >= 0) { ++ hi = au_hinode(iinfo, bindex); ++ bbot = iinfo->ii_bbot; ++ while (bindex++ <= bbot) { ++ if (hi->hi_inode) ++ au_hiput(hi); ++ hi++; ++ } ++ } ++ au_kfree_rcu(iinfo->ii_hinode); ++ AuRwDestroy(&iinfo->ii_rwsem); ++} +diff -Nurp linux-5.4/fs/aufs/inode.c linux-5.4-aufs/fs/aufs/inode.c +--- linux-5.4/fs/aufs/inode.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/inode.c 2019-11-28 01:25:59.066925618 +0200 +@@ -0,0 +1,516 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode functions ++ */ ++ ++#include ++#include "aufs.h" ++ ++struct inode *au_igrab(struct inode *inode) ++{ ++ if (inode) { ++ AuDebugOn(!atomic_read(&inode->i_count)); ++ ihold(inode); ++ } ++ return inode; ++} ++ ++static void au_refresh_hinode_attr(struct inode *inode, int do_version) ++{ ++ au_cpup_attr_all(inode, /*force*/0); ++ au_update_iigen(inode, /*half*/1); ++ if (do_version) ++ inode_inc_iversion(inode); ++} ++ ++static int au_ii_refresh(struct inode *inode, int *update) ++{ ++ int err, e, nbr; ++ umode_t type; ++ aufs_bindex_t bindex, new_bindex; ++ struct super_block *sb; ++ struct au_iinfo *iinfo; ++ struct au_hinode *p, *q, tmp; ++ ++ AuDebugOn(au_is_bad_inode(inode)); ++ IiMustWriteLock(inode); ++ ++ *update = 0; ++ sb = inode->i_sb; ++ nbr = au_sbbot(sb) + 1; ++ type = inode->i_mode & S_IFMT; ++ iinfo = au_ii(inode); ++ err = au_hinode_realloc(iinfo, nbr, /*may_shrink*/0); ++ if (unlikely(err)) ++ goto out; ++ ++ AuDebugOn(iinfo->ii_btop < 0); ++ p = au_hinode(iinfo, iinfo->ii_btop); ++ for (bindex = iinfo->ii_btop; bindex <= iinfo->ii_bbot; ++ bindex++, p++) { ++ if (!p->hi_inode) ++ continue; ++ ++ AuDebugOn(type != (p->hi_inode->i_mode & S_IFMT)); ++ new_bindex = au_br_index(sb, p->hi_id); ++ if (new_bindex == bindex) ++ continue; ++ ++ if (new_bindex < 0) { ++ *update = 1; ++ au_hiput(p); ++ p->hi_inode = NULL; ++ continue; ++ } ++ ++ if (new_bindex < iinfo->ii_btop) ++ iinfo->ii_btop = new_bindex; ++ if (iinfo->ii_bbot < new_bindex) ++ iinfo->ii_bbot = new_bindex; ++ /* swap two lower inode, and loop again */ ++ q = au_hinode(iinfo, new_bindex); ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hi_inode) { ++ bindex--; ++ p--; ++ } ++ } ++ au_update_ibrange(inode, /*do_put_zero*/0); ++ au_hinode_realloc(iinfo, nbr, /*may_shrink*/1); /* harmless if err */ ++ e = au_dy_irefresh(inode); ++ if (unlikely(e && !err)) ++ err = e; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_refresh_iop(struct inode *inode, int force_getattr) ++{ ++ int type; ++ struct au_sbinfo *sbi = au_sbi(inode->i_sb); ++ const struct inode_operations *iop ++ = force_getattr ? aufs_iop : sbi->si_iop_array; ++ ++ if (inode->i_op == iop) ++ return; ++ ++ switch (inode->i_mode & S_IFMT) { ++ case S_IFDIR: ++ type = AuIop_DIR; ++ break; ++ case S_IFLNK: ++ type = AuIop_SYMLINK; ++ break; ++ default: ++ type = AuIop_OTHER; ++ break; ++ } ++ ++ inode->i_op = iop + type; ++ /* unnecessary smp_wmb() */ ++} ++ ++int au_refresh_hinode_self(struct inode *inode) ++{ ++ int err, update; ++ ++ err = au_ii_refresh(inode, &update); ++ if (!err) ++ au_refresh_hinode_attr(inode, update && S_ISDIR(inode->i_mode)); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_refresh_hinode(struct inode *inode, struct dentry *dentry) ++{ ++ int err, e, update; ++ unsigned int flags; ++ umode_t mode; ++ aufs_bindex_t bindex, bbot; ++ unsigned char isdir; ++ struct au_hinode *p; ++ struct au_iinfo *iinfo; ++ ++ err = au_ii_refresh(inode, &update); ++ if (unlikely(err)) ++ goto out; ++ ++ update = 0; ++ iinfo = au_ii(inode); ++ p = au_hinode(iinfo, iinfo->ii_btop); ++ mode = (inode->i_mode & S_IFMT); ++ isdir = S_ISDIR(mode); ++ flags = au_hi_flags(inode, isdir); ++ bbot = au_dbbot(dentry); ++ for (bindex = au_dbtop(dentry); bindex <= bbot; bindex++) { ++ struct inode *h_i, *h_inode; ++ struct dentry *h_d; ++ ++ h_d = au_h_dptr(dentry, bindex); ++ if (!h_d || d_is_negative(h_d)) ++ continue; ++ ++ h_inode = d_inode(h_d); ++ AuDebugOn(mode != (h_inode->i_mode & S_IFMT)); ++ if (iinfo->ii_btop <= bindex && bindex <= iinfo->ii_bbot) { ++ h_i = au_h_iptr(inode, bindex); ++ if (h_i) { ++ if (h_i == h_inode) ++ continue; ++ err = -EIO; ++ break; ++ } ++ } ++ if (bindex < iinfo->ii_btop) ++ iinfo->ii_btop = bindex; ++ if (iinfo->ii_bbot < bindex) ++ iinfo->ii_bbot = bindex; ++ au_set_h_iptr(inode, bindex, au_igrab(h_inode), flags); ++ update = 1; ++ } ++ au_update_ibrange(inode, /*do_put_zero*/0); ++ e = au_dy_irefresh(inode); ++ if (unlikely(e && !err)) ++ err = e; ++ if (!err) ++ au_refresh_hinode_attr(inode, update && isdir); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int set_inode(struct inode *inode, struct dentry *dentry) ++{ ++ int err; ++ unsigned int flags; ++ umode_t mode; ++ aufs_bindex_t bindex, btop, btail; ++ unsigned char isdir; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct au_iinfo *iinfo; ++ struct inode_operations *iop; ++ ++ IiMustWriteLock(inode); ++ ++ err = 0; ++ isdir = 0; ++ iop = au_sbi(inode->i_sb)->si_iop_array; ++ btop = au_dbtop(dentry); ++ h_dentry = au_h_dptr(dentry, btop); ++ h_inode = d_inode(h_dentry); ++ mode = h_inode->i_mode; ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ btail = au_dbtail(dentry); ++ inode->i_op = iop + AuIop_OTHER; ++ inode->i_fop = &aufs_file_fop; ++ err = au_dy_iaop(inode, btop, h_inode); ++ if (unlikely(err)) ++ goto out; ++ break; ++ case S_IFDIR: ++ isdir = 1; ++ btail = au_dbtaildir(dentry); ++ inode->i_op = iop + AuIop_DIR; ++ inode->i_fop = &aufs_dir_fop; ++ break; ++ case S_IFLNK: ++ btail = au_dbtail(dentry); ++ inode->i_op = iop + AuIop_SYMLINK; ++ break; ++ case S_IFBLK: ++ case S_IFCHR: ++ case S_IFIFO: ++ case S_IFSOCK: ++ btail = au_dbtail(dentry); ++ inode->i_op = iop + AuIop_OTHER; ++ init_special_inode(inode, mode, h_inode->i_rdev); ++ break; ++ default: ++ AuIOErr("Unknown file type 0%o\n", mode); ++ err = -EIO; ++ goto out; ++ } ++ ++ /* do not set hnotify for whiteouted dirs (SHWH mode) */ ++ flags = au_hi_flags(inode, isdir); ++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH) ++ && au_ftest_hi(flags, HNOTIFY) ++ && dentry->d_name.len > AUFS_WH_PFX_LEN ++ && !memcmp(dentry->d_name.name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) ++ au_fclr_hi(flags, HNOTIFY); ++ iinfo = au_ii(inode); ++ iinfo->ii_btop = btop; ++ iinfo->ii_bbot = btail; ++ for (bindex = btop; bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry) ++ au_set_h_iptr(inode, bindex, ++ au_igrab(d_inode(h_dentry)), flags); ++ } ++ au_cpup_attr_all(inode, /*force*/1); ++ /* ++ * to force calling aufs_get_acl() every time, ++ * do not call cache_no_acl() for aufs inode. ++ */ ++ ++out: ++ return err; ++} ++ ++/* ++ * successful returns with iinfo write_locked ++ * minus: errno ++ * zero: success, matched ++ * plus: no error, but unmatched ++ */ ++static int reval_inode(struct inode *inode, struct dentry *dentry) ++{ ++ int err; ++ unsigned int gen, igflags; ++ aufs_bindex_t bindex, bbot; ++ struct inode *h_inode, *h_dinode; ++ struct dentry *h_dentry; ++ ++ /* ++ * before this function, if aufs got any iinfo lock, it must be only ++ * one, the parent dir. ++ * it can happen by UDBA and the obsoleted inode number. ++ */ ++ err = -EIO; ++ if (unlikely(inode->i_ino == parent_ino(dentry))) ++ goto out; ++ ++ err = 1; ++ ii_write_lock_new_child(inode); ++ h_dentry = au_h_dptr(dentry, au_dbtop(dentry)); ++ h_dinode = d_inode(h_dentry); ++ bbot = au_ibbot(inode); ++ for (bindex = au_ibtop(inode); bindex <= bbot; bindex++) { ++ h_inode = au_h_iptr(inode, bindex); ++ if (!h_inode || h_inode != h_dinode) ++ continue; ++ ++ err = 0; ++ gen = au_iigen(inode, &igflags); ++ if (gen == au_digen(dentry) ++ && !au_ig_ftest(igflags, HALF_REFRESHED)) ++ break; ++ ++ /* fully refresh inode using dentry */ ++ err = au_refresh_hinode(inode, dentry); ++ if (!err) ++ au_update_iigen(inode, /*half*/0); ++ break; ++ } ++ ++ if (unlikely(err)) ++ ii_write_unlock(inode); ++out: ++ return err; ++} ++ ++int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ unsigned int d_type, ino_t *ino) ++{ ++ int err, idx; ++ const int isnondir = d_type != DT_DIR; ++ ++ /* prevent hardlinked inode number from race condition */ ++ if (isnondir) { ++ err = au_xinondir_enter(sb, bindex, h_ino, &idx); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ err = au_xino_read(sb, bindex, h_ino, ino); ++ if (unlikely(err)) ++ goto out_xinondir; ++ ++ if (!*ino) { ++ err = -EIO; ++ *ino = au_xino_new_ino(sb); ++ if (unlikely(!*ino)) ++ goto out_xinondir; ++ err = au_xino_write(sb, bindex, h_ino, *ino); ++ if (unlikely(err)) ++ goto out_xinondir; ++ } ++ ++out_xinondir: ++ if (isnondir && idx >= 0) ++ au_xinondir_leave(sb, bindex, h_ino, idx); ++out: ++ return err; ++} ++ ++/* successful returns with iinfo write_locked */ ++/* todo: return with unlocked? */ ++struct inode *au_new_inode(struct dentry *dentry, int must_new) ++{ ++ struct inode *inode, *h_inode; ++ struct dentry *h_dentry; ++ struct super_block *sb; ++ ino_t h_ino, ino; ++ int err, idx, hlinked; ++ aufs_bindex_t btop; ++ ++ sb = dentry->d_sb; ++ btop = au_dbtop(dentry); ++ h_dentry = au_h_dptr(dentry, btop); ++ h_inode = d_inode(h_dentry); ++ h_ino = h_inode->i_ino; ++ hlinked = !d_is_dir(h_dentry) && h_inode->i_nlink > 1; ++ ++new_ino: ++ /* ++ * stop 'race'-ing between hardlinks under different ++ * parents. ++ */ ++ if (hlinked) { ++ err = au_xinondir_enter(sb, btop, h_ino, &idx); ++ inode = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ err = au_xino_read(sb, btop, h_ino, &ino); ++ inode = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_xinondir; ++ ++ if (!ino) { ++ ino = au_xino_new_ino(sb); ++ if (unlikely(!ino)) { ++ inode = ERR_PTR(-EIO); ++ goto out_xinondir; ++ } ++ } ++ ++ AuDbg("i%lu\n", (unsigned long)ino); ++ inode = au_iget_locked(sb, ino); ++ err = PTR_ERR(inode); ++ if (IS_ERR(inode)) ++ goto out_xinondir; ++ ++ AuDbg("%lx, new %d\n", inode->i_state, !!(inode->i_state & I_NEW)); ++ if (inode->i_state & I_NEW) { ++ ii_write_lock_new_child(inode); ++ err = set_inode(inode, dentry); ++ if (!err) { ++ unlock_new_inode(inode); ++ goto out_xinondir; /* success */ ++ } ++ ++ /* ++ * iget_failed() calls iput(), but we need to call ++ * ii_write_unlock() after iget_failed(). so dirty hack for ++ * i_count. ++ */ ++ atomic_inc(&inode->i_count); ++ iget_failed(inode); ++ ii_write_unlock(inode); ++ au_xino_write(sb, btop, h_ino, /*ino*/0); ++ /* ignore this error */ ++ goto out_iput; ++ } else if (!must_new && !IS_DEADDIR(inode) && inode->i_nlink) { ++ /* ++ * horrible race condition between lookup, readdir and copyup ++ * (or something). ++ */ ++ if (hlinked && idx >= 0) ++ au_xinondir_leave(sb, btop, h_ino, idx); ++ err = reval_inode(inode, dentry); ++ if (unlikely(err < 0)) { ++ hlinked = 0; ++ goto out_iput; ++ } ++ if (!err) ++ goto out; /* success */ ++ else if (hlinked && idx >= 0) { ++ err = au_xinondir_enter(sb, btop, h_ino, &idx); ++ if (unlikely(err)) { ++ iput(inode); ++ inode = ERR_PTR(err); ++ goto out; ++ } ++ } ++ } ++ ++ if (unlikely(au_test_fs_unique_ino(h_inode))) ++ AuWarn1("Warning: Un-notified UDBA or repeatedly renamed dir," ++ " b%d, %s, %pd, hi%lu, i%lu.\n", ++ btop, au_sbtype(h_dentry->d_sb), dentry, ++ (unsigned long)h_ino, (unsigned long)ino); ++ ino = 0; ++ err = au_xino_write(sb, btop, h_ino, /*ino*/0); ++ if (!err) { ++ iput(inode); ++ if (hlinked && idx >= 0) ++ au_xinondir_leave(sb, btop, h_ino, idx); ++ goto new_ino; ++ } ++ ++out_iput: ++ iput(inode); ++ inode = ERR_PTR(err); ++out_xinondir: ++ if (hlinked && idx >= 0) ++ au_xinondir_leave(sb, btop, h_ino, idx); ++out: ++ return inode; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_test_ro(struct super_block *sb, aufs_bindex_t bindex, ++ struct inode *inode) ++{ ++ int err; ++ struct inode *hi; ++ ++ err = au_br_rdonly(au_sbr(sb, bindex)); ++ ++ /* pseudo-link after flushed may happen out of bounds */ ++ if (!err ++ && inode ++ && au_ibtop(inode) <= bindex ++ && bindex <= au_ibbot(inode)) { ++ /* ++ * permission check is unnecessary since vfsub routine ++ * will be called later ++ */ ++ hi = au_h_iptr(inode, bindex); ++ if (hi) ++ err = IS_IMMUTABLE(hi) ? -EROFS : 0; ++ } ++ ++ return err; ++} ++ ++int au_test_h_perm(struct inode *h_inode, int mask) ++{ ++ if (uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) ++ return 0; ++ return inode_permission(h_inode, mask); ++} ++ ++int au_test_h_perm_sio(struct inode *h_inode, int mask) ++{ ++ if (au_test_nfs(h_inode->i_sb) ++ && (mask & MAY_WRITE) ++ && S_ISDIR(h_inode->i_mode)) ++ mask |= MAY_READ; /* force permission check */ ++ return au_test_h_perm(h_inode, mask); ++} +diff -Nurp linux-5.4/fs/aufs/inode.h linux-5.4-aufs/fs/aufs/inode.h +--- linux-5.4/fs/aufs/inode.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/inode.h 2019-11-28 01:25:59.066925618 +0200 +@@ -0,0 +1,685 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode operations ++ */ ++ ++#ifndef __AUFS_INODE_H__ ++#define __AUFS_INODE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "rwsem.h" ++ ++struct vfsmount; ++ ++struct au_hnotify { ++#ifdef CONFIG_AUFS_HNOTIFY ++#ifdef CONFIG_AUFS_HFSNOTIFY ++ /* never use fsnotify_add_vfsmount_mark() */ ++ struct fsnotify_mark hn_mark; ++#endif ++ struct inode *hn_aufs_inode; /* no get/put */ ++ struct rcu_head rcu; ++#endif ++} ____cacheline_aligned_in_smp; ++ ++struct au_hinode { ++ struct inode *hi_inode; ++ aufs_bindex_t hi_id; ++#ifdef CONFIG_AUFS_HNOTIFY ++ struct au_hnotify *hi_notify; ++#endif ++ ++ /* reference to the copied-up whiteout with get/put */ ++ struct dentry *hi_whdentry; ++}; ++ ++/* ig_flags */ ++#define AuIG_HALF_REFRESHED 1 ++#define au_ig_ftest(flags, name) ((flags) & AuIG_##name) ++#define au_ig_fset(flags, name) \ ++ do { (flags) |= AuIG_##name; } while (0) ++#define au_ig_fclr(flags, name) \ ++ do { (flags) &= ~AuIG_##name; } while (0) ++ ++struct au_iigen { ++ spinlock_t ig_spin; ++ __u32 ig_generation, ig_flags; ++}; ++ ++struct au_vdir; ++struct au_iinfo { ++ struct au_iigen ii_generation; ++ struct super_block *ii_hsb1; /* no get/put */ ++ ++ struct au_rwsem ii_rwsem; ++ aufs_bindex_t ii_btop, ii_bbot; ++ __u32 ii_higen; ++ struct au_hinode *ii_hinode; ++ struct au_vdir *ii_vdir; ++}; ++ ++struct au_icntnr { ++ struct au_iinfo iinfo; ++ struct inode vfs_inode; ++ struct hlist_bl_node plink; ++ struct rcu_head rcu; ++} ____cacheline_aligned_in_smp; ++ ++/* au_pin flags */ ++#define AuPin_DI_LOCKED 1 ++#define AuPin_MNT_WRITE (1 << 1) ++#define au_ftest_pin(flags, name) ((flags) & AuPin_##name) ++#define au_fset_pin(flags, name) \ ++ do { (flags) |= AuPin_##name; } while (0) ++#define au_fclr_pin(flags, name) \ ++ do { (flags) &= ~AuPin_##name; } while (0) ++ ++struct au_pin { ++ /* input */ ++ struct dentry *dentry; ++ unsigned int udba; ++ unsigned char lsc_di, lsc_hi, flags; ++ aufs_bindex_t bindex; ++ ++ /* output */ ++ struct dentry *parent; ++ struct au_hinode *hdir; ++ struct vfsmount *h_mnt; ++ ++ /* temporary unlock/relock for copyup */ ++ struct dentry *h_dentry, *h_parent; ++ struct au_branch *br; ++ struct task_struct *task; ++}; ++ ++void au_pin_hdir_unlock(struct au_pin *p); ++int au_pin_hdir_lock(struct au_pin *p); ++int au_pin_hdir_relock(struct au_pin *p); ++void au_pin_hdir_acquire_nest(struct au_pin *p); ++void au_pin_hdir_release(struct au_pin *p); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_iinfo *au_ii(struct inode *inode) ++{ ++ BUG_ON(is_bad_inode(inode)); ++ return &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* inode.c */ ++struct inode *au_igrab(struct inode *inode); ++void au_refresh_iop(struct inode *inode, int force_getattr); ++int au_refresh_hinode_self(struct inode *inode); ++int au_refresh_hinode(struct inode *inode, struct dentry *dentry); ++int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ unsigned int d_type, ino_t *ino); ++struct inode *au_new_inode(struct dentry *dentry, int must_new); ++int au_test_ro(struct super_block *sb, aufs_bindex_t bindex, ++ struct inode *inode); ++int au_test_h_perm(struct inode *h_inode, int mask); ++int au_test_h_perm_sio(struct inode *h_inode, int mask); ++ ++static inline int au_wh_ino(struct super_block *sb, aufs_bindex_t bindex, ++ ino_t h_ino, unsigned int d_type, ino_t *ino) ++{ ++#ifdef CONFIG_AUFS_SHWH ++ return au_ino(sb, bindex, h_ino, d_type, ino); ++#else ++ return 0; ++#endif ++} ++ ++/* i_op.c */ ++enum { ++ AuIop_SYMLINK, ++ AuIop_DIR, ++ AuIop_OTHER, ++ AuIop_Last ++}; ++extern struct inode_operations aufs_iop[AuIop_Last], ++ aufs_iop_nogetattr[AuIop_Last]; ++ ++/* au_wr_dir flags */ ++#define AuWrDir_ADD_ENTRY 1 ++#define AuWrDir_ISDIR (1 << 1) ++#define AuWrDir_TMPFILE (1 << 2) ++#define au_ftest_wrdir(flags, name) ((flags) & AuWrDir_##name) ++#define au_fset_wrdir(flags, name) \ ++ do { (flags) |= AuWrDir_##name; } while (0) ++#define au_fclr_wrdir(flags, name) \ ++ do { (flags) &= ~AuWrDir_##name; } while (0) ++ ++struct au_wr_dir_args { ++ aufs_bindex_t force_btgt; ++ unsigned char flags; ++}; ++int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry, ++ struct au_wr_dir_args *args); ++ ++struct dentry *au_pinned_h_parent(struct au_pin *pin); ++void au_pin_init(struct au_pin *pin, struct dentry *dentry, ++ aufs_bindex_t bindex, int lsc_di, int lsc_hi, ++ unsigned int udba, unsigned char flags); ++int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int udba, unsigned char flags) __must_check; ++int au_do_pin(struct au_pin *pin) __must_check; ++void au_unpin(struct au_pin *pin); ++int au_reval_for_attr(struct dentry *dentry, unsigned int sigen); ++ ++#define AuIcpup_DID_CPUP 1 ++#define au_ftest_icpup(flags, name) ((flags) & AuIcpup_##name) ++#define au_fset_icpup(flags, name) \ ++ do { (flags) |= AuIcpup_##name; } while (0) ++#define au_fclr_icpup(flags, name) \ ++ do { (flags) &= ~AuIcpup_##name; } while (0) ++ ++struct au_icpup_args { ++ unsigned char flags; ++ unsigned char pin_flags; ++ aufs_bindex_t btgt; ++ unsigned int udba; ++ struct au_pin pin; ++ struct path h_path; ++ struct inode *h_inode; ++}; ++ ++int au_pin_and_icpup(struct dentry *dentry, struct iattr *ia, ++ struct au_icpup_args *a); ++ ++int au_h_path_getattr(struct dentry *dentry, int force, struct path *h_path, ++ int locked); ++ ++/* i_op_add.c */ ++int au_may_add(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir); ++int aufs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, ++ dev_t dev); ++int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname); ++int aufs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ++ bool want_excl); ++struct vfsub_aopen_args; ++int au_aopen_or_create(struct inode *dir, struct dentry *dentry, ++ struct vfsub_aopen_args *args); ++int aufs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode); ++int aufs_link(struct dentry *src_dentry, struct inode *dir, ++ struct dentry *dentry); ++int aufs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode); ++ ++/* i_op_del.c */ ++int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup); ++int au_may_del(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir); ++int aufs_unlink(struct inode *dir, struct dentry *dentry); ++int aufs_rmdir(struct inode *dir, struct dentry *dentry); ++ ++/* i_op_ren.c */ ++int au_wbr(struct dentry *dentry, aufs_bindex_t btgt); ++int aufs_rename(struct inode *src_dir, struct dentry *src_dentry, ++ struct inode *dir, struct dentry *dentry, ++ unsigned int flags); ++ ++/* iinfo.c */ ++struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex); ++void au_hiput(struct au_hinode *hinode); ++void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_wh); ++unsigned int au_hi_flags(struct inode *inode, int isdir); ++ ++/* hinode flags */ ++#define AuHi_XINO 1 ++#define AuHi_HNOTIFY (1 << 1) ++#define au_ftest_hi(flags, name) ((flags) & AuHi_##name) ++#define au_fset_hi(flags, name) \ ++ do { (flags) |= AuHi_##name; } while (0) ++#define au_fclr_hi(flags, name) \ ++ do { (flags) &= ~AuHi_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_HNOTIFY ++#undef AuHi_HNOTIFY ++#define AuHi_HNOTIFY 0 ++#endif ++ ++void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode, unsigned int flags); ++ ++void au_update_iigen(struct inode *inode, int half); ++void au_update_ibrange(struct inode *inode, int do_put_zero); ++ ++void au_icntnr_init_once(void *_c); ++void au_hinode_init(struct au_hinode *hinode); ++int au_iinfo_init(struct inode *inode); ++void au_iinfo_fin(struct inode *inode); ++int au_hinode_realloc(struct au_iinfo *iinfo, int nbr, int may_shrink); ++ ++#ifdef CONFIG_PROC_FS ++/* plink.c */ ++int au_plink_maint(struct super_block *sb, int flags); ++struct au_sbinfo; ++void au_plink_maint_leave(struct au_sbinfo *sbinfo); ++int au_plink_maint_enter(struct super_block *sb); ++#ifdef CONFIG_AUFS_DEBUG ++void au_plink_list(struct super_block *sb); ++#else ++AuStubVoid(au_plink_list, struct super_block *sb) ++#endif ++int au_plink_test(struct inode *inode); ++struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex); ++void au_plink_append(struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_dentry); ++void au_plink_put(struct super_block *sb, int verbose); ++void au_plink_clean(struct super_block *sb, int verbose); ++void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id); ++#else ++AuStubInt0(au_plink_maint, struct super_block *sb, int flags); ++AuStubVoid(au_plink_maint_leave, struct au_sbinfo *sbinfo); ++AuStubInt0(au_plink_maint_enter, struct super_block *sb); ++AuStubVoid(au_plink_list, struct super_block *sb); ++AuStubInt0(au_plink_test, struct inode *inode); ++AuStub(struct dentry *, au_plink_lkup, return NULL, ++ struct inode *inode, aufs_bindex_t bindex); ++AuStubVoid(au_plink_append, struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_dentry); ++AuStubVoid(au_plink_put, struct super_block *sb, int verbose); ++AuStubVoid(au_plink_clean, struct super_block *sb, int verbose); ++AuStubVoid(au_plink_half_refresh, struct super_block *sb, aufs_bindex_t br_id); ++#endif /* CONFIG_PROC_FS */ ++ ++#ifdef CONFIG_AUFS_XATTR ++/* xattr.c */ ++int au_cpup_xattr(struct dentry *h_dst, struct dentry *h_src, int ignore_flags, ++ unsigned int verbose); ++ssize_t aufs_listxattr(struct dentry *dentry, char *list, size_t size); ++void au_xattr_init(struct super_block *sb); ++#else ++AuStubInt0(au_cpup_xattr, struct dentry *h_dst, struct dentry *h_src, ++ int ignore_flags, unsigned int verbose); ++AuStubVoid(au_xattr_init, struct super_block *sb); ++#endif ++ ++#ifdef CONFIG_FS_POSIX_ACL ++struct posix_acl *aufs_get_acl(struct inode *inode, int type); ++int aufs_set_acl(struct inode *inode, struct posix_acl *acl, int type); ++#endif ++ ++#if IS_ENABLED(CONFIG_AUFS_XATTR) || IS_ENABLED(CONFIG_FS_POSIX_ACL) ++enum { ++ AU_XATTR_SET, ++ AU_ACL_SET ++}; ++ ++struct au_sxattr { ++ int type; ++ union { ++ struct { ++ const char *name; ++ const void *value; ++ size_t size; ++ int flags; ++ } set; ++ struct { ++ struct posix_acl *acl; ++ int type; ++ } acl_set; ++ } u; ++}; ++ssize_t au_sxattr(struct dentry *dentry, struct inode *inode, ++ struct au_sxattr *arg); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for iinfo */ ++enum { ++ AuLsc_II_CHILD, /* child first */ ++ AuLsc_II_CHILD2, /* rename(2), link(2), and cpup at hnotify */ ++ AuLsc_II_CHILD3, /* copyup dirs */ ++ AuLsc_II_PARENT, /* see AuLsc_I_PARENT in vfsub.h */ ++ AuLsc_II_PARENT2, ++ AuLsc_II_PARENT3, /* copyup dirs */ ++ AuLsc_II_NEW_CHILD ++}; ++ ++/* ++ * ii_read_lock_child, ii_write_lock_child, ++ * ii_read_lock_child2, ii_write_lock_child2, ++ * ii_read_lock_child3, ii_write_lock_child3, ++ * ii_read_lock_parent, ii_write_lock_parent, ++ * ii_read_lock_parent2, ii_write_lock_parent2, ++ * ii_read_lock_parent3, ii_write_lock_parent3, ++ * ii_read_lock_new_child, ii_write_lock_new_child, ++ */ ++#define AuReadLockFunc(name, lsc) \ ++static inline void ii_read_lock_##name(struct inode *i) \ ++{ \ ++ au_rw_read_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \ ++} ++ ++#define AuWriteLockFunc(name, lsc) \ ++static inline void ii_write_lock_##name(struct inode *i) \ ++{ \ ++ au_rw_write_lock_nested(&au_ii(i)->ii_rwsem, AuLsc_II_##lsc); \ ++} ++ ++#define AuRWLockFuncs(name, lsc) \ ++ AuReadLockFunc(name, lsc) \ ++ AuWriteLockFunc(name, lsc) ++ ++AuRWLockFuncs(child, CHILD); ++AuRWLockFuncs(child2, CHILD2); ++AuRWLockFuncs(child3, CHILD3); ++AuRWLockFuncs(parent, PARENT); ++AuRWLockFuncs(parent2, PARENT2); ++AuRWLockFuncs(parent3, PARENT3); ++AuRWLockFuncs(new_child, NEW_CHILD); ++ ++#undef AuReadLockFunc ++#undef AuWriteLockFunc ++#undef AuRWLockFuncs ++ ++#define ii_read_unlock(i) au_rw_read_unlock(&au_ii(i)->ii_rwsem) ++#define ii_write_unlock(i) au_rw_write_unlock(&au_ii(i)->ii_rwsem) ++#define ii_downgrade_lock(i) au_rw_dgrade_lock(&au_ii(i)->ii_rwsem) ++ ++#define IiMustNoWaiters(i) AuRwMustNoWaiters(&au_ii(i)->ii_rwsem) ++#define IiMustAnyLock(i) AuRwMustAnyLock(&au_ii(i)->ii_rwsem) ++#define IiMustWriteLock(i) AuRwMustWriteLock(&au_ii(i)->ii_rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline void au_icntnr_init(struct au_icntnr *c) ++{ ++#ifdef CONFIG_AUFS_DEBUG ++ c->vfs_inode.i_mode = 0; ++#endif ++} ++ ++static inline unsigned int au_iigen(struct inode *inode, unsigned int *igflags) ++{ ++ unsigned int gen; ++ struct au_iinfo *iinfo; ++ struct au_iigen *iigen; ++ ++ iinfo = au_ii(inode); ++ iigen = &iinfo->ii_generation; ++ spin_lock(&iigen->ig_spin); ++ if (igflags) ++ *igflags = iigen->ig_flags; ++ gen = iigen->ig_generation; ++ spin_unlock(&iigen->ig_spin); ++ ++ return gen; ++} ++ ++/* tiny test for inode number */ ++/* tmpfs generation is too rough */ ++static inline int au_test_higen(struct inode *inode, struct inode *h_inode) ++{ ++ struct au_iinfo *iinfo; ++ ++ iinfo = au_ii(inode); ++ AuRwMustAnyLock(&iinfo->ii_rwsem); ++ return !(iinfo->ii_hsb1 == h_inode->i_sb ++ && iinfo->ii_higen == h_inode->i_generation); ++} ++ ++static inline void au_iigen_dec(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct au_iigen *iigen; ++ ++ iinfo = au_ii(inode); ++ iigen = &iinfo->ii_generation; ++ spin_lock(&iigen->ig_spin); ++ iigen->ig_generation--; ++ spin_unlock(&iigen->ig_spin); ++} ++ ++static inline int au_iigen_test(struct inode *inode, unsigned int sigen) ++{ ++ int err; ++ ++ err = 0; ++ if (unlikely(inode && au_iigen(inode, NULL) != sigen)) ++ err = -EIO; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_hinode *au_hinode(struct au_iinfo *iinfo, ++ aufs_bindex_t bindex) ++{ ++ return iinfo->ii_hinode + bindex; ++} ++ ++static inline int au_is_bad_inode(struct inode *inode) ++{ ++ return !!(is_bad_inode(inode) || !au_hinode(au_ii(inode), 0)); ++} ++ ++static inline aufs_bindex_t au_ii_br_id(struct inode *inode, ++ aufs_bindex_t bindex) ++{ ++ IiMustAnyLock(inode); ++ return au_hinode(au_ii(inode), bindex)->hi_id; ++} ++ ++static inline aufs_bindex_t au_ibtop(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_btop; ++} ++ ++static inline aufs_bindex_t au_ibbot(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_bbot; ++} ++ ++static inline struct au_vdir *au_ivdir(struct inode *inode) ++{ ++ IiMustAnyLock(inode); ++ return au_ii(inode)->ii_vdir; ++} ++ ++static inline struct dentry *au_hi_wh(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustAnyLock(inode); ++ return au_hinode(au_ii(inode), bindex)->hi_whdentry; ++} ++ ++static inline void au_set_ibtop(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustWriteLock(inode); ++ au_ii(inode)->ii_btop = bindex; ++} ++ ++static inline void au_set_ibbot(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustWriteLock(inode); ++ au_ii(inode)->ii_bbot = bindex; ++} ++ ++static inline void au_set_ivdir(struct inode *inode, struct au_vdir *vdir) ++{ ++ IiMustWriteLock(inode); ++ au_ii(inode)->ii_vdir = vdir; ++} ++ ++static inline struct au_hinode *au_hi(struct inode *inode, aufs_bindex_t bindex) ++{ ++ IiMustAnyLock(inode); ++ return au_hinode(au_ii(inode), bindex); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct dentry *au_pinned_parent(struct au_pin *pin) ++{ ++ if (pin) ++ return pin->parent; ++ return NULL; ++} ++ ++static inline struct inode *au_pinned_h_dir(struct au_pin *pin) ++{ ++ if (pin && pin->hdir) ++ return pin->hdir->hi_inode; ++ return NULL; ++} ++ ++static inline struct au_hinode *au_pinned_hdir(struct au_pin *pin) ++{ ++ if (pin) ++ return pin->hdir; ++ return NULL; ++} ++ ++static inline void au_pin_set_dentry(struct au_pin *pin, struct dentry *dentry) ++{ ++ if (pin) ++ pin->dentry = dentry; ++} ++ ++static inline void au_pin_set_parent_lflag(struct au_pin *pin, ++ unsigned char lflag) ++{ ++ if (pin) { ++ if (lflag) ++ au_fset_pin(pin->flags, DI_LOCKED); ++ else ++ au_fclr_pin(pin->flags, DI_LOCKED); ++ } ++} ++ ++#if 0 /* reserved */ ++static inline void au_pin_set_parent(struct au_pin *pin, struct dentry *parent) ++{ ++ if (pin) { ++ dput(pin->parent); ++ pin->parent = dget(parent); ++ } ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_branch; ++#ifdef CONFIG_AUFS_HNOTIFY ++struct au_hnotify_op { ++ void (*ctl)(struct au_hinode *hinode, int do_set); ++ int (*alloc)(struct au_hinode *hinode); ++ ++ /* ++ * if it returns true, the the caller should free hinode->hi_notify, ++ * otherwise ->free() frees it. ++ */ ++ int (*free)(struct au_hinode *hinode, ++ struct au_hnotify *hn) __must_check; ++ ++ void (*fin)(void); ++ int (*init)(void); ++ ++ int (*reset_br)(unsigned int udba, struct au_branch *br, int perm); ++ void (*fin_br)(struct au_branch *br); ++ int (*init_br)(struct au_branch *br, int perm); ++}; ++ ++/* hnotify.c */ ++int au_hn_alloc(struct au_hinode *hinode, struct inode *inode); ++void au_hn_free(struct au_hinode *hinode); ++void au_hn_ctl(struct au_hinode *hinode, int do_set); ++void au_hn_reset(struct inode *inode, unsigned int flags); ++int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask, ++ const struct qstr *h_child_qstr, struct inode *h_child_inode); ++int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm); ++int au_hnotify_init_br(struct au_branch *br, int perm); ++void au_hnotify_fin_br(struct au_branch *br); ++int __init au_hnotify_init(void); ++void au_hnotify_fin(void); ++ ++/* hfsnotify.c */ ++extern const struct au_hnotify_op au_hnotify_op; ++ ++static inline ++void au_hn_init(struct au_hinode *hinode) ++{ ++ hinode->hi_notify = NULL; ++} ++ ++static inline struct au_hnotify *au_hn(struct au_hinode *hinode) ++{ ++ return hinode->hi_notify; ++} ++ ++#else ++AuStub(int, au_hn_alloc, return -EOPNOTSUPP, ++ struct au_hinode *hinode __maybe_unused, ++ struct inode *inode __maybe_unused) ++AuStub(struct au_hnotify *, au_hn, return NULL, struct au_hinode *hinode) ++AuStubVoid(au_hn_free, struct au_hinode *hinode __maybe_unused) ++AuStubVoid(au_hn_ctl, struct au_hinode *hinode __maybe_unused, ++ int do_set __maybe_unused) ++AuStubVoid(au_hn_reset, struct inode *inode __maybe_unused, ++ unsigned int flags __maybe_unused) ++AuStubInt0(au_hnotify_reset_br, unsigned int udba __maybe_unused, ++ struct au_branch *br __maybe_unused, ++ int perm __maybe_unused) ++AuStubInt0(au_hnotify_init_br, struct au_branch *br __maybe_unused, ++ int perm __maybe_unused) ++AuStubVoid(au_hnotify_fin_br, struct au_branch *br __maybe_unused) ++AuStubInt0(__init au_hnotify_init, void) ++AuStubVoid(au_hnotify_fin, void) ++AuStubVoid(au_hn_init, struct au_hinode *hinode __maybe_unused) ++#endif /* CONFIG_AUFS_HNOTIFY */ ++ ++static inline void au_hn_suspend(struct au_hinode *hdir) ++{ ++ au_hn_ctl(hdir, /*do_set*/0); ++} ++ ++static inline void au_hn_resume(struct au_hinode *hdir) ++{ ++ au_hn_ctl(hdir, /*do_set*/1); ++} ++ ++static inline void au_hn_inode_lock(struct au_hinode *hdir) ++{ ++ inode_lock(hdir->hi_inode); ++ au_hn_suspend(hdir); ++} ++ ++static inline void au_hn_inode_lock_nested(struct au_hinode *hdir, ++ unsigned int sc __maybe_unused) ++{ ++ inode_lock_nested(hdir->hi_inode, sc); ++ au_hn_suspend(hdir); ++} ++ ++#if 0 /* unused */ ++#include "vfsub.h" ++static inline void au_hn_inode_lock_shared_nested(struct au_hinode *hdir, ++ unsigned int sc) ++{ ++ inode_lock_shared_nested(hdir->hi_inode, sc); ++ au_hn_suspend(hdir); ++} ++#endif ++ ++static inline void au_hn_inode_unlock(struct au_hinode *hdir) ++{ ++ au_hn_resume(hdir); ++ inode_unlock(hdir->hi_inode); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_INODE_H__ */ +diff -Nurp linux-5.4/fs/aufs/ioctl.c linux-5.4-aufs/fs/aufs/ioctl.c +--- linux-5.4/fs/aufs/ioctl.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/ioctl.c 2019-11-28 01:25:59.066925618 +0200 +@@ -0,0 +1,207 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * ioctl ++ * plink-management and readdir in userspace. ++ * assist the pathconf(3) wrapper library. ++ * move-down ++ * File-based Hierarchical Storage Management. ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++static int au_wbr_fd(struct path *path, struct aufs_wbr_fd __user *arg) ++{ ++ int err, fd; ++ aufs_bindex_t wbi, bindex, bbot; ++ struct file *h_file; ++ struct super_block *sb; ++ struct dentry *root; ++ struct au_branch *br; ++ struct aufs_wbr_fd wbrfd = { ++ .oflags = au_dir_roflags, ++ .brid = -1 ++ }; ++ const int valid = O_RDONLY | O_NONBLOCK | O_LARGEFILE | O_DIRECTORY ++ | O_NOATIME | O_CLOEXEC; ++ ++ AuDebugOn(wbrfd.oflags & ~valid); ++ ++ if (arg) { ++ err = copy_from_user(&wbrfd, arg, sizeof(wbrfd)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ goto out; ++ } ++ ++ err = -EINVAL; ++ AuDbg("wbrfd{0%o, %d}\n", wbrfd.oflags, wbrfd.brid); ++ wbrfd.oflags |= au_dir_roflags; ++ AuDbg("0%o\n", wbrfd.oflags); ++ if (unlikely(wbrfd.oflags & ~valid)) ++ goto out; ++ } ++ ++ fd = get_unused_fd_flags(0); ++ err = fd; ++ if (unlikely(fd < 0)) ++ goto out; ++ ++ h_file = ERR_PTR(-EINVAL); ++ wbi = 0; ++ br = NULL; ++ sb = path->dentry->d_sb; ++ root = sb->s_root; ++ aufs_read_lock(root, AuLock_IR); ++ bbot = au_sbbot(sb); ++ if (wbrfd.brid >= 0) { ++ wbi = au_br_index(sb, wbrfd.brid); ++ if (unlikely(wbi < 0 || wbi > bbot)) ++ goto out_unlock; ++ } ++ ++ h_file = ERR_PTR(-ENOENT); ++ br = au_sbr(sb, wbi); ++ if (!au_br_writable(br->br_perm)) { ++ if (arg) ++ goto out_unlock; ++ ++ bindex = wbi + 1; ++ wbi = -1; ++ for (; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_writable(br->br_perm)) { ++ wbi = bindex; ++ br = au_sbr(sb, wbi); ++ break; ++ } ++ } ++ } ++ AuDbg("wbi %d\n", wbi); ++ if (wbi >= 0) ++ h_file = au_h_open(root, wbi, wbrfd.oflags, NULL, ++ /*force_wr*/0); ++ ++out_unlock: ++ aufs_read_unlock(root, AuLock_IR); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out_fd; ++ ++ au_lcnt_dec(&br->br_nfiles); /* cf. au_h_open() */ ++ fd_install(fd, h_file); ++ err = fd; ++ goto out; /* success */ ++ ++out_fd: ++ put_unused_fd(fd); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long err; ++ struct dentry *dentry; ++ ++ switch (cmd) { ++ case AUFS_CTL_RDU: ++ case AUFS_CTL_RDU_INO: ++ err = au_rdu_ioctl(file, cmd, arg); ++ break; ++ ++ case AUFS_CTL_WBR_FD: ++ err = au_wbr_fd(&file->f_path, (void __user *)arg); ++ break; ++ ++ case AUFS_CTL_IBUSY: ++ err = au_ibusy_ioctl(file, arg); ++ break; ++ ++ case AUFS_CTL_BRINFO: ++ err = au_brinfo_ioctl(file, arg); ++ break; ++ ++ case AUFS_CTL_FHSM_FD: ++ dentry = file->f_path.dentry; ++ if (IS_ROOT(dentry)) ++ err = au_fhsm_fd(dentry->d_sb, arg); ++ else ++ err = -ENOTTY; ++ break; ++ ++ default: ++ /* do not call the lower */ ++ AuDbg("0x%x\n", cmd); ++ err = -ENOTTY; ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long err; ++ ++ switch (cmd) { ++ case AUFS_CTL_MVDOWN: ++ err = au_mvdown(file->f_path.dentry, (void __user *)arg); ++ break; ++ ++ case AUFS_CTL_WBR_FD: ++ err = au_wbr_fd(&file->f_path, (void __user *)arg); ++ break; ++ ++ default: ++ /* do not call the lower */ ++ AuDbg("0x%x\n", cmd); ++ err = -ENOTTY; ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++#ifdef CONFIG_COMPAT ++long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ long err; ++ ++ switch (cmd) { ++ case AUFS_CTL_RDU: ++ case AUFS_CTL_RDU_INO: ++ err = au_rdu_compat_ioctl(file, cmd, arg); ++ break; ++ ++ case AUFS_CTL_IBUSY: ++ err = au_ibusy_compat_ioctl(file, arg); ++ break; ++ ++ case AUFS_CTL_BRINFO: ++ err = au_brinfo_compat_ioctl(file, arg); ++ break; ++ ++ default: ++ err = aufs_ioctl_dir(file, cmd, arg); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++long aufs_compat_ioctl_nondir(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ return aufs_ioctl_nondir(file, cmd, (unsigned long)compat_ptr(arg)); ++} ++#endif +diff -Nurp linux-5.4/fs/aufs/i_op_add.c linux-5.4-aufs/fs/aufs/i_op_add.c +--- linux-5.4/fs/aufs/i_op_add.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/i_op_add.c 2019-11-28 01:25:59.065925618 +0200 +@@ -0,0 +1,923 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode operations (add entry) ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* ++ * final procedure of adding a new entry, except link(2). ++ * remove whiteout, instantiate, copyup the parent dir's times and size ++ * and update version. ++ * if it failed, re-create the removed whiteout. ++ */ ++static int epilog(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct dentry *dentry) ++{ ++ int err, rerr; ++ aufs_bindex_t bwh; ++ struct path h_path; ++ struct super_block *sb; ++ struct inode *inode, *h_dir; ++ struct dentry *wh; ++ ++ bwh = -1; ++ sb = dir->i_sb; ++ if (wh_dentry) { ++ h_dir = d_inode(wh_dentry->d_parent); /* dir inode is locked */ ++ IMustLock(h_dir); ++ AuDebugOn(au_h_iptr(dir, bindex) != h_dir); ++ bwh = au_dbwh(dentry); ++ h_path.dentry = wh_dentry; ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ err = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path, ++ dentry); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ inode = au_new_inode(dentry, /*must_new*/1); ++ if (!IS_ERR(inode)) { ++ d_instantiate(dentry, inode); ++ dir = d_inode(dentry->d_parent); /* dir inode is locked */ ++ IMustLock(dir); ++ au_dir_ts(dir, bindex); ++ inode_inc_iversion(dir); ++ au_fhsm_wrote(sb, bindex, /*force*/0); ++ return 0; /* success */ ++ } ++ ++ err = PTR_ERR(inode); ++ if (!wh_dentry) ++ goto out; ++ ++ /* revert */ ++ /* dir inode is locked */ ++ wh = au_wh_create(dentry, bwh, wh_dentry->d_parent); ++ rerr = PTR_ERR(wh); ++ if (IS_ERR(wh)) { ++ AuIOErr("%pd reverting whiteout failed(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } else ++ dput(wh); ++ ++out: ++ return err; ++} ++ ++static int au_d_may_add(struct dentry *dentry) ++{ ++ int err; ++ ++ err = 0; ++ if (unlikely(d_unhashed(dentry))) ++ err = -ENOENT; ++ if (unlikely(d_really_is_positive(dentry))) ++ err = -EEXIST; ++ return err; ++} ++ ++/* ++ * simple tests for the adding inode operations. ++ * following the checks in vfs, plus the parent-child relationship. ++ */ ++int au_may_add(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir) ++{ ++ int err; ++ umode_t h_mode; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ ++ err = -ENAMETOOLONG; ++ if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ goto out; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (d_really_is_negative(dentry)) { ++ err = -EEXIST; ++ if (unlikely(d_is_positive(h_dentry))) ++ goto out; ++ } else { ++ /* rename(2) case */ ++ err = -EIO; ++ if (unlikely(d_is_negative(h_dentry))) ++ goto out; ++ h_inode = d_inode(h_dentry); ++ if (unlikely(!h_inode->i_nlink)) ++ goto out; ++ ++ h_mode = h_inode->i_mode; ++ if (!isdir) { ++ err = -EISDIR; ++ if (unlikely(S_ISDIR(h_mode))) ++ goto out; ++ } else if (unlikely(!S_ISDIR(h_mode))) { ++ err = -ENOTDIR; ++ goto out; ++ } ++ } ++ ++ err = 0; ++ /* expected parent dir is locked */ ++ if (unlikely(h_parent != h_dentry->d_parent)) ++ err = -EIO; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * initial procedure of adding a new entry. ++ * prepare writable branch and the parent dir, lock it, ++ * and lookup whiteout for the new entry. ++ */ ++static struct dentry* ++lock_hdir_lkup_wh(struct dentry *dentry, struct au_dtime *dt, ++ struct dentry *src_dentry, struct au_pin *pin, ++ struct au_wr_dir_args *wr_dir_args) ++{ ++ struct dentry *wh_dentry, *h_parent; ++ struct super_block *sb; ++ struct au_branch *br; ++ int err; ++ unsigned int udba; ++ aufs_bindex_t bcpup; ++ ++ AuDbg("%pd\n", dentry); ++ ++ err = au_wr_dir(dentry, src_dentry, wr_dir_args); ++ bcpup = err; ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err < 0)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ udba = au_opt_udba(sb); ++ err = au_pin(pin, dentry, bcpup, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ h_parent = au_pinned_h_parent(pin); ++ if (udba != AuOpt_UDBA_NONE ++ && au_dbtop(dentry) == bcpup) ++ err = au_may_add(dentry, bcpup, h_parent, ++ au_ftest_wrdir(wr_dir_args->flags, ISDIR)); ++ else if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ err = -ENAMETOOLONG; ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_unpin; ++ ++ br = au_sbr(sb, bcpup); ++ if (dt) { ++ struct path tmp = { ++ .dentry = h_parent, ++ .mnt = au_br_mnt(br) ++ }; ++ au_dtime_store(dt, au_pinned_parent(pin), &tmp); ++ } ++ ++ wh_dentry = NULL; ++ if (bcpup != au_dbwh(dentry)) ++ goto out; /* success */ ++ ++ /* ++ * ENAMETOOLONG here means that if we allowed create such name, then it ++ * would not be able to removed in the future. So we don't allow such ++ * name here and we don't handle ENAMETOOLONG differently here. ++ */ ++ wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, br); ++ ++out_unpin: ++ if (IS_ERR(wh_dentry)) ++ au_unpin(pin); ++out: ++ return wh_dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++enum { Mknod, Symlink, Creat }; ++struct simple_arg { ++ int type; ++ union { ++ struct { ++ umode_t mode; ++ bool want_excl; ++ bool try_aopen; ++ struct vfsub_aopen_args *aopen; ++ } c; ++ struct { ++ const char *symname; ++ } s; ++ struct { ++ umode_t mode; ++ dev_t dev; ++ } m; ++ } u; ++}; ++ ++static int add_simple(struct inode *dir, struct dentry *dentry, ++ struct simple_arg *arg) ++{ ++ int err, rerr; ++ aufs_bindex_t btop; ++ unsigned char created; ++ const unsigned char try_aopen ++ = (arg->type == Creat && arg->u.c.try_aopen); ++ struct vfsub_aopen_args *aopen = arg->u.c.aopen; ++ struct dentry *wh_dentry, *parent; ++ struct inode *h_dir; ++ struct super_block *sb; ++ struct au_branch *br; ++ /* to reduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct au_pin pin; ++ struct path h_path; ++ struct au_wr_dir_args wr_dir_args; ++ } *a; ++ ++ AuDbg("%pd\n", dentry); ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ a->wr_dir_args.force_btgt = -1; ++ a->wr_dir_args.flags = AuWrDir_ADD_ENTRY; ++ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ if (!try_aopen) { ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_free; ++ } ++ err = au_d_may_add(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ if (!try_aopen) ++ di_write_lock_parent(parent); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL, ++ &a->pin, &a->wr_dir_args); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ btop = au_dbtop(dentry); ++ sb = dentry->d_sb; ++ br = au_sbr(sb, btop); ++ a->h_path.dentry = au_h_dptr(dentry, btop); ++ a->h_path.mnt = au_br_mnt(br); ++ h_dir = au_pinned_h_dir(&a->pin); ++ switch (arg->type) { ++ case Creat: ++ if (!try_aopen || !h_dir->i_op->atomic_open) { ++ err = vfsub_create(h_dir, &a->h_path, arg->u.c.mode, ++ arg->u.c.want_excl); ++ created = !err; ++ if (!err && try_aopen) ++ aopen->file->f_mode |= FMODE_CREATED; ++ } else { ++ aopen->br = br; ++ err = vfsub_atomic_open(h_dir, a->h_path.dentry, aopen); ++ AuDbg("err %d\n", err); ++ AuDbgFile(aopen->file); ++ created = err >= 0 ++ && !!(aopen->file->f_mode & FMODE_CREATED); ++ } ++ break; ++ case Symlink: ++ err = vfsub_symlink(h_dir, &a->h_path, arg->u.s.symname); ++ created = !err; ++ break; ++ case Mknod: ++ err = vfsub_mknod(h_dir, &a->h_path, arg->u.m.mode, ++ arg->u.m.dev); ++ created = !err; ++ break; ++ default: ++ BUG(); ++ } ++ if (unlikely(err < 0)) ++ goto out_unpin; ++ ++ err = epilog(dir, btop, wh_dentry, dentry); ++ if (!err) ++ goto out_unpin; /* success */ ++ ++ /* revert */ ++ if (created /* && d_is_positive(a->h_path.dentry) */) { ++ /* no delegation since it is just created */ ++ rerr = vfsub_unlink(h_dir, &a->h_path, /*delegated*/NULL, ++ /*force*/0); ++ if (rerr) { ++ AuIOErr("%pd revert failure(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } ++ au_dtime_revert(&a->dt); ++ } ++ if (try_aopen && h_dir->i_op->atomic_open ++ && (aopen->file->f_mode & FMODE_OPENED)) ++ /* aopen->file is still opened */ ++ au_lcnt_dec(&aopen->br->br_nfiles); ++ ++out_unpin: ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++out_parent: ++ if (!try_aopen) ++ di_write_unlock(parent); ++out_unlock: ++ if (unlikely(err)) { ++ au_update_dbtop(dentry); ++ d_drop(dentry); ++ } ++ if (!try_aopen) ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ au_kfree_rcu(a); ++out: ++ return err; ++} ++ ++int aufs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, ++ dev_t dev) ++{ ++ struct simple_arg arg = { ++ .type = Mknod, ++ .u.m = { ++ .mode = mode, ++ .dev = dev ++ } ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) ++{ ++ struct simple_arg arg = { ++ .type = Symlink, ++ .u.s.symname = symname ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int aufs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ++ bool want_excl) ++{ ++ struct simple_arg arg = { ++ .type = Creat, ++ .u.c = { ++ .mode = mode, ++ .want_excl = want_excl ++ } ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int au_aopen_or_create(struct inode *dir, struct dentry *dentry, ++ struct vfsub_aopen_args *aopen_args) ++{ ++ struct simple_arg arg = { ++ .type = Creat, ++ .u.c = { ++ .mode = aopen_args->create_mode, ++ .want_excl = aopen_args->open_flag & O_EXCL, ++ .try_aopen = true, ++ .aopen = aopen_args ++ } ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int aufs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct super_block *sb; ++ struct dentry *parent, *h_parent, *h_dentry; ++ struct inode *h_dir, *inode; ++ struct vfsmount *h_mnt; ++ struct au_wr_dir_args wr_dir_args = { ++ .force_btgt = -1, ++ .flags = AuWrDir_TMPFILE ++ }; ++ ++ /* copy-up may happen */ ++ inode_lock(dir); ++ ++ sb = dir->i_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_di_init(dentry); ++ if (unlikely(err)) ++ goto out_si; ++ ++ err = -EBUSY; ++ parent = d_find_any_alias(dir); ++ AuDebugOn(!parent); ++ di_write_lock_parent(parent); ++ if (unlikely(d_inode(parent) != dir)) ++ goto out_parent; ++ ++ err = au_digen_test(parent, au_sigen(sb)); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ bindex = au_dbtop(parent); ++ au_set_dbtop(dentry, bindex); ++ au_set_dbbot(dentry, bindex); ++ err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args); ++ bindex = err; ++ if (unlikely(err < 0)) ++ goto out_parent; ++ ++ err = -EOPNOTSUPP; ++ h_dir = au_h_iptr(dir, bindex); ++ if (unlikely(!h_dir->i_op->tmpfile)) ++ goto out_parent; ++ ++ h_mnt = au_sbr_mnt(sb, bindex); ++ err = vfsub_mnt_want_write(h_mnt); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ h_parent = au_h_dptr(parent, bindex); ++ h_dentry = vfs_tmpfile(h_parent, mode, /*open_flag*/0); ++ if (IS_ERR(h_dentry)) { ++ err = PTR_ERR(h_dentry); ++ goto out_mnt; ++ } ++ ++ au_set_dbtop(dentry, bindex); ++ au_set_dbbot(dentry, bindex); ++ au_set_h_dptr(dentry, bindex, dget(h_dentry)); ++ inode = au_new_inode(dentry, /*must_new*/1); ++ if (IS_ERR(inode)) { ++ err = PTR_ERR(inode); ++ au_set_h_dptr(dentry, bindex, NULL); ++ au_set_dbtop(dentry, -1); ++ au_set_dbbot(dentry, -1); ++ } else { ++ if (!inode->i_nlink) ++ set_nlink(inode, 1); ++ d_tmpfile(dentry, inode); ++ au_di(dentry)->di_tmpfile = 1; ++ ++ /* update without i_mutex */ ++ if (au_ibtop(dir) == au_dbtop(dentry)) ++ au_cpup_attr_timesizes(dir); ++ } ++ dput(h_dentry); ++ ++out_mnt: ++ vfsub_mnt_drop_write(h_mnt); ++out_parent: ++ di_write_unlock(parent); ++ dput(parent); ++ di_write_unlock(dentry); ++ if (unlikely(err)) { ++ au_di_fin(dentry); ++ dentry->d_fsdata = NULL; ++ } ++out_si: ++ si_read_unlock(sb); ++out: ++ inode_unlock(dir); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_link_args { ++ aufs_bindex_t bdst, bsrc; ++ struct au_pin pin; ++ struct path h_path; ++ struct dentry *src_parent, *parent; ++}; ++ ++static int au_cpup_before_link(struct dentry *src_dentry, ++ struct au_link_args *a) ++{ ++ int err; ++ struct dentry *h_src_dentry; ++ struct au_cp_generic cpg = { ++ .dentry = src_dentry, ++ .bdst = a->bdst, ++ .bsrc = a->bsrc, ++ .len = -1, ++ .pin = &a->pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN /* | AuCpup_KEEPLINO */ ++ }; ++ ++ di_read_lock_parent(a->src_parent, AuLock_IR); ++ err = au_test_and_cpup_dirs(src_dentry, a->bdst); ++ if (unlikely(err)) ++ goto out; ++ ++ h_src_dentry = au_h_dptr(src_dentry, a->bsrc); ++ err = au_pin(&a->pin, src_dentry, a->bdst, ++ au_opt_udba(src_dentry->d_sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&a->pin); ++ ++out: ++ di_read_unlock(a->src_parent, AuLock_IR); ++ return err; ++} ++ ++static int au_cpup_or_link(struct dentry *src_dentry, struct dentry *dentry, ++ struct au_link_args *a) ++{ ++ int err; ++ unsigned char plink; ++ aufs_bindex_t bbot; ++ struct dentry *h_src_dentry; ++ struct inode *h_inode, *inode, *delegated; ++ struct super_block *sb; ++ struct file *h_file; ++ ++ plink = 0; ++ h_inode = NULL; ++ sb = src_dentry->d_sb; ++ inode = d_inode(src_dentry); ++ if (au_ibtop(inode) <= a->bdst) ++ h_inode = au_h_iptr(inode, a->bdst); ++ if (!h_inode || !h_inode->i_nlink) { ++ /* copyup src_dentry as the name of dentry. */ ++ bbot = au_dbbot(dentry); ++ if (bbot < a->bsrc) ++ au_set_dbbot(dentry, a->bsrc); ++ au_set_h_dptr(dentry, a->bsrc, ++ dget(au_h_dptr(src_dentry, a->bsrc))); ++ dget(a->h_path.dentry); ++ au_set_h_dptr(dentry, a->bdst, NULL); ++ AuDbg("temporary d_inode...\n"); ++ spin_lock(&dentry->d_lock); ++ dentry->d_inode = d_inode(src_dentry); /* tmp */ ++ spin_unlock(&dentry->d_lock); ++ h_file = au_h_open_pre(dentry, a->bsrc, /*force_wr*/0); ++ if (IS_ERR(h_file)) ++ err = PTR_ERR(h_file); ++ else { ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = a->bdst, ++ .bsrc = -1, ++ .len = -1, ++ .pin = &a->pin, ++ .flags = AuCpup_KEEPLINO ++ }; ++ err = au_sio_cpup_simple(&cpg); ++ au_h_open_post(dentry, a->bsrc, h_file); ++ if (!err) { ++ dput(a->h_path.dentry); ++ a->h_path.dentry = au_h_dptr(dentry, a->bdst); ++ } else ++ au_set_h_dptr(dentry, a->bdst, ++ a->h_path.dentry); ++ } ++ spin_lock(&dentry->d_lock); ++ dentry->d_inode = NULL; /* restore */ ++ spin_unlock(&dentry->d_lock); ++ AuDbg("temporary d_inode...done\n"); ++ au_set_h_dptr(dentry, a->bsrc, NULL); ++ au_set_dbbot(dentry, bbot); ++ } else { ++ /* the inode of src_dentry already exists on a.bdst branch */ ++ h_src_dentry = d_find_alias(h_inode); ++ if (!h_src_dentry && au_plink_test(inode)) { ++ plink = 1; ++ h_src_dentry = au_plink_lkup(inode, a->bdst); ++ err = PTR_ERR(h_src_dentry); ++ if (IS_ERR(h_src_dentry)) ++ goto out; ++ ++ if (unlikely(d_is_negative(h_src_dentry))) { ++ dput(h_src_dentry); ++ h_src_dentry = NULL; ++ } ++ ++ } ++ if (h_src_dentry) { ++ delegated = NULL; ++ err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), ++ &a->h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ dput(h_src_dentry); ++ } else { ++ AuIOErr("no dentry found for hi%lu on b%d\n", ++ h_inode->i_ino, a->bdst); ++ err = -EIO; ++ } ++ } ++ ++ if (!err && !plink) ++ au_plink_append(inode, a->bdst, a->h_path.dentry); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int aufs_link(struct dentry *src_dentry, struct inode *dir, ++ struct dentry *dentry) ++{ ++ int err, rerr; ++ struct au_dtime dt; ++ struct au_link_args *a; ++ struct dentry *wh_dentry, *h_src_dentry; ++ struct inode *inode, *delegated; ++ struct super_block *sb; ++ struct au_wr_dir_args wr_dir_args = { ++ /* .force_btgt = -1, */ ++ .flags = AuWrDir_ADD_ENTRY ++ }; ++ ++ IMustLock(dir); ++ inode = d_inode(src_dentry); ++ IMustLock(inode); ++ ++ err = -ENOMEM; ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ a->parent = dentry->d_parent; /* dir inode is locked */ ++ err = aufs_read_and_write_lock2(dentry, src_dentry, ++ AuLock_NOPLM | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_kfree; ++ err = au_d_linkable(src_dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ err = au_d_may_add(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ a->src_parent = dget_parent(src_dentry); ++ wr_dir_args.force_btgt = au_ibtop(inode); ++ ++ di_write_lock_parent(a->parent); ++ wr_dir_args.force_btgt = au_wbr(dentry, wr_dir_args.force_btgt); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &dt, src_dentry, &a->pin, ++ &wr_dir_args); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ a->bdst = au_dbtop(dentry); ++ a->h_path.dentry = au_h_dptr(dentry, a->bdst); ++ a->h_path.mnt = au_sbr_mnt(sb, a->bdst); ++ a->bsrc = au_ibtop(inode); ++ h_src_dentry = au_h_d_alias(src_dentry, a->bsrc); ++ if (!h_src_dentry && au_di(src_dentry)->di_tmpfile) ++ h_src_dentry = dget(au_hi_wh(inode, a->bsrc)); ++ if (!h_src_dentry) { ++ a->bsrc = au_dbtop(src_dentry); ++ h_src_dentry = au_h_d_alias(src_dentry, a->bsrc); ++ AuDebugOn(!h_src_dentry); ++ } else if (IS_ERR(h_src_dentry)) { ++ err = PTR_ERR(h_src_dentry); ++ goto out_parent; ++ } ++ ++ /* ++ * aufs doesn't touch the credential so ++ * security_dentry_create_files_as() is unnecessary. ++ */ ++ if (au_opt_test(au_mntflags(sb), PLINK)) { ++ if (a->bdst < a->bsrc ++ /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) ++ err = au_cpup_or_link(src_dentry, dentry, a); ++ else { ++ delegated = NULL; ++ err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), ++ &a->h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ } ++ dput(h_src_dentry); ++ } else { ++ /* ++ * copyup src_dentry to the branch we process, ++ * and then link(2) to it. ++ */ ++ dput(h_src_dentry); ++ if (a->bdst < a->bsrc ++ /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) { ++ au_unpin(&a->pin); ++ di_write_unlock(a->parent); ++ err = au_cpup_before_link(src_dentry, a); ++ di_write_lock_parent(a->parent); ++ if (!err) ++ err = au_pin(&a->pin, dentry, a->bdst, ++ au_opt_udba(sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_wh; ++ } ++ if (!err) { ++ h_src_dentry = au_h_dptr(src_dentry, a->bdst); ++ err = -ENOENT; ++ if (h_src_dentry && d_is_positive(h_src_dentry)) { ++ delegated = NULL; ++ err = vfsub_link(h_src_dentry, ++ au_pinned_h_dir(&a->pin), ++ &a->h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry" ++ " for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ } ++ } ++ } ++ if (unlikely(err)) ++ goto out_unpin; ++ ++ if (wh_dentry) { ++ a->h_path.dentry = wh_dentry; ++ err = au_wh_unlink_dentry(au_pinned_h_dir(&a->pin), &a->h_path, ++ dentry); ++ if (unlikely(err)) ++ goto out_revert; ++ } ++ ++ au_dir_ts(dir, a->bdst); ++ inode_inc_iversion(dir); ++ inc_nlink(inode); ++ inode->i_ctime = dir->i_ctime; ++ d_instantiate(dentry, au_igrab(inode)); ++ if (d_unhashed(a->h_path.dentry)) ++ /* some filesystem calls d_drop() */ ++ d_drop(dentry); ++ /* some filesystems consume an inode even hardlink */ ++ au_fhsm_wrote(sb, a->bdst, /*force*/0); ++ goto out_unpin; /* success */ ++ ++out_revert: ++ /* no delegation since it is just created */ ++ rerr = vfsub_unlink(au_pinned_h_dir(&a->pin), &a->h_path, ++ /*delegated*/NULL, /*force*/0); ++ if (unlikely(rerr)) { ++ AuIOErr("%pd reverting failed(%d, %d)\n", dentry, err, rerr); ++ err = -EIO; ++ } ++ au_dtime_revert(&dt); ++out_unpin: ++ au_unpin(&a->pin); ++out_wh: ++ dput(wh_dentry); ++out_parent: ++ di_write_unlock(a->parent); ++ dput(a->src_parent); ++out_unlock: ++ if (unlikely(err)) { ++ au_update_dbtop(dentry); ++ d_drop(dentry); ++ } ++ aufs_read_and_write_unlock2(dentry, src_dentry); ++out_kfree: ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int aufs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ++{ ++ int err, rerr; ++ aufs_bindex_t bindex; ++ unsigned char diropq; ++ struct path h_path; ++ struct dentry *wh_dentry, *parent, *opq_dentry; ++ struct inode *h_inode; ++ struct super_block *sb; ++ struct { ++ struct au_pin pin; ++ struct au_dtime dt; ++ } *a; /* reduce the stack usage */ ++ struct au_wr_dir_args wr_dir_args = { ++ .force_btgt = -1, ++ .flags = AuWrDir_ADD_ENTRY | AuWrDir_ISDIR ++ }; ++ ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_free; ++ err = au_d_may_add(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_write_lock_parent(parent); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL, ++ &a->pin, &wr_dir_args); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ sb = dentry->d_sb; ++ bindex = au_dbtop(dentry); ++ h_path.dentry = au_h_dptr(dentry, bindex); ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ err = vfsub_mkdir(au_pinned_h_dir(&a->pin), &h_path, mode); ++ if (unlikely(err)) ++ goto out_unpin; ++ ++ /* make the dir opaque */ ++ diropq = 0; ++ h_inode = d_inode(h_path.dentry); ++ if (wh_dentry ++ || au_opt_test(au_mntflags(sb), ALWAYS_DIROPQ)) { ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ opq_dentry = au_diropq_create(dentry, bindex); ++ inode_unlock(h_inode); ++ err = PTR_ERR(opq_dentry); ++ if (IS_ERR(opq_dentry)) ++ goto out_dir; ++ dput(opq_dentry); ++ diropq = 1; ++ } ++ ++ err = epilog(dir, bindex, wh_dentry, dentry); ++ if (!err) { ++ inc_nlink(dir); ++ goto out_unpin; /* success */ ++ } ++ ++ /* revert */ ++ if (diropq) { ++ AuLabel(revert opq); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ rerr = au_diropq_remove(dentry, bindex); ++ inode_unlock(h_inode); ++ if (rerr) { ++ AuIOErr("%pd reverting diropq failed(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } ++ } ++ ++out_dir: ++ AuLabel(revert dir); ++ rerr = vfsub_rmdir(au_pinned_h_dir(&a->pin), &h_path); ++ if (rerr) { ++ AuIOErr("%pd reverting dir failed(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } ++ au_dtime_revert(&a->dt); ++out_unpin: ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++out_parent: ++ di_write_unlock(parent); ++out_unlock: ++ if (unlikely(err)) { ++ au_update_dbtop(dentry); ++ d_drop(dentry); ++ } ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ au_kfree_rcu(a); ++out: ++ return err; ++} +diff -Nurp linux-5.4/fs/aufs/i_op.c linux-5.4-aufs/fs/aufs/i_op.c +--- linux-5.4/fs/aufs/i_op.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/i_op.c 2019-11-28 01:25:59.065925618 +0200 +@@ -0,0 +1,1492 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode operations (except add/del/rename) ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++static int h_permission(struct inode *h_inode, int mask, ++ struct path *h_path, int brperm) ++{ ++ int err; ++ const unsigned char write_mask = !!(mask & (MAY_WRITE | MAY_APPEND)); ++ ++ err = -EPERM; ++ if (write_mask && IS_IMMUTABLE(h_inode)) ++ goto out; ++ ++ err = -EACCES; ++ if (((mask & MAY_EXEC) ++ && S_ISREG(h_inode->i_mode) ++ && (path_noexec(h_path) ++ || !(h_inode->i_mode & 0111)))) ++ goto out; ++ ++ /* ++ * - skip the lower fs test in the case of write to ro branch. ++ * - nfs dir permission write check is optimized, but a policy for ++ * link/rename requires a real check. ++ * - nfs always sets SB_POSIXACL regardless its mount option 'noacl.' ++ * in this case, generic_permission() returns -EOPNOTSUPP. ++ */ ++ if ((write_mask && !au_br_writable(brperm)) ++ || (au_test_nfs(h_inode->i_sb) && S_ISDIR(h_inode->i_mode) ++ && write_mask && !(mask & MAY_READ)) ++ || !h_inode->i_op->permission) { ++ /* AuLabel(generic_permission); */ ++ /* AuDbg("get_acl %ps\n", h_inode->i_op->get_acl); */ ++ err = generic_permission(h_inode, mask); ++ if (err == -EOPNOTSUPP && au_test_nfs_noacl(h_inode)) ++ err = h_inode->i_op->permission(h_inode, mask); ++ AuTraceErr(err); ++ } else { ++ /* AuLabel(h_inode->permission); */ ++ err = h_inode->i_op->permission(h_inode, mask); ++ AuTraceErr(err); ++ } ++ ++ if (!err) ++ err = devcgroup_inode_permission(h_inode, mask); ++ if (!err) ++ err = security_inode_permission(h_inode, mask); ++ ++#if 0 ++ if (!err) { ++ /* todo: do we need to call ima_path_check()? */ ++ struct path h_path = { ++ .dentry = ++ .mnt = h_mnt ++ }; ++ err = ima_path_check(&h_path, ++ mask & (MAY_READ | MAY_WRITE | MAY_EXEC), ++ IMA_COUNT_LEAVE); ++ } ++#endif ++ ++out: ++ return err; ++} ++ ++static int aufs_permission(struct inode *inode, int mask) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ const unsigned char isdir = !!S_ISDIR(inode->i_mode), ++ write_mask = !!(mask & (MAY_WRITE | MAY_APPEND)); ++ struct inode *h_inode; ++ struct super_block *sb; ++ struct au_branch *br; ++ ++ /* todo: support rcu-walk? */ ++ if (mask & MAY_NOT_BLOCK) ++ return -ECHILD; ++ ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ ii_read_lock_child(inode); ++#if 0 ++ err = au_iigen_test(inode, au_sigen(sb)); ++ if (unlikely(err)) ++ goto out; ++#endif ++ ++ if (!isdir ++ || write_mask ++ || au_opt_test(au_mntflags(sb), DIRPERM1)) { ++ err = au_busy_or_stale(); ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ if (unlikely(!h_inode ++ || (h_inode->i_mode & S_IFMT) ++ != (inode->i_mode & S_IFMT))) ++ goto out; ++ ++ err = 0; ++ bindex = au_ibtop(inode); ++ br = au_sbr(sb, bindex); ++ err = h_permission(h_inode, mask, &br->br_path, br->br_perm); ++ if (write_mask ++ && !err ++ && !special_file(h_inode->i_mode)) { ++ /* test whether the upper writable branch exists */ ++ err = -EROFS; ++ for (; bindex >= 0; bindex--) ++ if (!au_br_rdonly(au_sbr(sb, bindex))) { ++ err = 0; ++ break; ++ } ++ } ++ goto out; ++ } ++ ++ /* non-write to dir */ ++ err = 0; ++ bbot = au_ibbot(inode); ++ for (bindex = au_ibtop(inode); !err && bindex <= bbot; bindex++) { ++ h_inode = au_h_iptr(inode, bindex); ++ if (h_inode) { ++ err = au_busy_or_stale(); ++ if (unlikely(!S_ISDIR(h_inode->i_mode))) ++ break; ++ ++ br = au_sbr(sb, bindex); ++ err = h_permission(h_inode, mask, &br->br_path, ++ br->br_perm); ++ } ++ } ++ ++out: ++ ii_read_unlock(inode); ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry *aufs_lookup(struct inode *dir, struct dentry *dentry, ++ unsigned int flags) ++{ ++ struct dentry *ret, *parent; ++ struct inode *inode; ++ struct super_block *sb; ++ int err, npositive; ++ ++ IMustLock(dir); ++ ++ /* todo: support rcu-walk? */ ++ ret = ERR_PTR(-ECHILD); ++ if (flags & LOOKUP_RCU) ++ goto out; ++ ++ ret = ERR_PTR(-ENAMETOOLONG); ++ if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ goto out; ++ ++ sb = dir->i_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ ret = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_di_init(dentry); ++ ret = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_si; ++ ++ inode = NULL; ++ npositive = 0; /* suppress a warning */ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_read_lock_parent(parent, AuLock_IR); ++ err = au_alive_dir(parent); ++ if (!err) ++ err = au_digen_test(parent, au_sigen(sb)); ++ if (!err) { ++ /* regardless LOOKUP_CREATE, always ALLOW_NEG */ ++ npositive = au_lkup_dentry(dentry, au_dbtop(parent), ++ AuLkup_ALLOW_NEG); ++ err = npositive; ++ } ++ di_read_unlock(parent, AuLock_IR); ++ ret = ERR_PTR(err); ++ if (unlikely(err < 0)) ++ goto out_unlock; ++ ++ if (npositive) { ++ inode = au_new_inode(dentry, /*must_new*/0); ++ if (IS_ERR(inode)) { ++ ret = (void *)inode; ++ inode = NULL; ++ goto out_unlock; ++ } ++ } ++ ++ if (inode) ++ atomic_inc(&inode->i_count); ++ ret = d_splice_alias(inode, dentry); ++#if 0 ++ if (unlikely(d_need_lookup(dentry))) { ++ spin_lock(&dentry->d_lock); ++ dentry->d_flags &= ~DCACHE_NEED_LOOKUP; ++ spin_unlock(&dentry->d_lock); ++ } else ++#endif ++ if (inode) { ++ if (!IS_ERR(ret)) { ++ iput(inode); ++ if (ret && ret != dentry) ++ ii_write_unlock(inode); ++ } else { ++ ii_write_unlock(inode); ++ iput(inode); ++ inode = NULL; ++ } ++ } ++ ++out_unlock: ++ di_write_unlock(dentry); ++out_si: ++ si_read_unlock(sb); ++out: ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * very dirty and complicated aufs ->atomic_open(). ++ * aufs_atomic_open() ++ * + au_aopen_or_create() ++ * + add_simple() ++ * + vfsub_atomic_open() ++ * + branch fs ->atomic_open() ++ * may call the actual 'open' for h_file ++ * + inc br_nfiles only if opened ++ * + au_aopen_no_open() or au_aopen_do_open() ++ * ++ * au_aopen_do_open() ++ * + finish_open() ++ * + au_do_aopen() ++ * + au_do_open() the body of all 'open' ++ * + au_do_open_nondir() ++ * set the passed h_file ++ * ++ * au_aopen_no_open() ++ * + finish_no_open() ++ */ ++ ++struct aopen_node { ++ struct hlist_bl_node hblist; ++ struct file *file, *h_file; ++}; ++ ++static int au_do_aopen(struct inode *inode, struct file *file) ++{ ++ struct hlist_bl_head *aopen; ++ struct hlist_bl_node *pos; ++ struct aopen_node *node; ++ struct au_do_open_args args = { ++ .aopen = 1, ++ .open = au_do_open_nondir ++ }; ++ ++ aopen = &au_sbi(inode->i_sb)->si_aopen; ++ hlist_bl_lock(aopen); ++ hlist_bl_for_each_entry(node, pos, aopen, hblist) ++ if (node->file == file) { ++ args.h_file = node->h_file; ++ break; ++ } ++ hlist_bl_unlock(aopen); ++ /* AuDebugOn(!args.h_file); */ ++ ++ return au_do_open(file, &args); ++} ++ ++static int au_aopen_do_open(struct file *file, struct dentry *dentry, ++ struct aopen_node *aopen_node) ++{ ++ int err; ++ struct hlist_bl_head *aopen; ++ ++ AuLabel(here); ++ aopen = &au_sbi(dentry->d_sb)->si_aopen; ++ au_hbl_add(&aopen_node->hblist, aopen); ++ err = finish_open(file, dentry, au_do_aopen); ++ au_hbl_del(&aopen_node->hblist, aopen); ++ /* AuDbgFile(file); */ ++ AuDbg("%pd%s%s\n", dentry, ++ (file->f_mode & FMODE_CREATED) ? " created" : "", ++ (file->f_mode & FMODE_OPENED) ? " opened" : ""); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_aopen_no_open(struct file *file, struct dentry *dentry) ++{ ++ int err; ++ ++ AuLabel(here); ++ dget(dentry); ++ err = finish_no_open(file, dentry); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int aufs_atomic_open(struct inode *dir, struct dentry *dentry, ++ struct file *file, unsigned int open_flag, ++ umode_t create_mode) ++{ ++ int err, did_open; ++ unsigned int lkup_flags; ++ aufs_bindex_t bindex; ++ struct super_block *sb; ++ struct dentry *parent, *d; ++ struct vfsub_aopen_args args = { ++ .open_flag = open_flag, ++ .create_mode = create_mode ++ }; ++ struct aopen_node aopen_node = { ++ .file = file ++ }; ++ ++ IMustLock(dir); ++ AuDbg("open_flag 0%o\n", open_flag); ++ AuDbgDentry(dentry); ++ ++ err = 0; ++ if (!au_di(dentry)) { ++ lkup_flags = LOOKUP_OPEN; ++ if (open_flag & O_CREAT) ++ lkup_flags |= LOOKUP_CREATE; ++ d = aufs_lookup(dir, dentry, lkup_flags); ++ if (IS_ERR(d)) { ++ err = PTR_ERR(d); ++ AuTraceErr(err); ++ goto out; ++ } else if (d) { ++ /* ++ * obsoleted dentry found. ++ * another error will be returned later. ++ */ ++ d_drop(d); ++ AuDbgDentry(d); ++ dput(d); ++ } ++ AuDbgDentry(dentry); ++ } ++ ++ if (d_is_positive(dentry) ++ || d_unhashed(dentry) ++ || d_unlinked(dentry) ++ || !(open_flag & O_CREAT)) { ++ err = au_aopen_no_open(file, dentry); ++ goto out; /* success */ ++ } ++ ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_GEN); ++ if (unlikely(err)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ parent = dentry->d_parent; /* dir is locked */ ++ di_write_lock_parent(parent); ++ err = au_lkup_dentry(dentry, /*btop*/0, AuLkup_ALLOW_NEG); ++ if (unlikely(err < 0)) ++ goto out_parent; ++ ++ AuDbgDentry(dentry); ++ if (d_is_positive(dentry)) { ++ err = au_aopen_no_open(file, dentry); ++ goto out_parent; /* success */ ++ } ++ ++ args.file = alloc_empty_file(file->f_flags, current_cred()); ++ err = PTR_ERR(args.file); ++ if (IS_ERR(args.file)) ++ goto out_parent; ++ ++ bindex = au_dbtop(dentry); ++ err = au_aopen_or_create(dir, dentry, &args); ++ AuTraceErr(err); ++ AuDbgFile(args.file); ++ file->f_mode = args.file->f_mode & ~FMODE_OPENED; ++ did_open = !!(args.file->f_mode & FMODE_OPENED); ++ if (!did_open) { ++ fput(args.file); ++ args.file = NULL; ++ } ++ di_write_unlock(parent); ++ di_write_unlock(dentry); ++ if (unlikely(err < 0)) { ++ if (args.file) ++ fput(args.file); ++ goto out_sb; ++ } ++ ++ if (!did_open) ++ err = au_aopen_no_open(file, dentry); ++ else { ++ aopen_node.h_file = args.file; ++ err = au_aopen_do_open(file, dentry, &aopen_node); ++ } ++ if (unlikely(err < 0)) { ++ if (args.file) ++ fput(args.file); ++ if (did_open) ++ au_lcnt_dec(&args.br->br_nfiles); ++ } ++ goto out_sb; /* success */ ++ ++out_parent: ++ di_write_unlock(parent); ++ di_write_unlock(dentry); ++out_sb: ++ si_read_unlock(sb); ++out: ++ AuTraceErr(err); ++ AuDbgFile(file); ++ return err; ++} ++ ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_wr_dir_cpup(struct dentry *dentry, struct dentry *parent, ++ const unsigned char add_entry, aufs_bindex_t bcpup, ++ aufs_bindex_t btop) ++{ ++ int err; ++ struct dentry *h_parent; ++ struct inode *h_dir; ++ ++ if (add_entry) ++ IMustLock(d_inode(parent)); ++ else ++ di_write_lock_parent(parent); ++ ++ err = 0; ++ if (!au_h_dptr(parent, bcpup)) { ++ if (btop > bcpup) ++ err = au_cpup_dirs(dentry, bcpup); ++ else if (btop < bcpup) ++ err = au_cpdown_dirs(dentry, bcpup); ++ else ++ BUG(); ++ } ++ if (!err && add_entry && !au_ftest_wrdir(add_entry, TMPFILE)) { ++ h_parent = au_h_dptr(parent, bcpup); ++ h_dir = d_inode(h_parent); ++ inode_lock_shared_nested(h_dir, AuLsc_I_PARENT); ++ err = au_lkup_neg(dentry, bcpup, /*wh*/0); ++ /* todo: no unlock here */ ++ inode_unlock_shared(h_dir); ++ ++ AuDbg("bcpup %d\n", bcpup); ++ if (!err) { ++ if (d_really_is_negative(dentry)) ++ au_set_h_dptr(dentry, btop, NULL); ++ au_update_dbrange(dentry, /*do_put_zero*/0); ++ } ++ } ++ ++ if (!add_entry) ++ di_write_unlock(parent); ++ if (!err) ++ err = bcpup; /* success */ ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * decide the branch and the parent dir where we will create a new entry. ++ * returns new bindex or an error. ++ * copyup the parent dir if needed. ++ */ ++int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry, ++ struct au_wr_dir_args *args) ++{ ++ int err; ++ unsigned int flags; ++ aufs_bindex_t bcpup, btop, src_btop; ++ const unsigned char add_entry ++ = au_ftest_wrdir(args->flags, ADD_ENTRY) ++ | au_ftest_wrdir(args->flags, TMPFILE); ++ struct super_block *sb; ++ struct dentry *parent; ++ struct au_sbinfo *sbinfo; ++ ++ sb = dentry->d_sb; ++ sbinfo = au_sbi(sb); ++ parent = dget_parent(dentry); ++ btop = au_dbtop(dentry); ++ bcpup = btop; ++ if (args->force_btgt < 0) { ++ if (src_dentry) { ++ src_btop = au_dbtop(src_dentry); ++ if (src_btop < btop) ++ bcpup = src_btop; ++ } else if (add_entry) { ++ flags = 0; ++ if (au_ftest_wrdir(args->flags, ISDIR)) ++ au_fset_wbr(flags, DIR); ++ err = AuWbrCreate(sbinfo, dentry, flags); ++ bcpup = err; ++ } ++ ++ if (bcpup < 0 || au_test_ro(sb, bcpup, d_inode(dentry))) { ++ if (add_entry) ++ err = AuWbrCopyup(sbinfo, dentry); ++ else { ++ if (!IS_ROOT(dentry)) { ++ di_read_lock_parent(parent, !AuLock_IR); ++ err = AuWbrCopyup(sbinfo, dentry); ++ di_read_unlock(parent, !AuLock_IR); ++ } else ++ err = AuWbrCopyup(sbinfo, dentry); ++ } ++ bcpup = err; ++ if (unlikely(err < 0)) ++ goto out; ++ } ++ } else { ++ bcpup = args->force_btgt; ++ AuDebugOn(au_test_ro(sb, bcpup, d_inode(dentry))); ++ } ++ ++ AuDbg("btop %d, bcpup %d\n", btop, bcpup); ++ err = bcpup; ++ if (bcpup == btop) ++ goto out; /* success */ ++ ++ /* copyup the new parent into the branch we process */ ++ err = au_wr_dir_cpup(dentry, parent, add_entry, bcpup, btop); ++ if (err >= 0) { ++ if (d_really_is_negative(dentry)) { ++ au_set_h_dptr(dentry, btop, NULL); ++ au_set_dbtop(dentry, bcpup); ++ au_set_dbbot(dentry, bcpup); ++ } ++ AuDebugOn(add_entry ++ && !au_ftest_wrdir(args->flags, TMPFILE) ++ && !au_h_dptr(dentry, bcpup)); ++ } ++ ++out: ++ dput(parent); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_pin_hdir_unlock(struct au_pin *p) ++{ ++ if (p->hdir) ++ au_hn_inode_unlock(p->hdir); ++} ++ ++int au_pin_hdir_lock(struct au_pin *p) ++{ ++ int err; ++ ++ err = 0; ++ if (!p->hdir) ++ goto out; ++ ++ /* even if an error happens later, keep this lock */ ++ au_hn_inode_lock_nested(p->hdir, p->lsc_hi); ++ ++ err = -EBUSY; ++ if (unlikely(p->hdir->hi_inode != d_inode(p->h_parent))) ++ goto out; ++ ++ err = 0; ++ if (p->h_dentry) ++ err = au_h_verify(p->h_dentry, p->udba, p->hdir->hi_inode, ++ p->h_parent, p->br); ++ ++out: ++ return err; ++} ++ ++int au_pin_hdir_relock(struct au_pin *p) ++{ ++ int err, i; ++ struct inode *h_i; ++ struct dentry *h_d[] = { ++ p->h_dentry, ++ p->h_parent ++ }; ++ ++ err = au_pin_hdir_lock(p); ++ if (unlikely(err)) ++ goto out; ++ ++ for (i = 0; !err && i < sizeof(h_d)/sizeof(*h_d); i++) { ++ if (!h_d[i]) ++ continue; ++ if (d_is_positive(h_d[i])) { ++ h_i = d_inode(h_d[i]); ++ err = !h_i->i_nlink; ++ } ++ } ++ ++out: ++ return err; ++} ++ ++static void au_pin_hdir_set_owner(struct au_pin *p, struct task_struct *task) ++{ ++ atomic_long_set(&p->hdir->hi_inode->i_rwsem.owner, (long)task); ++} ++ ++void au_pin_hdir_acquire_nest(struct au_pin *p) ++{ ++ if (p->hdir) { ++ rwsem_acquire_nest(&p->hdir->hi_inode->i_rwsem.dep_map, ++ p->lsc_hi, 0, NULL, _RET_IP_); ++ au_pin_hdir_set_owner(p, current); ++ } ++} ++ ++void au_pin_hdir_release(struct au_pin *p) ++{ ++ if (p->hdir) { ++ au_pin_hdir_set_owner(p, p->task); ++ rwsem_release(&p->hdir->hi_inode->i_rwsem.dep_map, 1, _RET_IP_); ++ } ++} ++ ++struct dentry *au_pinned_h_parent(struct au_pin *pin) ++{ ++ if (pin && pin->parent) ++ return au_h_dptr(pin->parent, pin->bindex); ++ return NULL; ++} ++ ++void au_unpin(struct au_pin *p) ++{ ++ if (p->hdir) ++ au_pin_hdir_unlock(p); ++ if (p->h_mnt && au_ftest_pin(p->flags, MNT_WRITE)) ++ vfsub_mnt_drop_write(p->h_mnt); ++ if (!p->hdir) ++ return; ++ ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_unlock(p->parent, AuLock_IR); ++ iput(p->hdir->hi_inode); ++ dput(p->parent); ++ p->parent = NULL; ++ p->hdir = NULL; ++ p->h_mnt = NULL; ++ /* do not clear p->task */ ++} ++ ++int au_do_pin(struct au_pin *p) ++{ ++ int err; ++ struct super_block *sb; ++ struct inode *h_dir; ++ ++ err = 0; ++ sb = p->dentry->d_sb; ++ p->br = au_sbr(sb, p->bindex); ++ if (IS_ROOT(p->dentry)) { ++ if (au_ftest_pin(p->flags, MNT_WRITE)) { ++ p->h_mnt = au_br_mnt(p->br); ++ err = vfsub_mnt_want_write(p->h_mnt); ++ if (unlikely(err)) { ++ au_fclr_pin(p->flags, MNT_WRITE); ++ goto out_err; ++ } ++ } ++ goto out; ++ } ++ ++ p->h_dentry = NULL; ++ if (p->bindex <= au_dbbot(p->dentry)) ++ p->h_dentry = au_h_dptr(p->dentry, p->bindex); ++ ++ p->parent = dget_parent(p->dentry); ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_lock(p->parent, AuLock_IR, p->lsc_di); ++ ++ h_dir = NULL; ++ p->h_parent = au_h_dptr(p->parent, p->bindex); ++ p->hdir = au_hi(d_inode(p->parent), p->bindex); ++ if (p->hdir) ++ h_dir = p->hdir->hi_inode; ++ ++ /* ++ * udba case, or ++ * if DI_LOCKED is not set, then p->parent may be different ++ * and h_parent can be NULL. ++ */ ++ if (unlikely(!p->hdir || !h_dir || !p->h_parent)) { ++ err = -EBUSY; ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_unlock(p->parent, AuLock_IR); ++ dput(p->parent); ++ p->parent = NULL; ++ goto out_err; ++ } ++ ++ if (au_ftest_pin(p->flags, MNT_WRITE)) { ++ p->h_mnt = au_br_mnt(p->br); ++ err = vfsub_mnt_want_write(p->h_mnt); ++ if (unlikely(err)) { ++ au_fclr_pin(p->flags, MNT_WRITE); ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_unlock(p->parent, AuLock_IR); ++ dput(p->parent); ++ p->parent = NULL; ++ goto out_err; ++ } ++ } ++ ++ au_igrab(h_dir); ++ err = au_pin_hdir_lock(p); ++ if (!err) ++ goto out; /* success */ ++ ++ au_unpin(p); ++ ++out_err: ++ pr_err("err %d\n", err); ++ err = au_busy_or_stale(); ++out: ++ return err; ++} ++ ++void au_pin_init(struct au_pin *p, struct dentry *dentry, ++ aufs_bindex_t bindex, int lsc_di, int lsc_hi, ++ unsigned int udba, unsigned char flags) ++{ ++ p->dentry = dentry; ++ p->udba = udba; ++ p->lsc_di = lsc_di; ++ p->lsc_hi = lsc_hi; ++ p->flags = flags; ++ p->bindex = bindex; ++ ++ p->parent = NULL; ++ p->hdir = NULL; ++ p->h_mnt = NULL; ++ ++ p->h_dentry = NULL; ++ p->h_parent = NULL; ++ p->br = NULL; ++ p->task = current; ++} ++ ++int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int udba, unsigned char flags) ++{ ++ au_pin_init(pin, dentry, bindex, AuLsc_DI_PARENT, AuLsc_I_PARENT2, ++ udba, flags); ++ return au_do_pin(pin); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * ->setattr() and ->getattr() are called in various cases. ++ * chmod, stat: dentry is revalidated. ++ * fchmod, fstat: file and dentry are not revalidated, additionally they may be ++ * unhashed. ++ * for ->setattr(), ia->ia_file is passed from ftruncate only. ++ */ ++/* todo: consolidate with do_refresh() and simple_reval_dpath() */ ++int au_reval_for_attr(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ struct dentry *parent; ++ ++ err = 0; ++ if (au_digen_test(dentry, sigen)) { ++ parent = dget_parent(dentry); ++ di_read_lock_parent(parent, AuLock_IR); ++ err = au_refresh_dentry(dentry, parent); ++ di_read_unlock(parent, AuLock_IR); ++ dput(parent); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_pin_and_icpup(struct dentry *dentry, struct iattr *ia, ++ struct au_icpup_args *a) ++{ ++ int err; ++ loff_t sz; ++ aufs_bindex_t btop, ibtop; ++ struct dentry *hi_wh, *parent; ++ struct inode *inode; ++ struct au_wr_dir_args wr_dir_args = { ++ .force_btgt = -1, ++ .flags = 0 ++ }; ++ ++ if (d_is_dir(dentry)) ++ au_fset_wrdir(wr_dir_args.flags, ISDIR); ++ /* plink or hi_wh() case */ ++ btop = au_dbtop(dentry); ++ inode = d_inode(dentry); ++ ibtop = au_ibtop(inode); ++ if (btop != ibtop && !au_test_ro(inode->i_sb, ibtop, inode)) ++ wr_dir_args.force_btgt = ibtop; ++ err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args); ++ if (unlikely(err < 0)) ++ goto out; ++ a->btgt = err; ++ if (err != btop) ++ au_fset_icpup(a->flags, DID_CPUP); ++ ++ err = 0; ++ a->pin_flags = AuPin_MNT_WRITE; ++ parent = NULL; ++ if (!IS_ROOT(dentry)) { ++ au_fset_pin(a->pin_flags, DI_LOCKED); ++ parent = dget_parent(dentry); ++ di_write_lock_parent(parent); ++ } ++ ++ err = au_pin(&a->pin, dentry, a->btgt, a->udba, a->pin_flags); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ sz = -1; ++ a->h_path.dentry = au_h_dptr(dentry, btop); ++ a->h_inode = d_inode(a->h_path.dentry); ++ if (ia && (ia->ia_valid & ATTR_SIZE)) { ++ inode_lock_shared_nested(a->h_inode, AuLsc_I_CHILD); ++ if (ia->ia_size < i_size_read(a->h_inode)) ++ sz = ia->ia_size; ++ inode_unlock_shared(a->h_inode); ++ } ++ ++ hi_wh = NULL; ++ if (au_ftest_icpup(a->flags, DID_CPUP) && d_unlinked(dentry)) { ++ hi_wh = au_hi_wh(inode, a->btgt); ++ if (!hi_wh) { ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = a->btgt, ++ .bsrc = -1, ++ .len = sz, ++ .pin = &a->pin ++ }; ++ err = au_sio_cpup_wh(&cpg, /*file*/NULL); ++ if (unlikely(err)) ++ goto out_unlock; ++ hi_wh = au_hi_wh(inode, a->btgt); ++ /* todo: revalidate hi_wh? */ ++ } ++ } ++ ++ if (parent) { ++ au_pin_set_parent_lflag(&a->pin, /*lflag*/0); ++ di_downgrade_lock(parent, AuLock_IR); ++ dput(parent); ++ parent = NULL; ++ } ++ if (!au_ftest_icpup(a->flags, DID_CPUP)) ++ goto out; /* success */ ++ ++ if (!d_unhashed(dentry)) { ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = a->btgt, ++ .bsrc = btop, ++ .len = sz, ++ .pin = &a->pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ err = au_sio_cpup_simple(&cpg); ++ if (!err) ++ a->h_path.dentry = au_h_dptr(dentry, a->btgt); ++ } else if (!hi_wh) ++ a->h_path.dentry = au_h_dptr(dentry, a->btgt); ++ else ++ a->h_path.dentry = hi_wh; /* do not dget here */ ++ ++out_unlock: ++ a->h_inode = d_inode(a->h_path.dentry); ++ if (!err) ++ goto out; /* success */ ++ au_unpin(&a->pin); ++out_parent: ++ if (parent) { ++ di_write_unlock(parent); ++ dput(parent); ++ } ++out: ++ if (!err) ++ inode_lock_nested(a->h_inode, AuLsc_I_CHILD); ++ return err; ++} ++ ++static int aufs_setattr(struct dentry *dentry, struct iattr *ia) ++{ ++ int err; ++ struct inode *inode, *delegated; ++ struct super_block *sb; ++ struct file *file; ++ struct au_icpup_args *a; ++ ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ ++ err = setattr_prepare(dentry, ia); ++ if (unlikely(err)) ++ goto out; ++ ++ err = -ENOMEM; ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ if (ia->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) ++ ia->ia_valid &= ~ATTR_MODE; ++ ++ file = NULL; ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out_kfree; ++ ++ if (ia->ia_valid & ATTR_FILE) { ++ /* currently ftruncate(2) only */ ++ AuDebugOn(!d_is_reg(dentry)); ++ file = ia->ia_file; ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1, ++ /*fi_lsc*/0); ++ if (unlikely(err)) ++ goto out_si; ++ ia->ia_file = au_hf_top(file); ++ a->udba = AuOpt_UDBA_NONE; ++ } else { ++ /* fchmod() doesn't pass ia_file */ ++ a->udba = au_opt_udba(sb); ++ di_write_lock_child(dentry); ++ /* no d_unlinked(), to set UDBA_NONE for root */ ++ if (d_unhashed(dentry)) ++ a->udba = AuOpt_UDBA_NONE; ++ if (a->udba != AuOpt_UDBA_NONE) { ++ AuDebugOn(IS_ROOT(dentry)); ++ err = au_reval_for_attr(dentry, au_sigen(sb)); ++ if (unlikely(err)) ++ goto out_dentry; ++ } ++ } ++ ++ err = au_pin_and_icpup(dentry, ia, a); ++ if (unlikely(err < 0)) ++ goto out_dentry; ++ if (au_ftest_icpup(a->flags, DID_CPUP)) { ++ ia->ia_file = NULL; ++ ia->ia_valid &= ~ATTR_FILE; ++ } ++ ++ a->h_path.mnt = au_sbr_mnt(sb, a->btgt); ++ if ((ia->ia_valid & (ATTR_MODE | ATTR_CTIME)) ++ == (ATTR_MODE | ATTR_CTIME)) { ++ err = security_path_chmod(&a->h_path, ia->ia_mode); ++ if (unlikely(err)) ++ goto out_unlock; ++ } else if ((ia->ia_valid & (ATTR_UID | ATTR_GID)) ++ && (ia->ia_valid & ATTR_CTIME)) { ++ err = security_path_chown(&a->h_path, ia->ia_uid, ia->ia_gid); ++ if (unlikely(err)) ++ goto out_unlock; ++ } ++ ++ if (ia->ia_valid & ATTR_SIZE) { ++ struct file *f; ++ ++ if (ia->ia_size < i_size_read(inode)) ++ /* unmap only */ ++ truncate_setsize(inode, ia->ia_size); ++ ++ f = NULL; ++ if (ia->ia_valid & ATTR_FILE) ++ f = ia->ia_file; ++ inode_unlock(a->h_inode); ++ err = vfsub_trunc(&a->h_path, ia->ia_size, ia->ia_valid, f); ++ inode_lock_nested(a->h_inode, AuLsc_I_CHILD); ++ } else { ++ delegated = NULL; ++ while (1) { ++ err = vfsub_notify_change(&a->h_path, ia, &delegated); ++ if (delegated) { ++ err = break_deleg_wait(&delegated); ++ if (!err) ++ continue; ++ } ++ break; ++ } ++ } ++ /* ++ * regardless aufs 'acl' option setting. ++ * why don't all acl-aware fs call this func from their ->setattr()? ++ */ ++ if (!err && (ia->ia_valid & ATTR_MODE)) ++ err = vfsub_acl_chmod(a->h_inode, ia->ia_mode); ++ if (!err) ++ au_cpup_attr_changeable(inode); ++ ++out_unlock: ++ inode_unlock(a->h_inode); ++ au_unpin(&a->pin); ++ if (unlikely(err)) ++ au_update_dbtop(dentry); ++out_dentry: ++ di_write_unlock(dentry); ++ if (file) { ++ fi_write_unlock(file); ++ ia->ia_file = file; ++ ia->ia_valid |= ATTR_FILE; ++ } ++out_si: ++ si_read_unlock(sb); ++out_kfree: ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++#if IS_ENABLED(CONFIG_AUFS_XATTR) || IS_ENABLED(CONFIG_FS_POSIX_ACL) ++static int au_h_path_to_set_attr(struct dentry *dentry, ++ struct au_icpup_args *a, struct path *h_path) ++{ ++ int err; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ a->udba = au_opt_udba(sb); ++ /* no d_unlinked(), to set UDBA_NONE for root */ ++ if (d_unhashed(dentry)) ++ a->udba = AuOpt_UDBA_NONE; ++ if (a->udba != AuOpt_UDBA_NONE) { ++ AuDebugOn(IS_ROOT(dentry)); ++ err = au_reval_for_attr(dentry, au_sigen(sb)); ++ if (unlikely(err)) ++ goto out; ++ } ++ err = au_pin_and_icpup(dentry, /*ia*/NULL, a); ++ if (unlikely(err < 0)) ++ goto out; ++ ++ h_path->dentry = a->h_path.dentry; ++ h_path->mnt = au_sbr_mnt(sb, a->btgt); ++ ++out: ++ return err; ++} ++ ++ssize_t au_sxattr(struct dentry *dentry, struct inode *inode, ++ struct au_sxattr *arg) ++{ ++ int err; ++ struct path h_path; ++ struct super_block *sb; ++ struct au_icpup_args *a; ++ struct inode *h_inode; ++ ++ IMustLock(inode); ++ ++ err = -ENOMEM; ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out_kfree; ++ ++ h_path.dentry = NULL; /* silence gcc */ ++ di_write_lock_child(dentry); ++ err = au_h_path_to_set_attr(dentry, a, &h_path); ++ if (unlikely(err)) ++ goto out_di; ++ ++ inode_unlock(a->h_inode); ++ switch (arg->type) { ++ case AU_XATTR_SET: ++ AuDebugOn(d_is_negative(h_path.dentry)); ++ err = vfsub_setxattr(h_path.dentry, ++ arg->u.set.name, arg->u.set.value, ++ arg->u.set.size, arg->u.set.flags); ++ break; ++ case AU_ACL_SET: ++ err = -EOPNOTSUPP; ++ h_inode = d_inode(h_path.dentry); ++ if (h_inode->i_op->set_acl) ++ /* this will call posix_acl_update_mode */ ++ err = h_inode->i_op->set_acl(h_inode, ++ arg->u.acl_set.acl, ++ arg->u.acl_set.type); ++ break; ++ } ++ if (!err) ++ au_cpup_attr_timesizes(inode); ++ ++ au_unpin(&a->pin); ++ if (unlikely(err)) ++ au_update_dbtop(dentry); ++ ++out_di: ++ di_write_unlock(dentry); ++ si_read_unlock(sb); ++out_kfree: ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++#endif ++ ++static void au_refresh_iattr(struct inode *inode, struct kstat *st, ++ unsigned int nlink) ++{ ++ unsigned int n; ++ ++ inode->i_mode = st->mode; ++ /* don't i_[ug]id_write() here */ ++ inode->i_uid = st->uid; ++ inode->i_gid = st->gid; ++ inode->i_atime = st->atime; ++ inode->i_mtime = st->mtime; ++ inode->i_ctime = st->ctime; ++ ++ au_cpup_attr_nlink(inode, /*force*/0); ++ if (S_ISDIR(inode->i_mode)) { ++ n = inode->i_nlink; ++ n -= nlink; ++ n += st->nlink; ++ smp_mb(); /* for i_nlink */ ++ /* 0 can happen */ ++ set_nlink(inode, n); ++ } ++ ++ spin_lock(&inode->i_lock); ++ inode->i_blocks = st->blocks; ++ i_size_write(inode, st->size); ++ spin_unlock(&inode->i_lock); ++} ++ ++/* ++ * common routine for aufs_getattr() and au_getxattr(). ++ * returns zero or negative (an error). ++ * @dentry will be read-locked in success. ++ */ ++int au_h_path_getattr(struct dentry *dentry, int force, struct path *h_path, ++ int locked) ++{ ++ int err; ++ unsigned int mnt_flags, sigen; ++ unsigned char udba_none; ++ aufs_bindex_t bindex; ++ struct super_block *sb, *h_sb; ++ struct inode *inode; ++ ++ h_path->mnt = NULL; ++ h_path->dentry = NULL; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ mnt_flags = au_mntflags(sb); ++ udba_none = !!au_opt_test(mnt_flags, UDBA_NONE); ++ ++ if (unlikely(locked)) ++ goto body; /* skip locking dinfo */ ++ ++ /* support fstat(2) */ ++ if (!d_unlinked(dentry) && !udba_none) { ++ sigen = au_sigen(sb); ++ err = au_digen_test(dentry, sigen); ++ if (!err) { ++ di_read_lock_child(dentry, AuLock_IR); ++ err = au_dbrange_test(dentry); ++ if (unlikely(err)) { ++ di_read_unlock(dentry, AuLock_IR); ++ goto out; ++ } ++ } else { ++ AuDebugOn(IS_ROOT(dentry)); ++ di_write_lock_child(dentry); ++ err = au_dbrange_test(dentry); ++ if (!err) ++ err = au_reval_for_attr(dentry, sigen); ++ if (!err) ++ di_downgrade_lock(dentry, AuLock_IR); ++ else { ++ di_write_unlock(dentry); ++ goto out; ++ } ++ } ++ } else ++ di_read_lock_child(dentry, AuLock_IR); ++ ++body: ++ inode = d_inode(dentry); ++ bindex = au_ibtop(inode); ++ h_path->mnt = au_sbr_mnt(sb, bindex); ++ h_sb = h_path->mnt->mnt_sb; ++ if (!force ++ && !au_test_fs_bad_iattr(h_sb) ++ && udba_none) ++ goto out; /* success */ ++ ++ if (au_dbtop(dentry) == bindex) ++ h_path->dentry = au_h_dptr(dentry, bindex); ++ else if (au_opt_test(mnt_flags, PLINK) && au_plink_test(inode)) { ++ h_path->dentry = au_plink_lkup(inode, bindex); ++ if (IS_ERR(h_path->dentry)) ++ /* pretending success */ ++ h_path->dentry = NULL; ++ else ++ dput(h_path->dentry); ++ } ++ ++out: ++ return err; ++} ++ ++static int aufs_getattr(const struct path *path, struct kstat *st, ++ u32 request, unsigned int query) ++{ ++ int err; ++ unsigned char positive; ++ struct path h_path; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ dentry = path->dentry; ++ inode = d_inode(dentry); ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out; ++ err = au_h_path_getattr(dentry, /*force*/0, &h_path, /*locked*/0); ++ if (unlikely(err)) ++ goto out_si; ++ if (unlikely(!h_path.dentry)) ++ /* illegally overlapped or something */ ++ goto out_fill; /* pretending success */ ++ ++ positive = d_is_positive(h_path.dentry); ++ if (positive) ++ /* no vfsub version */ ++ err = vfs_getattr(&h_path, st, request, query); ++ if (!err) { ++ if (positive) ++ au_refresh_iattr(inode, st, ++ d_inode(h_path.dentry)->i_nlink); ++ goto out_fill; /* success */ ++ } ++ AuTraceErr(err); ++ goto out_di; ++ ++out_fill: ++ generic_fillattr(inode, st); ++out_di: ++ di_read_unlock(dentry, AuLock_IR); ++out_si: ++ si_read_unlock(sb); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static const char *aufs_get_link(struct dentry *dentry, struct inode *inode, ++ struct delayed_call *done) ++{ ++ const char *ret; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ int err; ++ aufs_bindex_t bindex; ++ ++ ret = NULL; /* suppress a warning */ ++ err = -ECHILD; ++ if (!dentry) ++ goto out; ++ ++ err = aufs_read_lock(dentry, AuLock_IR | AuLock_GEN); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_d_hashed_positive(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ err = -EINVAL; ++ inode = d_inode(dentry); ++ bindex = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, bindex); ++ if (unlikely(!h_inode->i_op->get_link)) ++ goto out_unlock; ++ ++ err = -EBUSY; ++ h_dentry = NULL; ++ if (au_dbtop(dentry) <= bindex) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry) ++ dget(h_dentry); ++ } ++ if (!h_dentry) { ++ h_dentry = d_find_any_alias(h_inode); ++ if (IS_ERR(h_dentry)) { ++ err = PTR_ERR(h_dentry); ++ goto out_unlock; ++ } ++ } ++ if (unlikely(!h_dentry)) ++ goto out_unlock; ++ ++ err = 0; ++ AuDbg("%ps\n", h_inode->i_op->get_link); ++ AuDbgDentry(h_dentry); ++ ret = vfs_get_link(h_dentry, done); ++ dput(h_dentry); ++ if (IS_ERR(ret)) ++ err = PTR_ERR(ret); ++ ++out_unlock: ++ aufs_read_unlock(dentry, AuLock_IR); ++out: ++ if (unlikely(err)) ++ ret = ERR_PTR(err); ++ AuTraceErrPtr(ret); ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_is_special(struct inode *inode) ++{ ++ return (inode->i_mode & (S_IFBLK | S_IFCHR | S_IFIFO | S_IFSOCK)); ++} ++ ++static int aufs_update_time(struct inode *inode, struct timespec64 *ts, ++ int flags) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct super_block *sb; ++ struct inode *h_inode; ++ struct vfsmount *h_mnt; ++ ++ sb = inode->i_sb; ++ WARN_ONCE((flags & S_ATIME) && !IS_NOATIME(inode), ++ "unexpected s_flags 0x%lx", sb->s_flags); ++ ++ /* mmap_sem might be acquired already, cf. aufs_mmap() */ ++ lockdep_off(); ++ si_read_lock(sb, AuLock_FLUSH); ++ ii_write_lock_child(inode); ++ ++ err = 0; ++ bindex = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, bindex); ++ if (!au_test_ro(sb, bindex, inode)) { ++ h_mnt = au_sbr_mnt(sb, bindex); ++ err = vfsub_mnt_want_write(h_mnt); ++ if (!err) { ++ err = vfsub_update_time(h_inode, ts, flags); ++ vfsub_mnt_drop_write(h_mnt); ++ } ++ } else if (au_is_special(h_inode)) { ++ /* ++ * Never copy-up here. ++ * These special files may already be opened and used for ++ * communicating. If we copied it up, then the communication ++ * would be corrupted. ++ */ ++ AuWarn1("timestamps for i%lu are ignored " ++ "since it is on readonly branch (hi%lu).\n", ++ inode->i_ino, h_inode->i_ino); ++ } else if (flags & ~S_ATIME) { ++ err = -EIO; ++ AuIOErr1("unexpected flags 0x%x\n", flags); ++ AuDebugOn(1); ++ } ++ ++ if (!err) ++ au_cpup_attr_timesizes(inode); ++ ii_write_unlock(inode); ++ si_read_unlock(sb); ++ lockdep_on(); ++ ++ if (!err && (flags & S_VERSION)) ++ inode_inc_iversion(inode); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* no getattr version will be set by module.c:aufs_init() */ ++struct inode_operations aufs_iop_nogetattr[AuIop_Last], ++ aufs_iop[] = { ++ [AuIop_SYMLINK] = { ++ .permission = aufs_permission, ++#ifdef CONFIG_FS_POSIX_ACL ++ .get_acl = aufs_get_acl, ++ .set_acl = aufs_set_acl, /* unsupport for symlink? */ ++#endif ++ ++ .setattr = aufs_setattr, ++ .getattr = aufs_getattr, ++ ++#ifdef CONFIG_AUFS_XATTR ++ .listxattr = aufs_listxattr, ++#endif ++ ++ .get_link = aufs_get_link, ++ ++ /* .update_time = aufs_update_time */ ++ }, ++ [AuIop_DIR] = { ++ .create = aufs_create, ++ .lookup = aufs_lookup, ++ .link = aufs_link, ++ .unlink = aufs_unlink, ++ .symlink = aufs_symlink, ++ .mkdir = aufs_mkdir, ++ .rmdir = aufs_rmdir, ++ .mknod = aufs_mknod, ++ .rename = aufs_rename, ++ ++ .permission = aufs_permission, ++#ifdef CONFIG_FS_POSIX_ACL ++ .get_acl = aufs_get_acl, ++ .set_acl = aufs_set_acl, ++#endif ++ ++ .setattr = aufs_setattr, ++ .getattr = aufs_getattr, ++ ++#ifdef CONFIG_AUFS_XATTR ++ .listxattr = aufs_listxattr, ++#endif ++ ++ .update_time = aufs_update_time, ++ .atomic_open = aufs_atomic_open, ++ .tmpfile = aufs_tmpfile ++ }, ++ [AuIop_OTHER] = { ++ .permission = aufs_permission, ++#ifdef CONFIG_FS_POSIX_ACL ++ .get_acl = aufs_get_acl, ++ .set_acl = aufs_set_acl, ++#endif ++ ++ .setattr = aufs_setattr, ++ .getattr = aufs_getattr, ++ ++#ifdef CONFIG_AUFS_XATTR ++ .listxattr = aufs_listxattr, ++#endif ++ ++ .update_time = aufs_update_time ++ } ++}; +diff -Nurp linux-5.4/fs/aufs/i_op_del.c linux-5.4-aufs/fs/aufs/i_op_del.c +--- linux-5.4/fs/aufs/i_op_del.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/i_op_del.c 2019-11-28 01:25:59.066925618 +0200 +@@ -0,0 +1,500 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode operations (del entry) ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* ++ * decide if a new whiteout for @dentry is necessary or not. ++ * when it is necessary, prepare the parent dir for the upper branch whose ++ * branch index is @bcpup for creation. the actual creation of the whiteout will ++ * be done by caller. ++ * return value: ++ * 0: wh is unnecessary ++ * plus: wh is necessary ++ * minus: error ++ */ ++int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup) ++{ ++ int need_wh, err; ++ aufs_bindex_t btop; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ btop = au_dbtop(dentry); ++ if (*bcpup < 0) { ++ *bcpup = btop; ++ if (au_test_ro(sb, btop, d_inode(dentry))) { ++ err = AuWbrCopyup(au_sbi(sb), dentry); ++ *bcpup = err; ++ if (unlikely(err < 0)) ++ goto out; ++ } ++ } else ++ AuDebugOn(btop < *bcpup ++ || au_test_ro(sb, *bcpup, d_inode(dentry))); ++ AuDbg("bcpup %d, btop %d\n", *bcpup, btop); ++ ++ if (*bcpup != btop) { ++ err = au_cpup_dirs(dentry, *bcpup); ++ if (unlikely(err)) ++ goto out; ++ need_wh = 1; ++ } else { ++ struct au_dinfo *dinfo, *tmp; ++ ++ need_wh = -ENOMEM; ++ dinfo = au_di(dentry); ++ tmp = au_di_alloc(sb, AuLsc_DI_TMP); ++ if (tmp) { ++ au_di_cp(tmp, dinfo); ++ au_di_swap(tmp, dinfo); ++ /* returns the number of positive dentries */ ++ need_wh = au_lkup_dentry(dentry, btop + 1, ++ /* AuLkup_IGNORE_PERM */ 0); ++ au_di_swap(tmp, dinfo); ++ au_rw_write_unlock(&tmp->di_rwsem); ++ au_di_free(tmp); ++ } ++ } ++ AuDbg("need_wh %d\n", need_wh); ++ err = need_wh; ++ ++out: ++ return err; ++} ++ ++/* ++ * simple tests for the del-entry operations. ++ * following the checks in vfs, plus the parent-child relationship. ++ */ ++int au_may_del(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir) ++{ ++ int err; ++ umode_t h_mode; ++ struct dentry *h_dentry, *h_latest; ++ struct inode *h_inode; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (d_really_is_positive(dentry)) { ++ err = -ENOENT; ++ if (unlikely(d_is_negative(h_dentry))) ++ goto out; ++ h_inode = d_inode(h_dentry); ++ if (unlikely(!h_inode->i_nlink)) ++ goto out; ++ ++ h_mode = h_inode->i_mode; ++ if (!isdir) { ++ err = -EISDIR; ++ if (unlikely(S_ISDIR(h_mode))) ++ goto out; ++ } else if (unlikely(!S_ISDIR(h_mode))) { ++ err = -ENOTDIR; ++ goto out; ++ } ++ } else { ++ /* rename(2) case */ ++ err = -EIO; ++ if (unlikely(d_is_positive(h_dentry))) ++ goto out; ++ } ++ ++ err = -ENOENT; ++ /* expected parent dir is locked */ ++ if (unlikely(h_parent != h_dentry->d_parent)) ++ goto out; ++ err = 0; ++ ++ /* ++ * rmdir a dir may break the consistency on some filesystem. ++ * let's try heavy test. ++ */ ++ err = -EACCES; ++ if (unlikely(!au_opt_test(au_mntflags(dentry->d_sb), DIRPERM1) ++ && au_test_h_perm(d_inode(h_parent), ++ MAY_EXEC | MAY_WRITE))) ++ goto out; ++ ++ h_latest = au_sio_lkup_one(&dentry->d_name, h_parent); ++ err = -EIO; ++ if (IS_ERR(h_latest)) ++ goto out; ++ if (h_latest == h_dentry) ++ err = 0; ++ dput(h_latest); ++ ++out: ++ return err; ++} ++ ++/* ++ * decide the branch where we operate for @dentry. the branch index will be set ++ * @rbcpup. after deciding it, 'pin' it and store the timestamps of the parent ++ * dir for reverting. ++ * when a new whiteout is necessary, create it. ++ */ ++static struct dentry* ++lock_hdir_create_wh(struct dentry *dentry, int isdir, aufs_bindex_t *rbcpup, ++ struct au_dtime *dt, struct au_pin *pin) ++{ ++ struct dentry *wh_dentry; ++ struct super_block *sb; ++ struct path h_path; ++ int err, need_wh; ++ unsigned int udba; ++ aufs_bindex_t bcpup; ++ ++ need_wh = au_wr_dir_need_wh(dentry, isdir, rbcpup); ++ wh_dentry = ERR_PTR(need_wh); ++ if (unlikely(need_wh < 0)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ udba = au_opt_udba(sb); ++ bcpup = *rbcpup; ++ err = au_pin(pin, dentry, bcpup, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ h_path.dentry = au_pinned_h_parent(pin); ++ if (udba != AuOpt_UDBA_NONE ++ && au_dbtop(dentry) == bcpup) { ++ err = au_may_del(dentry, bcpup, h_path.dentry, isdir); ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_unpin; ++ } ++ ++ h_path.mnt = au_sbr_mnt(sb, bcpup); ++ au_dtime_store(dt, au_pinned_parent(pin), &h_path); ++ wh_dentry = NULL; ++ if (!need_wh) ++ goto out; /* success, no need to create whiteout */ ++ ++ wh_dentry = au_wh_create(dentry, bcpup, h_path.dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_unpin; ++ ++ /* returns with the parent is locked and wh_dentry is dget-ed */ ++ goto out; /* success */ ++ ++out_unpin: ++ au_unpin(pin); ++out: ++ return wh_dentry; ++} ++ ++/* ++ * when removing a dir, rename it to a unique temporary whiteout-ed name first ++ * in order to be revertible and save time for removing many child whiteouts ++ * under the dir. ++ * returns 1 when there are too many child whiteout and caller should remove ++ * them asynchronously. returns 0 when the number of children is enough small to ++ * remove now or the branch fs is a remote fs. ++ * otherwise return an error. ++ */ ++static int renwh_and_rmdir(struct dentry *dentry, aufs_bindex_t bindex, ++ struct au_nhash *whlist, struct inode *dir) ++{ ++ int rmdir_later, err, dirwh; ++ struct dentry *h_dentry; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ sb = dentry->d_sb; ++ SiMustAnyLock(sb); ++ h_dentry = au_h_dptr(dentry, bindex); ++ err = au_whtmp_ren(h_dentry, au_sbr(sb, bindex)); ++ if (unlikely(err)) ++ goto out; ++ ++ /* stop monitoring */ ++ inode = d_inode(dentry); ++ au_hn_free(au_hi(inode, bindex)); ++ ++ if (!au_test_fs_remote(h_dentry->d_sb)) { ++ dirwh = au_sbi(sb)->si_dirwh; ++ rmdir_later = (dirwh <= 1); ++ if (!rmdir_later) ++ rmdir_later = au_nhash_test_longer_wh(whlist, bindex, ++ dirwh); ++ if (rmdir_later) ++ return rmdir_later; ++ } ++ ++ err = au_whtmp_rmdir(dir, bindex, h_dentry, whlist); ++ if (unlikely(err)) { ++ AuIOErr("rmdir %pd, b%d failed, %d. ignored\n", ++ h_dentry, bindex, err); ++ err = 0; ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * final procedure for deleting a entry. ++ * maintain dentry and iattr. ++ */ ++static void epilog(struct inode *dir, struct dentry *dentry, ++ aufs_bindex_t bindex) ++{ ++ struct inode *inode; ++ ++ inode = d_inode(dentry); ++ d_drop(dentry); ++ inode->i_ctime = dir->i_ctime; ++ ++ au_dir_ts(dir, bindex); ++ inode_inc_iversion(dir); ++} ++ ++/* ++ * when an error happened, remove the created whiteout and revert everything. ++ */ ++static int do_revert(int err, struct inode *dir, aufs_bindex_t bindex, ++ aufs_bindex_t bwh, struct dentry *wh_dentry, ++ struct dentry *dentry, struct au_dtime *dt) ++{ ++ int rerr; ++ struct path h_path = { ++ .dentry = wh_dentry, ++ .mnt = au_sbr_mnt(dir->i_sb, bindex) ++ }; ++ ++ rerr = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path, dentry); ++ if (!rerr) { ++ au_set_dbwh(dentry, bwh); ++ au_dtime_revert(dt); ++ return 0; ++ } ++ ++ AuIOErr("%pd reverting whiteout failed(%d, %d)\n", dentry, err, rerr); ++ return -EIO; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int aufs_unlink(struct inode *dir, struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bwh, bindex, btop; ++ struct inode *inode, *h_dir, *delegated; ++ struct dentry *parent, *wh_dentry; ++ /* to reduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct au_pin pin; ++ struct path h_path; ++ } *a; ++ ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_free; ++ err = au_d_hashed_positive(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ err = -EISDIR; ++ if (unlikely(d_is_dir(dentry))) ++ goto out_unlock; /* possible? */ ++ ++ btop = au_dbtop(dentry); ++ bwh = au_dbwh(dentry); ++ bindex = -1; ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_write_lock_parent(parent); ++ wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/0, &bindex, &a->dt, ++ &a->pin); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ a->h_path.mnt = au_sbr_mnt(dentry->d_sb, btop); ++ a->h_path.dentry = au_h_dptr(dentry, btop); ++ dget(a->h_path.dentry); ++ if (bindex == btop) { ++ h_dir = au_pinned_h_dir(&a->pin); ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, &a->h_path, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ } else { ++ /* dir inode is locked */ ++ h_dir = d_inode(wh_dentry->d_parent); ++ IMustLock(h_dir); ++ err = 0; ++ } ++ ++ if (!err) { ++ vfsub_drop_nlink(inode); ++ epilog(dir, dentry, bindex); ++ ++ /* update target timestamps */ ++ if (bindex == btop) { ++ vfsub_update_h_iattr(&a->h_path, /*did*/NULL); ++ /*ignore*/ ++ inode->i_ctime = d_inode(a->h_path.dentry)->i_ctime; ++ } else ++ /* todo: this timestamp may be reverted later */ ++ inode->i_ctime = h_dir->i_ctime; ++ goto out_unpin; /* success */ ++ } ++ ++ /* revert */ ++ if (wh_dentry) { ++ int rerr; ++ ++ rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry, ++ &a->dt); ++ if (rerr) ++ err = rerr; ++ } ++ ++out_unpin: ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++ dput(a->h_path.dentry); ++out_parent: ++ di_write_unlock(parent); ++out_unlock: ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ au_kfree_rcu(a); ++out: ++ return err; ++} ++ ++int aufs_rmdir(struct inode *dir, struct dentry *dentry) ++{ ++ int err, rmdir_later; ++ aufs_bindex_t bwh, bindex, btop; ++ struct inode *inode; ++ struct dentry *parent, *wh_dentry, *h_dentry; ++ struct au_whtmp_rmdir *args; ++ /* to reduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct au_pin pin; ++ } *a; ++ ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_free; ++ err = au_alive_dir(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ err = -ENOTDIR; ++ if (unlikely(!d_is_dir(dentry))) ++ goto out_unlock; /* possible? */ ++ ++ err = -ENOMEM; ++ args = au_whtmp_rmdir_alloc(dir->i_sb, GFP_NOFS); ++ if (unlikely(!args)) ++ goto out_unlock; ++ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_write_lock_parent(parent); ++ err = au_test_empty(dentry, &args->whlist); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ btop = au_dbtop(dentry); ++ bwh = au_dbwh(dentry); ++ bindex = -1; ++ wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/1, &bindex, &a->dt, ++ &a->pin); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ h_dentry = au_h_dptr(dentry, btop); ++ dget(h_dentry); ++ rmdir_later = 0; ++ if (bindex == btop) { ++ err = renwh_and_rmdir(dentry, btop, &args->whlist, dir); ++ if (err > 0) { ++ rmdir_later = err; ++ err = 0; ++ } ++ } else { ++ /* stop monitoring */ ++ au_hn_free(au_hi(inode, btop)); ++ ++ /* dir inode is locked */ ++ IMustLock(d_inode(wh_dentry->d_parent)); ++ err = 0; ++ } ++ ++ if (!err) { ++ vfsub_dead_dir(inode); ++ au_set_dbdiropq(dentry, -1); ++ epilog(dir, dentry, bindex); ++ ++ if (rmdir_later) { ++ au_whtmp_kick_rmdir(dir, btop, h_dentry, args); ++ args = NULL; ++ } ++ ++ goto out_unpin; /* success */ ++ } ++ ++ /* revert */ ++ AuLabel(revert); ++ if (wh_dentry) { ++ int rerr; ++ ++ rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry, ++ &a->dt); ++ if (rerr) ++ err = rerr; ++ } ++ ++out_unpin: ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++ dput(h_dentry); ++out_parent: ++ di_write_unlock(parent); ++ if (args) ++ au_whtmp_rmdir_free(args); ++out_unlock: ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff -Nurp linux-5.4/fs/aufs/i_op_ren.c linux-5.4-aufs/fs/aufs/i_op_ren.c +--- linux-5.4/fs/aufs/i_op_ren.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/i_op_ren.c 2019-11-28 01:25:59.066925618 +0200 +@@ -0,0 +1,1237 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode operation (rename entry) ++ * todo: this is crazy monster ++ */ ++ ++#include ++#include "aufs.h" ++ ++enum { AuSRC, AuDST, AuSrcDst }; ++enum { AuPARENT, AuCHILD, AuParentChild }; ++ ++#define AuRen_ISDIR_SRC 1 ++#define AuRen_ISDIR_DST (1 << 1) ++#define AuRen_ISSAMEDIR (1 << 2) ++#define AuRen_WHSRC (1 << 3) ++#define AuRen_WHDST (1 << 4) ++#define AuRen_MNT_WRITE (1 << 5) ++#define AuRen_DT_DSTDIR (1 << 6) ++#define AuRen_DIROPQ_SRC (1 << 7) ++#define AuRen_DIROPQ_DST (1 << 8) ++#define AuRen_DIRREN (1 << 9) ++#define AuRen_DROPPED_SRC (1 << 10) ++#define AuRen_DROPPED_DST (1 << 11) ++#define au_ftest_ren(flags, name) ((flags) & AuRen_##name) ++#define au_fset_ren(flags, name) \ ++ do { (flags) |= AuRen_##name; } while (0) ++#define au_fclr_ren(flags, name) \ ++ do { (flags) &= ~AuRen_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_DIRREN ++#undef AuRen_DIRREN ++#define AuRen_DIRREN 0 ++#endif ++ ++struct au_ren_args { ++ struct { ++ struct dentry *dentry, *h_dentry, *parent, *h_parent, ++ *wh_dentry; ++ struct inode *dir, *inode; ++ struct au_hinode *hdir, *hinode; ++ struct au_dtime dt[AuParentChild]; ++ aufs_bindex_t btop, bdiropq; ++ } sd[AuSrcDst]; ++ ++#define src_dentry sd[AuSRC].dentry ++#define src_dir sd[AuSRC].dir ++#define src_inode sd[AuSRC].inode ++#define src_h_dentry sd[AuSRC].h_dentry ++#define src_parent sd[AuSRC].parent ++#define src_h_parent sd[AuSRC].h_parent ++#define src_wh_dentry sd[AuSRC].wh_dentry ++#define src_hdir sd[AuSRC].hdir ++#define src_hinode sd[AuSRC].hinode ++#define src_h_dir sd[AuSRC].hdir->hi_inode ++#define src_dt sd[AuSRC].dt ++#define src_btop sd[AuSRC].btop ++#define src_bdiropq sd[AuSRC].bdiropq ++ ++#define dst_dentry sd[AuDST].dentry ++#define dst_dir sd[AuDST].dir ++#define dst_inode sd[AuDST].inode ++#define dst_h_dentry sd[AuDST].h_dentry ++#define dst_parent sd[AuDST].parent ++#define dst_h_parent sd[AuDST].h_parent ++#define dst_wh_dentry sd[AuDST].wh_dentry ++#define dst_hdir sd[AuDST].hdir ++#define dst_hinode sd[AuDST].hinode ++#define dst_h_dir sd[AuDST].hdir->hi_inode ++#define dst_dt sd[AuDST].dt ++#define dst_btop sd[AuDST].btop ++#define dst_bdiropq sd[AuDST].bdiropq ++ ++ struct dentry *h_trap; ++ struct au_branch *br; ++ struct path h_path; ++ struct au_nhash whlist; ++ aufs_bindex_t btgt, src_bwh; ++ ++ struct { ++ unsigned short auren_flags; ++ unsigned char flags; /* syscall parameter */ ++ unsigned char exchange; ++ } __packed; ++ ++ struct au_whtmp_rmdir *thargs; ++ struct dentry *h_dst; ++ struct au_hinode *h_root; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * functions for reverting. ++ * when an error happened in a single rename systemcall, we should revert ++ * everything as if nothing happened. ++ * we don't need to revert the copied-up/down the parent dir since they are ++ * harmless. ++ */ ++ ++#define RevertFailure(fmt, ...) do { \ ++ AuIOErr("revert failure: " fmt " (%d, %d)\n", \ ++ ##__VA_ARGS__, err, rerr); \ ++ err = -EIO; \ ++} while (0) ++ ++static void au_ren_do_rev_diropq(int err, struct au_ren_args *a, int idx) ++{ ++ int rerr; ++ struct dentry *d; ++#define src_or_dst(member) a->sd[idx].member ++ ++ d = src_or_dst(dentry); /* {src,dst}_dentry */ ++ au_hn_inode_lock_nested(src_or_dst(hinode), AuLsc_I_CHILD); ++ rerr = au_diropq_remove(d, a->btgt); ++ au_hn_inode_unlock(src_or_dst(hinode)); ++ au_set_dbdiropq(d, src_or_dst(bdiropq)); ++ if (rerr) ++ RevertFailure("remove diropq %pd", d); ++ ++#undef src_or_dst_ ++} ++ ++static void au_ren_rev_diropq(int err, struct au_ren_args *a) ++{ ++ if (au_ftest_ren(a->auren_flags, DIROPQ_SRC)) ++ au_ren_do_rev_diropq(err, a, AuSRC); ++ if (au_ftest_ren(a->auren_flags, DIROPQ_DST)) ++ au_ren_do_rev_diropq(err, a, AuDST); ++} ++ ++static void au_ren_rev_rename(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ struct inode *delegated; ++ ++ a->h_path.dentry = vfsub_lkup_one(&a->src_dentry->d_name, ++ a->src_h_parent); ++ rerr = PTR_ERR(a->h_path.dentry); ++ if (IS_ERR(a->h_path.dentry)) { ++ RevertFailure("lkup one %pd", a->src_dentry); ++ return; ++ } ++ ++ delegated = NULL; ++ rerr = vfsub_rename(a->dst_h_dir, ++ au_h_dptr(a->src_dentry, a->btgt), ++ a->src_h_dir, &a->h_path, &delegated, a->flags); ++ if (unlikely(rerr == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ d_drop(a->h_path.dentry); ++ dput(a->h_path.dentry); ++ /* au_set_h_dptr(a->src_dentry, a->btgt, NULL); */ ++ if (rerr) ++ RevertFailure("rename %pd", a->src_dentry); ++} ++ ++static void au_ren_rev_whtmp(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ struct inode *delegated; ++ ++ a->h_path.dentry = vfsub_lkup_one(&a->dst_dentry->d_name, ++ a->dst_h_parent); ++ rerr = PTR_ERR(a->h_path.dentry); ++ if (IS_ERR(a->h_path.dentry)) { ++ RevertFailure("lkup one %pd", a->dst_dentry); ++ return; ++ } ++ if (d_is_positive(a->h_path.dentry)) { ++ d_drop(a->h_path.dentry); ++ dput(a->h_path.dentry); ++ return; ++ } ++ ++ delegated = NULL; ++ rerr = vfsub_rename(a->dst_h_dir, a->h_dst, a->dst_h_dir, &a->h_path, ++ &delegated, a->flags); ++ if (unlikely(rerr == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ d_drop(a->h_path.dentry); ++ dput(a->h_path.dentry); ++ if (!rerr) ++ au_set_h_dptr(a->dst_dentry, a->btgt, dget(a->h_dst)); ++ else ++ RevertFailure("rename %pd", a->h_dst); ++} ++ ++static void au_ren_rev_whsrc(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ ++ a->h_path.dentry = a->src_wh_dentry; ++ rerr = au_wh_unlink_dentry(a->src_h_dir, &a->h_path, a->src_dentry); ++ au_set_dbwh(a->src_dentry, a->src_bwh); ++ if (rerr) ++ RevertFailure("unlink %pd", a->src_wh_dentry); ++} ++#undef RevertFailure ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * when we have to copyup the renaming entry, do it with the rename-target name ++ * in order to minimize the cost (the later actual rename is unnecessary). ++ * otherwise rename it on the target branch. ++ */ ++static int au_ren_or_cpup(struct au_ren_args *a) ++{ ++ int err; ++ struct dentry *d; ++ struct inode *delegated; ++ ++ d = a->src_dentry; ++ if (au_dbtop(d) == a->btgt) { ++ a->h_path.dentry = a->dst_h_dentry; ++ AuDebugOn(au_dbtop(d) != a->btgt); ++ delegated = NULL; ++ err = vfsub_rename(a->src_h_dir, au_h_dptr(d, a->btgt), ++ a->dst_h_dir, &a->h_path, &delegated, ++ a->flags); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ } else ++ BUG(); ++ ++ if (!err && a->h_dst) ++ /* it will be set to dinfo later */ ++ dget(a->h_dst); ++ ++ return err; ++} ++ ++/* cf. aufs_rmdir() */ ++static int au_ren_del_whtmp(struct au_ren_args *a) ++{ ++ int err; ++ struct inode *dir; ++ ++ dir = a->dst_dir; ++ SiMustAnyLock(dir->i_sb); ++ if (!au_nhash_test_longer_wh(&a->whlist, a->btgt, ++ au_sbi(dir->i_sb)->si_dirwh) ++ || au_test_fs_remote(a->h_dst->d_sb)) { ++ err = au_whtmp_rmdir(dir, a->btgt, a->h_dst, &a->whlist); ++ if (unlikely(err)) ++ pr_warn("failed removing whtmp dir %pd (%d), " ++ "ignored.\n", a->h_dst, err); ++ } else { ++ au_nhash_wh_free(&a->thargs->whlist); ++ a->thargs->whlist = a->whlist; ++ a->whlist.nh_num = 0; ++ au_whtmp_kick_rmdir(dir, a->btgt, a->h_dst, a->thargs); ++ dput(a->h_dst); ++ a->thargs = NULL; ++ } ++ ++ return 0; ++} ++ ++/* make it 'opaque' dir. */ ++static int au_ren_do_diropq(struct au_ren_args *a, int idx) ++{ ++ int err; ++ struct dentry *d, *diropq; ++#define src_or_dst(member) a->sd[idx].member ++ ++ err = 0; ++ d = src_or_dst(dentry); /* {src,dst}_dentry */ ++ src_or_dst(bdiropq) = au_dbdiropq(d); ++ src_or_dst(hinode) = au_hi(src_or_dst(inode), a->btgt); ++ au_hn_inode_lock_nested(src_or_dst(hinode), AuLsc_I_CHILD); ++ diropq = au_diropq_create(d, a->btgt); ++ au_hn_inode_unlock(src_or_dst(hinode)); ++ if (IS_ERR(diropq)) ++ err = PTR_ERR(diropq); ++ else ++ dput(diropq); ++ ++#undef src_or_dst_ ++ return err; ++} ++ ++static int au_ren_diropq(struct au_ren_args *a) ++{ ++ int err; ++ unsigned char always; ++ struct dentry *d; ++ ++ err = 0; ++ d = a->dst_dentry; /* already renamed on the branch */ ++ always = !!au_opt_test(au_mntflags(d->d_sb), ALWAYS_DIROPQ); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC) ++ && !au_ftest_ren(a->auren_flags, DIRREN) ++ && a->btgt != au_dbdiropq(a->src_dentry) ++ && (a->dst_wh_dentry ++ || a->btgt <= au_dbdiropq(d) ++ /* hide the lower to keep xino */ ++ /* the lowers may not be a dir, but we hide them anyway */ ++ || a->btgt < au_dbbot(d) ++ || always)) { ++ AuDbg("here\n"); ++ err = au_ren_do_diropq(a, AuSRC); ++ if (unlikely(err)) ++ goto out; ++ au_fset_ren(a->auren_flags, DIROPQ_SRC); ++ } ++ if (!a->exchange) ++ goto out; /* success */ ++ ++ d = a->src_dentry; /* already renamed on the branch */ ++ if (au_ftest_ren(a->auren_flags, ISDIR_DST) ++ && a->btgt != au_dbdiropq(a->dst_dentry) ++ && (a->btgt < au_dbdiropq(d) ++ || a->btgt < au_dbbot(d) ++ || always)) { ++ AuDbgDentry(a->src_dentry); ++ AuDbgDentry(a->dst_dentry); ++ err = au_ren_do_diropq(a, AuDST); ++ if (unlikely(err)) ++ goto out_rev_src; ++ au_fset_ren(a->auren_flags, DIROPQ_DST); ++ } ++ goto out; /* success */ ++ ++out_rev_src: ++ AuDbg("err %d, reverting src\n", err); ++ au_ren_rev_diropq(err, a); ++out: ++ return err; ++} ++ ++static int do_rename(struct au_ren_args *a) ++{ ++ int err; ++ struct dentry *d, *h_d; ++ ++ if (!a->exchange) { ++ /* prepare workqueue args for asynchronous rmdir */ ++ h_d = a->dst_h_dentry; ++ if (au_ftest_ren(a->auren_flags, ISDIR_DST) ++ /* && !au_ftest_ren(a->auren_flags, DIRREN) */ ++ && d_is_positive(h_d)) { ++ err = -ENOMEM; ++ a->thargs = au_whtmp_rmdir_alloc(a->src_dentry->d_sb, ++ GFP_NOFS); ++ if (unlikely(!a->thargs)) ++ goto out; ++ a->h_dst = dget(h_d); ++ } ++ ++ /* create whiteout for src_dentry */ ++ if (au_ftest_ren(a->auren_flags, WHSRC)) { ++ a->src_bwh = au_dbwh(a->src_dentry); ++ AuDebugOn(a->src_bwh >= 0); ++ a->src_wh_dentry = au_wh_create(a->src_dentry, a->btgt, ++ a->src_h_parent); ++ err = PTR_ERR(a->src_wh_dentry); ++ if (IS_ERR(a->src_wh_dentry)) ++ goto out_thargs; ++ } ++ ++ /* lookup whiteout for dentry */ ++ if (au_ftest_ren(a->auren_flags, WHDST)) { ++ h_d = au_wh_lkup(a->dst_h_parent, ++ &a->dst_dentry->d_name, a->br); ++ err = PTR_ERR(h_d); ++ if (IS_ERR(h_d)) ++ goto out_whsrc; ++ if (d_is_negative(h_d)) ++ dput(h_d); ++ else ++ a->dst_wh_dentry = h_d; ++ } ++ ++ /* rename dentry to tmpwh */ ++ if (a->thargs) { ++ err = au_whtmp_ren(a->dst_h_dentry, a->br); ++ if (unlikely(err)) ++ goto out_whdst; ++ ++ d = a->dst_dentry; ++ au_set_h_dptr(d, a->btgt, NULL); ++ err = au_lkup_neg(d, a->btgt, /*wh*/0); ++ if (unlikely(err)) ++ goto out_whtmp; ++ a->dst_h_dentry = au_h_dptr(d, a->btgt); ++ } ++ } ++ ++ BUG_ON(d_is_positive(a->dst_h_dentry) && a->src_btop != a->btgt); ++#if 0 ++ BUG_ON(!au_ftest_ren(a->auren_flags, DIRREN) ++ && d_is_positive(a->dst_h_dentry) ++ && a->src_btop != a->btgt); ++#endif ++ ++ /* rename by vfs_rename or cpup */ ++ err = au_ren_or_cpup(a); ++ if (unlikely(err)) ++ /* leave the copied-up one */ ++ goto out_whtmp; ++ ++ /* make dir opaque */ ++ err = au_ren_diropq(a); ++ if (unlikely(err)) ++ goto out_rename; ++ ++ /* update target timestamps */ ++ if (a->exchange) { ++ AuDebugOn(au_dbtop(a->dst_dentry) != a->btgt); ++ a->h_path.dentry = au_h_dptr(a->dst_dentry, a->btgt); ++ vfsub_update_h_iattr(&a->h_path, /*did*/NULL); /*ignore*/ ++ a->dst_inode->i_ctime = d_inode(a->h_path.dentry)->i_ctime; ++ } ++ AuDebugOn(au_dbtop(a->src_dentry) != a->btgt); ++ a->h_path.dentry = au_h_dptr(a->src_dentry, a->btgt); ++ vfsub_update_h_iattr(&a->h_path, /*did*/NULL); /*ignore*/ ++ a->src_inode->i_ctime = d_inode(a->h_path.dentry)->i_ctime; ++ ++ if (!a->exchange) { ++ /* remove whiteout for dentry */ ++ if (a->dst_wh_dentry) { ++ a->h_path.dentry = a->dst_wh_dentry; ++ err = au_wh_unlink_dentry(a->dst_h_dir, &a->h_path, ++ a->dst_dentry); ++ if (unlikely(err)) ++ goto out_diropq; ++ } ++ ++ /* remove whtmp */ ++ if (a->thargs) ++ au_ren_del_whtmp(a); /* ignore this error */ ++ ++ au_fhsm_wrote(a->src_dentry->d_sb, a->btgt, /*force*/0); ++ } ++ err = 0; ++ goto out_success; ++ ++out_diropq: ++ au_ren_rev_diropq(err, a); ++out_rename: ++ au_ren_rev_rename(err, a); ++ dput(a->h_dst); ++out_whtmp: ++ if (a->thargs) ++ au_ren_rev_whtmp(err, a); ++out_whdst: ++ dput(a->dst_wh_dentry); ++ a->dst_wh_dentry = NULL; ++out_whsrc: ++ if (a->src_wh_dentry) ++ au_ren_rev_whsrc(err, a); ++out_success: ++ dput(a->src_wh_dentry); ++ dput(a->dst_wh_dentry); ++out_thargs: ++ if (a->thargs) { ++ dput(a->h_dst); ++ au_whtmp_rmdir_free(a->thargs); ++ a->thargs = NULL; ++ } ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * test if @dentry dir can be rename destination or not. ++ * success means, it is a logically empty dir. ++ */ ++static int may_rename_dstdir(struct dentry *dentry, struct au_nhash *whlist) ++{ ++ return au_test_empty(dentry, whlist); ++} ++ ++/* ++ * test if @a->src_dentry dir can be rename source or not. ++ * if it can, return 0. ++ * success means, ++ * - it is a logically empty dir. ++ * - or, it exists on writable branch and has no children including whiteouts ++ * on the lower branch unless DIRREN is on. ++ */ ++static int may_rename_srcdir(struct au_ren_args *a) ++{ ++ int err; ++ unsigned int rdhash; ++ aufs_bindex_t btop, btgt; ++ struct dentry *dentry; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++ dentry = a->src_dentry; ++ sb = dentry->d_sb; ++ sbinfo = au_sbi(sb); ++ if (au_opt_test(sbinfo->si_mntflags, DIRREN)) ++ au_fset_ren(a->auren_flags, DIRREN); ++ ++ btgt = a->btgt; ++ btop = au_dbtop(dentry); ++ if (btop != btgt) { ++ struct au_nhash whlist; ++ ++ SiMustAnyLock(sb); ++ rdhash = sbinfo->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, ++ dentry)); ++ err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_test_empty(dentry, &whlist); ++ au_nhash_wh_free(&whlist); ++ goto out; ++ } ++ ++ if (btop == au_dbtaildir(dentry)) ++ return 0; /* success */ ++ ++ err = au_test_empty_lower(dentry); ++ ++out: ++ if (err == -ENOTEMPTY) { ++ if (au_ftest_ren(a->auren_flags, DIRREN)) { ++ err = 0; ++ } else { ++ AuWarn1("renaming dir who has child(ren) on multiple " ++ "branches, is not supported\n"); ++ err = -EXDEV; ++ } ++ } ++ return err; ++} ++ ++/* side effect: sets whlist and h_dentry */ ++static int au_ren_may_dir(struct au_ren_args *a) ++{ ++ int err; ++ unsigned int rdhash; ++ struct dentry *d; ++ ++ d = a->dst_dentry; ++ SiMustAnyLock(d->d_sb); ++ ++ err = 0; ++ if (au_ftest_ren(a->auren_flags, ISDIR_DST) && a->dst_inode) { ++ rdhash = au_sbi(d->d_sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, d)); ++ err = au_nhash_alloc(&a->whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ ++ if (!a->exchange) { ++ au_set_dbtop(d, a->dst_btop); ++ err = may_rename_dstdir(d, &a->whlist); ++ au_set_dbtop(d, a->btgt); ++ } else ++ err = may_rename_srcdir(a); ++ } ++ a->dst_h_dentry = au_h_dptr(d, au_dbtop(d)); ++ if (unlikely(err)) ++ goto out; ++ ++ d = a->src_dentry; ++ a->src_h_dentry = au_h_dptr(d, au_dbtop(d)); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC)) { ++ err = may_rename_srcdir(a); ++ if (unlikely(err)) { ++ au_nhash_wh_free(&a->whlist); ++ a->whlist.nh_num = 0; ++ } ++ } ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * simple tests for rename. ++ * following the checks in vfs, plus the parent-child relationship. ++ */ ++static int au_may_ren(struct au_ren_args *a) ++{ ++ int err, isdir; ++ struct inode *h_inode; ++ ++ if (a->src_btop == a->btgt) { ++ err = au_may_del(a->src_dentry, a->btgt, a->src_h_parent, ++ au_ftest_ren(a->auren_flags, ISDIR_SRC)); ++ if (unlikely(err)) ++ goto out; ++ err = -EINVAL; ++ if (unlikely(a->src_h_dentry == a->h_trap)) ++ goto out; ++ } ++ ++ err = 0; ++ if (a->dst_btop != a->btgt) ++ goto out; ++ ++ err = -ENOTEMPTY; ++ if (unlikely(a->dst_h_dentry == a->h_trap)) ++ goto out; ++ ++ err = -EIO; ++ isdir = !!au_ftest_ren(a->auren_flags, ISDIR_DST); ++ if (d_really_is_negative(a->dst_dentry)) { ++ if (d_is_negative(a->dst_h_dentry)) ++ err = au_may_add(a->dst_dentry, a->btgt, ++ a->dst_h_parent, isdir); ++ } else { ++ if (unlikely(d_is_negative(a->dst_h_dentry))) ++ goto out; ++ h_inode = d_inode(a->dst_h_dentry); ++ if (h_inode->i_nlink) ++ err = au_may_del(a->dst_dentry, a->btgt, ++ a->dst_h_parent, isdir); ++ } ++ ++out: ++ if (unlikely(err == -ENOENT || err == -EEXIST)) ++ err = -EIO; ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * locking order ++ * (VFS) ++ * - src_dir and dir by lock_rename() ++ * - inode if exists ++ * (aufs) ++ * - lock all ++ * + src_dentry and dentry by aufs_read_and_write_lock2() which calls, ++ * + si_read_lock ++ * + di_write_lock2_child() ++ * + di_write_lock_child() ++ * + ii_write_lock_child() ++ * + di_write_lock_child2() ++ * + ii_write_lock_child2() ++ * + src_parent and parent ++ * + di_write_lock_parent() ++ * + ii_write_lock_parent() ++ * + di_write_lock_parent2() ++ * + ii_write_lock_parent2() ++ * + lower src_dir and dir by vfsub_lock_rename() ++ * + verify the every relationships between child and parent. if any ++ * of them failed, unlock all and return -EBUSY. ++ */ ++static void au_ren_unlock(struct au_ren_args *a) ++{ ++ vfsub_unlock_rename(a->src_h_parent, a->src_hdir, ++ a->dst_h_parent, a->dst_hdir); ++ if (au_ftest_ren(a->auren_flags, DIRREN) ++ && a->h_root) ++ au_hn_inode_unlock(a->h_root); ++ if (au_ftest_ren(a->auren_flags, MNT_WRITE)) ++ vfsub_mnt_drop_write(au_br_mnt(a->br)); ++} ++ ++static int au_ren_lock(struct au_ren_args *a) ++{ ++ int err; ++ unsigned int udba; ++ ++ err = 0; ++ a->src_h_parent = au_h_dptr(a->src_parent, a->btgt); ++ a->src_hdir = au_hi(a->src_dir, a->btgt); ++ a->dst_h_parent = au_h_dptr(a->dst_parent, a->btgt); ++ a->dst_hdir = au_hi(a->dst_dir, a->btgt); ++ ++ err = vfsub_mnt_want_write(au_br_mnt(a->br)); ++ if (unlikely(err)) ++ goto out; ++ au_fset_ren(a->auren_flags, MNT_WRITE); ++ if (au_ftest_ren(a->auren_flags, DIRREN)) { ++ struct dentry *root; ++ struct inode *dir; ++ ++ /* ++ * sbinfo is already locked, so this ii_read_lock is ++ * unnecessary. but our debugging feature checks it. ++ */ ++ root = a->src_inode->i_sb->s_root; ++ if (root != a->src_parent && root != a->dst_parent) { ++ dir = d_inode(root); ++ ii_read_lock_parent3(dir); ++ a->h_root = au_hi(dir, a->btgt); ++ ii_read_unlock(dir); ++ au_hn_inode_lock_nested(a->h_root, AuLsc_I_PARENT3); ++ } ++ } ++ a->h_trap = vfsub_lock_rename(a->src_h_parent, a->src_hdir, ++ a->dst_h_parent, a->dst_hdir); ++ udba = au_opt_udba(a->src_dentry->d_sb); ++ if (unlikely(a->src_hdir->hi_inode != d_inode(a->src_h_parent) ++ || a->dst_hdir->hi_inode != d_inode(a->dst_h_parent))) ++ err = au_busy_or_stale(); ++ if (!err && au_dbtop(a->src_dentry) == a->btgt) ++ err = au_h_verify(a->src_h_dentry, udba, ++ d_inode(a->src_h_parent), a->src_h_parent, ++ a->br); ++ if (!err && au_dbtop(a->dst_dentry) == a->btgt) ++ err = au_h_verify(a->dst_h_dentry, udba, ++ d_inode(a->dst_h_parent), a->dst_h_parent, ++ a->br); ++ if (!err) ++ goto out; /* success */ ++ ++ err = au_busy_or_stale(); ++ au_ren_unlock(a); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_ren_refresh_dir(struct au_ren_args *a) ++{ ++ struct inode *dir; ++ ++ dir = a->dst_dir; ++ inode_inc_iversion(dir); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC)) { ++ /* is this updating defined in POSIX? */ ++ au_cpup_attr_timesizes(a->src_inode); ++ au_cpup_attr_nlink(dir, /*force*/1); ++ } ++ au_dir_ts(dir, a->btgt); ++ ++ if (a->exchange) { ++ dir = a->src_dir; ++ inode_inc_iversion(dir); ++ if (au_ftest_ren(a->auren_flags, ISDIR_DST)) { ++ /* is this updating defined in POSIX? */ ++ au_cpup_attr_timesizes(a->dst_inode); ++ au_cpup_attr_nlink(dir, /*force*/1); ++ } ++ au_dir_ts(dir, a->btgt); ++ } ++ ++ if (au_ftest_ren(a->auren_flags, ISSAMEDIR)) ++ return; ++ ++ dir = a->src_dir; ++ inode_inc_iversion(dir); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC)) ++ au_cpup_attr_nlink(dir, /*force*/1); ++ au_dir_ts(dir, a->btgt); ++} ++ ++static void au_ren_refresh(struct au_ren_args *a) ++{ ++ aufs_bindex_t bbot, bindex; ++ struct dentry *d, *h_d; ++ struct inode *i, *h_i; ++ struct super_block *sb; ++ ++ d = a->dst_dentry; ++ d_drop(d); ++ if (a->h_dst) ++ /* already dget-ed by au_ren_or_cpup() */ ++ au_set_h_dptr(d, a->btgt, a->h_dst); ++ ++ i = a->dst_inode; ++ if (i) { ++ if (!a->exchange) { ++ if (!au_ftest_ren(a->auren_flags, ISDIR_DST)) ++ vfsub_drop_nlink(i); ++ else { ++ vfsub_dead_dir(i); ++ au_cpup_attr_timesizes(i); ++ } ++ au_update_dbrange(d, /*do_put_zero*/1); ++ } else ++ au_cpup_attr_nlink(i, /*force*/1); ++ } else { ++ bbot = a->btgt; ++ for (bindex = au_dbtop(d); bindex < bbot; bindex++) ++ au_set_h_dptr(d, bindex, NULL); ++ bbot = au_dbbot(d); ++ for (bindex = a->btgt + 1; bindex <= bbot; bindex++) ++ au_set_h_dptr(d, bindex, NULL); ++ au_update_dbrange(d, /*do_put_zero*/0); ++ } ++ ++ if (a->exchange ++ || au_ftest_ren(a->auren_flags, DIRREN)) { ++ d_drop(a->src_dentry); ++ if (au_ftest_ren(a->auren_flags, DIRREN)) ++ au_set_dbwh(a->src_dentry, -1); ++ return; ++ } ++ ++ d = a->src_dentry; ++ au_set_dbwh(d, -1); ++ bbot = au_dbbot(d); ++ for (bindex = a->btgt + 1; bindex <= bbot; bindex++) { ++ h_d = au_h_dptr(d, bindex); ++ if (h_d) ++ au_set_h_dptr(d, bindex, NULL); ++ } ++ au_set_dbbot(d, a->btgt); ++ ++ sb = d->d_sb; ++ i = a->src_inode; ++ if (au_opt_test(au_mntflags(sb), PLINK) && au_plink_test(i)) ++ return; /* success */ ++ ++ bbot = au_ibbot(i); ++ for (bindex = a->btgt + 1; bindex <= bbot; bindex++) { ++ h_i = au_h_iptr(i, bindex); ++ if (h_i) { ++ au_xino_write(sb, bindex, h_i->i_ino, /*ino*/0); ++ /* ignore this error */ ++ au_set_h_iptr(i, bindex, NULL, 0); ++ } ++ } ++ au_set_ibbot(i, a->btgt); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* mainly for link(2) and rename(2) */ ++int au_wbr(struct dentry *dentry, aufs_bindex_t btgt) ++{ ++ aufs_bindex_t bdiropq, bwh; ++ struct dentry *parent; ++ struct au_branch *br; ++ ++ parent = dentry->d_parent; ++ IMustLock(d_inode(parent)); /* dir is locked */ ++ ++ bdiropq = au_dbdiropq(parent); ++ bwh = au_dbwh(dentry); ++ br = au_sbr(dentry->d_sb, btgt); ++ if (au_br_rdonly(br) ++ || (0 <= bdiropq && bdiropq < btgt) ++ || (0 <= bwh && bwh < btgt)) ++ btgt = -1; ++ ++ AuDbg("btgt %d\n", btgt); ++ return btgt; ++} ++ ++/* sets src_btop, dst_btop and btgt */ ++static int au_ren_wbr(struct au_ren_args *a) ++{ ++ int err; ++ struct au_wr_dir_args wr_dir_args = { ++ /* .force_btgt = -1, */ ++ .flags = AuWrDir_ADD_ENTRY ++ }; ++ ++ a->src_btop = au_dbtop(a->src_dentry); ++ a->dst_btop = au_dbtop(a->dst_dentry); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC) ++ || au_ftest_ren(a->auren_flags, ISDIR_DST)) ++ au_fset_wrdir(wr_dir_args.flags, ISDIR); ++ wr_dir_args.force_btgt = a->src_btop; ++ if (a->dst_inode && a->dst_btop < a->src_btop) ++ wr_dir_args.force_btgt = a->dst_btop; ++ wr_dir_args.force_btgt = au_wbr(a->dst_dentry, wr_dir_args.force_btgt); ++ err = au_wr_dir(a->dst_dentry, a->src_dentry, &wr_dir_args); ++ a->btgt = err; ++ if (a->exchange) ++ au_update_dbtop(a->dst_dentry); ++ ++ return err; ++} ++ ++static void au_ren_dt(struct au_ren_args *a) ++{ ++ a->h_path.dentry = a->src_h_parent; ++ au_dtime_store(a->src_dt + AuPARENT, a->src_parent, &a->h_path); ++ if (!au_ftest_ren(a->auren_flags, ISSAMEDIR)) { ++ a->h_path.dentry = a->dst_h_parent; ++ au_dtime_store(a->dst_dt + AuPARENT, a->dst_parent, &a->h_path); ++ } ++ ++ au_fclr_ren(a->auren_flags, DT_DSTDIR); ++ if (!au_ftest_ren(a->auren_flags, ISDIR_SRC) ++ && !a->exchange) ++ return; ++ ++ a->h_path.dentry = a->src_h_dentry; ++ au_dtime_store(a->src_dt + AuCHILD, a->src_dentry, &a->h_path); ++ if (d_is_positive(a->dst_h_dentry)) { ++ au_fset_ren(a->auren_flags, DT_DSTDIR); ++ a->h_path.dentry = a->dst_h_dentry; ++ au_dtime_store(a->dst_dt + AuCHILD, a->dst_dentry, &a->h_path); ++ } ++} ++ ++static void au_ren_rev_dt(int err, struct au_ren_args *a) ++{ ++ struct dentry *h_d; ++ struct inode *h_inode; ++ ++ au_dtime_revert(a->src_dt + AuPARENT); ++ if (!au_ftest_ren(a->auren_flags, ISSAMEDIR)) ++ au_dtime_revert(a->dst_dt + AuPARENT); ++ ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC) && err != -EIO) { ++ h_d = a->src_dt[AuCHILD].dt_h_path.dentry; ++ h_inode = d_inode(h_d); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ au_dtime_revert(a->src_dt + AuCHILD); ++ inode_unlock(h_inode); ++ ++ if (au_ftest_ren(a->auren_flags, DT_DSTDIR)) { ++ h_d = a->dst_dt[AuCHILD].dt_h_path.dentry; ++ h_inode = d_inode(h_d); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ au_dtime_revert(a->dst_dt + AuCHILD); ++ inode_unlock(h_inode); ++ } ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int aufs_rename(struct inode *_src_dir, struct dentry *_src_dentry, ++ struct inode *_dst_dir, struct dentry *_dst_dentry, ++ unsigned int _flags) ++{ ++ int err, lock_flags; ++ void *rev; ++ /* reduce stack space */ ++ struct au_ren_args *a; ++ struct au_pin pin; ++ ++ AuDbg("%pd, %pd, 0x%x\n", _src_dentry, _dst_dentry, _flags); ++ IMustLock(_src_dir); ++ IMustLock(_dst_dir); ++ ++ err = -EINVAL; ++ if (unlikely(_flags & RENAME_WHITEOUT)) ++ goto out; ++ ++ err = -ENOMEM; ++ BUILD_BUG_ON(sizeof(*a) > PAGE_SIZE); ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ a->flags = _flags; ++ BUILD_BUG_ON(sizeof(a->exchange) == sizeof(u8) ++ && RENAME_EXCHANGE > U8_MAX); ++ a->exchange = _flags & RENAME_EXCHANGE; ++ a->src_dir = _src_dir; ++ a->src_dentry = _src_dentry; ++ a->src_inode = NULL; ++ if (d_really_is_positive(a->src_dentry)) ++ a->src_inode = d_inode(a->src_dentry); ++ a->src_parent = a->src_dentry->d_parent; /* dir inode is locked */ ++ a->dst_dir = _dst_dir; ++ a->dst_dentry = _dst_dentry; ++ a->dst_inode = NULL; ++ if (d_really_is_positive(a->dst_dentry)) ++ a->dst_inode = d_inode(a->dst_dentry); ++ a->dst_parent = a->dst_dentry->d_parent; /* dir inode is locked */ ++ if (a->dst_inode) { ++ /* ++ * if EXCHANGE && src is non-dir && dst is dir, ++ * dst is not locked. ++ */ ++ /* IMustLock(a->dst_inode); */ ++ au_igrab(a->dst_inode); ++ } ++ ++ err = -ENOTDIR; ++ lock_flags = AuLock_FLUSH | AuLock_NOPLM | AuLock_GEN; ++ if (d_is_dir(a->src_dentry)) { ++ au_fset_ren(a->auren_flags, ISDIR_SRC); ++ if (unlikely(!a->exchange ++ && d_really_is_positive(a->dst_dentry) ++ && !d_is_dir(a->dst_dentry))) ++ goto out_free; ++ lock_flags |= AuLock_DIRS; ++ } ++ if (a->dst_inode && d_is_dir(a->dst_dentry)) { ++ au_fset_ren(a->auren_flags, ISDIR_DST); ++ if (unlikely(!a->exchange ++ && d_really_is_positive(a->src_dentry) ++ && !d_is_dir(a->src_dentry))) ++ goto out_free; ++ lock_flags |= AuLock_DIRS; ++ } ++ err = aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry, ++ lock_flags); ++ if (unlikely(err)) ++ goto out_free; ++ ++ err = au_d_hashed_positive(a->src_dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ err = -ENOENT; ++ if (a->dst_inode) { ++ /* ++ * If it is a dir, VFS unhash it before this ++ * function. It means we cannot rely upon d_unhashed(). ++ */ ++ if (unlikely(!a->dst_inode->i_nlink)) ++ goto out_unlock; ++ if (!au_ftest_ren(a->auren_flags, ISDIR_DST)) { ++ err = au_d_hashed_positive(a->dst_dentry); ++ if (unlikely(err && !a->exchange)) ++ goto out_unlock; ++ } else if (unlikely(IS_DEADDIR(a->dst_inode))) ++ goto out_unlock; ++ } else if (unlikely(d_unhashed(a->dst_dentry))) ++ goto out_unlock; ++ ++ /* ++ * is it possible? ++ * yes, it happened (in linux-3.3-rcN) but I don't know why. ++ * there may exist a problem somewhere else. ++ */ ++ err = -EINVAL; ++ if (unlikely(d_inode(a->dst_parent) == d_inode(a->src_dentry))) ++ goto out_unlock; ++ ++ au_fset_ren(a->auren_flags, ISSAMEDIR); /* temporary */ ++ di_write_lock_parent(a->dst_parent); ++ ++ /* which branch we process */ ++ err = au_ren_wbr(a); ++ if (unlikely(err < 0)) ++ goto out_parent; ++ a->br = au_sbr(a->dst_dentry->d_sb, a->btgt); ++ a->h_path.mnt = au_br_mnt(a->br); ++ ++ /* are they available to be renamed */ ++ err = au_ren_may_dir(a); ++ if (unlikely(err)) ++ goto out_children; ++ ++ /* prepare the writable parent dir on the same branch */ ++ if (a->dst_btop == a->btgt) { ++ au_fset_ren(a->auren_flags, WHDST); ++ } else { ++ err = au_cpup_dirs(a->dst_dentry, a->btgt); ++ if (unlikely(err)) ++ goto out_children; ++ } ++ ++ err = 0; ++ if (!a->exchange) { ++ if (a->src_dir != a->dst_dir) { ++ /* ++ * this temporary unlock is safe, ++ * because both dir->i_mutex are locked. ++ */ ++ di_write_unlock(a->dst_parent); ++ di_write_lock_parent(a->src_parent); ++ err = au_wr_dir_need_wh(a->src_dentry, ++ au_ftest_ren(a->auren_flags, ++ ISDIR_SRC), ++ &a->btgt); ++ di_write_unlock(a->src_parent); ++ di_write_lock2_parent(a->src_parent, a->dst_parent, ++ /*isdir*/1); ++ au_fclr_ren(a->auren_flags, ISSAMEDIR); ++ } else ++ err = au_wr_dir_need_wh(a->src_dentry, ++ au_ftest_ren(a->auren_flags, ++ ISDIR_SRC), ++ &a->btgt); ++ } ++ if (unlikely(err < 0)) ++ goto out_children; ++ if (err) ++ au_fset_ren(a->auren_flags, WHSRC); ++ ++ /* cpup src */ ++ if (a->src_btop != a->btgt) { ++ err = au_pin(&pin, a->src_dentry, a->btgt, ++ au_opt_udba(a->src_dentry->d_sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (!err) { ++ struct au_cp_generic cpg = { ++ .dentry = a->src_dentry, ++ .bdst = a->btgt, ++ .bsrc = a->src_btop, ++ .len = -1, ++ .pin = &pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ AuDebugOn(au_dbtop(a->src_dentry) != a->src_btop); ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&pin); ++ } ++ if (unlikely(err)) ++ goto out_children; ++ a->src_btop = a->btgt; ++ a->src_h_dentry = au_h_dptr(a->src_dentry, a->btgt); ++ if (!a->exchange) ++ au_fset_ren(a->auren_flags, WHSRC); ++ } ++ ++ /* cpup dst */ ++ if (a->exchange && a->dst_inode ++ && a->dst_btop != a->btgt) { ++ err = au_pin(&pin, a->dst_dentry, a->btgt, ++ au_opt_udba(a->dst_dentry->d_sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (!err) { ++ struct au_cp_generic cpg = { ++ .dentry = a->dst_dentry, ++ .bdst = a->btgt, ++ .bsrc = a->dst_btop, ++ .len = -1, ++ .pin = &pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&pin); ++ } ++ if (unlikely(err)) ++ goto out_children; ++ a->dst_btop = a->btgt; ++ a->dst_h_dentry = au_h_dptr(a->dst_dentry, a->btgt); ++ } ++ ++ /* lock them all */ ++ err = au_ren_lock(a); ++ if (unlikely(err)) ++ /* leave the copied-up one */ ++ goto out_children; ++ ++ if (!a->exchange) { ++ if (!au_opt_test(au_mntflags(a->dst_dir->i_sb), UDBA_NONE)) ++ err = au_may_ren(a); ++ else if (unlikely(a->dst_dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ err = -ENAMETOOLONG; ++ if (unlikely(err)) ++ goto out_hdir; ++ } ++ ++ /* store timestamps to be revertible */ ++ au_ren_dt(a); ++ ++ /* store dirren info */ ++ if (au_ftest_ren(a->auren_flags, DIRREN)) { ++ err = au_dr_rename(a->src_dentry, a->btgt, ++ &a->dst_dentry->d_name, &rev); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out_dt; ++ } ++ ++ /* here we go */ ++ err = do_rename(a); ++ if (unlikely(err)) ++ goto out_dirren; ++ ++ if (au_ftest_ren(a->auren_flags, DIRREN)) ++ au_dr_rename_fin(a->src_dentry, a->btgt, rev); ++ ++ /* update dir attributes */ ++ au_ren_refresh_dir(a); ++ ++ /* dput/iput all lower dentries */ ++ au_ren_refresh(a); ++ ++ goto out_hdir; /* success */ ++ ++out_dirren: ++ if (au_ftest_ren(a->auren_flags, DIRREN)) ++ au_dr_rename_rev(a->src_dentry, a->btgt, rev); ++out_dt: ++ au_ren_rev_dt(err, a); ++out_hdir: ++ au_ren_unlock(a); ++out_children: ++ au_nhash_wh_free(&a->whlist); ++ if (err && a->dst_inode && a->dst_btop != a->btgt) { ++ AuDbg("btop %d, btgt %d\n", a->dst_btop, a->btgt); ++ au_set_h_dptr(a->dst_dentry, a->btgt, NULL); ++ au_set_dbtop(a->dst_dentry, a->dst_btop); ++ } ++out_parent: ++ if (!err) { ++ if (d_unhashed(a->src_dentry)) ++ au_fset_ren(a->auren_flags, DROPPED_SRC); ++ if (d_unhashed(a->dst_dentry)) ++ au_fset_ren(a->auren_flags, DROPPED_DST); ++ if (!a->exchange) ++ d_move(a->src_dentry, a->dst_dentry); ++ else { ++ d_exchange(a->src_dentry, a->dst_dentry); ++ if (au_ftest_ren(a->auren_flags, DROPPED_DST)) ++ d_drop(a->dst_dentry); ++ } ++ if (au_ftest_ren(a->auren_flags, DROPPED_SRC)) ++ d_drop(a->src_dentry); ++ } else { ++ au_update_dbtop(a->dst_dentry); ++ if (!a->dst_inode) ++ d_drop(a->dst_dentry); ++ } ++ if (au_ftest_ren(a->auren_flags, ISSAMEDIR)) ++ di_write_unlock(a->dst_parent); ++ else ++ di_write_unlock2(a->src_parent, a->dst_parent); ++out_unlock: ++ aufs_read_and_write_unlock2(a->dst_dentry, a->src_dentry); ++out_free: ++ iput(a->dst_inode); ++ if (a->thargs) ++ au_whtmp_rmdir_free(a->thargs); ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff -Nurp linux-5.4/fs/aufs/Kconfig linux-5.4-aufs/fs/aufs/Kconfig +--- linux-5.4/fs/aufs/Kconfig 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/Kconfig 2019-11-28 01:25:59.062925618 +0200 +@@ -0,0 +1,199 @@ ++# SPDX-License-Identifier: GPL-2.0 ++config AUFS_FS ++ bool "Aufs (Advanced multi layered unification filesystem) support" ++ help ++ Aufs is a stackable unification filesystem such as Unionfs, ++ which unifies several directories and provides a merged single ++ directory. ++ In the early days, aufs was entirely re-designed and ++ re-implemented Unionfs Version 1.x series. Introducing many ++ original ideas, approaches and improvements, it becomes totally ++ different from Unionfs while keeping the basic features. ++ ++if AUFS_FS ++choice ++ prompt "Maximum number of branches" ++ default AUFS_BRANCH_MAX_127 ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++config AUFS_BRANCH_MAX_127 ++ bool "127" ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++config AUFS_BRANCH_MAX_511 ++ bool "511" ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++config AUFS_BRANCH_MAX_1023 ++ bool "1023" ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++config AUFS_BRANCH_MAX_32767 ++ bool "32767" ++ help ++ Specifies the maximum number of branches (or member directories) ++ in a single aufs. The larger value consumes more system ++ resources and has a minor impact to performance. ++endchoice ++ ++config AUFS_SBILIST ++ bool ++ depends on AUFS_MAGIC_SYSRQ || PROC_FS ++ default y ++ help ++ Automatic configuration for internal use. ++ When aufs supports Magic SysRq or /proc, enabled automatically. ++ ++config AUFS_HNOTIFY ++ bool "Detect direct branch access (bypassing aufs)" ++ help ++ If you want to modify files on branches directly, eg. bypassing aufs, ++ and want aufs to detect the changes of them fully, then enable this ++ option and use 'udba=notify' mount option. ++ Currently there is only one available configuration, "fsnotify". ++ It will have a negative impact to the performance. ++ See detail in aufs.5. ++ ++choice ++ prompt "method" if AUFS_HNOTIFY ++ default AUFS_HFSNOTIFY ++config AUFS_HFSNOTIFY ++ bool "fsnotify" ++ select FSNOTIFY ++endchoice ++ ++config AUFS_EXPORT ++ bool "NFS-exportable aufs" ++ depends on EXPORTFS = y ++ help ++ If you want to export your mounted aufs via NFS, then enable this ++ option. There are several requirements for this configuration. ++ See detail in aufs.5. ++ ++config AUFS_INO_T_64 ++ bool ++ depends on AUFS_EXPORT ++ depends on 64BIT && !(ALPHA || S390) ++ default y ++ help ++ Automatic configuration for internal use. ++ /* typedef unsigned long/int __kernel_ino_t */ ++ /* alpha and s390x are int */ ++ ++config AUFS_XATTR ++ bool "support for XATTR/EA (including Security Labels)" ++ help ++ If your branch fs supports XATTR/EA and you want to make them ++ available in aufs too, then enable this opsion and specify the ++ branch attributes for EA. ++ See detail in aufs.5. ++ ++config AUFS_FHSM ++ bool "File-based Hierarchical Storage Management" ++ help ++ Hierarchical Storage Management (or HSM) is a well-known feature ++ in the storage world. Aufs provides this feature as file-based. ++ with multiple branches. ++ These multiple branches are prioritized, ie. the topmost one ++ should be the fastest drive and be used heavily. ++ ++config AUFS_RDU ++ bool "Readdir in userspace" ++ help ++ Aufs has two methods to provide a merged view for a directory, ++ by a user-space library and by kernel-space natively. The latter ++ is always enabled but sometimes large and slow. ++ If you enable this option, install the library in aufs2-util ++ package, and set some environment variables for your readdir(3), ++ then the work will be handled in user-space which generally ++ shows better performance in most cases. ++ See detail in aufs.5. ++ ++config AUFS_DIRREN ++ bool "Workaround for rename(2)-ing a directory" ++ help ++ By default, aufs returns EXDEV error in renameing a dir who has ++ his child on the lower branch, since it is a bad idea to issue ++ rename(2) internally for every lower branch. But user may not ++ accept this behaviour. So here is a workaround to allow such ++ rename(2) and store some extra infromation on the writable ++ branch. Obviously this costs high (and I don't like it). ++ To use this feature, you need to enable this configuration AND ++ to specify the mount option `dirren.' ++ See details in aufs.5 and the design documents. ++ ++config AUFS_SHWH ++ bool "Show whiteouts" ++ help ++ If you want to make the whiteouts in aufs visible, then enable ++ this option and specify 'shwh' mount option. Although it may ++ sounds like philosophy or something, but in technically it ++ simply shows the name of whiteout with keeping its behaviour. ++ ++config AUFS_BR_RAMFS ++ bool "Ramfs (initramfs/rootfs) as an aufs branch" ++ help ++ If you want to use ramfs as an aufs branch fs, then enable this ++ option. Generally tmpfs is recommended. ++ Aufs prohibited them to be a branch fs by default, because ++ initramfs becomes unusable after switch_root or something ++ generally. If you sets initramfs as an aufs branch and boot your ++ system by switch_root, you will meet a problem easily since the ++ files in initramfs may be inaccessible. ++ Unless you are going to use ramfs as an aufs branch fs without ++ switch_root or something, leave it N. ++ ++config AUFS_BR_FUSE ++ bool "Fuse fs as an aufs branch" ++ depends on FUSE_FS ++ select AUFS_POLL ++ help ++ If you want to use fuse-based userspace filesystem as an aufs ++ branch fs, then enable this option. ++ It implements the internal poll(2) operation which is ++ implemented by fuse only (curretnly). ++ ++config AUFS_POLL ++ bool ++ help ++ Automatic configuration for internal use. ++ ++config AUFS_BR_HFSPLUS ++ bool "Hfsplus as an aufs branch" ++ depends on HFSPLUS_FS ++ default y ++ help ++ If you want to use hfsplus fs as an aufs branch fs, then enable ++ this option. This option introduces a small overhead at ++ copying-up a file on hfsplus. ++ ++config AUFS_BDEV_LOOP ++ bool ++ depends on BLK_DEV_LOOP ++ default y ++ help ++ Automatic configuration for internal use. ++ Convert =[ym] into =y. ++ ++config AUFS_DEBUG ++ bool "Debug aufs" ++ help ++ Enable this to compile aufs internal debug code. ++ It will have a negative impact to the performance. ++ ++config AUFS_MAGIC_SYSRQ ++ bool ++ depends on AUFS_DEBUG && MAGIC_SYSRQ ++ default y ++ help ++ Automatic configuration for internal use. ++ When aufs supports Magic SysRq, enabled automatically. ++endif +diff -Nurp linux-5.4/fs/aufs/lcnt.h linux-5.4-aufs/fs/aufs/lcnt.h +--- linux-5.4/fs/aufs/lcnt.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/lcnt.h 2019-11-28 01:25:59.066925618 +0200 +@@ -0,0 +1,173 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2018-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * simple long counter wrapper ++ */ ++ ++#ifndef __AUFS_LCNT_H__ ++#define __AUFS_LCNT_H__ ++ ++#ifdef __KERNEL__ ++ ++#include "debug.h" ++ ++#define AuLCntATOMIC 1 ++#define AuLCntPCPUCNT 2 ++/* ++ * why does percpu_refcount require extra synchronize_rcu()s in ++ * au_br_do_free() ++ */ ++#define AuLCntPCPUREF 3 ++ ++/* #define AuLCntChosen AuLCntATOMIC */ ++#define AuLCntChosen AuLCntPCPUCNT ++/* #define AuLCntChosen AuLCntPCPUREF */ ++ ++#if AuLCntChosen == AuLCntATOMIC ++#include ++ ++typedef atomic_long_t au_lcnt_t; ++ ++static inline int au_lcnt_init(au_lcnt_t *cnt, void *release __maybe_unused) ++{ ++ atomic_long_set(cnt, 0); ++ return 0; ++} ++ ++static inline void au_lcnt_wait_for_fin(au_lcnt_t *cnt __maybe_unused) ++{ ++ /* empty */ ++} ++ ++static inline void au_lcnt_fin(au_lcnt_t *cnt __maybe_unused, ++ int do_sync __maybe_unused) ++{ ++ /* empty */ ++} ++ ++static inline void au_lcnt_inc(au_lcnt_t *cnt) ++{ ++ atomic_long_inc(cnt); ++} ++ ++static inline void au_lcnt_dec(au_lcnt_t *cnt) ++{ ++ atomic_long_dec(cnt); ++} ++ ++static inline long au_lcnt_read(au_lcnt_t *cnt, int do_rev __maybe_unused) ++{ ++ return atomic_long_read(cnt); ++} ++#endif ++ ++#if AuLCntChosen == AuLCntPCPUCNT ++#include ++ ++typedef struct percpu_counter au_lcnt_t; ++ ++static inline int au_lcnt_init(au_lcnt_t *cnt, void *release __maybe_unused) ++{ ++ return percpu_counter_init(cnt, 0, GFP_NOFS); ++} ++ ++static inline void au_lcnt_wait_for_fin(au_lcnt_t *cnt __maybe_unused) ++{ ++ /* empty */ ++} ++ ++static inline void au_lcnt_fin(au_lcnt_t *cnt, int do_sync __maybe_unused) ++{ ++ percpu_counter_destroy(cnt); ++} ++ ++static inline void au_lcnt_inc(au_lcnt_t *cnt) ++{ ++ percpu_counter_inc(cnt); ++} ++ ++static inline void au_lcnt_dec(au_lcnt_t *cnt) ++{ ++ percpu_counter_dec(cnt); ++} ++ ++static inline long au_lcnt_read(au_lcnt_t *cnt, int do_rev __maybe_unused) ++{ ++ s64 n; ++ ++ n = percpu_counter_sum(cnt); ++ BUG_ON(n < 0); ++ if (LONG_MAX != LLONG_MAX ++ && n > LONG_MAX) ++ AuWarn1("%s\n", "wrap-around"); ++ ++ return n; ++} ++#endif ++ ++#if AuLCntChosen == AuLCntPCPUREF ++#include ++ ++typedef struct percpu_ref au_lcnt_t; ++ ++static inline int au_lcnt_init(au_lcnt_t *cnt, percpu_ref_func_t *release) ++{ ++ if (!release) ++ release = percpu_ref_exit; ++ return percpu_ref_init(cnt, release, /*percpu mode*/0, GFP_NOFS); ++} ++ ++static inline void au_lcnt_wait_for_fin(au_lcnt_t *cnt __maybe_unused) ++{ ++ synchronize_rcu(); ++} ++ ++static inline void au_lcnt_fin(au_lcnt_t *cnt, int do_sync) ++{ ++ percpu_ref_kill(cnt); ++ if (do_sync) ++ au_lcnt_wait_for_fin(cnt); ++} ++ ++static inline void au_lcnt_inc(au_lcnt_t *cnt) ++{ ++ percpu_ref_get(cnt); ++} ++ ++static inline void au_lcnt_dec(au_lcnt_t *cnt) ++{ ++ percpu_ref_put(cnt); ++} ++ ++/* ++ * avoid calling this func as possible. ++ */ ++static inline long au_lcnt_read(au_lcnt_t *cnt, int do_rev) ++{ ++ long l; ++ ++ percpu_ref_switch_to_atomic_sync(cnt); ++ l = atomic_long_read(&cnt->count); ++ if (do_rev) ++ percpu_ref_switch_to_percpu(cnt); ++ ++ /* percpu_ref is initialized by 1 instead of 0 */ ++ return l - 1; ++} ++#endif ++ ++#ifdef CONFIG_AUFS_DEBUG ++#define AuLCntZero(val) do { \ ++ long l = val; \ ++ if (l) \ ++ AuDbg("%s = %ld\n", #val, l); \ ++} while (0) ++#else ++#define AuLCntZero(val) do {} while (0) ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_LCNT_H__ */ +diff -Nurp linux-5.4/fs/aufs/loop.c linux-5.4-aufs/fs/aufs/loop.c +--- linux-5.4/fs/aufs/loop.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/loop.c 2019-11-28 01:25:59.066925618 +0200 +@@ -0,0 +1,135 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * support for loopback block device as a branch ++ */ ++ ++#include "aufs.h" ++ ++/* added into drivers/block/loop.c */ ++static struct file *(*backing_file_func)(struct super_block *sb); ++ ++/* ++ * test if two lower dentries have overlapping branches. ++ */ ++int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_adding) ++{ ++ struct super_block *h_sb; ++ struct file *backing_file; ++ ++ if (unlikely(!backing_file_func)) { ++ /* don't load "loop" module here */ ++ backing_file_func = symbol_get(loop_backing_file); ++ if (unlikely(!backing_file_func)) ++ /* "loop" module is not loaded */ ++ return 0; ++ } ++ ++ h_sb = h_adding->d_sb; ++ backing_file = backing_file_func(h_sb); ++ if (!backing_file) ++ return 0; ++ ++ h_adding = backing_file->f_path.dentry; ++ /* ++ * h_adding can be local NFS. ++ * in this case aufs cannot detect the loop. ++ */ ++ if (unlikely(h_adding->d_sb == sb)) ++ return 1; ++ return !!au_test_subdir(h_adding, sb->s_root); ++} ++ ++/* true if a kernel thread named 'loop[0-9].*' accesses a file */ ++int au_test_loopback_kthread(void) ++{ ++ int ret; ++ struct task_struct *tsk = current; ++ char c, comm[sizeof(tsk->comm)]; ++ ++ ret = 0; ++ if (tsk->flags & PF_KTHREAD) { ++ get_task_comm(comm, tsk); ++ c = comm[4]; ++ ret = ('0' <= c && c <= '9' ++ && !strncmp(comm, "loop", 4)); ++ } ++ ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define au_warn_loopback_step 16 ++static int au_warn_loopback_nelem = au_warn_loopback_step; ++static unsigned long *au_warn_loopback_array; ++ ++void au_warn_loopback(struct super_block *h_sb) ++{ ++ int i, new_nelem; ++ unsigned long *a, magic; ++ static DEFINE_SPINLOCK(spin); ++ ++ magic = h_sb->s_magic; ++ spin_lock(&spin); ++ a = au_warn_loopback_array; ++ for (i = 0; i < au_warn_loopback_nelem && *a; i++) ++ if (a[i] == magic) { ++ spin_unlock(&spin); ++ return; ++ } ++ ++ /* h_sb is new to us, print it */ ++ if (i < au_warn_loopback_nelem) { ++ a[i] = magic; ++ goto pr; ++ } ++ ++ /* expand the array */ ++ new_nelem = au_warn_loopback_nelem + au_warn_loopback_step; ++ a = au_kzrealloc(au_warn_loopback_array, ++ au_warn_loopback_nelem * sizeof(unsigned long), ++ new_nelem * sizeof(unsigned long), GFP_ATOMIC, ++ /*may_shrink*/0); ++ if (a) { ++ au_warn_loopback_nelem = new_nelem; ++ au_warn_loopback_array = a; ++ a[i] = magic; ++ goto pr; ++ } ++ ++ spin_unlock(&spin); ++ AuWarn1("realloc failed, ignored\n"); ++ return; ++ ++pr: ++ spin_unlock(&spin); ++ pr_warn("you may want to try another patch for loopback file " ++ "on %s(0x%lx) branch\n", au_sbtype(h_sb), magic); ++} ++ ++int au_loopback_init(void) ++{ ++ int err; ++ struct super_block *sb __maybe_unused; ++ ++ BUILD_BUG_ON(sizeof(sb->s_magic) != sizeof(*au_warn_loopback_array)); ++ ++ err = 0; ++ au_warn_loopback_array = kcalloc(au_warn_loopback_step, ++ sizeof(unsigned long), GFP_NOFS); ++ if (unlikely(!au_warn_loopback_array)) ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++void au_loopback_fin(void) ++{ ++ if (backing_file_func) ++ symbol_put(loop_backing_file); ++ au_kfree_try_rcu(au_warn_loopback_array); ++} +diff -Nurp linux-5.4/fs/aufs/loop.h linux-5.4-aufs/fs/aufs/loop.h +--- linux-5.4/fs/aufs/loop.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/loop.h 2019-11-28 01:25:59.066925618 +0200 +@@ -0,0 +1,42 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * support for loopback mount as a branch ++ */ ++ ++#ifndef __AUFS_LOOP_H__ ++#define __AUFS_LOOP_H__ ++ ++#ifdef __KERNEL__ ++ ++struct dentry; ++struct super_block; ++ ++#ifdef CONFIG_AUFS_BDEV_LOOP ++/* drivers/block/loop.c */ ++struct file *loop_backing_file(struct super_block *sb); ++ ++/* loop.c */ ++int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_adding); ++int au_test_loopback_kthread(void); ++void au_warn_loopback(struct super_block *h_sb); ++ ++int au_loopback_init(void); ++void au_loopback_fin(void); ++#else ++AuStub(struct file *, loop_backing_file, return NULL, struct super_block *sb) ++ ++AuStubInt0(au_test_loopback_overlap, struct super_block *sb, ++ struct dentry *h_adding) ++AuStubInt0(au_test_loopback_kthread, void) ++AuStubVoid(au_warn_loopback, struct super_block *h_sb) ++ ++AuStubInt0(au_loopback_init, void) ++AuStubVoid(au_loopback_fin, void) ++#endif /* BLK_DEV_LOOP */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_LOOP_H__ */ +diff -Nurp linux-5.4/fs/aufs/magic.mk linux-5.4-aufs/fs/aufs/magic.mk +--- linux-5.4/fs/aufs/magic.mk 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/magic.mk 2019-11-28 01:25:59.066925618 +0200 +@@ -0,0 +1,31 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++# defined in ${srctree}/fs/fuse/inode.c ++# tristate ++ifdef CONFIG_FUSE_FS ++ccflags-y += -DFUSE_SUPER_MAGIC=0x65735546 ++endif ++ ++# defined in ${srctree}/fs/xfs/xfs_sb.h ++# tristate ++ifdef CONFIG_XFS_FS ++ccflags-y += -DXFS_SB_MAGIC=0x58465342 ++endif ++ ++# defined in ${srctree}/fs/configfs/mount.c ++# tristate ++ifdef CONFIG_CONFIGFS_FS ++ccflags-y += -DCONFIGFS_MAGIC=0x62656570 ++endif ++ ++# defined in ${srctree}/fs/ubifs/ubifs.h ++# tristate ++ifdef CONFIG_UBIFS_FS ++ccflags-y += -DUBIFS_SUPER_MAGIC=0x24051905 ++endif ++ ++# defined in ${srctree}/fs/hfsplus/hfsplus_raw.h ++# tristate ++ifdef CONFIG_HFSPLUS_FS ++ccflags-y += -DHFSPLUS_SUPER_MAGIC=0x482b ++endif +diff -Nurp linux-5.4/fs/aufs/Makefile linux-5.4-aufs/fs/aufs/Makefile +--- linux-5.4/fs/aufs/Makefile 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/Makefile 2019-11-28 01:25:59.062925618 +0200 +@@ -0,0 +1,39 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++include ${srctree}/${src}/magic.mk ++-include ${srctree}/${src}/priv_def.mk ++ ++# cf. include/linux/kernel.h ++# enable pr_debug ++ccflags-y += -DDEBUG ++# sparse requires the full pathname ++ccflags-y += -include ${srctree}/include/uapi/linux/aufs_type.h ++ ++obj-$(CONFIG_AUFS_FS) += aufs.o ++aufs-y := module.o sbinfo.o super.o branch.o xino.o sysaufs.o opts.o \ ++ wkq.o vfsub.o dcsub.o \ ++ cpup.o whout.o wbr_policy.o \ ++ dinfo.o dentry.o \ ++ dynop.o \ ++ finfo.o file.o f_op.o \ ++ dir.o vdir.o \ ++ iinfo.o inode.o i_op.o i_op_add.o i_op_del.o i_op_ren.o \ ++ mvdown.o ioctl.o ++ ++# all are boolean ++aufs-$(CONFIG_PROC_FS) += procfs.o plink.o ++aufs-$(CONFIG_SYSFS) += sysfs.o ++aufs-$(CONFIG_DEBUG_FS) += dbgaufs.o ++aufs-$(CONFIG_AUFS_BDEV_LOOP) += loop.o ++aufs-$(CONFIG_AUFS_HNOTIFY) += hnotify.o ++aufs-$(CONFIG_AUFS_HFSNOTIFY) += hfsnotify.o ++aufs-$(CONFIG_AUFS_EXPORT) += export.o ++aufs-$(CONFIG_AUFS_XATTR) += xattr.o ++aufs-$(CONFIG_FS_POSIX_ACL) += posix_acl.o ++aufs-$(CONFIG_AUFS_DIRREN) += dirren.o ++aufs-$(CONFIG_AUFS_FHSM) += fhsm.o ++aufs-$(CONFIG_AUFS_POLL) += poll.o ++aufs-$(CONFIG_AUFS_RDU) += rdu.o ++aufs-$(CONFIG_AUFS_BR_HFSPLUS) += hfsplus.o ++aufs-$(CONFIG_AUFS_DEBUG) += debug.o ++aufs-$(CONFIG_AUFS_MAGIC_SYSRQ) += sysrq.o +diff -Nurp linux-5.4/fs/aufs/module.c linux-5.4-aufs/fs/aufs/module.c +--- linux-5.4/fs/aufs/module.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/module.c 2019-11-28 01:25:59.066925618 +0200 +@@ -0,0 +1,259 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * module global variables and operations ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++/* shrinkable realloc */ ++void *au_krealloc(void *p, unsigned int new_sz, gfp_t gfp, int may_shrink) ++{ ++ size_t sz; ++ int diff; ++ ++ sz = 0; ++ diff = -1; ++ if (p) { ++#if 0 /* unused */ ++ if (!new_sz) { ++ au_kfree_rcu(p); ++ p = NULL; ++ goto out; ++ } ++#else ++ AuDebugOn(!new_sz); ++#endif ++ sz = ksize(p); ++ diff = au_kmidx_sub(sz, new_sz); ++ } ++ if (sz && !diff) ++ goto out; ++ ++ if (sz < new_sz) ++ /* expand or SLOB */ ++ p = krealloc(p, new_sz, gfp); ++ else if (new_sz < sz && may_shrink) { ++ /* shrink */ ++ void *q; ++ ++ q = kmalloc(new_sz, gfp); ++ if (q) { ++ if (p) { ++ memcpy(q, p, new_sz); ++ au_kfree_try_rcu(p); ++ } ++ p = q; ++ } else ++ p = NULL; ++ } ++ ++out: ++ return p; ++} ++ ++void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp, ++ int may_shrink) ++{ ++ p = au_krealloc(p, new_sz, gfp, may_shrink); ++ if (p && new_sz > nused) ++ memset(p + nused, 0, new_sz - nused); ++ return p; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * aufs caches ++ */ ++struct kmem_cache *au_cache[AuCache_Last]; ++ ++static void au_cache_fin(void) ++{ ++ int i; ++ ++ /* ++ * Make sure all delayed rcu free inodes are flushed before we ++ * destroy cache. ++ */ ++ rcu_barrier(); ++ ++ /* excluding AuCache_HNOTIFY */ ++ BUILD_BUG_ON(AuCache_HNOTIFY + 1 != AuCache_Last); ++ for (i = 0; i < AuCache_HNOTIFY; i++) { ++ kmem_cache_destroy(au_cache[i]); ++ au_cache[i] = NULL; ++ } ++} ++ ++static int __init au_cache_init(void) ++{ ++ au_cache[AuCache_DINFO] = AuCacheCtor(au_dinfo, au_di_init_once); ++ if (au_cache[AuCache_DINFO]) ++ /* SLAB_DESTROY_BY_RCU */ ++ au_cache[AuCache_ICNTNR] = AuCacheCtor(au_icntnr, ++ au_icntnr_init_once); ++ if (au_cache[AuCache_ICNTNR]) ++ au_cache[AuCache_FINFO] = AuCacheCtor(au_finfo, ++ au_fi_init_once); ++ if (au_cache[AuCache_FINFO]) ++ au_cache[AuCache_VDIR] = AuCache(au_vdir); ++ if (au_cache[AuCache_VDIR]) ++ au_cache[AuCache_DEHSTR] = AuCache(au_vdir_dehstr); ++ if (au_cache[AuCache_DEHSTR]) ++ return 0; ++ ++ au_cache_fin(); ++ return -ENOMEM; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_dir_roflags; ++ ++#ifdef CONFIG_AUFS_SBILIST ++/* ++ * iterate_supers_type() doesn't protect us from ++ * remounting (branch management) ++ */ ++struct hlist_bl_head au_sbilist; ++#endif ++ ++/* ++ * functions for module interface. ++ */ ++MODULE_LICENSE("GPL"); ++/* MODULE_LICENSE("GPL v2"); */ ++MODULE_AUTHOR("Junjiro R. Okajima "); ++MODULE_DESCRIPTION(AUFS_NAME ++ " -- Advanced multi layered unification filesystem"); ++MODULE_VERSION(AUFS_VERSION); ++ ++/* this module parameter has no meaning when SYSFS is disabled */ ++int sysaufs_brs = 1; ++MODULE_PARM_DESC(brs, "use /fs/aufs/si_*/brN"); ++module_param_named(brs, sysaufs_brs, int, 0444); ++ ++/* this module parameter has no meaning when USER_NS is disabled */ ++bool au_userns; ++MODULE_PARM_DESC(allow_userns, "allow unprivileged to mount under userns"); ++module_param_named(allow_userns, au_userns, bool, 0444); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static char au_esc_chars[0x20 + 3]; /* 0x01-0x20, backslash, del, and NULL */ ++ ++int au_seq_path(struct seq_file *seq, struct path *path) ++{ ++ int err; ++ ++ err = seq_path(seq, path, au_esc_chars); ++ if (err >= 0) ++ err = 0; ++ else ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int __init aufs_init(void) ++{ ++ int err, i; ++ char *p; ++ ++ p = au_esc_chars; ++ for (i = 1; i <= ' '; i++) ++ *p++ = i; ++ *p++ = '\\'; ++ *p++ = '\x7f'; ++ *p = 0; ++ ++ au_dir_roflags = au_file_roflags(O_DIRECTORY | O_LARGEFILE); ++ ++ memcpy(aufs_iop_nogetattr, aufs_iop, sizeof(aufs_iop)); ++ for (i = 0; i < AuIop_Last; i++) ++ aufs_iop_nogetattr[i].getattr = NULL; ++ ++ memset(au_cache, 0, sizeof(au_cache)); /* including hnotify */ ++ ++ au_sbilist_init(); ++ sysaufs_brs_init(); ++ au_debug_init(); ++ au_dy_init(); ++ err = sysaufs_init(); ++ if (unlikely(err)) ++ goto out; ++ err = dbgaufs_init(); ++ if (unlikely(err)) ++ goto out_sysaufs; ++ err = au_procfs_init(); ++ if (unlikely(err)) ++ goto out_dbgaufs; ++ err = au_wkq_init(); ++ if (unlikely(err)) ++ goto out_procfs; ++ err = au_loopback_init(); ++ if (unlikely(err)) ++ goto out_wkq; ++ err = au_hnotify_init(); ++ if (unlikely(err)) ++ goto out_loopback; ++ err = au_sysrq_init(); ++ if (unlikely(err)) ++ goto out_hin; ++ err = au_cache_init(); ++ if (unlikely(err)) ++ goto out_sysrq; ++ ++ aufs_fs_type.fs_flags |= au_userns ? FS_USERNS_MOUNT : 0; ++ err = register_filesystem(&aufs_fs_type); ++ if (unlikely(err)) ++ goto out_cache; ++ ++ /* since we define pr_fmt, call printk directly */ ++ printk(KERN_INFO AUFS_NAME " " AUFS_VERSION "\n"); ++ goto out; /* success */ ++ ++out_cache: ++ au_cache_fin(); ++out_sysrq: ++ au_sysrq_fin(); ++out_hin: ++ au_hnotify_fin(); ++out_loopback: ++ au_loopback_fin(); ++out_wkq: ++ au_wkq_fin(); ++out_procfs: ++ au_procfs_fin(); ++out_dbgaufs: ++ dbgaufs_fin(); ++out_sysaufs: ++ sysaufs_fin(); ++ au_dy_fin(); ++out: ++ return err; ++} ++ ++static void __exit aufs_exit(void) ++{ ++ unregister_filesystem(&aufs_fs_type); ++ au_cache_fin(); ++ au_sysrq_fin(); ++ au_hnotify_fin(); ++ au_loopback_fin(); ++ au_wkq_fin(); ++ au_procfs_fin(); ++ dbgaufs_fin(); ++ sysaufs_fin(); ++ au_dy_fin(); ++} ++ ++module_init(aufs_init); ++module_exit(aufs_exit); +diff -Nurp linux-5.4/fs/aufs/module.h linux-5.4-aufs/fs/aufs/module.h +--- linux-5.4/fs/aufs/module.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/module.h 2019-11-28 01:25:59.066925618 +0200 +@@ -0,0 +1,153 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * module initialization and module-global ++ */ ++ ++#ifndef __AUFS_MODULE_H__ ++#define __AUFS_MODULE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "debug.h" ++#include "dentry.h" ++#include "dir.h" ++#include "file.h" ++#include "inode.h" ++ ++struct path; ++struct seq_file; ++ ++/* module parameters */ ++extern int sysaufs_brs; ++extern bool au_userns; ++ ++/* ---------------------------------------------------------------------- */ ++ ++extern int au_dir_roflags; ++ ++void *au_krealloc(void *p, unsigned int new_sz, gfp_t gfp, int may_shrink); ++void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp, ++ int may_shrink); ++ ++/* ++ * Comparing the size of the object with sizeof(struct rcu_head) ++ * case 1: object is always larger ++ * --> au_kfree_rcu() or au_kfree_do_rcu() ++ * case 2: object is always smaller ++ * --> au_kfree_small() ++ * case 3: object can be any size ++ * --> au_kfree_try_rcu() ++ */ ++ ++static inline void au_kfree_do_rcu(const void *p) ++{ ++ struct { ++ struct rcu_head rcu; ++ } *a = (void *)p; ++ ++ kfree_rcu(a, rcu); ++} ++ ++#define au_kfree_rcu(_p) do { \ ++ typeof(_p) p = (_p); \ ++ BUILD_BUG_ON(sizeof(*p) < sizeof(struct rcu_head)); \ ++ if (p) \ ++ au_kfree_do_rcu(p); \ ++ } while (0) ++ ++#define au_kfree_do_sz_test(sz) (sz >= sizeof(struct rcu_head)) ++#define au_kfree_sz_test(p) (p && au_kfree_do_sz_test(ksize(p))) ++ ++static inline void au_kfree_try_rcu(const void *p) ++{ ++ if (!p) ++ return; ++ if (au_kfree_sz_test(p)) ++ au_kfree_do_rcu(p); ++ else ++ kfree(p); ++} ++ ++static inline void au_kfree_small(const void *p) ++{ ++ if (!p) ++ return; ++ AuDebugOn(au_kfree_sz_test(p)); ++ kfree(p); ++} ++ ++static inline int au_kmidx_sub(size_t sz, size_t new_sz) ++{ ++#ifndef CONFIG_SLOB ++ return kmalloc_index(sz) - kmalloc_index(new_sz); ++#else ++ return -1; /* SLOB is untested */ ++#endif ++} ++ ++int au_seq_path(struct seq_file *seq, struct path *path); ++ ++#ifdef CONFIG_PROC_FS ++/* procfs.c */ ++int __init au_procfs_init(void); ++void au_procfs_fin(void); ++#else ++AuStubInt0(au_procfs_init, void); ++AuStubVoid(au_procfs_fin, void); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* kmem cache */ ++enum { ++ AuCache_DINFO, ++ AuCache_ICNTNR, ++ AuCache_FINFO, ++ AuCache_VDIR, ++ AuCache_DEHSTR, ++ AuCache_HNOTIFY, /* must be last */ ++ AuCache_Last ++}; ++ ++extern struct kmem_cache *au_cache[AuCache_Last]; ++ ++#define AuCacheFlags (SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD) ++#define AuCache(type) KMEM_CACHE(type, AuCacheFlags) ++#define AuCacheCtor(type, ctor) \ ++ kmem_cache_create(#type, sizeof(struct type), \ ++ __alignof__(struct type), AuCacheFlags, ctor) ++ ++#define AuCacheFuncs(name, index) \ ++ static inline struct au_##name *au_cache_alloc_##name(void) \ ++ { return kmem_cache_alloc(au_cache[AuCache_##index], GFP_NOFS); } \ ++ static inline void au_cache_free_##name##_norcu(struct au_##name *p) \ ++ { kmem_cache_free(au_cache[AuCache_##index], p); } \ ++ \ ++ static inline void au_cache_free_##name##_rcu_cb(struct rcu_head *rcu) \ ++ { void *p = rcu; \ ++ p -= offsetof(struct au_##name, rcu); \ ++ kmem_cache_free(au_cache[AuCache_##index], p); } \ ++ static inline void au_cache_free_##name##_rcu(struct au_##name *p) \ ++ { BUILD_BUG_ON(sizeof(struct au_##name) < sizeof(struct rcu_head)); \ ++ call_rcu(&p->rcu, au_cache_free_##name##_rcu_cb); } \ ++ \ ++ static inline void au_cache_free_##name(struct au_##name *p) \ ++ { /* au_cache_free_##name##_norcu(p); */ \ ++ au_cache_free_##name##_rcu(p); } ++ ++AuCacheFuncs(dinfo, DINFO); ++AuCacheFuncs(icntnr, ICNTNR); ++AuCacheFuncs(finfo, FINFO); ++AuCacheFuncs(vdir, VDIR); ++AuCacheFuncs(vdir_dehstr, DEHSTR); ++#ifdef CONFIG_AUFS_HNOTIFY ++AuCacheFuncs(hnotify, HNOTIFY); ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_MODULE_H__ */ +diff -Nurp linux-5.4/fs/aufs/mvdown.c linux-5.4-aufs/fs/aufs/mvdown.c +--- linux-5.4/fs/aufs/mvdown.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/mvdown.c 2019-11-28 01:25:59.067925618 +0200 +@@ -0,0 +1,693 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2011-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * move-down, opposite of copy-up ++ */ ++ ++#include "aufs.h" ++ ++struct au_mvd_args { ++ struct { ++ struct super_block *h_sb; ++ struct dentry *h_parent; ++ struct au_hinode *hdir; ++ struct inode *h_dir, *h_inode; ++ struct au_pin pin; ++ } info[AUFS_MVDOWN_NARRAY]; ++ ++ struct aufs_mvdown mvdown; ++ struct dentry *dentry, *parent; ++ struct inode *inode, *dir; ++ struct super_block *sb; ++ aufs_bindex_t bopq, bwh, bfound; ++ unsigned char rename_lock; ++}; ++ ++#define mvd_errno mvdown.au_errno ++#define mvd_bsrc mvdown.stbr[AUFS_MVDOWN_UPPER].bindex ++#define mvd_src_brid mvdown.stbr[AUFS_MVDOWN_UPPER].brid ++#define mvd_bdst mvdown.stbr[AUFS_MVDOWN_LOWER].bindex ++#define mvd_dst_brid mvdown.stbr[AUFS_MVDOWN_LOWER].brid ++ ++#define mvd_h_src_sb info[AUFS_MVDOWN_UPPER].h_sb ++#define mvd_h_src_parent info[AUFS_MVDOWN_UPPER].h_parent ++#define mvd_hdir_src info[AUFS_MVDOWN_UPPER].hdir ++#define mvd_h_src_dir info[AUFS_MVDOWN_UPPER].h_dir ++#define mvd_h_src_inode info[AUFS_MVDOWN_UPPER].h_inode ++#define mvd_pin_src info[AUFS_MVDOWN_UPPER].pin ++ ++#define mvd_h_dst_sb info[AUFS_MVDOWN_LOWER].h_sb ++#define mvd_h_dst_parent info[AUFS_MVDOWN_LOWER].h_parent ++#define mvd_hdir_dst info[AUFS_MVDOWN_LOWER].hdir ++#define mvd_h_dst_dir info[AUFS_MVDOWN_LOWER].h_dir ++#define mvd_h_dst_inode info[AUFS_MVDOWN_LOWER].h_inode ++#define mvd_pin_dst info[AUFS_MVDOWN_LOWER].pin ++ ++#define AU_MVD_PR(flag, ...) do { \ ++ if (flag) \ ++ pr_err(__VA_ARGS__); \ ++ } while (0) ++ ++static int find_lower_writable(struct au_mvd_args *a) ++{ ++ struct super_block *sb; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ sb = a->sb; ++ bindex = a->mvd_bsrc; ++ bbot = au_sbbot(sb); ++ if (a->mvdown.flags & AUFS_MVDOWN_FHSM_LOWER) ++ for (bindex++; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm) ++ && !sb_rdonly(au_br_sb(br))) ++ return bindex; ++ } ++ else if (!(a->mvdown.flags & AUFS_MVDOWN_ROLOWER)) ++ for (bindex++; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!au_br_rdonly(br)) ++ return bindex; ++ } ++ else ++ for (bindex++; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!sb_rdonly(au_br_sb(br))) { ++ if (au_br_rdonly(br)) ++ a->mvdown.flags ++ |= AUFS_MVDOWN_ROLOWER_R; ++ return bindex; ++ } ++ } ++ ++ return -1; ++} ++ ++/* make the parent dir on bdst */ ++static int au_do_mkdir(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ ++ err = 0; ++ a->mvd_hdir_src = au_hi(a->dir, a->mvd_bsrc); ++ a->mvd_hdir_dst = au_hi(a->dir, a->mvd_bdst); ++ a->mvd_h_src_parent = au_h_dptr(a->parent, a->mvd_bsrc); ++ a->mvd_h_dst_parent = NULL; ++ if (au_dbbot(a->parent) >= a->mvd_bdst) ++ a->mvd_h_dst_parent = au_h_dptr(a->parent, a->mvd_bdst); ++ if (!a->mvd_h_dst_parent) { ++ err = au_cpdown_dirs(a->dentry, a->mvd_bdst); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "cpdown_dirs failed\n"); ++ goto out; ++ } ++ a->mvd_h_dst_parent = au_h_dptr(a->parent, a->mvd_bdst); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* lock them all */ ++static int au_do_lock(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct dentry *h_trap; ++ ++ a->mvd_h_src_sb = au_sbr_sb(a->sb, a->mvd_bsrc); ++ a->mvd_h_dst_sb = au_sbr_sb(a->sb, a->mvd_bdst); ++ err = au_pin(&a->mvd_pin_dst, a->dentry, a->mvd_bdst, ++ au_opt_udba(a->sb), ++ AuPin_MNT_WRITE | AuPin_DI_LOCKED); ++ AuTraceErr(err); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "pin_dst failed\n"); ++ goto out; ++ } ++ ++ if (a->mvd_h_src_sb != a->mvd_h_dst_sb) { ++ a->rename_lock = 0; ++ au_pin_init(&a->mvd_pin_src, a->dentry, a->mvd_bsrc, ++ AuLsc_DI_PARENT, AuLsc_I_PARENT3, ++ au_opt_udba(a->sb), ++ AuPin_MNT_WRITE | AuPin_DI_LOCKED); ++ err = au_do_pin(&a->mvd_pin_src); ++ AuTraceErr(err); ++ a->mvd_h_src_dir = d_inode(a->mvd_h_src_parent); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "pin_src failed\n"); ++ goto out_dst; ++ } ++ goto out; /* success */ ++ } ++ ++ a->rename_lock = 1; ++ au_pin_hdir_unlock(&a->mvd_pin_dst); ++ err = au_pin(&a->mvd_pin_src, a->dentry, a->mvd_bsrc, ++ au_opt_udba(a->sb), ++ AuPin_MNT_WRITE | AuPin_DI_LOCKED); ++ AuTraceErr(err); ++ a->mvd_h_src_dir = d_inode(a->mvd_h_src_parent); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "pin_src failed\n"); ++ au_pin_hdir_lock(&a->mvd_pin_dst); ++ goto out_dst; ++ } ++ au_pin_hdir_unlock(&a->mvd_pin_src); ++ h_trap = vfsub_lock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, ++ a->mvd_h_dst_parent, a->mvd_hdir_dst); ++ if (h_trap) { ++ err = (h_trap != a->mvd_h_src_parent); ++ if (err) ++ err = (h_trap != a->mvd_h_dst_parent); ++ } ++ BUG_ON(err); /* it should never happen */ ++ if (unlikely(a->mvd_h_src_dir != au_pinned_h_dir(&a->mvd_pin_src))) { ++ err = -EBUSY; ++ AuTraceErr(err); ++ vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, ++ a->mvd_h_dst_parent, a->mvd_hdir_dst); ++ au_pin_hdir_lock(&a->mvd_pin_src); ++ au_unpin(&a->mvd_pin_src); ++ au_pin_hdir_lock(&a->mvd_pin_dst); ++ goto out_dst; ++ } ++ goto out; /* success */ ++ ++out_dst: ++ au_unpin(&a->mvd_pin_dst); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static void au_do_unlock(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ if (!a->rename_lock) ++ au_unpin(&a->mvd_pin_src); ++ else { ++ vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, ++ a->mvd_h_dst_parent, a->mvd_hdir_dst); ++ au_pin_hdir_lock(&a->mvd_pin_src); ++ au_unpin(&a->mvd_pin_src); ++ au_pin_hdir_lock(&a->mvd_pin_dst); ++ } ++ au_unpin(&a->mvd_pin_dst); ++} ++ ++/* copy-down the file */ ++static int au_do_cpdown(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct au_cp_generic cpg = { ++ .dentry = a->dentry, ++ .bdst = a->mvd_bdst, ++ .bsrc = a->mvd_bsrc, ++ .len = -1, ++ .pin = &a->mvd_pin_dst, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ ++ AuDbg("b%d, b%d\n", cpg.bsrc, cpg.bdst); ++ if (a->mvdown.flags & AUFS_MVDOWN_OWLOWER) ++ au_fset_cpup(cpg.flags, OVERWRITE); ++ if (a->mvdown.flags & AUFS_MVDOWN_ROLOWER) ++ au_fset_cpup(cpg.flags, RWDST); ++ err = au_sio_cpdown_simple(&cpg); ++ if (unlikely(err)) ++ AU_MVD_PR(dmsg, "cpdown failed\n"); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * unlink the whiteout on bdst if exist which may be created by UDBA while we ++ * were sleeping ++ */ ++static int au_do_unlink_wh(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct path h_path; ++ struct au_branch *br; ++ struct inode *delegated; ++ ++ br = au_sbr(a->sb, a->mvd_bdst); ++ h_path.dentry = au_wh_lkup(a->mvd_h_dst_parent, &a->dentry->d_name, br); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) { ++ AU_MVD_PR(dmsg, "wh_lkup failed\n"); ++ goto out; ++ } ++ ++ err = 0; ++ if (d_is_positive(h_path.dentry)) { ++ h_path.mnt = au_br_mnt(br); ++ delegated = NULL; ++ err = vfsub_unlink(d_inode(a->mvd_h_dst_parent), &h_path, ++ &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) ++ AU_MVD_PR(dmsg, "wh_unlink failed\n"); ++ } ++ dput(h_path.dentry); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * unlink the topmost h_dentry ++ */ ++static int au_do_unlink(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct path h_path; ++ struct inode *delegated; ++ ++ h_path.mnt = au_sbr_mnt(a->sb, a->mvd_bsrc); ++ h_path.dentry = au_h_dptr(a->dentry, a->mvd_bsrc); ++ delegated = NULL; ++ err = vfsub_unlink(a->mvd_h_src_dir, &h_path, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) ++ AU_MVD_PR(dmsg, "unlink failed\n"); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* Since mvdown succeeded, we ignore an error of this function */ ++static void au_do_stfs(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct au_branch *br; ++ ++ a->mvdown.flags |= AUFS_MVDOWN_STFS_FAILED; ++ br = au_sbr(a->sb, a->mvd_bsrc); ++ err = au_br_stfs(br, &a->mvdown.stbr[AUFS_MVDOWN_UPPER].stfs); ++ if (!err) { ++ br = au_sbr(a->sb, a->mvd_bdst); ++ a->mvdown.stbr[AUFS_MVDOWN_LOWER].brid = br->br_id; ++ err = au_br_stfs(br, &a->mvdown.stbr[AUFS_MVDOWN_LOWER].stfs); ++ } ++ if (!err) ++ a->mvdown.flags &= ~AUFS_MVDOWN_STFS_FAILED; ++ else ++ AU_MVD_PR(dmsg, "statfs failed (%d), ignored\n", err); ++} ++ ++/* ++ * copy-down the file and unlink the bsrc file. ++ * - unlink the bdst whout if exist ++ * - copy-down the file (with whtmp name and rename) ++ * - unlink the bsrc file ++ */ ++static int au_do_mvdown(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ ++ err = au_do_mkdir(dmsg, a); ++ if (!err) ++ err = au_do_lock(dmsg, a); ++ if (unlikely(err)) ++ goto out; ++ ++ /* ++ * do not revert the activities we made on bdst since they should be ++ * harmless in aufs. ++ */ ++ ++ err = au_do_cpdown(dmsg, a); ++ if (!err) ++ err = au_do_unlink_wh(dmsg, a); ++ if (!err && !(a->mvdown.flags & AUFS_MVDOWN_KUPPER)) ++ err = au_do_unlink(dmsg, a); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ AuDbg("%pd2, 0x%x, %d --> %d\n", ++ a->dentry, a->mvdown.flags, a->mvd_bsrc, a->mvd_bdst); ++ if (find_lower_writable(a) < 0) ++ a->mvdown.flags |= AUFS_MVDOWN_BOTTOM; ++ ++ if (a->mvdown.flags & AUFS_MVDOWN_STFS) ++ au_do_stfs(dmsg, a); ++ ++ /* maintain internal array */ ++ if (!(a->mvdown.flags & AUFS_MVDOWN_KUPPER)) { ++ au_set_h_dptr(a->dentry, a->mvd_bsrc, NULL); ++ au_set_dbtop(a->dentry, a->mvd_bdst); ++ au_set_h_iptr(a->inode, a->mvd_bsrc, NULL, /*flags*/0); ++ au_set_ibtop(a->inode, a->mvd_bdst); ++ } else { ++ /* hide the lower */ ++ au_set_h_dptr(a->dentry, a->mvd_bdst, NULL); ++ au_set_dbbot(a->dentry, a->mvd_bsrc); ++ au_set_h_iptr(a->inode, a->mvd_bdst, NULL, /*flags*/0); ++ au_set_ibbot(a->inode, a->mvd_bsrc); ++ } ++ if (au_dbbot(a->dentry) < a->mvd_bdst) ++ au_set_dbbot(a->dentry, a->mvd_bdst); ++ if (au_ibbot(a->inode) < a->mvd_bdst) ++ au_set_ibbot(a->inode, a->mvd_bdst); ++ ++out_unlock: ++ au_do_unlock(dmsg, a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* make sure the file is idle */ ++static int au_mvd_args_busy(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err, plinked; ++ ++ err = 0; ++ plinked = !!au_opt_test(au_mntflags(a->sb), PLINK); ++ if (au_dbtop(a->dentry) == a->mvd_bsrc ++ && au_dcount(a->dentry) == 1 ++ && atomic_read(&a->inode->i_count) == 1 ++ /* && a->mvd_h_src_inode->i_nlink == 1 */ ++ && (!plinked || !au_plink_test(a->inode)) ++ && a->inode->i_nlink == 1) ++ goto out; ++ ++ err = -EBUSY; ++ AU_MVD_PR(dmsg, ++ "b%d, d{b%d, c%d?}, i{c%d?, l%u}, hi{l%u}, p{%d, %d}\n", ++ a->mvd_bsrc, au_dbtop(a->dentry), au_dcount(a->dentry), ++ atomic_read(&a->inode->i_count), a->inode->i_nlink, ++ a->mvd_h_src_inode->i_nlink, ++ plinked, plinked ? au_plink_test(a->inode) : 0); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* make sure the parent dir is fine */ ++static int au_mvd_args_parent(const unsigned char dmsg, ++ struct au_mvd_args *a) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ ++ err = 0; ++ if (unlikely(au_alive_dir(a->parent))) { ++ err = -ENOENT; ++ AU_MVD_PR(dmsg, "parent dir is dead\n"); ++ goto out; ++ } ++ ++ a->bopq = au_dbdiropq(a->parent); ++ bindex = au_wbr_nonopq(a->dentry, a->mvd_bdst); ++ AuDbg("b%d\n", bindex); ++ if (unlikely((bindex >= 0 && bindex < a->mvd_bdst) ++ || (a->bopq != -1 && a->bopq < a->mvd_bdst))) { ++ err = -EINVAL; ++ a->mvd_errno = EAU_MVDOWN_OPAQUE; ++ AU_MVD_PR(dmsg, "ancestor is opaque b%d, b%d\n", ++ a->bopq, a->mvd_bdst); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_mvd_args_intermediate(const unsigned char dmsg, ++ struct au_mvd_args *a) ++{ ++ int err; ++ struct au_dinfo *dinfo, *tmp; ++ ++ /* lookup the next lower positive entry */ ++ err = -ENOMEM; ++ tmp = au_di_alloc(a->sb, AuLsc_DI_TMP); ++ if (unlikely(!tmp)) ++ goto out; ++ ++ a->bfound = -1; ++ a->bwh = -1; ++ dinfo = au_di(a->dentry); ++ au_di_cp(tmp, dinfo); ++ au_di_swap(tmp, dinfo); ++ ++ /* returns the number of positive dentries */ ++ err = au_lkup_dentry(a->dentry, a->mvd_bsrc + 1, ++ /* AuLkup_IGNORE_PERM */ 0); ++ if (!err) ++ a->bwh = au_dbwh(a->dentry); ++ else if (err > 0) ++ a->bfound = au_dbtop(a->dentry); ++ ++ au_di_swap(tmp, dinfo); ++ au_rw_write_unlock(&tmp->di_rwsem); ++ au_di_free(tmp); ++ if (unlikely(err < 0)) ++ AU_MVD_PR(dmsg, "failed look-up lower\n"); ++ ++ /* ++ * here, we have these cases. ++ * bfound == -1 ++ * no positive dentry under bsrc. there are more sub-cases. ++ * bwh < 0 ++ * there no whiteout, we can safely move-down. ++ * bwh <= bsrc ++ * impossible ++ * bsrc < bwh && bwh < bdst ++ * there is a whiteout on RO branch. cannot proceed. ++ * bwh == bdst ++ * there is a whiteout on the RW target branch. it should ++ * be removed. ++ * bdst < bwh ++ * there is a whiteout somewhere unrelated branch. ++ * -1 < bfound && bfound <= bsrc ++ * impossible. ++ * bfound < bdst ++ * found, but it is on RO branch between bsrc and bdst. cannot ++ * proceed. ++ * bfound == bdst ++ * found, replace it if AUFS_MVDOWN_FORCE is set. otherwise return ++ * error. ++ * bdst < bfound ++ * found, after we create the file on bdst, it will be hidden. ++ */ ++ ++ AuDebugOn(a->bfound == -1 ++ && a->bwh != -1 ++ && a->bwh <= a->mvd_bsrc); ++ AuDebugOn(-1 < a->bfound ++ && a->bfound <= a->mvd_bsrc); ++ ++ err = -EINVAL; ++ if (a->bfound == -1 ++ && a->mvd_bsrc < a->bwh ++ && a->bwh != -1 ++ && a->bwh < a->mvd_bdst) { ++ a->mvd_errno = EAU_MVDOWN_WHITEOUT; ++ AU_MVD_PR(dmsg, "bsrc %d, bdst %d, bfound %d, bwh %d\n", ++ a->mvd_bsrc, a->mvd_bdst, a->bfound, a->bwh); ++ goto out; ++ } else if (a->bfound != -1 && a->bfound < a->mvd_bdst) { ++ a->mvd_errno = EAU_MVDOWN_UPPER; ++ AU_MVD_PR(dmsg, "bdst %d, bfound %d\n", ++ a->mvd_bdst, a->bfound); ++ goto out; ++ } ++ ++ err = 0; /* success */ ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_mvd_args_exist(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ ++ err = 0; ++ if (!(a->mvdown.flags & AUFS_MVDOWN_OWLOWER) ++ && a->bfound == a->mvd_bdst) ++ err = -EEXIST; ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_mvd_args(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct au_branch *br; ++ ++ err = -EISDIR; ++ if (unlikely(S_ISDIR(a->inode->i_mode))) ++ goto out; ++ ++ err = -EINVAL; ++ if (!(a->mvdown.flags & AUFS_MVDOWN_BRID_UPPER)) ++ a->mvd_bsrc = au_ibtop(a->inode); ++ else { ++ a->mvd_bsrc = au_br_index(a->sb, a->mvd_src_brid); ++ if (unlikely(a->mvd_bsrc < 0 ++ || (a->mvd_bsrc < au_dbtop(a->dentry) ++ || au_dbbot(a->dentry) < a->mvd_bsrc ++ || !au_h_dptr(a->dentry, a->mvd_bsrc)) ++ || (a->mvd_bsrc < au_ibtop(a->inode) ++ || au_ibbot(a->inode) < a->mvd_bsrc ++ || !au_h_iptr(a->inode, a->mvd_bsrc)))) { ++ a->mvd_errno = EAU_MVDOWN_NOUPPER; ++ AU_MVD_PR(dmsg, "no upper\n"); ++ goto out; ++ } ++ } ++ if (unlikely(a->mvd_bsrc == au_sbbot(a->sb))) { ++ a->mvd_errno = EAU_MVDOWN_BOTTOM; ++ AU_MVD_PR(dmsg, "on the bottom\n"); ++ goto out; ++ } ++ a->mvd_h_src_inode = au_h_iptr(a->inode, a->mvd_bsrc); ++ br = au_sbr(a->sb, a->mvd_bsrc); ++ err = au_br_rdonly(br); ++ if (!(a->mvdown.flags & AUFS_MVDOWN_ROUPPER)) { ++ if (unlikely(err)) ++ goto out; ++ } else if (!(vfsub_native_ro(a->mvd_h_src_inode) ++ || IS_APPEND(a->mvd_h_src_inode))) { ++ if (err) ++ a->mvdown.flags |= AUFS_MVDOWN_ROUPPER_R; ++ /* go on */ ++ } else ++ goto out; ++ ++ err = -EINVAL; ++ if (!(a->mvdown.flags & AUFS_MVDOWN_BRID_LOWER)) { ++ a->mvd_bdst = find_lower_writable(a); ++ if (unlikely(a->mvd_bdst < 0)) { ++ a->mvd_errno = EAU_MVDOWN_BOTTOM; ++ AU_MVD_PR(dmsg, "no writable lower branch\n"); ++ goto out; ++ } ++ } else { ++ a->mvd_bdst = au_br_index(a->sb, a->mvd_dst_brid); ++ if (unlikely(a->mvd_bdst < 0 ++ || au_sbbot(a->sb) < a->mvd_bdst)) { ++ a->mvd_errno = EAU_MVDOWN_NOLOWERBR; ++ AU_MVD_PR(dmsg, "no lower brid\n"); ++ goto out; ++ } ++ } ++ ++ err = au_mvd_args_busy(dmsg, a); ++ if (!err) ++ err = au_mvd_args_parent(dmsg, a); ++ if (!err) ++ err = au_mvd_args_intermediate(dmsg, a); ++ if (!err) ++ err = au_mvd_args_exist(dmsg, a); ++ if (!err) ++ AuDbg("b%d, b%d\n", a->mvd_bsrc, a->mvd_bdst); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *uarg) ++{ ++ int err, e; ++ unsigned char dmsg; ++ struct au_mvd_args *args; ++ struct inode *inode; ++ ++ inode = d_inode(dentry); ++ err = -EPERM; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = -ENOMEM; ++ args = kmalloc(sizeof(*args), GFP_NOFS); ++ if (unlikely(!args)) ++ goto out; ++ ++ err = copy_from_user(&args->mvdown, uarg, sizeof(args->mvdown)); ++ if (!err) ++ /* VERIFY_WRITE */ ++ err = !access_ok(uarg, sizeof(*uarg)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out_free; ++ } ++ AuDbg("flags 0x%x\n", args->mvdown.flags); ++ args->mvdown.flags &= ~(AUFS_MVDOWN_ROLOWER_R | AUFS_MVDOWN_ROUPPER_R); ++ args->mvdown.au_errno = 0; ++ args->dentry = dentry; ++ args->inode = inode; ++ args->sb = dentry->d_sb; ++ ++ err = -ENOENT; ++ dmsg = !!(args->mvdown.flags & AUFS_MVDOWN_DMSG); ++ args->parent = dget_parent(dentry); ++ args->dir = d_inode(args->parent); ++ inode_lock_nested(args->dir, I_MUTEX_PARENT); ++ dput(args->parent); ++ if (unlikely(args->parent != dentry->d_parent)) { ++ AU_MVD_PR(dmsg, "parent dir is moved\n"); ++ goto out_dir; ++ } ++ ++ inode_lock_nested(inode, I_MUTEX_CHILD); ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_NOPLMW); ++ if (unlikely(err)) ++ goto out_inode; ++ ++ di_write_lock_parent(args->parent); ++ err = au_mvd_args(dmsg, args); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ err = au_do_mvdown(dmsg, args); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ au_cpup_attr_timesizes(args->dir); ++ au_cpup_attr_timesizes(inode); ++ if (!(args->mvdown.flags & AUFS_MVDOWN_KUPPER)) ++ au_cpup_igen(inode, au_h_iptr(inode, args->mvd_bdst)); ++ /* au_digen_dec(dentry); */ ++ ++out_parent: ++ di_write_unlock(args->parent); ++ aufs_read_unlock(dentry, AuLock_DW); ++out_inode: ++ inode_unlock(inode); ++out_dir: ++ inode_unlock(args->dir); ++out_free: ++ e = copy_to_user(uarg, &args->mvdown, sizeof(args->mvdown)); ++ if (unlikely(e)) ++ err = -EFAULT; ++ au_kfree_rcu(args); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff -Nurp linux-5.4/fs/aufs/opts.c linux-5.4-aufs/fs/aufs/opts.c +--- linux-5.4/fs/aufs/opts.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/opts.c 2019-11-28 01:25:59.067925618 +0200 +@@ -0,0 +1,1867 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * mount options/flags ++ */ ++ ++#include ++#include /* a distribution requires */ ++#include ++#include "aufs.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++enum { ++ Opt_br, ++ Opt_add, Opt_del, Opt_mod, Opt_append, Opt_prepend, ++ Opt_idel, Opt_imod, ++ Opt_dirwh, Opt_rdcache, Opt_rdblk, Opt_rdhash, ++ Opt_rdblk_def, Opt_rdhash_def, ++ Opt_xino, Opt_noxino, ++ Opt_trunc_xino, Opt_trunc_xino_v, Opt_notrunc_xino, ++ Opt_trunc_xino_path, Opt_itrunc_xino, ++ Opt_trunc_xib, Opt_notrunc_xib, ++ Opt_shwh, Opt_noshwh, ++ Opt_plink, Opt_noplink, Opt_list_plink, ++ Opt_udba, ++ Opt_dio, Opt_nodio, ++ Opt_diropq_a, Opt_diropq_w, ++ Opt_warn_perm, Opt_nowarn_perm, ++ Opt_wbr_copyup, Opt_wbr_create, ++ Opt_fhsm_sec, ++ Opt_verbose, Opt_noverbose, ++ Opt_sum, Opt_nosum, Opt_wsum, ++ Opt_dirperm1, Opt_nodirperm1, ++ Opt_dirren, Opt_nodirren, ++ Opt_acl, Opt_noacl, ++ Opt_tail, Opt_ignore, Opt_ignore_silent, Opt_err ++}; ++ ++static match_table_t options = { ++ {Opt_br, "br=%s"}, ++ {Opt_br, "br:%s"}, ++ ++ {Opt_add, "add=%d:%s"}, ++ {Opt_add, "add:%d:%s"}, ++ {Opt_add, "ins=%d:%s"}, ++ {Opt_add, "ins:%d:%s"}, ++ {Opt_append, "append=%s"}, ++ {Opt_append, "append:%s"}, ++ {Opt_prepend, "prepend=%s"}, ++ {Opt_prepend, "prepend:%s"}, ++ ++ {Opt_del, "del=%s"}, ++ {Opt_del, "del:%s"}, ++ /* {Opt_idel, "idel:%d"}, */ ++ {Opt_mod, "mod=%s"}, ++ {Opt_mod, "mod:%s"}, ++ /* {Opt_imod, "imod:%d:%s"}, */ ++ ++ {Opt_dirwh, "dirwh=%d"}, ++ ++ {Opt_xino, "xino=%s"}, ++ {Opt_noxino, "noxino"}, ++ {Opt_trunc_xino, "trunc_xino"}, ++ {Opt_trunc_xino_v, "trunc_xino_v=%d:%d"}, ++ {Opt_notrunc_xino, "notrunc_xino"}, ++ {Opt_trunc_xino_path, "trunc_xino=%s"}, ++ {Opt_itrunc_xino, "itrunc_xino=%d"}, ++ /* {Opt_zxino, "zxino=%s"}, */ ++ {Opt_trunc_xib, "trunc_xib"}, ++ {Opt_notrunc_xib, "notrunc_xib"}, ++ ++#ifdef CONFIG_PROC_FS ++ {Opt_plink, "plink"}, ++#else ++ {Opt_ignore_silent, "plink"}, ++#endif ++ ++ {Opt_noplink, "noplink"}, ++ ++#ifdef CONFIG_AUFS_DEBUG ++ {Opt_list_plink, "list_plink"}, ++#endif ++ ++ {Opt_udba, "udba=%s"}, ++ ++ {Opt_dio, "dio"}, ++ {Opt_nodio, "nodio"}, ++ ++#ifdef CONFIG_AUFS_DIRREN ++ {Opt_dirren, "dirren"}, ++ {Opt_nodirren, "nodirren"}, ++#else ++ {Opt_ignore, "dirren"}, ++ {Opt_ignore_silent, "nodirren"}, ++#endif ++ ++#ifdef CONFIG_AUFS_FHSM ++ {Opt_fhsm_sec, "fhsm_sec=%d"}, ++#else ++ {Opt_ignore, "fhsm_sec=%d"}, ++#endif ++ ++ {Opt_diropq_a, "diropq=always"}, ++ {Opt_diropq_a, "diropq=a"}, ++ {Opt_diropq_w, "diropq=whiteouted"}, ++ {Opt_diropq_w, "diropq=w"}, ++ ++ {Opt_warn_perm, "warn_perm"}, ++ {Opt_nowarn_perm, "nowarn_perm"}, ++ ++ /* keep them temporary */ ++ {Opt_ignore_silent, "nodlgt"}, ++ {Opt_ignore, "clean_plink"}, ++ ++#ifdef CONFIG_AUFS_SHWH ++ {Opt_shwh, "shwh"}, ++#endif ++ {Opt_noshwh, "noshwh"}, ++ ++ {Opt_dirperm1, "dirperm1"}, ++ {Opt_nodirperm1, "nodirperm1"}, ++ ++ {Opt_verbose, "verbose"}, ++ {Opt_verbose, "v"}, ++ {Opt_noverbose, "noverbose"}, ++ {Opt_noverbose, "quiet"}, ++ {Opt_noverbose, "q"}, ++ {Opt_noverbose, "silent"}, ++ ++ {Opt_sum, "sum"}, ++ {Opt_nosum, "nosum"}, ++ {Opt_wsum, "wsum"}, ++ ++ {Opt_rdcache, "rdcache=%d"}, ++ {Opt_rdblk, "rdblk=%d"}, ++ {Opt_rdblk_def, "rdblk=def"}, ++ {Opt_rdhash, "rdhash=%d"}, ++ {Opt_rdhash_def, "rdhash=def"}, ++ ++ {Opt_wbr_create, "create=%s"}, ++ {Opt_wbr_create, "create_policy=%s"}, ++ {Opt_wbr_copyup, "cpup=%s"}, ++ {Opt_wbr_copyup, "copyup=%s"}, ++ {Opt_wbr_copyup, "copyup_policy=%s"}, ++ ++ /* generic VFS flag */ ++#ifdef CONFIG_FS_POSIX_ACL ++ {Opt_acl, "acl"}, ++ {Opt_noacl, "noacl"}, ++#else ++ {Opt_ignore, "acl"}, ++ {Opt_ignore_silent, "noacl"}, ++#endif ++ ++ /* internal use for the scripts */ ++ {Opt_ignore_silent, "si=%s"}, ++ ++ {Opt_br, "dirs=%s"}, ++ {Opt_ignore, "debug=%d"}, ++ {Opt_ignore, "delete=whiteout"}, ++ {Opt_ignore, "delete=all"}, ++ {Opt_ignore, "imap=%s"}, ++ ++ /* temporary workaround, due to old mount(8)? */ ++ {Opt_ignore_silent, "relatime"}, ++ ++ {Opt_err, NULL} ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static const char *au_parser_pattern(int val, match_table_t tbl) ++{ ++ struct match_token *p; ++ ++ p = tbl; ++ while (p->pattern) { ++ if (p->token == val) ++ return p->pattern; ++ p++; ++ } ++ BUG(); ++ return "??"; ++} ++ ++static const char *au_optstr(int *val, match_table_t tbl) ++{ ++ struct match_token *p; ++ int v; ++ ++ v = *val; ++ if (!v) ++ goto out; ++ p = tbl; ++ while (p->pattern) { ++ if (p->token ++ && (v & p->token) == p->token) { ++ *val &= ~p->token; ++ return p->pattern; ++ } ++ p++; ++ } ++ ++out: ++ return NULL; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static match_table_t brperm = { ++ {AuBrPerm_RO, AUFS_BRPERM_RO}, ++ {AuBrPerm_RR, AUFS_BRPERM_RR}, ++ {AuBrPerm_RW, AUFS_BRPERM_RW}, ++ {0, NULL} ++}; ++ ++static match_table_t brattr = { ++ /* general */ ++ {AuBrAttr_COO_REG, AUFS_BRATTR_COO_REG}, ++ {AuBrAttr_COO_ALL, AUFS_BRATTR_COO_ALL}, ++ /* 'unpin' attrib is meaningless since linux-3.18-rc1 */ ++ {AuBrAttr_UNPIN, AUFS_BRATTR_UNPIN}, ++#ifdef CONFIG_AUFS_FHSM ++ {AuBrAttr_FHSM, AUFS_BRATTR_FHSM}, ++#endif ++#ifdef CONFIG_AUFS_XATTR ++ {AuBrAttr_ICEX, AUFS_BRATTR_ICEX}, ++ {AuBrAttr_ICEX_SEC, AUFS_BRATTR_ICEX_SEC}, ++ {AuBrAttr_ICEX_SYS, AUFS_BRATTR_ICEX_SYS}, ++ {AuBrAttr_ICEX_TR, AUFS_BRATTR_ICEX_TR}, ++ {AuBrAttr_ICEX_USR, AUFS_BRATTR_ICEX_USR}, ++ {AuBrAttr_ICEX_OTH, AUFS_BRATTR_ICEX_OTH}, ++#endif ++ ++ /* ro/rr branch */ ++ {AuBrRAttr_WH, AUFS_BRRATTR_WH}, ++ ++ /* rw branch */ ++ {AuBrWAttr_MOO, AUFS_BRWATTR_MOO}, ++ {AuBrWAttr_NoLinkWH, AUFS_BRWATTR_NLWH}, ++ ++ {0, NULL} ++}; ++ ++static int br_attr_val(char *str, match_table_t table, substring_t args[]) ++{ ++ int attr, v; ++ char *p; ++ ++ attr = 0; ++ do { ++ p = strchr(str, '+'); ++ if (p) ++ *p = 0; ++ v = match_token(str, table, args); ++ if (v) { ++ if (v & AuBrAttr_CMOO_Mask) ++ attr &= ~AuBrAttr_CMOO_Mask; ++ attr |= v; ++ } else { ++ if (p) ++ *p = '+'; ++ pr_warn("ignored branch attribute %s\n", str); ++ break; ++ } ++ if (p) ++ str = p + 1; ++ } while (p); ++ ++ return attr; ++} ++ ++static int au_do_optstr_br_attr(au_br_perm_str_t *str, int perm) ++{ ++ int sz; ++ const char *p; ++ char *q; ++ ++ q = str->a; ++ *q = 0; ++ p = au_optstr(&perm, brattr); ++ if (p) { ++ sz = strlen(p); ++ memcpy(q, p, sz + 1); ++ q += sz; ++ } else ++ goto out; ++ ++ do { ++ p = au_optstr(&perm, brattr); ++ if (p) { ++ *q++ = '+'; ++ sz = strlen(p); ++ memcpy(q, p, sz + 1); ++ q += sz; ++ } ++ } while (p); ++ ++out: ++ return q - str->a; ++} ++ ++static int noinline_for_stack br_perm_val(char *perm) ++{ ++ int val, bad, sz; ++ char *p; ++ substring_t args[MAX_OPT_ARGS]; ++ au_br_perm_str_t attr; ++ ++ p = strchr(perm, '+'); ++ if (p) ++ *p = 0; ++ val = match_token(perm, brperm, args); ++ if (!val) { ++ if (p) ++ *p = '+'; ++ pr_warn("ignored branch permission %s\n", perm); ++ val = AuBrPerm_RO; ++ goto out; ++ } ++ if (!p) ++ goto out; ++ ++ val |= br_attr_val(p + 1, brattr, args); ++ ++ bad = 0; ++ switch (val & AuBrPerm_Mask) { ++ case AuBrPerm_RO: ++ case AuBrPerm_RR: ++ bad = val & AuBrWAttr_Mask; ++ val &= ~AuBrWAttr_Mask; ++ break; ++ case AuBrPerm_RW: ++ bad = val & AuBrRAttr_Mask; ++ val &= ~AuBrRAttr_Mask; ++ break; ++ } ++ ++ /* ++ * 'unpin' attrib becomes meaningless since linux-3.18-rc1, but aufs ++ * does not treat it as an error, just warning. ++ * this is a tiny guard for the user operation. ++ */ ++ if (val & AuBrAttr_UNPIN) { ++ bad |= AuBrAttr_UNPIN; ++ val &= ~AuBrAttr_UNPIN; ++ } ++ ++ if (unlikely(bad)) { ++ sz = au_do_optstr_br_attr(&attr, bad); ++ AuDebugOn(!sz); ++ pr_warn("ignored branch attribute %s\n", attr.a); ++ } ++ ++out: ++ return val; ++} ++ ++void au_optstr_br_perm(au_br_perm_str_t *str, int perm) ++{ ++ au_br_perm_str_t attr; ++ const char *p; ++ char *q; ++ int sz; ++ ++ q = str->a; ++ p = au_optstr(&perm, brperm); ++ AuDebugOn(!p || !*p); ++ sz = strlen(p); ++ memcpy(q, p, sz + 1); ++ q += sz; ++ ++ sz = au_do_optstr_br_attr(&attr, perm); ++ if (sz) { ++ *q++ = '+'; ++ memcpy(q, attr.a, sz + 1); ++ } ++ ++ AuDebugOn(strlen(str->a) >= sizeof(str->a)); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static match_table_t udbalevel = { ++ {AuOpt_UDBA_REVAL, "reval"}, ++ {AuOpt_UDBA_NONE, "none"}, ++#ifdef CONFIG_AUFS_HNOTIFY ++ {AuOpt_UDBA_HNOTIFY, "notify"}, /* abstraction */ ++#ifdef CONFIG_AUFS_HFSNOTIFY ++ {AuOpt_UDBA_HNOTIFY, "fsnotify"}, ++#endif ++#endif ++ {-1, NULL} ++}; ++ ++static int noinline_for_stack udba_val(char *str) ++{ ++ substring_t args[MAX_OPT_ARGS]; ++ ++ return match_token(str, udbalevel, args); ++} ++ ++const char *au_optstr_udba(int udba) ++{ ++ return au_parser_pattern(udba, udbalevel); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static match_table_t au_wbr_create_policy = { ++ {AuWbrCreate_TDP, "tdp"}, ++ {AuWbrCreate_TDP, "top-down-parent"}, ++ {AuWbrCreate_RR, "rr"}, ++ {AuWbrCreate_RR, "round-robin"}, ++ {AuWbrCreate_MFS, "mfs"}, ++ {AuWbrCreate_MFS, "most-free-space"}, ++ {AuWbrCreate_MFSV, "mfs:%d"}, ++ {AuWbrCreate_MFSV, "most-free-space:%d"}, ++ ++ /* top-down regardless the parent, and then mfs */ ++ {AuWbrCreate_TDMFS, "tdmfs:%d"}, ++ {AuWbrCreate_TDMFSV, "tdmfs:%d:%d"}, ++ ++ {AuWbrCreate_MFSRR, "mfsrr:%d"}, ++ {AuWbrCreate_MFSRRV, "mfsrr:%d:%d"}, ++ {AuWbrCreate_PMFS, "pmfs"}, ++ {AuWbrCreate_PMFSV, "pmfs:%d"}, ++ {AuWbrCreate_PMFSRR, "pmfsrr:%d"}, ++ {AuWbrCreate_PMFSRRV, "pmfsrr:%d:%d"}, ++ ++ {-1, NULL} ++}; ++ ++static int au_wbr_mfs_wmark(substring_t *arg, char *str, ++ struct au_opt_wbr_create *create) ++{ ++ int err; ++ unsigned long long ull; ++ ++ err = 0; ++ if (!match_u64(arg, &ull)) ++ create->mfsrr_watermark = ull; ++ else { ++ pr_err("bad integer in %s\n", str); ++ err = -EINVAL; ++ } ++ ++ return err; ++} ++ ++static int au_wbr_mfs_sec(substring_t *arg, char *str, ++ struct au_opt_wbr_create *create) ++{ ++ int n, err; ++ ++ err = 0; ++ if (!match_int(arg, &n) && 0 <= n && n <= AUFS_MFS_MAX_SEC) ++ create->mfs_second = n; ++ else { ++ pr_err("bad integer in %s\n", str); ++ err = -EINVAL; ++ } ++ ++ return err; ++} ++ ++static int noinline_for_stack ++au_wbr_create_val(char *str, struct au_opt_wbr_create *create) ++{ ++ int err, e; ++ substring_t args[MAX_OPT_ARGS]; ++ ++ err = match_token(str, au_wbr_create_policy, args); ++ create->wbr_create = err; ++ switch (err) { ++ case AuWbrCreate_MFSRRV: ++ case AuWbrCreate_TDMFSV: ++ case AuWbrCreate_PMFSRRV: ++ e = au_wbr_mfs_wmark(&args[0], str, create); ++ if (!e) ++ e = au_wbr_mfs_sec(&args[1], str, create); ++ if (unlikely(e)) ++ err = e; ++ break; ++ case AuWbrCreate_MFSRR: ++ case AuWbrCreate_TDMFS: ++ case AuWbrCreate_PMFSRR: ++ e = au_wbr_mfs_wmark(&args[0], str, create); ++ if (unlikely(e)) { ++ err = e; ++ break; ++ } ++ /*FALLTHROUGH*/ ++ case AuWbrCreate_MFS: ++ case AuWbrCreate_PMFS: ++ create->mfs_second = AUFS_MFS_DEF_SEC; ++ break; ++ case AuWbrCreate_MFSV: ++ case AuWbrCreate_PMFSV: ++ e = au_wbr_mfs_sec(&args[0], str, create); ++ if (unlikely(e)) ++ err = e; ++ break; ++ } ++ ++ return err; ++} ++ ++const char *au_optstr_wbr_create(int wbr_create) ++{ ++ return au_parser_pattern(wbr_create, au_wbr_create_policy); ++} ++ ++static match_table_t au_wbr_copyup_policy = { ++ {AuWbrCopyup_TDP, "tdp"}, ++ {AuWbrCopyup_TDP, "top-down-parent"}, ++ {AuWbrCopyup_BUP, "bup"}, ++ {AuWbrCopyup_BUP, "bottom-up-parent"}, ++ {AuWbrCopyup_BU, "bu"}, ++ {AuWbrCopyup_BU, "bottom-up"}, ++ {-1, NULL} ++}; ++ ++static int noinline_for_stack au_wbr_copyup_val(char *str) ++{ ++ substring_t args[MAX_OPT_ARGS]; ++ ++ return match_token(str, au_wbr_copyup_policy, args); ++} ++ ++const char *au_optstr_wbr_copyup(int wbr_copyup) ++{ ++ return au_parser_pattern(wbr_copyup, au_wbr_copyup_policy); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static const int lkup_dirflags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY; ++ ++static void dump_opts(struct au_opts *opts) ++{ ++#ifdef CONFIG_AUFS_DEBUG ++ /* reduce stack space */ ++ union { ++ struct au_opt_add *add; ++ struct au_opt_del *del; ++ struct au_opt_mod *mod; ++ struct au_opt_xino *xino; ++ struct au_opt_xino_itrunc *xino_itrunc; ++ struct au_opt_wbr_create *create; ++ } u; ++ struct au_opt *opt; ++ ++ opt = opts->opt; ++ while (opt->type != Opt_tail) { ++ switch (opt->type) { ++ case Opt_add: ++ u.add = &opt->add; ++ AuDbg("add {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->pathname, u.add->perm, ++ u.add->path.dentry); ++ break; ++ case Opt_del: ++ case Opt_idel: ++ u.del = &opt->del; ++ AuDbg("del {%s, %p}\n", ++ u.del->pathname, u.del->h_path.dentry); ++ break; ++ case Opt_mod: ++ case Opt_imod: ++ u.mod = &opt->mod; ++ AuDbg("mod {%s, 0x%x, %p}\n", ++ u.mod->path, u.mod->perm, u.mod->h_root); ++ break; ++ case Opt_append: ++ u.add = &opt->add; ++ AuDbg("append {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->pathname, u.add->perm, ++ u.add->path.dentry); ++ break; ++ case Opt_prepend: ++ u.add = &opt->add; ++ AuDbg("prepend {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->pathname, u.add->perm, ++ u.add->path.dentry); ++ break; ++ case Opt_dirwh: ++ AuDbg("dirwh %d\n", opt->dirwh); ++ break; ++ case Opt_rdcache: ++ AuDbg("rdcache %d\n", opt->rdcache); ++ break; ++ case Opt_rdblk: ++ AuDbg("rdblk %u\n", opt->rdblk); ++ break; ++ case Opt_rdblk_def: ++ AuDbg("rdblk_def\n"); ++ break; ++ case Opt_rdhash: ++ AuDbg("rdhash %u\n", opt->rdhash); ++ break; ++ case Opt_rdhash_def: ++ AuDbg("rdhash_def\n"); ++ break; ++ case Opt_xino: ++ u.xino = &opt->xino; ++ AuDbg("xino {%s %pD}\n", u.xino->path, u.xino->file); ++ break; ++ case Opt_trunc_xino: ++ AuLabel(trunc_xino); ++ break; ++ case Opt_notrunc_xino: ++ AuLabel(notrunc_xino); ++ break; ++ case Opt_trunc_xino_path: ++ case Opt_itrunc_xino: ++ u.xino_itrunc = &opt->xino_itrunc; ++ AuDbg("trunc_xino %d\n", u.xino_itrunc->bindex); ++ break; ++ case Opt_noxino: ++ AuLabel(noxino); ++ break; ++ case Opt_trunc_xib: ++ AuLabel(trunc_xib); ++ break; ++ case Opt_notrunc_xib: ++ AuLabel(notrunc_xib); ++ break; ++ case Opt_shwh: ++ AuLabel(shwh); ++ break; ++ case Opt_noshwh: ++ AuLabel(noshwh); ++ break; ++ case Opt_dirperm1: ++ AuLabel(dirperm1); ++ break; ++ case Opt_nodirperm1: ++ AuLabel(nodirperm1); ++ break; ++ case Opt_plink: ++ AuLabel(plink); ++ break; ++ case Opt_noplink: ++ AuLabel(noplink); ++ break; ++ case Opt_list_plink: ++ AuLabel(list_plink); ++ break; ++ case Opt_udba: ++ AuDbg("udba %d, %s\n", ++ opt->udba, au_optstr_udba(opt->udba)); ++ break; ++ case Opt_dio: ++ AuLabel(dio); ++ break; ++ case Opt_nodio: ++ AuLabel(nodio); ++ break; ++ case Opt_diropq_a: ++ AuLabel(diropq_a); ++ break; ++ case Opt_diropq_w: ++ AuLabel(diropq_w); ++ break; ++ case Opt_warn_perm: ++ AuLabel(warn_perm); ++ break; ++ case Opt_nowarn_perm: ++ AuLabel(nowarn_perm); ++ break; ++ case Opt_verbose: ++ AuLabel(verbose); ++ break; ++ case Opt_noverbose: ++ AuLabel(noverbose); ++ break; ++ case Opt_sum: ++ AuLabel(sum); ++ break; ++ case Opt_nosum: ++ AuLabel(nosum); ++ break; ++ case Opt_wsum: ++ AuLabel(wsum); ++ break; ++ case Opt_wbr_create: ++ u.create = &opt->wbr_create; ++ AuDbg("create %d, %s\n", u.create->wbr_create, ++ au_optstr_wbr_create(u.create->wbr_create)); ++ switch (u.create->wbr_create) { ++ case AuWbrCreate_MFSV: ++ case AuWbrCreate_PMFSV: ++ AuDbg("%d sec\n", u.create->mfs_second); ++ break; ++ case AuWbrCreate_MFSRR: ++ case AuWbrCreate_TDMFS: ++ AuDbg("%llu watermark\n", ++ u.create->mfsrr_watermark); ++ break; ++ case AuWbrCreate_MFSRRV: ++ case AuWbrCreate_TDMFSV: ++ case AuWbrCreate_PMFSRRV: ++ AuDbg("%llu watermark, %d sec\n", ++ u.create->mfsrr_watermark, ++ u.create->mfs_second); ++ break; ++ } ++ break; ++ case Opt_wbr_copyup: ++ AuDbg("copyup %d, %s\n", opt->wbr_copyup, ++ au_optstr_wbr_copyup(opt->wbr_copyup)); ++ break; ++ case Opt_fhsm_sec: ++ AuDbg("fhsm_sec %u\n", opt->fhsm_second); ++ break; ++ case Opt_dirren: ++ AuLabel(dirren); ++ break; ++ case Opt_nodirren: ++ AuLabel(nodirren); ++ break; ++ case Opt_acl: ++ AuLabel(acl); ++ break; ++ case Opt_noacl: ++ AuLabel(noacl); ++ break; ++ default: ++ BUG(); ++ } ++ opt++; ++ } ++#endif ++} ++ ++void au_opts_free(struct au_opts *opts) ++{ ++ struct au_opt *opt; ++ ++ opt = opts->opt; ++ while (opt->type != Opt_tail) { ++ switch (opt->type) { ++ case Opt_add: ++ case Opt_append: ++ case Opt_prepend: ++ path_put(&opt->add.path); ++ break; ++ case Opt_del: ++ case Opt_idel: ++ path_put(&opt->del.h_path); ++ break; ++ case Opt_mod: ++ case Opt_imod: ++ dput(opt->mod.h_root); ++ break; ++ case Opt_xino: ++ fput(opt->xino.file); ++ break; ++ } ++ opt++; ++ } ++} ++ ++static int opt_add(struct au_opt *opt, char *opt_str, unsigned long sb_flags, ++ aufs_bindex_t bindex) ++{ ++ int err; ++ struct au_opt_add *add = &opt->add; ++ char *p; ++ ++ add->bindex = bindex; ++ add->perm = AuBrPerm_RO; ++ add->pathname = opt_str; ++ p = strchr(opt_str, '='); ++ if (p) { ++ *p++ = 0; ++ if (*p) ++ add->perm = br_perm_val(p); ++ } ++ ++ err = vfsub_kern_path(add->pathname, lkup_dirflags, &add->path); ++ if (!err) { ++ if (!p) { ++ add->perm = AuBrPerm_RO; ++ if (au_test_fs_rr(add->path.dentry->d_sb)) ++ add->perm = AuBrPerm_RR; ++ else if (!bindex && !(sb_flags & SB_RDONLY)) ++ add->perm = AuBrPerm_RW; ++ } ++ opt->type = Opt_add; ++ goto out; ++ } ++ pr_err("lookup failed %s (%d)\n", add->pathname, err); ++ err = -EINVAL; ++ ++out: ++ return err; ++} ++ ++static int au_opts_parse_del(struct au_opt_del *del, substring_t args[]) ++{ ++ int err; ++ ++ del->pathname = args[0].from; ++ AuDbg("del path %s\n", del->pathname); ++ ++ err = vfsub_kern_path(del->pathname, lkup_dirflags, &del->h_path); ++ if (unlikely(err)) ++ pr_err("lookup failed %s (%d)\n", del->pathname, err); ++ ++ return err; ++} ++ ++#if 0 /* reserved for future use */ ++static int au_opts_parse_idel(struct super_block *sb, aufs_bindex_t bindex, ++ struct au_opt_del *del, substring_t args[]) ++{ ++ int err; ++ struct dentry *root; ++ ++ err = -EINVAL; ++ root = sb->s_root; ++ aufs_read_lock(root, AuLock_FLUSH); ++ if (bindex < 0 || au_sbbot(sb) < bindex) { ++ pr_err("out of bounds, %d\n", bindex); ++ goto out; ++ } ++ ++ err = 0; ++ del->h_path.dentry = dget(au_h_dptr(root, bindex)); ++ del->h_path.mnt = mntget(au_sbr_mnt(sb, bindex)); ++ ++out: ++ aufs_read_unlock(root, !AuLock_IR); ++ return err; ++} ++#endif ++ ++static int noinline_for_stack ++au_opts_parse_mod(struct au_opt_mod *mod, substring_t args[]) ++{ ++ int err; ++ struct path path; ++ char *p; ++ ++ err = -EINVAL; ++ mod->path = args[0].from; ++ p = strchr(mod->path, '='); ++ if (unlikely(!p)) { ++ pr_err("no permission %s\n", args[0].from); ++ goto out; ++ } ++ ++ *p++ = 0; ++ err = vfsub_kern_path(mod->path, lkup_dirflags, &path); ++ if (unlikely(err)) { ++ pr_err("lookup failed %s (%d)\n", mod->path, err); ++ goto out; ++ } ++ ++ mod->perm = br_perm_val(p); ++ AuDbg("mod path %s, perm 0x%x, %s\n", mod->path, mod->perm, p); ++ mod->h_root = dget(path.dentry); ++ path_put(&path); ++ ++out: ++ return err; ++} ++ ++#if 0 /* reserved for future use */ ++static int au_opts_parse_imod(struct super_block *sb, aufs_bindex_t bindex, ++ struct au_opt_mod *mod, substring_t args[]) ++{ ++ int err; ++ struct dentry *root; ++ ++ err = -EINVAL; ++ root = sb->s_root; ++ aufs_read_lock(root, AuLock_FLUSH); ++ if (bindex < 0 || au_sbbot(sb) < bindex) { ++ pr_err("out of bounds, %d\n", bindex); ++ goto out; ++ } ++ ++ err = 0; ++ mod->perm = br_perm_val(args[1].from); ++ AuDbg("mod path %s, perm 0x%x, %s\n", ++ mod->path, mod->perm, args[1].from); ++ mod->h_root = dget(au_h_dptr(root, bindex)); ++ ++out: ++ aufs_read_unlock(root, !AuLock_IR); ++ return err; ++} ++#endif ++ ++static int au_opts_parse_xino(struct super_block *sb, struct au_opt_xino *xino, ++ substring_t args[]) ++{ ++ int err; ++ struct file *file; ++ ++ file = au_xino_create(sb, args[0].from, /*silent*/0, /*wbrtop*/0); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ ++ err = -EINVAL; ++ if (unlikely(file->f_path.dentry->d_sb == sb)) { ++ fput(file); ++ pr_err("%s must be outside\n", args[0].from); ++ goto out; ++ } ++ ++ err = 0; ++ xino->file = file; ++ xino->path = args[0].from; ++ ++out: ++ return err; ++} ++ ++static int noinline_for_stack ++au_opts_parse_xino_itrunc_path(struct super_block *sb, ++ struct au_opt_xino_itrunc *xino_itrunc, ++ substring_t args[]) ++{ ++ int err; ++ aufs_bindex_t bbot, bindex; ++ struct path path; ++ struct dentry *root; ++ ++ err = vfsub_kern_path(args[0].from, lkup_dirflags, &path); ++ if (unlikely(err)) { ++ pr_err("lookup failed %s (%d)\n", args[0].from, err); ++ goto out; ++ } ++ ++ xino_itrunc->bindex = -1; ++ root = sb->s_root; ++ aufs_read_lock(root, AuLock_FLUSH); ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ if (au_h_dptr(root, bindex) == path.dentry) { ++ xino_itrunc->bindex = bindex; ++ break; ++ } ++ } ++ aufs_read_unlock(root, !AuLock_IR); ++ path_put(&path); ++ ++ if (unlikely(xino_itrunc->bindex < 0)) { ++ pr_err("no such branch %s\n", args[0].from); ++ err = -EINVAL; ++ } ++ ++out: ++ return err; ++} ++ ++/* called without aufs lock */ ++int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts) ++{ ++ int err, n, token; ++ aufs_bindex_t bindex; ++ unsigned char skipped; ++ struct dentry *root; ++ struct au_opt *opt, *opt_tail; ++ char *opt_str; ++ /* reduce the stack space */ ++ union { ++ struct au_opt_xino_itrunc *xino_itrunc; ++ struct au_opt_wbr_create *create; ++ } u; ++ struct { ++ substring_t args[MAX_OPT_ARGS]; ++ } *a; ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ root = sb->s_root; ++ err = 0; ++ bindex = 0; ++ opt = opts->opt; ++ opt_tail = opt + opts->max_opt - 1; ++ opt->type = Opt_tail; ++ while (!err && (opt_str = strsep(&str, ",")) && *opt_str) { ++ err = -EINVAL; ++ skipped = 0; ++ token = match_token(opt_str, options, a->args); ++ switch (token) { ++ case Opt_br: ++ err = 0; ++ while (!err && (opt_str = strsep(&a->args[0].from, ":")) ++ && *opt_str) { ++ err = opt_add(opt, opt_str, opts->sb_flags, ++ bindex++); ++ if (unlikely(!err && ++opt > opt_tail)) { ++ err = -E2BIG; ++ break; ++ } ++ opt->type = Opt_tail; ++ skipped = 1; ++ } ++ break; ++ case Opt_add: ++ if (unlikely(match_int(&a->args[0], &n))) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ bindex = n; ++ err = opt_add(opt, a->args[1].from, opts->sb_flags, ++ bindex); ++ if (!err) ++ opt->type = token; ++ break; ++ case Opt_append: ++ err = opt_add(opt, a->args[0].from, opts->sb_flags, ++ /*dummy bindex*/1); ++ if (!err) ++ opt->type = token; ++ break; ++ case Opt_prepend: ++ err = opt_add(opt, a->args[0].from, opts->sb_flags, ++ /*bindex*/0); ++ if (!err) ++ opt->type = token; ++ break; ++ case Opt_del: ++ err = au_opts_parse_del(&opt->del, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++#if 0 /* reserved for future use */ ++ case Opt_idel: ++ del->pathname = "(indexed)"; ++ if (unlikely(match_int(&args[0], &n))) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ err = au_opts_parse_idel(sb, n, &opt->del, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++#endif ++ case Opt_mod: ++ err = au_opts_parse_mod(&opt->mod, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++#ifdef IMOD /* reserved for future use */ ++ case Opt_imod: ++ u.mod->path = "(indexed)"; ++ if (unlikely(match_int(&a->args[0], &n))) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ err = au_opts_parse_imod(sb, n, &opt->mod, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++#endif ++ case Opt_xino: ++ err = au_opts_parse_xino(sb, &opt->xino, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++ ++ case Opt_trunc_xino_path: ++ err = au_opts_parse_xino_itrunc_path ++ (sb, &opt->xino_itrunc, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++ ++ case Opt_itrunc_xino: ++ u.xino_itrunc = &opt->xino_itrunc; ++ if (unlikely(match_int(&a->args[0], &n))) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ u.xino_itrunc->bindex = n; ++ aufs_read_lock(root, AuLock_FLUSH); ++ if (n < 0 || au_sbbot(sb) < n) { ++ pr_err("out of bounds, %d\n", n); ++ aufs_read_unlock(root, !AuLock_IR); ++ break; ++ } ++ aufs_read_unlock(root, !AuLock_IR); ++ err = 0; ++ opt->type = token; ++ break; ++ ++ case Opt_dirwh: ++ if (unlikely(match_int(&a->args[0], &opt->dirwh))) ++ break; ++ err = 0; ++ opt->type = token; ++ break; ++ ++ case Opt_rdcache: ++ if (unlikely(match_int(&a->args[0], &n))) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ if (unlikely(n > AUFS_RDCACHE_MAX)) { ++ pr_err("rdcache must be smaller than %d\n", ++ AUFS_RDCACHE_MAX); ++ break; ++ } ++ opt->rdcache = n; ++ err = 0; ++ opt->type = token; ++ break; ++ case Opt_rdblk: ++ if (unlikely(match_int(&a->args[0], &n) ++ || n < 0 ++ || n > KMALLOC_MAX_SIZE)) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ if (unlikely(n && n < NAME_MAX)) { ++ pr_err("rdblk must be larger than %d\n", ++ NAME_MAX); ++ break; ++ } ++ opt->rdblk = n; ++ err = 0; ++ opt->type = token; ++ break; ++ case Opt_rdhash: ++ if (unlikely(match_int(&a->args[0], &n) ++ || n < 0 ++ || n * sizeof(struct hlist_head) ++ > KMALLOC_MAX_SIZE)) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ opt->rdhash = n; ++ err = 0; ++ opt->type = token; ++ break; ++ ++ case Opt_trunc_xino: ++ case Opt_notrunc_xino: ++ case Opt_noxino: ++ case Opt_trunc_xib: ++ case Opt_notrunc_xib: ++ case Opt_shwh: ++ case Opt_noshwh: ++ case Opt_dirperm1: ++ case Opt_nodirperm1: ++ case Opt_plink: ++ case Opt_noplink: ++ case Opt_list_plink: ++ case Opt_dio: ++ case Opt_nodio: ++ case Opt_diropq_a: ++ case Opt_diropq_w: ++ case Opt_warn_perm: ++ case Opt_nowarn_perm: ++ case Opt_verbose: ++ case Opt_noverbose: ++ case Opt_sum: ++ case Opt_nosum: ++ case Opt_wsum: ++ case Opt_rdblk_def: ++ case Opt_rdhash_def: ++ case Opt_dirren: ++ case Opt_nodirren: ++ case Opt_acl: ++ case Opt_noacl: ++ err = 0; ++ opt->type = token; ++ break; ++ ++ case Opt_udba: ++ opt->udba = udba_val(a->args[0].from); ++ if (opt->udba >= 0) { ++ err = 0; ++ opt->type = token; ++ } else ++ pr_err("wrong value, %s\n", opt_str); ++ break; ++ ++ case Opt_wbr_create: ++ u.create = &opt->wbr_create; ++ u.create->wbr_create ++ = au_wbr_create_val(a->args[0].from, u.create); ++ if (u.create->wbr_create >= 0) { ++ err = 0; ++ opt->type = token; ++ } else ++ pr_err("wrong value, %s\n", opt_str); ++ break; ++ case Opt_wbr_copyup: ++ opt->wbr_copyup = au_wbr_copyup_val(a->args[0].from); ++ if (opt->wbr_copyup >= 0) { ++ err = 0; ++ opt->type = token; ++ } else ++ pr_err("wrong value, %s\n", opt_str); ++ break; ++ ++ case Opt_fhsm_sec: ++ if (unlikely(match_int(&a->args[0], &n) ++ || n < 0)) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ if (sysaufs_brs) { ++ opt->fhsm_second = n; ++ opt->type = token; ++ } else ++ pr_warn("ignored %s\n", opt_str); ++ err = 0; ++ break; ++ ++ case Opt_ignore: ++ pr_warn("ignored %s\n", opt_str); ++ /*FALLTHROUGH*/ ++ case Opt_ignore_silent: ++ skipped = 1; ++ err = 0; ++ break; ++ case Opt_err: ++ pr_err("unknown option %s\n", opt_str); ++ break; ++ } ++ ++ if (!err && !skipped) { ++ if (unlikely(++opt > opt_tail)) { ++ err = -E2BIG; ++ opt--; ++ opt->type = Opt_tail; ++ break; ++ } ++ opt->type = Opt_tail; ++ } ++ } ++ ++ au_kfree_rcu(a); ++ dump_opts(opts); ++ if (unlikely(err)) ++ au_opts_free(opts); ++ ++out: ++ return err; ++} ++ ++static int au_opt_wbr_create(struct super_block *sb, ++ struct au_opt_wbr_create *create) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ err = 1; /* handled */ ++ sbinfo = au_sbi(sb); ++ if (sbinfo->si_wbr_create_ops->fin) { ++ err = sbinfo->si_wbr_create_ops->fin(sb); ++ if (!err) ++ err = 1; ++ } ++ ++ sbinfo->si_wbr_create = create->wbr_create; ++ sbinfo->si_wbr_create_ops = au_wbr_create_ops + create->wbr_create; ++ switch (create->wbr_create) { ++ case AuWbrCreate_MFSRRV: ++ case AuWbrCreate_MFSRR: ++ case AuWbrCreate_TDMFS: ++ case AuWbrCreate_TDMFSV: ++ case AuWbrCreate_PMFSRR: ++ case AuWbrCreate_PMFSRRV: ++ sbinfo->si_wbr_mfs.mfsrr_watermark = create->mfsrr_watermark; ++ /*FALLTHROUGH*/ ++ case AuWbrCreate_MFS: ++ case AuWbrCreate_MFSV: ++ case AuWbrCreate_PMFS: ++ case AuWbrCreate_PMFSV: ++ sbinfo->si_wbr_mfs.mfs_expire ++ = msecs_to_jiffies(create->mfs_second * MSEC_PER_SEC); ++ break; ++ } ++ ++ if (sbinfo->si_wbr_create_ops->init) ++ sbinfo->si_wbr_create_ops->init(sb); /* ignore */ ++ ++ return err; ++} ++ ++/* ++ * returns, ++ * plus: processed without an error ++ * zero: unprocessed ++ */ ++static int au_opt_simple(struct super_block *sb, struct au_opt *opt, ++ struct au_opts *opts) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ err = 1; /* handled */ ++ sbinfo = au_sbi(sb); ++ switch (opt->type) { ++ case Opt_udba: ++ sbinfo->si_mntflags &= ~AuOptMask_UDBA; ++ sbinfo->si_mntflags |= opt->udba; ++ opts->given_udba |= opt->udba; ++ break; ++ ++ case Opt_plink: ++ au_opt_set(sbinfo->si_mntflags, PLINK); ++ break; ++ case Opt_noplink: ++ if (au_opt_test(sbinfo->si_mntflags, PLINK)) ++ au_plink_put(sb, /*verbose*/1); ++ au_opt_clr(sbinfo->si_mntflags, PLINK); ++ break; ++ case Opt_list_plink: ++ if (au_opt_test(sbinfo->si_mntflags, PLINK)) ++ au_plink_list(sb); ++ break; ++ ++ case Opt_dio: ++ au_opt_set(sbinfo->si_mntflags, DIO); ++ au_fset_opts(opts->flags, REFRESH_DYAOP); ++ break; ++ case Opt_nodio: ++ au_opt_clr(sbinfo->si_mntflags, DIO); ++ au_fset_opts(opts->flags, REFRESH_DYAOP); ++ break; ++ ++ case Opt_fhsm_sec: ++ au_fhsm_set(sbinfo, opt->fhsm_second); ++ break; ++ ++ case Opt_diropq_a: ++ au_opt_set(sbinfo->si_mntflags, ALWAYS_DIROPQ); ++ break; ++ case Opt_diropq_w: ++ au_opt_clr(sbinfo->si_mntflags, ALWAYS_DIROPQ); ++ break; ++ ++ case Opt_warn_perm: ++ au_opt_set(sbinfo->si_mntflags, WARN_PERM); ++ break; ++ case Opt_nowarn_perm: ++ au_opt_clr(sbinfo->si_mntflags, WARN_PERM); ++ break; ++ ++ case Opt_verbose: ++ au_opt_set(sbinfo->si_mntflags, VERBOSE); ++ break; ++ case Opt_noverbose: ++ au_opt_clr(sbinfo->si_mntflags, VERBOSE); ++ break; ++ ++ case Opt_sum: ++ au_opt_set(sbinfo->si_mntflags, SUM); ++ break; ++ case Opt_wsum: ++ au_opt_clr(sbinfo->si_mntflags, SUM); ++ au_opt_set(sbinfo->si_mntflags, SUM_W); ++ break; ++ case Opt_nosum: ++ au_opt_clr(sbinfo->si_mntflags, SUM); ++ au_opt_clr(sbinfo->si_mntflags, SUM_W); ++ break; ++ ++ case Opt_wbr_create: ++ err = au_opt_wbr_create(sb, &opt->wbr_create); ++ break; ++ case Opt_wbr_copyup: ++ sbinfo->si_wbr_copyup = opt->wbr_copyup; ++ sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + opt->wbr_copyup; ++ break; ++ ++ case Opt_dirwh: ++ sbinfo->si_dirwh = opt->dirwh; ++ break; ++ ++ case Opt_rdcache: ++ sbinfo->si_rdcache ++ = msecs_to_jiffies(opt->rdcache * MSEC_PER_SEC); ++ break; ++ case Opt_rdblk: ++ sbinfo->si_rdblk = opt->rdblk; ++ break; ++ case Opt_rdblk_def: ++ sbinfo->si_rdblk = AUFS_RDBLK_DEF; ++ break; ++ case Opt_rdhash: ++ sbinfo->si_rdhash = opt->rdhash; ++ break; ++ case Opt_rdhash_def: ++ sbinfo->si_rdhash = AUFS_RDHASH_DEF; ++ break; ++ ++ case Opt_shwh: ++ au_opt_set(sbinfo->si_mntflags, SHWH); ++ break; ++ case Opt_noshwh: ++ au_opt_clr(sbinfo->si_mntflags, SHWH); ++ break; ++ ++ case Opt_dirperm1: ++ au_opt_set(sbinfo->si_mntflags, DIRPERM1); ++ break; ++ case Opt_nodirperm1: ++ au_opt_clr(sbinfo->si_mntflags, DIRPERM1); ++ break; ++ ++ case Opt_trunc_xino: ++ au_opt_set(sbinfo->si_mntflags, TRUNC_XINO); ++ break; ++ case Opt_notrunc_xino: ++ au_opt_clr(sbinfo->si_mntflags, TRUNC_XINO); ++ break; ++ ++ case Opt_trunc_xino_path: ++ case Opt_itrunc_xino: ++ err = au_xino_trunc(sb, opt->xino_itrunc.bindex, ++ /*idx_begin*/0); ++ if (!err) ++ err = 1; ++ break; ++ ++ case Opt_trunc_xib: ++ au_fset_opts(opts->flags, TRUNC_XIB); ++ break; ++ case Opt_notrunc_xib: ++ au_fclr_opts(opts->flags, TRUNC_XIB); ++ break; ++ ++ case Opt_dirren: ++ err = 1; ++ if (!au_opt_test(sbinfo->si_mntflags, DIRREN)) { ++ err = au_dr_opt_set(sb); ++ if (!err) ++ err = 1; ++ } ++ if (err == 1) ++ au_opt_set(sbinfo->si_mntflags, DIRREN); ++ break; ++ case Opt_nodirren: ++ err = 1; ++ if (au_opt_test(sbinfo->si_mntflags, DIRREN)) { ++ err = au_dr_opt_clr(sb, au_ftest_opts(opts->flags, ++ DR_FLUSHED)); ++ if (!err) ++ err = 1; ++ } ++ if (err == 1) ++ au_opt_clr(sbinfo->si_mntflags, DIRREN); ++ break; ++ ++ case Opt_acl: ++ sb->s_flags |= SB_POSIXACL; ++ break; ++ case Opt_noacl: ++ sb->s_flags &= ~SB_POSIXACL; ++ break; ++ ++ default: ++ err = 0; ++ break; ++ } ++ ++ return err; ++} ++ ++/* ++ * returns tri-state. ++ * plus: processed without an error ++ * zero: unprocessed ++ * minus: error ++ */ ++static int au_opt_br(struct super_block *sb, struct au_opt *opt, ++ struct au_opts *opts) ++{ ++ int err, do_refresh; ++ ++ err = 0; ++ switch (opt->type) { ++ case Opt_append: ++ opt->add.bindex = au_sbbot(sb) + 1; ++ if (opt->add.bindex < 0) ++ opt->add.bindex = 0; ++ goto add; ++ /* Always goto add, not fallthrough */ ++ case Opt_prepend: ++ opt->add.bindex = 0; ++ /* fallthrough */ ++ add: /* indented label */ ++ case Opt_add: ++ err = au_br_add(sb, &opt->add, ++ au_ftest_opts(opts->flags, REMOUNT)); ++ if (!err) { ++ err = 1; ++ au_fset_opts(opts->flags, REFRESH); ++ } ++ break; ++ ++ case Opt_del: ++ case Opt_idel: ++ err = au_br_del(sb, &opt->del, ++ au_ftest_opts(opts->flags, REMOUNT)); ++ if (!err) { ++ err = 1; ++ au_fset_opts(opts->flags, TRUNC_XIB); ++ au_fset_opts(opts->flags, REFRESH); ++ } ++ break; ++ ++ case Opt_mod: ++ case Opt_imod: ++ err = au_br_mod(sb, &opt->mod, ++ au_ftest_opts(opts->flags, REMOUNT), ++ &do_refresh); ++ if (!err) { ++ err = 1; ++ if (do_refresh) ++ au_fset_opts(opts->flags, REFRESH); ++ } ++ break; ++ } ++ return err; ++} ++ ++static int au_opt_xino(struct super_block *sb, struct au_opt *opt, ++ struct au_opt_xino **opt_xino, ++ struct au_opts *opts) ++{ ++ int err; ++ ++ err = 0; ++ switch (opt->type) { ++ case Opt_xino: ++ err = au_xino_set(sb, &opt->xino, ++ !!au_ftest_opts(opts->flags, REMOUNT)); ++ if (unlikely(err)) ++ break; ++ ++ *opt_xino = &opt->xino; ++ break; ++ ++ case Opt_noxino: ++ au_xino_clr(sb); ++ *opt_xino = (void *)-1; ++ break; ++ } ++ ++ return err; ++} ++ ++int au_opts_verify(struct super_block *sb, unsigned long sb_flags, ++ unsigned int pending) ++{ ++ int err, fhsm; ++ aufs_bindex_t bindex, bbot; ++ unsigned char do_plink, skip, do_free, can_no_dreval; ++ struct au_branch *br; ++ struct au_wbr *wbr; ++ struct dentry *root, *dentry; ++ struct inode *dir, *h_dir; ++ struct au_sbinfo *sbinfo; ++ struct au_hinode *hdir; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!(sbinfo->si_mntflags & AuOptMask_UDBA)); ++ ++ if (!(sb_flags & SB_RDONLY)) { ++ if (unlikely(!au_br_writable(au_sbr_perm(sb, 0)))) ++ pr_warn("first branch should be rw\n"); ++ if (unlikely(au_opt_test(sbinfo->si_mntflags, SHWH))) ++ pr_warn_once("shwh should be used with ro\n"); ++ } ++ ++ if (au_opt_test((sbinfo->si_mntflags | pending), UDBA_HNOTIFY) ++ && !au_opt_test(sbinfo->si_mntflags, XINO)) ++ pr_warn_once("udba=*notify requires xino\n"); ++ ++ if (au_opt_test(sbinfo->si_mntflags, DIRPERM1)) ++ pr_warn_once("dirperm1 breaks the protection" ++ " by the permission bits on the lower branch\n"); ++ ++ err = 0; ++ fhsm = 0; ++ root = sb->s_root; ++ dir = d_inode(root); ++ do_plink = !!au_opt_test(sbinfo->si_mntflags, PLINK); ++ can_no_dreval = !!au_opt_test((sbinfo->si_mntflags | pending), ++ UDBA_NONE); ++ bbot = au_sbbot(sb); ++ for (bindex = 0; !err && bindex <= bbot; bindex++) { ++ skip = 0; ++ h_dir = au_h_iptr(dir, bindex); ++ br = au_sbr(sb, bindex); ++ ++ if ((br->br_perm & AuBrAttr_ICEX) ++ && !h_dir->i_op->listxattr) ++ br->br_perm &= ~AuBrAttr_ICEX; ++#if 0 ++ if ((br->br_perm & AuBrAttr_ICEX_SEC) ++ && (au_br_sb(br)->s_flags & SB_NOSEC)) ++ br->br_perm &= ~AuBrAttr_ICEX_SEC; ++#endif ++ ++ do_free = 0; ++ wbr = br->br_wbr; ++ if (wbr) ++ wbr_wh_read_lock(wbr); ++ ++ if (!au_br_writable(br->br_perm)) { ++ do_free = !!wbr; ++ skip = (!wbr ++ || (!wbr->wbr_whbase ++ && !wbr->wbr_plink ++ && !wbr->wbr_orph)); ++ } else if (!au_br_wh_linkable(br->br_perm)) { ++ /* skip = (!br->br_whbase && !br->br_orph); */ ++ skip = (!wbr || !wbr->wbr_whbase); ++ if (skip && wbr) { ++ if (do_plink) ++ skip = !!wbr->wbr_plink; ++ else ++ skip = !wbr->wbr_plink; ++ } ++ } else { ++ /* skip = (br->br_whbase && br->br_ohph); */ ++ skip = (wbr && wbr->wbr_whbase); ++ if (skip) { ++ if (do_plink) ++ skip = !!wbr->wbr_plink; ++ else ++ skip = !wbr->wbr_plink; ++ } ++ } ++ if (wbr) ++ wbr_wh_read_unlock(wbr); ++ ++ if (can_no_dreval) { ++ dentry = br->br_path.dentry; ++ spin_lock(&dentry->d_lock); ++ if (dentry->d_flags & ++ (DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE)) ++ can_no_dreval = 0; ++ spin_unlock(&dentry->d_lock); ++ } ++ ++ if (au_br_fhsm(br->br_perm)) { ++ fhsm++; ++ AuDebugOn(!br->br_fhsm); ++ } ++ ++ if (skip) ++ continue; ++ ++ hdir = au_hi(dir, bindex); ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ if (wbr) ++ wbr_wh_write_lock(wbr); ++ err = au_wh_init(br, sb); ++ if (wbr) ++ wbr_wh_write_unlock(wbr); ++ au_hn_inode_unlock(hdir); ++ ++ if (!err && do_free) { ++ au_kfree_rcu(wbr); ++ br->br_wbr = NULL; ++ } ++ } ++ ++ if (can_no_dreval) ++ au_fset_si(sbinfo, NO_DREVAL); ++ else ++ au_fclr_si(sbinfo, NO_DREVAL); ++ ++ if (fhsm >= 2) { ++ au_fset_si(sbinfo, FHSM); ++ for (bindex = bbot; bindex >= 0; bindex--) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm)) { ++ au_fhsm_set_bottom(sb, bindex); ++ break; ++ } ++ } ++ } else { ++ au_fclr_si(sbinfo, FHSM); ++ au_fhsm_set_bottom(sb, -1); ++ } ++ ++ return err; ++} ++ ++int au_opts_mount(struct super_block *sb, struct au_opts *opts) ++{ ++ int err; ++ unsigned int tmp; ++ aufs_bindex_t bindex, bbot; ++ struct au_opt *opt; ++ struct au_opt_xino *opt_xino, xino; ++ struct au_sbinfo *sbinfo; ++ struct au_branch *br; ++ struct inode *dir; ++ ++ SiMustWriteLock(sb); ++ ++ err = 0; ++ opt_xino = NULL; ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) ++ err = au_opt_simple(sb, opt++, opts); ++ if (err > 0) ++ err = 0; ++ else if (unlikely(err < 0)) ++ goto out; ++ ++ /* disable xino and udba temporary */ ++ sbinfo = au_sbi(sb); ++ tmp = sbinfo->si_mntflags; ++ au_opt_clr(sbinfo->si_mntflags, XINO); ++ au_opt_set_udba(sbinfo->si_mntflags, UDBA_REVAL); ++ ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) ++ err = au_opt_br(sb, opt++, opts); ++ if (err > 0) ++ err = 0; ++ else if (unlikely(err < 0)) ++ goto out; ++ ++ bbot = au_sbbot(sb); ++ if (unlikely(bbot < 0)) { ++ err = -EINVAL; ++ pr_err("no branches\n"); ++ goto out; ++ } ++ ++ if (au_opt_test(tmp, XINO)) ++ au_opt_set(sbinfo->si_mntflags, XINO); ++ opt = opts->opt; ++ while (!err && opt->type != Opt_tail) ++ err = au_opt_xino(sb, opt++, &opt_xino, opts); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_opts_verify(sb, sb->s_flags, tmp); ++ if (unlikely(err)) ++ goto out; ++ ++ /* restore xino */ ++ if (au_opt_test(tmp, XINO) && !opt_xino) { ++ xino.file = au_xino_def(sb); ++ err = PTR_ERR(xino.file); ++ if (IS_ERR(xino.file)) ++ goto out; ++ ++ err = au_xino_set(sb, &xino, /*remount*/0); ++ fput(xino.file); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ /* restore udba */ ++ tmp &= AuOptMask_UDBA; ++ sbinfo->si_mntflags &= ~AuOptMask_UDBA; ++ sbinfo->si_mntflags |= tmp; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ err = au_hnotify_reset_br(tmp, br, br->br_perm); ++ if (unlikely(err)) ++ AuIOErr("hnotify failed on br %d, %d, ignored\n", ++ bindex, err); ++ /* go on even if err */ ++ } ++ if (au_opt_test(tmp, UDBA_HNOTIFY)) { ++ dir = d_inode(sb->s_root); ++ au_hn_reset(dir, au_hi_flags(dir, /*isdir*/1) & ~AuHi_XINO); ++ } ++ ++out: ++ return err; ++} ++ ++int au_opts_remount(struct super_block *sb, struct au_opts *opts) ++{ ++ int err, rerr; ++ unsigned char no_dreval; ++ struct inode *dir; ++ struct au_opt_xino *opt_xino; ++ struct au_opt *opt; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ err = au_dr_opt_flush(sb); ++ if (unlikely(err)) ++ goto out; ++ au_fset_opts(opts->flags, DR_FLUSHED); ++ ++ dir = d_inode(sb->s_root); ++ sbinfo = au_sbi(sb); ++ opt_xino = NULL; ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) { ++ err = au_opt_simple(sb, opt, opts); ++ if (!err) ++ err = au_opt_br(sb, opt, opts); ++ if (!err) ++ err = au_opt_xino(sb, opt, &opt_xino, opts); ++ opt++; ++ } ++ if (err > 0) ++ err = 0; ++ AuTraceErr(err); ++ /* go on even err */ ++ ++ no_dreval = !!au_ftest_si(sbinfo, NO_DREVAL); ++ rerr = au_opts_verify(sb, opts->sb_flags, /*pending*/0); ++ if (unlikely(rerr && !err)) ++ err = rerr; ++ ++ if (no_dreval != !!au_ftest_si(sbinfo, NO_DREVAL)) ++ au_fset_opts(opts->flags, REFRESH_IDOP); ++ ++ if (au_ftest_opts(opts->flags, TRUNC_XIB)) { ++ rerr = au_xib_trunc(sb); ++ if (unlikely(rerr && !err)) ++ err = rerr; ++ } ++ ++ /* will be handled by the caller */ ++ if (!au_ftest_opts(opts->flags, REFRESH) ++ && (opts->given_udba ++ || au_opt_test(sbinfo->si_mntflags, XINO) ++ || au_ftest_opts(opts->flags, REFRESH_IDOP) ++ )) ++ au_fset_opts(opts->flags, REFRESH); ++ ++ AuDbg("status 0x%x\n", opts->flags); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++unsigned int au_opt_udba(struct super_block *sb) ++{ ++ return au_mntflags(sb) & AuOptMask_UDBA; ++} +diff -Nurp linux-5.4/fs/aufs/opts.h linux-5.4-aufs/fs/aufs/opts.h +--- linux-5.4/fs/aufs/opts.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/opts.h 2019-11-28 01:25:59.067925618 +0200 +@@ -0,0 +1,212 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * mount options/flags ++ */ ++ ++#ifndef __AUFS_OPTS_H__ ++#define __AUFS_OPTS_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++struct file; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* mount flags */ ++#define AuOpt_XINO 1 /* external inode number bitmap ++ and translation table */ ++#define AuOpt_TRUNC_XINO (1 << 1) /* truncate xino files */ ++#define AuOpt_UDBA_NONE (1 << 2) /* users direct branch access */ ++#define AuOpt_UDBA_REVAL (1 << 3) ++#define AuOpt_UDBA_HNOTIFY (1 << 4) ++#define AuOpt_SHWH (1 << 5) /* show whiteout */ ++#define AuOpt_PLINK (1 << 6) /* pseudo-link */ ++#define AuOpt_DIRPERM1 (1 << 7) /* ignore the lower dir's perm ++ bits */ ++#define AuOpt_ALWAYS_DIROPQ (1 << 9) /* policy to creating diropq */ ++#define AuOpt_SUM (1 << 10) /* summation for statfs(2) */ ++#define AuOpt_SUM_W (1 << 11) /* unimplemented */ ++#define AuOpt_WARN_PERM (1 << 12) /* warn when add-branch */ ++#define AuOpt_VERBOSE (1 << 13) /* print the cause of error */ ++#define AuOpt_DIO (1 << 14) /* direct io */ ++#define AuOpt_DIRREN (1 << 15) /* directory rename */ ++ ++#ifndef CONFIG_AUFS_HNOTIFY ++#undef AuOpt_UDBA_HNOTIFY ++#define AuOpt_UDBA_HNOTIFY 0 ++#endif ++#ifndef CONFIG_AUFS_DIRREN ++#undef AuOpt_DIRREN ++#define AuOpt_DIRREN 0 ++#endif ++#ifndef CONFIG_AUFS_SHWH ++#undef AuOpt_SHWH ++#define AuOpt_SHWH 0 ++#endif ++ ++#define AuOpt_Def (AuOpt_XINO \ ++ | AuOpt_UDBA_REVAL \ ++ | AuOpt_PLINK \ ++ /* | AuOpt_DIRPERM1 */ \ ++ | AuOpt_WARN_PERM) ++#define AuOptMask_UDBA (AuOpt_UDBA_NONE \ ++ | AuOpt_UDBA_REVAL \ ++ | AuOpt_UDBA_HNOTIFY) ++ ++#define au_opt_test(flags, name) (flags & AuOpt_##name) ++#define au_opt_set(flags, name) do { \ ++ BUILD_BUG_ON(AuOpt_##name & AuOptMask_UDBA); \ ++ ((flags) |= AuOpt_##name); \ ++} while (0) ++#define au_opt_set_udba(flags, name) do { \ ++ (flags) &= ~AuOptMask_UDBA; \ ++ ((flags) |= AuOpt_##name); \ ++} while (0) ++#define au_opt_clr(flags, name) do { \ ++ ((flags) &= ~AuOpt_##name); \ ++} while (0) ++ ++static inline unsigned int au_opts_plink(unsigned int mntflags) ++{ ++#ifdef CONFIG_PROC_FS ++ return mntflags; ++#else ++ return mntflags & ~AuOpt_PLINK; ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policies to select one among multiple writable branches */ ++enum { ++ AuWbrCreate_TDP, /* top down parent */ ++ AuWbrCreate_RR, /* round robin */ ++ AuWbrCreate_MFS, /* most free space */ ++ AuWbrCreate_MFSV, /* mfs with seconds */ ++ AuWbrCreate_MFSRR, /* mfs then rr */ ++ AuWbrCreate_MFSRRV, /* mfs then rr with seconds */ ++ AuWbrCreate_TDMFS, /* top down regardless parent and mfs */ ++ AuWbrCreate_TDMFSV, /* top down regardless parent and mfs */ ++ AuWbrCreate_PMFS, /* parent and mfs */ ++ AuWbrCreate_PMFSV, /* parent and mfs with seconds */ ++ AuWbrCreate_PMFSRR, /* parent, mfs and round-robin */ ++ AuWbrCreate_PMFSRRV, /* plus seconds */ ++ ++ AuWbrCreate_Def = AuWbrCreate_TDP ++}; ++ ++enum { ++ AuWbrCopyup_TDP, /* top down parent */ ++ AuWbrCopyup_BUP, /* bottom up parent */ ++ AuWbrCopyup_BU, /* bottom up */ ++ ++ AuWbrCopyup_Def = AuWbrCopyup_TDP ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_opt_add { ++ aufs_bindex_t bindex; ++ char *pathname; ++ int perm; ++ struct path path; ++}; ++ ++struct au_opt_del { ++ char *pathname; ++ struct path h_path; ++}; ++ ++struct au_opt_mod { ++ char *path; ++ int perm; ++ struct dentry *h_root; ++}; ++ ++struct au_opt_xino { ++ char *path; ++ struct file *file; ++}; ++ ++struct au_opt_xino_itrunc { ++ aufs_bindex_t bindex; ++}; ++ ++struct au_opt_wbr_create { ++ int wbr_create; ++ int mfs_second; ++ unsigned long long mfsrr_watermark; ++}; ++ ++struct au_opt { ++ int type; ++ union { ++ struct au_opt_xino xino; ++ struct au_opt_xino_itrunc xino_itrunc; ++ struct au_opt_add add; ++ struct au_opt_del del; ++ struct au_opt_mod mod; ++ int dirwh; ++ int rdcache; ++ unsigned int rdblk; ++ unsigned int rdhash; ++ int udba; ++ struct au_opt_wbr_create wbr_create; ++ int wbr_copyup; ++ unsigned int fhsm_second; ++ }; ++}; ++ ++/* opts flags */ ++#define AuOpts_REMOUNT 1 ++#define AuOpts_REFRESH (1 << 1) ++#define AuOpts_TRUNC_XIB (1 << 2) ++#define AuOpts_REFRESH_DYAOP (1 << 3) ++#define AuOpts_REFRESH_IDOP (1 << 4) ++#define AuOpts_DR_FLUSHED (1 << 5) ++#define au_ftest_opts(flags, name) ((flags) & AuOpts_##name) ++#define au_fset_opts(flags, name) \ ++ do { (flags) |= AuOpts_##name; } while (0) ++#define au_fclr_opts(flags, name) \ ++ do { (flags) &= ~AuOpts_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_DIRREN ++#undef AuOpts_DR_FLUSHED ++#define AuOpts_DR_FLUSHED 0 ++#endif ++ ++struct au_opts { ++ struct au_opt *opt; ++ int max_opt; ++ ++ unsigned int given_udba; ++ unsigned int flags; ++ unsigned long sb_flags; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* opts.c */ ++void au_optstr_br_perm(au_br_perm_str_t *str, int perm); ++const char *au_optstr_udba(int udba); ++const char *au_optstr_wbr_copyup(int wbr_copyup); ++const char *au_optstr_wbr_create(int wbr_create); ++ ++void au_opts_free(struct au_opts *opts); ++struct super_block; ++int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts); ++int au_opts_verify(struct super_block *sb, unsigned long sb_flags, ++ unsigned int pending); ++int au_opts_mount(struct super_block *sb, struct au_opts *opts); ++int au_opts_remount(struct super_block *sb, struct au_opts *opts); ++ ++unsigned int au_opt_udba(struct super_block *sb); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_OPTS_H__ */ +diff -Nurp linux-5.4/fs/aufs/plink.c linux-5.4-aufs/fs/aufs/plink.c +--- linux-5.4/fs/aufs/plink.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/plink.c 2019-11-28 01:25:59.067925618 +0200 +@@ -0,0 +1,503 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * pseudo-link ++ */ ++ ++#include "aufs.h" ++ ++/* ++ * the pseudo-link maintenance mode. ++ * during a user process maintains the pseudo-links, ++ * prohibit adding a new plink and branch manipulation. ++ * ++ * Flags ++ * NOPLM: ++ * For entry functions which will handle plink, and i_mutex is already held ++ * in VFS. ++ * They cannot wait and should return an error at once. ++ * Callers has to check the error. ++ * NOPLMW: ++ * For entry functions which will handle plink, but i_mutex is not held ++ * in VFS. ++ * They can wait the plink maintenance mode to finish. ++ * ++ * They behave like F_SETLK and F_SETLKW. ++ * If the caller never handle plink, then both flags are unnecessary. ++ */ ++ ++int au_plink_maint(struct super_block *sb, int flags) ++{ ++ int err; ++ pid_t pid, ppid; ++ struct task_struct *parent, *prev; ++ struct au_sbinfo *sbi; ++ ++ SiMustAnyLock(sb); ++ ++ err = 0; ++ if (!au_opt_test(au_mntflags(sb), PLINK)) ++ goto out; ++ ++ sbi = au_sbi(sb); ++ pid = sbi->si_plink_maint_pid; ++ if (!pid || pid == current->pid) ++ goto out; ++ ++ /* todo: it highly depends upon /sbin/mount.aufs */ ++ prev = NULL; ++ parent = current; ++ ppid = 0; ++ rcu_read_lock(); ++ while (1) { ++ parent = rcu_dereference(parent->real_parent); ++ if (parent == prev) ++ break; ++ ppid = task_pid_vnr(parent); ++ if (pid == ppid) { ++ rcu_read_unlock(); ++ goto out; ++ } ++ prev = parent; ++ } ++ rcu_read_unlock(); ++ ++ if (au_ftest_lock(flags, NOPLMW)) { ++ /* if there is no i_mutex lock in VFS, we don't need to wait */ ++ /* AuDebugOn(!lockdep_depth(current)); */ ++ while (sbi->si_plink_maint_pid) { ++ si_read_unlock(sb); ++ /* gave up wake_up_bit() */ ++ wait_event(sbi->si_plink_wq, !sbi->si_plink_maint_pid); ++ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&sbi->si_nowait); ++ si_noflush_read_lock(sb); ++ } ++ } else if (au_ftest_lock(flags, NOPLM)) { ++ AuDbg("ppid %d, pid %d\n", ppid, pid); ++ err = -EAGAIN; ++ } ++ ++out: ++ return err; ++} ++ ++void au_plink_maint_leave(struct au_sbinfo *sbinfo) ++{ ++ spin_lock(&sbinfo->si_plink_maint_lock); ++ sbinfo->si_plink_maint_pid = 0; ++ spin_unlock(&sbinfo->si_plink_maint_lock); ++ wake_up_all(&sbinfo->si_plink_wq); ++} ++ ++int au_plink_maint_enter(struct super_block *sb) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ /* make sure i am the only one in this fs */ ++ si_write_lock(sb, AuLock_FLUSH); ++ if (au_opt_test(au_mntflags(sb), PLINK)) { ++ spin_lock(&sbinfo->si_plink_maint_lock); ++ if (!sbinfo->si_plink_maint_pid) ++ sbinfo->si_plink_maint_pid = current->pid; ++ else ++ err = -EBUSY; ++ spin_unlock(&sbinfo->si_plink_maint_lock); ++ } ++ si_write_unlock(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_DEBUG ++void au_plink_list(struct super_block *sb) ++{ ++ int i; ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_icntnr *icntnr; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); ++ ++ for (i = 0; i < AuPlink_NHASH; i++) { ++ hbl = sbinfo->si_plink + i; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(icntnr, pos, hbl, plink) ++ AuDbg("%lu\n", icntnr->vfs_inode.i_ino); ++ hlist_bl_unlock(hbl); ++ } ++} ++#endif ++ ++/* is the inode pseudo-linked? */ ++int au_plink_test(struct inode *inode) ++{ ++ int found, i; ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_icntnr *icntnr; ++ ++ sbinfo = au_sbi(inode->i_sb); ++ AuRwMustAnyLock(&sbinfo->si_rwsem); ++ AuDebugOn(!au_opt_test(au_mntflags(inode->i_sb), PLINK)); ++ AuDebugOn(au_plink_maint(inode->i_sb, AuLock_NOPLM)); ++ ++ found = 0; ++ i = au_plink_hash(inode->i_ino); ++ hbl = sbinfo->si_plink + i; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(icntnr, pos, hbl, plink) ++ if (&icntnr->vfs_inode == inode) { ++ found = 1; ++ break; ++ } ++ hlist_bl_unlock(hbl); ++ return found; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * generate a name for plink. ++ * the file will be stored under AUFS_WH_PLINKDIR. ++ */ ++/* 20 is max digits length of ulong 64 */ ++#define PLINK_NAME_LEN ((20 + 1) * 2) ++ ++static int plink_name(char *name, int len, struct inode *inode, ++ aufs_bindex_t bindex) ++{ ++ int rlen; ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, bindex); ++ rlen = snprintf(name, len, "%lu.%lu", inode->i_ino, h_inode->i_ino); ++ return rlen; ++} ++ ++struct au_do_plink_lkup_args { ++ struct dentry **errp; ++ struct qstr *tgtname; ++ struct dentry *h_parent; ++ struct au_branch *br; ++}; ++ ++static struct dentry *au_do_plink_lkup(struct qstr *tgtname, ++ struct dentry *h_parent, ++ struct au_branch *br) ++{ ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ ++ h_inode = d_inode(h_parent); ++ inode_lock_shared_nested(h_inode, AuLsc_I_CHILD2); ++ h_dentry = vfsub_lkup_one(tgtname, h_parent); ++ inode_unlock_shared(h_inode); ++ return h_dentry; ++} ++ ++static void au_call_do_plink_lkup(void *args) ++{ ++ struct au_do_plink_lkup_args *a = args; ++ *a->errp = au_do_plink_lkup(a->tgtname, a->h_parent, a->br); ++} ++ ++/* lookup the plink-ed @inode under the branch at @bindex */ ++struct dentry *au_plink_lkup(struct inode *inode, aufs_bindex_t bindex) ++{ ++ struct dentry *h_dentry, *h_parent; ++ struct au_branch *br; ++ int wkq_err; ++ char a[PLINK_NAME_LEN]; ++ struct qstr tgtname = QSTR_INIT(a, 0); ++ ++ AuDebugOn(au_plink_maint(inode->i_sb, AuLock_NOPLM)); ++ ++ br = au_sbr(inode->i_sb, bindex); ++ h_parent = br->br_wbr->wbr_plink; ++ tgtname.len = plink_name(a, sizeof(a), inode, bindex); ++ ++ if (!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) { ++ struct au_do_plink_lkup_args args = { ++ .errp = &h_dentry, ++ .tgtname = &tgtname, ++ .h_parent = h_parent, ++ .br = br ++ }; ++ ++ wkq_err = au_wkq_wait(au_call_do_plink_lkup, &args); ++ if (unlikely(wkq_err)) ++ h_dentry = ERR_PTR(wkq_err); ++ } else ++ h_dentry = au_do_plink_lkup(&tgtname, h_parent, br); ++ ++ return h_dentry; ++} ++ ++/* create a pseudo-link */ ++static int do_whplink(struct qstr *tgt, struct dentry *h_parent, ++ struct dentry *h_dentry, struct au_branch *br) ++{ ++ int err; ++ struct path h_path = { ++ .mnt = au_br_mnt(br) ++ }; ++ struct inode *h_dir, *delegated; ++ ++ h_dir = d_inode(h_parent); ++ inode_lock_nested(h_dir, AuLsc_I_CHILD2); ++again: ++ h_path.dentry = vfsub_lkup_one(tgt, h_parent); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) ++ goto out; ++ ++ err = 0; ++ /* wh.plink dir is not monitored */ ++ /* todo: is it really safe? */ ++ if (d_is_positive(h_path.dentry) ++ && d_inode(h_path.dentry) != d_inode(h_dentry)) { ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, &h_path, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ dput(h_path.dentry); ++ h_path.dentry = NULL; ++ if (!err) ++ goto again; ++ } ++ if (!err && d_is_negative(h_path.dentry)) { ++ delegated = NULL; ++ err = vfsub_link(h_dentry, h_dir, &h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ } ++ dput(h_path.dentry); ++ ++out: ++ inode_unlock(h_dir); ++ return err; ++} ++ ++struct do_whplink_args { ++ int *errp; ++ struct qstr *tgt; ++ struct dentry *h_parent; ++ struct dentry *h_dentry; ++ struct au_branch *br; ++}; ++ ++static void call_do_whplink(void *args) ++{ ++ struct do_whplink_args *a = args; ++ *a->errp = do_whplink(a->tgt, a->h_parent, a->h_dentry, a->br); ++} ++ ++static int whplink(struct dentry *h_dentry, struct inode *inode, ++ aufs_bindex_t bindex, struct au_branch *br) ++{ ++ int err, wkq_err; ++ struct au_wbr *wbr; ++ struct dentry *h_parent; ++ char a[PLINK_NAME_LEN]; ++ struct qstr tgtname = QSTR_INIT(a, 0); ++ ++ wbr = au_sbr(inode->i_sb, bindex)->br_wbr; ++ h_parent = wbr->wbr_plink; ++ tgtname.len = plink_name(a, sizeof(a), inode, bindex); ++ ++ /* always superio. */ ++ if (!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) { ++ struct do_whplink_args args = { ++ .errp = &err, ++ .tgt = &tgtname, ++ .h_parent = h_parent, ++ .h_dentry = h_dentry, ++ .br = br ++ }; ++ wkq_err = au_wkq_wait(call_do_whplink, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } else ++ err = do_whplink(&tgtname, h_parent, h_dentry, br); ++ ++ return err; ++} ++ ++/* ++ * create a new pseudo-link for @h_dentry on @bindex. ++ * the linked inode is held in aufs @inode. ++ */ ++void au_plink_append(struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_dentry) ++{ ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_icntnr *icntnr; ++ int found, err, cnt, i; ++ ++ sb = inode->i_sb; ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); ++ ++ found = au_plink_test(inode); ++ if (found) ++ return; ++ ++ i = au_plink_hash(inode->i_ino); ++ hbl = sbinfo->si_plink + i; ++ au_igrab(inode); ++ ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(icntnr, pos, hbl, plink) { ++ if (&icntnr->vfs_inode == inode) { ++ found = 1; ++ break; ++ } ++ } ++ if (!found) { ++ icntnr = container_of(inode, struct au_icntnr, vfs_inode); ++ hlist_bl_add_head(&icntnr->plink, hbl); ++ } ++ hlist_bl_unlock(hbl); ++ if (!found) { ++ cnt = au_hbl_count(hbl); ++#define msg "unexpectedly unbalanced or too many pseudo-links" ++ if (cnt > AUFS_PLINK_WARN) ++ AuWarn1(msg ", %d\n", cnt); ++#undef msg ++ err = whplink(h_dentry, inode, bindex, au_sbr(sb, bindex)); ++ if (unlikely(err)) { ++ pr_warn("err %d, damaged pseudo link.\n", err); ++ au_hbl_del(&icntnr->plink, hbl); ++ iput(&icntnr->vfs_inode); ++ } ++ } else ++ iput(&icntnr->vfs_inode); ++} ++ ++/* free all plinks */ ++void au_plink_put(struct super_block *sb, int verbose) ++{ ++ int i, warned; ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos, *tmp; ++ struct au_icntnr *icntnr; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); ++ ++ /* no spin_lock since sbinfo is write-locked */ ++ warned = 0; ++ for (i = 0; i < AuPlink_NHASH; i++) { ++ hbl = sbinfo->si_plink + i; ++ if (!warned && verbose && !hlist_bl_empty(hbl)) { ++ pr_warn("pseudo-link is not flushed"); ++ warned = 1; ++ } ++ hlist_bl_for_each_entry_safe(icntnr, pos, tmp, hbl, plink) ++ iput(&icntnr->vfs_inode); ++ INIT_HLIST_BL_HEAD(hbl); ++ } ++} ++ ++void au_plink_clean(struct super_block *sb, int verbose) ++{ ++ struct dentry *root; ++ ++ root = sb->s_root; ++ aufs_write_lock(root); ++ if (au_opt_test(au_mntflags(sb), PLINK)) ++ au_plink_put(sb, verbose); ++ aufs_write_unlock(root); ++} ++ ++static int au_plink_do_half_refresh(struct inode *inode, aufs_bindex_t br_id) ++{ ++ int do_put; ++ aufs_bindex_t btop, bbot, bindex; ++ ++ do_put = 0; ++ btop = au_ibtop(inode); ++ bbot = au_ibbot(inode); ++ if (btop >= 0) { ++ for (bindex = btop; bindex <= bbot; bindex++) { ++ if (!au_h_iptr(inode, bindex) ++ || au_ii_br_id(inode, bindex) != br_id) ++ continue; ++ au_set_h_iptr(inode, bindex, NULL, 0); ++ do_put = 1; ++ break; ++ } ++ if (do_put) ++ for (bindex = btop; bindex <= bbot; bindex++) ++ if (au_h_iptr(inode, bindex)) { ++ do_put = 0; ++ break; ++ } ++ } else ++ do_put = 1; ++ ++ return do_put; ++} ++ ++/* free the plinks on a branch specified by @br_id */ ++void au_plink_half_refresh(struct super_block *sb, aufs_bindex_t br_id) ++{ ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos, *tmp; ++ struct au_icntnr *icntnr; ++ struct inode *inode; ++ int i, do_put; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!au_opt_test(au_mntflags(sb), PLINK)); ++ AuDebugOn(au_plink_maint(sb, AuLock_NOPLM)); ++ ++ /* no bit_lock since sbinfo is write-locked */ ++ for (i = 0; i < AuPlink_NHASH; i++) { ++ hbl = sbinfo->si_plink + i; ++ hlist_bl_for_each_entry_safe(icntnr, pos, tmp, hbl, plink) { ++ inode = au_igrab(&icntnr->vfs_inode); ++ ii_write_lock_child(inode); ++ do_put = au_plink_do_half_refresh(inode, br_id); ++ if (do_put) { ++ hlist_bl_del(&icntnr->plink); ++ iput(inode); ++ } ++ ii_write_unlock(inode); ++ iput(inode); ++ } ++ } ++} +diff -Nurp linux-5.4/fs/aufs/poll.c linux-5.4-aufs/fs/aufs/poll.c +--- linux-5.4/fs/aufs/poll.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/poll.c 2019-11-28 01:25:59.067925618 +0200 +@@ -0,0 +1,38 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * poll operation ++ * There is only one filesystem which implements ->poll operation, currently. ++ */ ++ ++#include "aufs.h" ++ ++__poll_t aufs_poll(struct file *file, struct poll_table_struct *pt) ++{ ++ __poll_t mask; ++ struct file *h_file; ++ struct super_block *sb; ++ ++ /* We should pretend an error happened. */ ++ mask = EPOLLERR /* | EPOLLIN | EPOLLOUT */; ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLMW); ++ ++ h_file = au_read_pre(file, /*keep_fi*/0, /*lsc*/0); ++ if (IS_ERR(h_file)) { ++ AuDbg("h_file %ld\n", PTR_ERR(h_file)); ++ goto out; ++ } ++ ++ mask = vfs_poll(h_file, pt); ++ fput(h_file); /* instead of au_read_post() */ ++ ++out: ++ si_read_unlock(sb); ++ if (mask & EPOLLERR) ++ AuDbg("mask 0x%x\n", mask); ++ return mask; ++} +diff -Nurp linux-5.4/fs/aufs/posix_acl.c linux-5.4-aufs/fs/aufs/posix_acl.c +--- linux-5.4/fs/aufs/posix_acl.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/posix_acl.c 2019-11-28 01:25:59.067925618 +0200 +@@ -0,0 +1,92 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2014-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * posix acl operations ++ */ ++ ++#include ++#include "aufs.h" ++ ++struct posix_acl *aufs_get_acl(struct inode *inode, int type) ++{ ++ struct posix_acl *acl; ++ int err; ++ aufs_bindex_t bindex; ++ struct inode *h_inode; ++ struct super_block *sb; ++ ++ acl = NULL; ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ ii_read_lock_child(inode); ++ if (!(sb->s_flags & SB_POSIXACL)) ++ goto out; ++ ++ bindex = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, bindex); ++ if (unlikely(!h_inode ++ || ((h_inode->i_mode & S_IFMT) ++ != (inode->i_mode & S_IFMT)))) { ++ err = au_busy_or_stale(); ++ acl = ERR_PTR(err); ++ goto out; ++ } ++ ++ /* always topmost only */ ++ acl = get_acl(h_inode, type); ++ if (IS_ERR(acl)) ++ forget_cached_acl(inode, type); ++ else ++ set_cached_acl(inode, type, acl); ++ ++out: ++ ii_read_unlock(inode); ++ si_read_unlock(sb); ++ ++ AuTraceErrPtr(acl); ++ return acl; ++} ++ ++int aufs_set_acl(struct inode *inode, struct posix_acl *acl, int type) ++{ ++ int err; ++ ssize_t ssz; ++ struct dentry *dentry; ++ struct au_sxattr arg = { ++ .type = AU_ACL_SET, ++ .u.acl_set = { ++ .acl = acl, ++ .type = type ++ }, ++ }; ++ ++ IMustLock(inode); ++ ++ if (inode->i_ino == AUFS_ROOT_INO) ++ dentry = dget(inode->i_sb->s_root); ++ else { ++ dentry = d_find_alias(inode); ++ if (!dentry) ++ dentry = d_find_any_alias(inode); ++ if (!dentry) { ++ pr_warn("cannot handle this inode, " ++ "please report to aufs-users ML\n"); ++ err = -ENOENT; ++ goto out; ++ } ++ } ++ ++ ssz = au_sxattr(dentry, inode, &arg); ++ /* forget even it if succeeds since the branch might set differently */ ++ forget_cached_acl(inode, type); ++ dput(dentry); ++ err = ssz; ++ if (ssz >= 0) ++ err = 0; ++ ++out: ++ return err; ++} +diff -Nurp linux-5.4/fs/aufs/procfs.c linux-5.4-aufs/fs/aufs/procfs.c +--- linux-5.4/fs/aufs/procfs.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/procfs.c 2019-11-28 01:25:59.067925618 +0200 +@@ -0,0 +1,158 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2010-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * procfs interfaces ++ */ ++ ++#include ++#include "aufs.h" ++ ++static int au_procfs_plm_release(struct inode *inode, struct file *file) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ sbinfo = file->private_data; ++ if (sbinfo) { ++ au_plink_maint_leave(sbinfo); ++ kobject_put(&sbinfo->si_kobj); ++ } ++ ++ return 0; ++} ++ ++static void au_procfs_plm_write_clean(struct file *file) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ sbinfo = file->private_data; ++ if (sbinfo) ++ au_plink_clean(sbinfo->si_sb, /*verbose*/0); ++} ++ ++static int au_procfs_plm_write_si(struct file *file, unsigned long id) ++{ ++ int err; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_node *pos; ++ ++ err = -EBUSY; ++ if (unlikely(file->private_data)) ++ goto out; ++ ++ sb = NULL; ++ /* don't use au_sbilist_lock() here */ ++ hlist_bl_lock(&au_sbilist); ++ hlist_bl_for_each_entry(sbinfo, pos, &au_sbilist, si_list) ++ if (id == sysaufs_si_id(sbinfo)) { ++ if (kobject_get_unless_zero(&sbinfo->si_kobj)) ++ sb = sbinfo->si_sb; ++ break; ++ } ++ hlist_bl_unlock(&au_sbilist); ++ ++ err = -EINVAL; ++ if (unlikely(!sb)) ++ goto out; ++ ++ err = au_plink_maint_enter(sb); ++ if (!err) ++ /* keep kobject_get() */ ++ file->private_data = sbinfo; ++ else ++ kobject_put(&sbinfo->si_kobj); ++out: ++ return err; ++} ++ ++/* ++ * Accept a valid "si=xxxx" only. ++ * Once it is accepted successfully, accept "clean" too. ++ */ ++static ssize_t au_procfs_plm_write(struct file *file, const char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ ssize_t err; ++ unsigned long id; ++ /* last newline is allowed */ ++ char buf[3 + sizeof(unsigned long) * 2 + 1]; ++ ++ err = -EACCES; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = -EINVAL; ++ if (unlikely(count > sizeof(buf))) ++ goto out; ++ ++ err = copy_from_user(buf, ubuf, count); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ goto out; ++ } ++ buf[count] = 0; ++ ++ err = -EINVAL; ++ if (!strcmp("clean", buf)) { ++ au_procfs_plm_write_clean(file); ++ goto out_success; ++ } else if (unlikely(strncmp("si=", buf, 3))) ++ goto out; ++ ++ err = kstrtoul(buf + 3, 16, &id); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_procfs_plm_write_si(file, id); ++ if (unlikely(err)) ++ goto out; ++ ++out_success: ++ err = count; /* success */ ++out: ++ return err; ++} ++ ++static const struct file_operations au_procfs_plm_fop = { ++ .write = au_procfs_plm_write, ++ .release = au_procfs_plm_release, ++ .owner = THIS_MODULE ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct proc_dir_entry *au_procfs_dir; ++ ++void au_procfs_fin(void) ++{ ++ remove_proc_entry(AUFS_PLINK_MAINT_NAME, au_procfs_dir); ++ remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL); ++} ++ ++int __init au_procfs_init(void) ++{ ++ int err; ++ struct proc_dir_entry *entry; ++ ++ err = -ENOMEM; ++ au_procfs_dir = proc_mkdir(AUFS_PLINK_MAINT_DIR, NULL); ++ if (unlikely(!au_procfs_dir)) ++ goto out; ++ ++ entry = proc_create(AUFS_PLINK_MAINT_NAME, S_IFREG | 0200, ++ au_procfs_dir, &au_procfs_plm_fop); ++ if (unlikely(!entry)) ++ goto out_dir; ++ ++ err = 0; ++ goto out; /* success */ ++ ++ ++out_dir: ++ remove_proc_entry(AUFS_PLINK_MAINT_DIR, NULL); ++out: ++ return err; ++} +diff -Nurp linux-5.4/fs/aufs/rdu.c linux-5.4-aufs/fs/aufs/rdu.c +--- linux-5.4/fs/aufs/rdu.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/rdu.c 2019-11-28 01:25:59.067925618 +0200 +@@ -0,0 +1,371 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * readdir in userspace. ++ */ ++ ++#include ++#include ++#include ++#include "aufs.h" ++ ++/* bits for struct aufs_rdu.flags */ ++#define AuRdu_CALLED 1 ++#define AuRdu_CONT (1 << 1) ++#define AuRdu_FULL (1 << 2) ++#define au_ftest_rdu(flags, name) ((flags) & AuRdu_##name) ++#define au_fset_rdu(flags, name) \ ++ do { (flags) |= AuRdu_##name; } while (0) ++#define au_fclr_rdu(flags, name) \ ++ do { (flags) &= ~AuRdu_##name; } while (0) ++ ++struct au_rdu_arg { ++ struct dir_context ctx; ++ struct aufs_rdu *rdu; ++ union au_rdu_ent_ul ent; ++ unsigned long end; ++ ++ struct super_block *sb; ++ int err; ++}; ++ ++static int au_rdu_fill(struct dir_context *ctx, const char *name, int nlen, ++ loff_t offset, u64 h_ino, unsigned int d_type) ++{ ++ int err, len; ++ struct au_rdu_arg *arg = container_of(ctx, struct au_rdu_arg, ctx); ++ struct aufs_rdu *rdu = arg->rdu; ++ struct au_rdu_ent ent; ++ ++ err = 0; ++ arg->err = 0; ++ au_fset_rdu(rdu->cookie.flags, CALLED); ++ len = au_rdu_len(nlen); ++ if (arg->ent.ul + len < arg->end) { ++ ent.ino = h_ino; ++ ent.bindex = rdu->cookie.bindex; ++ ent.type = d_type; ++ ent.nlen = nlen; ++ if (unlikely(nlen > AUFS_MAX_NAMELEN)) ++ ent.type = DT_UNKNOWN; ++ ++ /* unnecessary to support mmap_sem since this is a dir */ ++ err = -EFAULT; ++ if (copy_to_user(arg->ent.e, &ent, sizeof(ent))) ++ goto out; ++ if (copy_to_user(arg->ent.e->name, name, nlen)) ++ goto out; ++ /* the terminating NULL */ ++ if (__put_user(0, arg->ent.e->name + nlen)) ++ goto out; ++ err = 0; ++ /* AuDbg("%p, %.*s\n", arg->ent.p, nlen, name); */ ++ arg->ent.ul += len; ++ rdu->rent++; ++ } else { ++ err = -EFAULT; ++ au_fset_rdu(rdu->cookie.flags, FULL); ++ rdu->full = 1; ++ rdu->tail = arg->ent; ++ } ++ ++out: ++ /* AuTraceErr(err); */ ++ return err; ++} ++ ++static int au_rdu_do(struct file *h_file, struct au_rdu_arg *arg) ++{ ++ int err; ++ loff_t offset; ++ struct au_rdu_cookie *cookie = &arg->rdu->cookie; ++ ++ /* we don't have to care (FMODE_32BITHASH | FMODE_64BITHASH) for ext4 */ ++ offset = vfsub_llseek(h_file, cookie->h_pos, SEEK_SET); ++ err = offset; ++ if (unlikely(offset != cookie->h_pos)) ++ goto out; ++ ++ err = 0; ++ do { ++ arg->err = 0; ++ au_fclr_rdu(cookie->flags, CALLED); ++ /* smp_mb(); */ ++ err = vfsub_iterate_dir(h_file, &arg->ctx); ++ if (err >= 0) ++ err = arg->err; ++ } while (!err ++ && au_ftest_rdu(cookie->flags, CALLED) ++ && !au_ftest_rdu(cookie->flags, FULL)); ++ cookie->h_pos = h_file->f_pos; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_rdu(struct file *file, struct aufs_rdu *rdu) ++{ ++ int err; ++ aufs_bindex_t bbot; ++ struct au_rdu_arg arg = { ++ .ctx = { ++ .actor = au_rdu_fill ++ } ++ }; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct file *h_file; ++ struct au_rdu_cookie *cookie = &rdu->cookie; ++ ++ /* VERIFY_WRITE */ ++ err = !access_ok(rdu->ent.e, rdu->sz); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ rdu->rent = 0; ++ rdu->tail = rdu->ent; ++ rdu->full = 0; ++ arg.rdu = rdu; ++ arg.ent = rdu->ent; ++ arg.end = arg.ent.ul; ++ arg.end += rdu->sz; ++ ++ err = -ENOTDIR; ++ if (unlikely(!file->f_op->iterate && !file->f_op->iterate_shared)) ++ goto out; ++ ++ err = security_file_permission(file, MAY_READ); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out; ++ ++ dentry = file->f_path.dentry; ++ inode = d_inode(dentry); ++ inode_lock_shared(inode); ++ ++ arg.sb = inode->i_sb; ++ err = si_read_lock(arg.sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out_mtx; ++ err = au_alive_dir(dentry); ++ if (unlikely(err)) ++ goto out_si; ++ /* todo: reval? */ ++ fi_read_lock(file); ++ ++ err = -EAGAIN; ++ if (unlikely(au_ftest_rdu(cookie->flags, CONT) ++ && cookie->generation != au_figen(file))) ++ goto out_unlock; ++ ++ err = 0; ++ if (!rdu->blk) { ++ rdu->blk = au_sbi(arg.sb)->si_rdblk; ++ if (!rdu->blk) ++ rdu->blk = au_dir_size(file, /*dentry*/NULL); ++ } ++ bbot = au_fbtop(file); ++ if (cookie->bindex < bbot) ++ cookie->bindex = bbot; ++ bbot = au_fbbot_dir(file); ++ /* AuDbg("b%d, b%d\n", cookie->bindex, bbot); */ ++ for (; !err && cookie->bindex <= bbot; ++ cookie->bindex++, cookie->h_pos = 0) { ++ h_file = au_hf_dir(file, cookie->bindex); ++ if (!h_file) ++ continue; ++ ++ au_fclr_rdu(cookie->flags, FULL); ++ err = au_rdu_do(h_file, &arg); ++ AuTraceErr(err); ++ if (unlikely(au_ftest_rdu(cookie->flags, FULL) || err)) ++ break; ++ } ++ AuDbg("rent %llu\n", rdu->rent); ++ ++ if (!err && !au_ftest_rdu(cookie->flags, CONT)) { ++ rdu->shwh = !!au_opt_test(au_sbi(arg.sb)->si_mntflags, SHWH); ++ au_fset_rdu(cookie->flags, CONT); ++ cookie->generation = au_figen(file); ++ } ++ ++ ii_read_lock_child(inode); ++ fsstack_copy_attr_atime(inode, au_h_iptr(inode, au_ibtop(inode))); ++ ii_read_unlock(inode); ++ ++out_unlock: ++ fi_read_unlock(file); ++out_si: ++ si_read_unlock(arg.sb); ++out_mtx: ++ inode_unlock_shared(inode); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_rdu_ino(struct file *file, struct aufs_rdu *rdu) ++{ ++ int err; ++ ino_t ino; ++ unsigned long long nent; ++ union au_rdu_ent_ul *u; ++ struct au_rdu_ent ent; ++ struct super_block *sb; ++ ++ err = 0; ++ nent = rdu->nent; ++ u = &rdu->ent; ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ while (nent-- > 0) { ++ /* unnecessary to support mmap_sem since this is a dir */ ++ err = copy_from_user(&ent, u->e, sizeof(ent)); ++ if (!err) ++ /* VERIFY_WRITE */ ++ err = !access_ok(&u->e->ino, sizeof(ino)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ break; ++ } ++ ++ /* AuDbg("b%d, i%llu\n", ent.bindex, ent.ino); */ ++ if (!ent.wh) ++ err = au_ino(sb, ent.bindex, ent.ino, ent.type, &ino); ++ else ++ err = au_wh_ino(sb, ent.bindex, ent.ino, ent.type, ++ &ino); ++ if (unlikely(err)) { ++ AuTraceErr(err); ++ break; ++ } ++ ++ err = __put_user(ino, &u->e->ino); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ break; ++ } ++ u->ul += au_rdu_len(ent.nlen); ++ } ++ si_read_unlock(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_rdu_verify(struct aufs_rdu *rdu) ++{ ++ AuDbg("rdu{%llu, %p, %u | %u | %llu, %u, %u | " ++ "%llu, b%d, 0x%x, g%u}\n", ++ rdu->sz, rdu->ent.e, rdu->verify[AufsCtlRduV_SZ], ++ rdu->blk, ++ rdu->rent, rdu->shwh, rdu->full, ++ rdu->cookie.h_pos, rdu->cookie.bindex, rdu->cookie.flags, ++ rdu->cookie.generation); ++ ++ if (rdu->verify[AufsCtlRduV_SZ] == sizeof(*rdu)) ++ return 0; ++ ++ AuDbg("%u:%u\n", ++ rdu->verify[AufsCtlRduV_SZ], (unsigned int)sizeof(*rdu)); ++ return -EINVAL; ++} ++ ++long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long err, e; ++ struct aufs_rdu rdu; ++ void __user *p = (void __user *)arg; ++ ++ err = copy_from_user(&rdu, p, sizeof(rdu)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ err = au_rdu_verify(&rdu); ++ if (unlikely(err)) ++ goto out; ++ ++ switch (cmd) { ++ case AUFS_CTL_RDU: ++ err = au_rdu(file, &rdu); ++ if (unlikely(err)) ++ break; ++ ++ e = copy_to_user(p, &rdu, sizeof(rdu)); ++ if (unlikely(e)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ } ++ break; ++ case AUFS_CTL_RDU_INO: ++ err = au_rdu_ino(file, &rdu); ++ break; ++ ++ default: ++ /* err = -ENOTTY; */ ++ err = -EINVAL; ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++#ifdef CONFIG_COMPAT ++long au_rdu_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long err, e; ++ struct aufs_rdu rdu; ++ void __user *p = compat_ptr(arg); ++ ++ /* todo: get_user()? */ ++ err = copy_from_user(&rdu, p, sizeof(rdu)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ rdu.ent.e = compat_ptr(rdu.ent.ul); ++ err = au_rdu_verify(&rdu); ++ if (unlikely(err)) ++ goto out; ++ ++ switch (cmd) { ++ case AUFS_CTL_RDU: ++ err = au_rdu(file, &rdu); ++ if (unlikely(err)) ++ break; ++ ++ rdu.ent.ul = ptr_to_compat(rdu.ent.e); ++ rdu.tail.ul = ptr_to_compat(rdu.tail.e); ++ e = copy_to_user(p, &rdu, sizeof(rdu)); ++ if (unlikely(e)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ } ++ break; ++ case AUFS_CTL_RDU_INO: ++ err = au_rdu_ino(file, &rdu); ++ break; ++ ++ default: ++ /* err = -ENOTTY; */ ++ err = -EINVAL; ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++#endif +diff -Nurp linux-5.4/fs/aufs/rwsem.h linux-5.4-aufs/fs/aufs/rwsem.h +--- linux-5.4/fs/aufs/rwsem.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/rwsem.h 2019-11-28 01:25:59.067925618 +0200 +@@ -0,0 +1,60 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * simple read-write semaphore wrappers ++ */ ++ ++#ifndef __AUFS_RWSEM_H__ ++#define __AUFS_RWSEM_H__ ++ ++#ifdef __KERNEL__ ++ ++#include "debug.h" ++ ++/* in the future, the name 'au_rwsem' will be totally gone */ ++#define au_rwsem rw_semaphore ++ ++/* to debug easier, do not make them inlined functions */ ++#define AuRwMustNoWaiters(rw) AuDebugOn(rwsem_is_contended(rw)) ++/* rwsem_is_locked() is unusable */ ++#define AuRwMustReadLock(rw) AuDebugOn(!lockdep_recursing(current) \ ++ && debug_locks \ ++ && !lockdep_is_held_type(rw, 1)) ++#define AuRwMustWriteLock(rw) AuDebugOn(!lockdep_recursing(current) \ ++ && debug_locks \ ++ && !lockdep_is_held_type(rw, 0)) ++#define AuRwMustAnyLock(rw) AuDebugOn(!lockdep_recursing(current) \ ++ && debug_locks \ ++ && !lockdep_is_held(rw)) ++#define AuRwDestroy(rw) AuDebugOn(!lockdep_recursing(current) \ ++ && debug_locks \ ++ && lockdep_is_held(rw)) ++ ++#define au_rw_init(rw) init_rwsem(rw) ++ ++#define au_rw_init_wlock(rw) do { \ ++ au_rw_init(rw); \ ++ down_write(rw); \ ++ } while (0) ++ ++#define au_rw_init_wlock_nested(rw, lsc) do { \ ++ au_rw_init(rw); \ ++ down_write_nested(rw, lsc); \ ++ } while (0) ++ ++#define au_rw_read_lock(rw) down_read(rw) ++#define au_rw_read_lock_nested(rw, lsc) down_read_nested(rw, lsc) ++#define au_rw_read_unlock(rw) up_read(rw) ++#define au_rw_dgrade_lock(rw) downgrade_write(rw) ++#define au_rw_write_lock(rw) down_write(rw) ++#define au_rw_write_lock_nested(rw, lsc) down_write_nested(rw, lsc) ++#define au_rw_write_unlock(rw) up_write(rw) ++/* why is not _nested version defined? */ ++#define au_rw_read_trylock(rw) down_read_trylock(rw) ++#define au_rw_write_trylock(rw) down_write_trylock(rw) ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_RWSEM_H__ */ +diff -Nurp linux-5.4/fs/aufs/sbinfo.c linux-5.4-aufs/fs/aufs/sbinfo.c +--- linux-5.4/fs/aufs/sbinfo.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/sbinfo.c 2019-11-28 01:25:59.067925618 +0200 +@@ -0,0 +1,301 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * superblock private data ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* ++ * they are necessary regardless sysfs is disabled. ++ */ ++void au_si_free(struct kobject *kobj) ++{ ++ int i; ++ struct au_sbinfo *sbinfo; ++ char *locked __maybe_unused; /* debug only */ ++ ++ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); ++ for (i = 0; i < AuPlink_NHASH; i++) ++ AuDebugOn(!hlist_bl_empty(sbinfo->si_plink + i)); ++ AuDebugOn(atomic_read(&sbinfo->si_nowait.nw_len)); ++ ++ AuLCntZero(au_lcnt_read(&sbinfo->si_ninodes, /*do_rev*/0)); ++ au_lcnt_fin(&sbinfo->si_ninodes, /*do_sync*/0); ++ AuLCntZero(au_lcnt_read(&sbinfo->si_nfiles, /*do_rev*/0)); ++ au_lcnt_fin(&sbinfo->si_nfiles, /*do_sync*/0); ++ ++ dbgaufs_si_fin(sbinfo); ++ au_rw_write_lock(&sbinfo->si_rwsem); ++ au_br_free(sbinfo); ++ au_rw_write_unlock(&sbinfo->si_rwsem); ++ ++ au_kfree_try_rcu(sbinfo->si_branch); ++ mutex_destroy(&sbinfo->si_xib_mtx); ++ AuRwDestroy(&sbinfo->si_rwsem); ++ ++ au_lcnt_wait_for_fin(&sbinfo->si_ninodes); ++ /* si_nfiles is waited too */ ++ au_kfree_rcu(sbinfo); ++} ++ ++int au_si_alloc(struct super_block *sb) ++{ ++ int err, i; ++ struct au_sbinfo *sbinfo; ++ ++ err = -ENOMEM; ++ sbinfo = kzalloc(sizeof(*sbinfo), GFP_NOFS); ++ if (unlikely(!sbinfo)) ++ goto out; ++ ++ /* will be reallocated separately */ ++ sbinfo->si_branch = kzalloc(sizeof(*sbinfo->si_branch), GFP_NOFS); ++ if (unlikely(!sbinfo->si_branch)) ++ goto out_sbinfo; ++ ++ err = sysaufs_si_init(sbinfo); ++ if (!err) { ++ dbgaufs_si_null(sbinfo); ++ err = dbgaufs_si_init(sbinfo); ++ if (unlikely(err)) ++ kobject_put(&sbinfo->si_kobj); ++ } ++ if (unlikely(err)) ++ goto out_br; ++ ++ au_nwt_init(&sbinfo->si_nowait); ++ au_rw_init_wlock(&sbinfo->si_rwsem); ++ ++ au_lcnt_init(&sbinfo->si_ninodes, /*release*/NULL); ++ au_lcnt_init(&sbinfo->si_nfiles, /*release*/NULL); ++ ++ sbinfo->si_bbot = -1; ++ sbinfo->si_last_br_id = AUFS_BRANCH_MAX / 2; ++ ++ sbinfo->si_wbr_copyup = AuWbrCopyup_Def; ++ sbinfo->si_wbr_create = AuWbrCreate_Def; ++ sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + sbinfo->si_wbr_copyup; ++ sbinfo->si_wbr_create_ops = au_wbr_create_ops + sbinfo->si_wbr_create; ++ ++ au_fhsm_init(sbinfo); ++ ++ sbinfo->si_mntflags = au_opts_plink(AuOpt_Def); ++ ++ sbinfo->si_xino_jiffy = jiffies; ++ sbinfo->si_xino_expire ++ = msecs_to_jiffies(AUFS_XINO_DEF_SEC * MSEC_PER_SEC); ++ mutex_init(&sbinfo->si_xib_mtx); ++ /* leave si_xib_last_pindex and si_xib_next_bit */ ++ ++ INIT_HLIST_BL_HEAD(&sbinfo->si_aopen); ++ ++ sbinfo->si_rdcache = msecs_to_jiffies(AUFS_RDCACHE_DEF * MSEC_PER_SEC); ++ sbinfo->si_rdblk = AUFS_RDBLK_DEF; ++ sbinfo->si_rdhash = AUFS_RDHASH_DEF; ++ sbinfo->si_dirwh = AUFS_DIRWH_DEF; ++ ++ for (i = 0; i < AuPlink_NHASH; i++) ++ INIT_HLIST_BL_HEAD(sbinfo->si_plink + i); ++ init_waitqueue_head(&sbinfo->si_plink_wq); ++ spin_lock_init(&sbinfo->si_plink_maint_lock); ++ ++ INIT_HLIST_BL_HEAD(&sbinfo->si_files); ++ ++ /* with getattr by default */ ++ sbinfo->si_iop_array = aufs_iop; ++ ++ /* leave other members for sysaufs and si_mnt. */ ++ sbinfo->si_sb = sb; ++ sb->s_fs_info = sbinfo; ++ si_pid_set(sb); ++ return 0; /* success */ ++ ++out_br: ++ au_kfree_try_rcu(sbinfo->si_branch); ++out_sbinfo: ++ au_kfree_rcu(sbinfo); ++out: ++ return err; ++} ++ ++int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr, int may_shrink) ++{ ++ int err, sz; ++ struct au_branch **brp; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ err = -ENOMEM; ++ sz = sizeof(*brp) * (sbinfo->si_bbot + 1); ++ if (unlikely(!sz)) ++ sz = sizeof(*brp); ++ brp = au_kzrealloc(sbinfo->si_branch, sz, sizeof(*brp) * nbr, GFP_NOFS, ++ may_shrink); ++ if (brp) { ++ sbinfo->si_branch = brp; ++ err = 0; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++unsigned int au_sigen_inc(struct super_block *sb) ++{ ++ unsigned int gen; ++ struct inode *inode; ++ ++ SiMustWriteLock(sb); ++ ++ gen = ++au_sbi(sb)->si_generation; ++ au_update_digen(sb->s_root); ++ inode = d_inode(sb->s_root); ++ au_update_iigen(inode, /*half*/0); ++ inode_inc_iversion(inode); ++ return gen; ++} ++ ++aufs_bindex_t au_new_br_id(struct super_block *sb) ++{ ++ aufs_bindex_t br_id; ++ int i; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ for (i = 0; i <= AUFS_BRANCH_MAX; i++) { ++ br_id = ++sbinfo->si_last_br_id; ++ AuDebugOn(br_id < 0); ++ if (br_id && au_br_index(sb, br_id) < 0) ++ return br_id; ++ } ++ ++ return -1; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* it is ok that new 'nwt' tasks are appended while we are sleeping */ ++int si_read_lock(struct super_block *sb, int flags) ++{ ++ int err; ++ ++ err = 0; ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ ++ si_noflush_read_lock(sb); ++ err = au_plink_maint(sb, flags); ++ if (unlikely(err)) ++ si_read_unlock(sb); ++ ++ return err; ++} ++ ++int si_write_lock(struct super_block *sb, int flags) ++{ ++ int err; ++ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ ++ si_noflush_write_lock(sb); ++ err = au_plink_maint(sb, flags); ++ if (unlikely(err)) ++ si_write_unlock(sb); ++ ++ return err; ++} ++ ++/* dentry and super_block lock. call at entry point */ ++int aufs_read_lock(struct dentry *dentry, int flags) ++{ ++ int err; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, flags); ++ if (unlikely(err)) ++ goto out; ++ ++ if (au_ftest_lock(flags, DW)) ++ di_write_lock_child(dentry); ++ else ++ di_read_lock_child(dentry, flags); ++ ++ if (au_ftest_lock(flags, GEN)) { ++ err = au_digen_test(dentry, au_sigen(sb)); ++ if (!au_opt_test(au_mntflags(sb), UDBA_NONE)) ++ AuDebugOn(!err && au_dbrange_test(dentry)); ++ else if (!err) ++ err = au_dbrange_test(dentry); ++ if (unlikely(err)) ++ aufs_read_unlock(dentry, flags); ++ } ++ ++out: ++ return err; ++} ++ ++void aufs_read_unlock(struct dentry *dentry, int flags) ++{ ++ if (au_ftest_lock(flags, DW)) ++ di_write_unlock(dentry); ++ else ++ di_read_unlock(dentry, flags); ++ si_read_unlock(dentry->d_sb); ++} ++ ++void aufs_write_lock(struct dentry *dentry) ++{ ++ si_write_lock(dentry->d_sb, AuLock_FLUSH | AuLock_NOPLMW); ++ di_write_lock_child(dentry); ++} ++ ++void aufs_write_unlock(struct dentry *dentry) ++{ ++ di_write_unlock(dentry); ++ si_write_unlock(dentry->d_sb); ++} ++ ++int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags) ++{ ++ int err; ++ unsigned int sigen; ++ struct super_block *sb; ++ ++ sb = d1->d_sb; ++ err = si_read_lock(sb, flags); ++ if (unlikely(err)) ++ goto out; ++ ++ di_write_lock2_child(d1, d2, au_ftest_lock(flags, DIRS)); ++ ++ if (au_ftest_lock(flags, GEN)) { ++ sigen = au_sigen(sb); ++ err = au_digen_test(d1, sigen); ++ AuDebugOn(!err && au_dbrange_test(d1)); ++ if (!err) { ++ err = au_digen_test(d2, sigen); ++ AuDebugOn(!err && au_dbrange_test(d2)); ++ } ++ if (unlikely(err)) ++ aufs_read_and_write_unlock2(d1, d2); ++ } ++ ++out: ++ return err; ++} ++ ++void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2) ++{ ++ di_write_unlock2(d1, d2); ++ si_read_unlock(d1->d_sb); ++} +diff -Nurp linux-5.4/fs/aufs/super.c linux-5.4-aufs/fs/aufs/super.c +--- linux-5.4/fs/aufs/super.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/super.c 2019-11-28 01:25:59.067925618 +0200 +@@ -0,0 +1,1034 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * mount and super_block operations ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++/* ++ * super_operations ++ */ ++static struct inode *aufs_alloc_inode(struct super_block *sb __maybe_unused) ++{ ++ struct au_icntnr *c; ++ ++ c = au_cache_alloc_icntnr(); ++ if (c) { ++ au_icntnr_init(c); ++ inode_set_iversion(&c->vfs_inode, 1); /* sigen(sb); */ ++ c->iinfo.ii_hinode = NULL; ++ return &c->vfs_inode; ++ } ++ return NULL; ++} ++ ++static void aufs_destroy_inode(struct inode *inode) ++{ ++ if (!au_is_bad_inode(inode)) ++ au_iinfo_fin(inode); ++} ++ ++static void aufs_free_inode(struct inode *inode) ++{ ++ au_cache_free_icntnr(container_of(inode, struct au_icntnr, vfs_inode)); ++} ++ ++struct inode *au_iget_locked(struct super_block *sb, ino_t ino) ++{ ++ struct inode *inode; ++ int err; ++ ++ inode = iget_locked(sb, ino); ++ if (unlikely(!inode)) { ++ inode = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ if (!(inode->i_state & I_NEW)) ++ goto out; ++ ++ err = au_xigen_new(inode); ++ if (!err) ++ err = au_iinfo_init(inode); ++ if (!err) ++ inode_inc_iversion(inode); ++ else { ++ iget_failed(inode); ++ inode = ERR_PTR(err); ++ } ++ ++out: ++ /* never return NULL */ ++ AuDebugOn(!inode); ++ AuTraceErrPtr(inode); ++ return inode; ++} ++ ++/* lock free root dinfo */ ++static int au_show_brs(struct seq_file *seq, struct super_block *sb) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct path path; ++ struct au_hdentry *hdp; ++ struct au_branch *br; ++ au_br_perm_str_t perm; ++ ++ err = 0; ++ bbot = au_sbbot(sb); ++ bindex = 0; ++ hdp = au_hdentry(au_di(sb->s_root), bindex); ++ for (; !err && bindex <= bbot; bindex++, hdp++) { ++ br = au_sbr(sb, bindex); ++ path.mnt = au_br_mnt(br); ++ path.dentry = hdp->hd_dentry; ++ err = au_seq_path(seq, &path); ++ if (!err) { ++ au_optstr_br_perm(&perm, br->br_perm); ++ seq_printf(seq, "=%s", perm.a); ++ if (bindex != bbot) ++ seq_putc(seq, ':'); ++ } ++ } ++ if (unlikely(err || seq_has_overflowed(seq))) ++ err = -E2BIG; ++ ++ return err; ++} ++ ++static void au_gen_fmt(char *fmt, int len __maybe_unused, const char *pat, ++ const char *append) ++{ ++ char *p; ++ ++ p = fmt; ++ while (*pat != ':') ++ *p++ = *pat++; ++ *p++ = *pat++; ++ strcpy(p, append); ++ AuDebugOn(strlen(fmt) >= len); ++} ++ ++static void au_show_wbr_create(struct seq_file *m, int v, ++ struct au_sbinfo *sbinfo) ++{ ++ const char *pat; ++ char fmt[32]; ++ struct au_wbr_mfs *mfs; ++ ++ AuRwMustAnyLock(&sbinfo->si_rwsem); ++ ++ seq_puts(m, ",create="); ++ pat = au_optstr_wbr_create(v); ++ mfs = &sbinfo->si_wbr_mfs; ++ switch (v) { ++ case AuWbrCreate_TDP: ++ case AuWbrCreate_RR: ++ case AuWbrCreate_MFS: ++ case AuWbrCreate_PMFS: ++ seq_puts(m, pat); ++ break; ++ case AuWbrCreate_MFSRR: ++ case AuWbrCreate_TDMFS: ++ case AuWbrCreate_PMFSRR: ++ au_gen_fmt(fmt, sizeof(fmt), pat, "%llu"); ++ seq_printf(m, fmt, mfs->mfsrr_watermark); ++ break; ++ case AuWbrCreate_MFSV: ++ case AuWbrCreate_PMFSV: ++ au_gen_fmt(fmt, sizeof(fmt), pat, "%lu"); ++ seq_printf(m, fmt, ++ jiffies_to_msecs(mfs->mfs_expire) ++ / MSEC_PER_SEC); ++ break; ++ case AuWbrCreate_MFSRRV: ++ case AuWbrCreate_TDMFSV: ++ case AuWbrCreate_PMFSRRV: ++ au_gen_fmt(fmt, sizeof(fmt), pat, "%llu:%lu"); ++ seq_printf(m, fmt, mfs->mfsrr_watermark, ++ jiffies_to_msecs(mfs->mfs_expire) / MSEC_PER_SEC); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++static int au_show_xino(struct seq_file *seq, struct super_block *sb) ++{ ++#ifdef CONFIG_SYSFS ++ return 0; ++#else ++ int err; ++ const int len = sizeof(AUFS_XINO_FNAME) - 1; ++ aufs_bindex_t bindex, brid; ++ struct qstr *name; ++ struct file *f; ++ struct dentry *d, *h_root; ++ struct au_branch *br; ++ ++ AuRwMustAnyLock(&sbinfo->si_rwsem); ++ ++ err = 0; ++ f = au_sbi(sb)->si_xib; ++ if (!f) ++ goto out; ++ ++ /* stop printing the default xino path on the first writable branch */ ++ h_root = NULL; ++ bindex = au_xi_root(sb, f->f_path.dentry); ++ if (bindex >= 0) { ++ br = au_sbr_sb(sb, bindex); ++ h_root = au_br_dentry(br); ++ } ++ ++ d = f->f_path.dentry; ++ name = &d->d_name; ++ /* safe ->d_parent because the file is unlinked */ ++ if (d->d_parent == h_root ++ && name->len == len ++ && !memcmp(name->name, AUFS_XINO_FNAME, len)) ++ goto out; ++ ++ seq_puts(seq, ",xino="); ++ err = au_xino_path(seq, f); ++ ++out: ++ return err; ++#endif ++} ++ ++/* seq_file will re-call me in case of too long string */ ++static int aufs_show_options(struct seq_file *m, struct dentry *dentry) ++{ ++ int err; ++ unsigned int mnt_flags, v; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++#define AuBool(name, str) do { \ ++ v = au_opt_test(mnt_flags, name); \ ++ if (v != au_opt_test(AuOpt_Def, name)) \ ++ seq_printf(m, ",%s" #str, v ? "" : "no"); \ ++} while (0) ++ ++#define AuStr(name, str) do { \ ++ v = mnt_flags & AuOptMask_##name; \ ++ if (v != (AuOpt_Def & AuOptMask_##name)) \ ++ seq_printf(m, "," #str "=%s", au_optstr_##str(v)); \ ++} while (0) ++ ++#define AuUInt(name, str, val) do { \ ++ if (val != AUFS_##name##_DEF) \ ++ seq_printf(m, "," #str "=%u", val); \ ++} while (0) ++ ++ sb = dentry->d_sb; ++ if (sb->s_flags & SB_POSIXACL) ++ seq_puts(m, ",acl"); ++#if 0 ++ if (sb->s_flags & SB_I_VERSION) ++ seq_puts(m, ",i_version"); ++#endif ++ ++ /* lock free root dinfo */ ++ si_noflush_read_lock(sb); ++ sbinfo = au_sbi(sb); ++ seq_printf(m, ",si=%lx", sysaufs_si_id(sbinfo)); ++ ++ mnt_flags = au_mntflags(sb); ++ if (au_opt_test(mnt_flags, XINO)) { ++ err = au_show_xino(m, sb); ++ if (unlikely(err)) ++ goto out; ++ } else ++ seq_puts(m, ",noxino"); ++ ++ AuBool(TRUNC_XINO, trunc_xino); ++ AuStr(UDBA, udba); ++ AuBool(SHWH, shwh); ++ AuBool(PLINK, plink); ++ AuBool(DIO, dio); ++ AuBool(DIRPERM1, dirperm1); ++ ++ v = sbinfo->si_wbr_create; ++ if (v != AuWbrCreate_Def) ++ au_show_wbr_create(m, v, sbinfo); ++ ++ v = sbinfo->si_wbr_copyup; ++ if (v != AuWbrCopyup_Def) ++ seq_printf(m, ",cpup=%s", au_optstr_wbr_copyup(v)); ++ ++ v = au_opt_test(mnt_flags, ALWAYS_DIROPQ); ++ if (v != au_opt_test(AuOpt_Def, ALWAYS_DIROPQ)) ++ seq_printf(m, ",diropq=%c", v ? 'a' : 'w'); ++ ++ AuUInt(DIRWH, dirwh, sbinfo->si_dirwh); ++ ++ v = jiffies_to_msecs(sbinfo->si_rdcache) / MSEC_PER_SEC; ++ AuUInt(RDCACHE, rdcache, v); ++ ++ AuUInt(RDBLK, rdblk, sbinfo->si_rdblk); ++ AuUInt(RDHASH, rdhash, sbinfo->si_rdhash); ++ ++ au_fhsm_show(m, sbinfo); ++ ++ AuBool(DIRREN, dirren); ++ AuBool(SUM, sum); ++ /* AuBool(SUM_W, wsum); */ ++ AuBool(WARN_PERM, warn_perm); ++ AuBool(VERBOSE, verbose); ++ ++out: ++ /* be sure to print "br:" last */ ++ if (!sysaufs_brs) { ++ seq_puts(m, ",br:"); ++ au_show_brs(m, sb); ++ } ++ si_read_unlock(sb); ++ return 0; ++ ++#undef AuBool ++#undef AuStr ++#undef AuUInt ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* sum mode which returns the summation for statfs(2) */ ++ ++static u64 au_add_till_max(u64 a, u64 b) ++{ ++ u64 old; ++ ++ old = a; ++ a += b; ++ if (old <= a) ++ return a; ++ return ULLONG_MAX; ++} ++ ++static u64 au_mul_till_max(u64 a, long mul) ++{ ++ u64 old; ++ ++ old = a; ++ a *= mul; ++ if (old <= a) ++ return a; ++ return ULLONG_MAX; ++} ++ ++static int au_statfs_sum(struct super_block *sb, struct kstatfs *buf) ++{ ++ int err; ++ long bsize, factor; ++ u64 blocks, bfree, bavail, files, ffree; ++ aufs_bindex_t bbot, bindex, i; ++ unsigned char shared; ++ struct path h_path; ++ struct super_block *h_sb; ++ ++ err = 0; ++ bsize = LONG_MAX; ++ files = 0; ++ ffree = 0; ++ blocks = 0; ++ bfree = 0; ++ bavail = 0; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ h_sb = h_path.mnt->mnt_sb; ++ shared = 0; ++ for (i = 0; !shared && i < bindex; i++) ++ shared = (au_sbr_sb(sb, i) == h_sb); ++ if (shared) ++ continue; ++ ++ /* sb->s_root for NFS is unreliable */ ++ h_path.dentry = h_path.mnt->mnt_root; ++ err = vfs_statfs(&h_path, buf); ++ if (unlikely(err)) ++ goto out; ++ ++ if (bsize > buf->f_bsize) { ++ /* ++ * we will reduce bsize, so we have to expand blocks ++ * etc. to match them again ++ */ ++ factor = (bsize / buf->f_bsize); ++ blocks = au_mul_till_max(blocks, factor); ++ bfree = au_mul_till_max(bfree, factor); ++ bavail = au_mul_till_max(bavail, factor); ++ bsize = buf->f_bsize; ++ } ++ ++ factor = (buf->f_bsize / bsize); ++ blocks = au_add_till_max(blocks, ++ au_mul_till_max(buf->f_blocks, factor)); ++ bfree = au_add_till_max(bfree, ++ au_mul_till_max(buf->f_bfree, factor)); ++ bavail = au_add_till_max(bavail, ++ au_mul_till_max(buf->f_bavail, factor)); ++ files = au_add_till_max(files, buf->f_files); ++ ffree = au_add_till_max(ffree, buf->f_ffree); ++ } ++ ++ buf->f_bsize = bsize; ++ buf->f_blocks = blocks; ++ buf->f_bfree = bfree; ++ buf->f_bavail = bavail; ++ buf->f_files = files; ++ buf->f_ffree = ffree; ++ buf->f_frsize = 0; ++ ++out: ++ return err; ++} ++ ++static int aufs_statfs(struct dentry *dentry, struct kstatfs *buf) ++{ ++ int err; ++ struct path h_path; ++ struct super_block *sb; ++ ++ /* lock free root dinfo */ ++ sb = dentry->d_sb; ++ si_noflush_read_lock(sb); ++ if (!au_opt_test(au_mntflags(sb), SUM)) { ++ /* sb->s_root for NFS is unreliable */ ++ h_path.mnt = au_sbr_mnt(sb, 0); ++ h_path.dentry = h_path.mnt->mnt_root; ++ err = vfs_statfs(&h_path, buf); ++ } else ++ err = au_statfs_sum(sb, buf); ++ si_read_unlock(sb); ++ ++ if (!err) { ++ buf->f_type = AUFS_SUPER_MAGIC; ++ buf->f_namelen = AUFS_MAX_NAMELEN; ++ memset(&buf->f_fsid, 0, sizeof(buf->f_fsid)); ++ } ++ /* buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1; */ ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_sync_fs(struct super_block *sb, int wait) ++{ ++ int err, e; ++ aufs_bindex_t bbot, bindex; ++ struct au_branch *br; ++ struct super_block *h_sb; ++ ++ err = 0; ++ si_noflush_read_lock(sb); ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!au_br_writable(br->br_perm)) ++ continue; ++ ++ h_sb = au_sbr_sb(sb, bindex); ++ e = vfsub_sync_filesystem(h_sb, wait); ++ if (unlikely(e && !err)) ++ err = e; ++ /* go on even if an error happens */ ++ } ++ si_read_unlock(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* final actions when unmounting a file system */ ++static void aufs_put_super(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ sbinfo = au_sbi(sb); ++ if (sbinfo) ++ kobject_put(&sbinfo->si_kobj); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, ++ struct super_block *sb, void *arg) ++{ ++ void *array; ++ unsigned long long n, sz; ++ ++ array = NULL; ++ n = 0; ++ if (!*hint) ++ goto out; ++ ++ if (*hint > ULLONG_MAX / sizeof(array)) { ++ array = ERR_PTR(-EMFILE); ++ pr_err("hint %llu\n", *hint); ++ goto out; ++ } ++ ++ sz = sizeof(array) * *hint; ++ array = kzalloc(sz, GFP_NOFS); ++ if (unlikely(!array)) ++ array = vzalloc(sz); ++ if (unlikely(!array)) { ++ array = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ ++ n = cb(sb, array, *hint, arg); ++ AuDebugOn(n > *hint); ++ ++out: ++ *hint = n; ++ return array; ++} ++ ++static unsigned long long au_iarray_cb(struct super_block *sb, void *a, ++ unsigned long long max __maybe_unused, ++ void *arg) ++{ ++ unsigned long long n; ++ struct inode **p, *inode; ++ struct list_head *head; ++ ++ n = 0; ++ p = a; ++ head = arg; ++ spin_lock(&sb->s_inode_list_lock); ++ list_for_each_entry(inode, head, i_sb_list) { ++ if (!au_is_bad_inode(inode) ++ && au_ii(inode)->ii_btop >= 0) { ++ spin_lock(&inode->i_lock); ++ if (atomic_read(&inode->i_count)) { ++ au_igrab(inode); ++ *p++ = inode; ++ n++; ++ AuDebugOn(n > max); ++ } ++ spin_unlock(&inode->i_lock); ++ } ++ } ++ spin_unlock(&sb->s_inode_list_lock); ++ ++ return n; ++} ++ ++struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max) ++{ ++ struct au_sbinfo *sbi; ++ ++ sbi = au_sbi(sb); ++ *max = au_lcnt_read(&sbi->si_ninodes, /*do_rev*/1); ++ return au_array_alloc(max, au_iarray_cb, sb, &sb->s_inodes); ++} ++ ++void au_iarray_free(struct inode **a, unsigned long long max) ++{ ++ unsigned long long ull; ++ ++ for (ull = 0; ull < max; ull++) ++ iput(a[ull]); ++ kvfree(a); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * refresh dentry and inode at remount time. ++ */ ++/* todo: consolidate with simple_reval_dpath() and au_reval_for_attr() */ ++static int au_do_refresh(struct dentry *dentry, unsigned int dir_flags, ++ struct dentry *parent) ++{ ++ int err; ++ ++ di_write_lock_child(dentry); ++ di_read_lock_parent(parent, AuLock_IR); ++ err = au_refresh_dentry(dentry, parent); ++ if (!err && dir_flags) ++ au_hn_reset(d_inode(dentry), dir_flags); ++ di_read_unlock(parent, AuLock_IR); ++ di_write_unlock(dentry); ++ ++ return err; ++} ++ ++static int au_do_refresh_d(struct dentry *dentry, unsigned int sigen, ++ struct au_sbinfo *sbinfo, ++ const unsigned int dir_flags, unsigned int do_idop) ++{ ++ int err; ++ struct dentry *parent; ++ ++ err = 0; ++ parent = dget_parent(dentry); ++ if (!au_digen_test(parent, sigen) && au_digen_test(dentry, sigen)) { ++ if (d_really_is_positive(dentry)) { ++ if (!d_is_dir(dentry)) ++ err = au_do_refresh(dentry, /*dir_flags*/0, ++ parent); ++ else { ++ err = au_do_refresh(dentry, dir_flags, parent); ++ if (unlikely(err)) ++ au_fset_si(sbinfo, FAILED_REFRESH_DIR); ++ } ++ } else ++ err = au_do_refresh(dentry, /*dir_flags*/0, parent); ++ AuDbgDentry(dentry); ++ } ++ dput(parent); ++ ++ if (!err) { ++ if (do_idop) ++ au_refresh_dop(dentry, /*force_reval*/0); ++ } else ++ au_refresh_dop(dentry, /*force_reval*/1); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_refresh_d(struct super_block *sb, unsigned int do_idop) ++{ ++ int err, i, j, ndentry, e; ++ unsigned int sigen; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries, *d; ++ struct au_sbinfo *sbinfo; ++ struct dentry *root = sb->s_root; ++ const unsigned int dir_flags = au_hi_flags(d_inode(root), /*isdir*/1); ++ ++ if (do_idop) ++ au_refresh_dop(root, /*force_reval*/0); ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, root, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ sigen = au_sigen(sb); ++ sbinfo = au_sbi(sb); ++ for (i = 0; i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ ndentry = dpage->ndentry; ++ for (j = 0; j < ndentry; j++) { ++ d = dentries[j]; ++ e = au_do_refresh_d(d, sigen, sbinfo, dir_flags, ++ do_idop); ++ if (unlikely(e && !err)) ++ err = e; ++ /* go on even err */ ++ } ++ } ++ ++out_dpages: ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++static int au_refresh_i(struct super_block *sb, unsigned int do_idop) ++{ ++ int err, e; ++ unsigned int sigen; ++ unsigned long long max, ull; ++ struct inode *inode, **array; ++ ++ array = au_iarray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ err = 0; ++ sigen = au_sigen(sb); ++ for (ull = 0; ull < max; ull++) { ++ inode = array[ull]; ++ if (unlikely(!inode)) ++ break; ++ ++ e = 0; ++ ii_write_lock_child(inode); ++ if (au_iigen(inode, NULL) != sigen) { ++ e = au_refresh_hinode_self(inode); ++ if (unlikely(e)) { ++ au_refresh_iop(inode, /*force_getattr*/1); ++ pr_err("error %d, i%lu\n", e, inode->i_ino); ++ if (!err) ++ err = e; ++ /* go on even if err */ ++ } ++ } ++ if (!e && do_idop) ++ au_refresh_iop(inode, /*force_getattr*/0); ++ ii_write_unlock(inode); ++ } ++ ++ au_iarray_free(array, max); ++ ++out: ++ return err; ++} ++ ++static void au_remount_refresh(struct super_block *sb, unsigned int do_idop) ++{ ++ int err, e; ++ unsigned int udba; ++ aufs_bindex_t bindex, bbot; ++ struct dentry *root; ++ struct inode *inode; ++ struct au_branch *br; ++ struct au_sbinfo *sbi; ++ ++ au_sigen_inc(sb); ++ sbi = au_sbi(sb); ++ au_fclr_si(sbi, FAILED_REFRESH_DIR); ++ ++ root = sb->s_root; ++ DiMustNoWaiters(root); ++ inode = d_inode(root); ++ IiMustNoWaiters(inode); ++ ++ udba = au_opt_udba(sb); ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ err = au_hnotify_reset_br(udba, br, br->br_perm); ++ if (unlikely(err)) ++ AuIOErr("hnotify failed on br %d, %d, ignored\n", ++ bindex, err); ++ /* go on even if err */ ++ } ++ au_hn_reset(inode, au_hi_flags(inode, /*isdir*/1)); ++ ++ if (do_idop) { ++ if (au_ftest_si(sbi, NO_DREVAL)) { ++ AuDebugOn(sb->s_d_op == &aufs_dop_noreval); ++ sb->s_d_op = &aufs_dop_noreval; ++ AuDebugOn(sbi->si_iop_array == aufs_iop_nogetattr); ++ sbi->si_iop_array = aufs_iop_nogetattr; ++ } else { ++ AuDebugOn(sb->s_d_op == &aufs_dop); ++ sb->s_d_op = &aufs_dop; ++ AuDebugOn(sbi->si_iop_array == aufs_iop); ++ sbi->si_iop_array = aufs_iop; ++ } ++ pr_info("reset to %ps and %ps\n", ++ sb->s_d_op, sbi->si_iop_array); ++ } ++ ++ di_write_unlock(root); ++ err = au_refresh_d(sb, do_idop); ++ e = au_refresh_i(sb, do_idop); ++ if (unlikely(e && !err)) ++ err = e; ++ /* aufs_write_lock() calls ..._child() */ ++ di_write_lock_child(root); ++ ++ au_cpup_attr_all(inode, /*force*/1); ++ ++ if (unlikely(err)) ++ AuIOErr("refresh failed, ignored, %d\n", err); ++} ++ ++/* stop extra interpretation of errno in mount(8), and strange error messages */ ++static int cvt_err(int err) ++{ ++ AuTraceErr(err); ++ ++ switch (err) { ++ case -ENOENT: ++ case -ENOTDIR: ++ case -EEXIST: ++ case -EIO: ++ err = -EINVAL; ++ } ++ return err; ++} ++ ++static int aufs_remount_fs(struct super_block *sb, int *flags, char *data) ++{ ++ int err, do_dx; ++ unsigned int mntflags; ++ struct au_opts opts = { ++ .opt = NULL ++ }; ++ struct dentry *root; ++ struct inode *inode; ++ struct au_sbinfo *sbinfo; ++ ++ err = 0; ++ root = sb->s_root; ++ if (!data || !*data) { ++ err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (!err) { ++ di_write_lock_child(root); ++ err = au_opts_verify(sb, *flags, /*pending*/0); ++ aufs_write_unlock(root); ++ } ++ goto out; ++ } ++ ++ err = -ENOMEM; ++ opts.opt = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!opts.opt)) ++ goto out; ++ opts.max_opt = PAGE_SIZE / sizeof(*opts.opt); ++ opts.flags = AuOpts_REMOUNT; ++ opts.sb_flags = *flags; ++ ++ /* parse it before aufs lock */ ++ err = au_opts_parse(sb, data, &opts); ++ if (unlikely(err)) ++ goto out_opts; ++ ++ sbinfo = au_sbi(sb); ++ inode = d_inode(root); ++ inode_lock(inode); ++ err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out_mtx; ++ di_write_lock_child(root); ++ ++ /* au_opts_remount() may return an error */ ++ err = au_opts_remount(sb, &opts); ++ au_opts_free(&opts); ++ ++ if (au_ftest_opts(opts.flags, REFRESH)) ++ au_remount_refresh(sb, au_ftest_opts(opts.flags, REFRESH_IDOP)); ++ ++ if (au_ftest_opts(opts.flags, REFRESH_DYAOP)) { ++ mntflags = au_mntflags(sb); ++ do_dx = !!au_opt_test(mntflags, DIO); ++ au_dy_arefresh(do_dx); ++ } ++ ++ au_fhsm_wrote_all(sb, /*force*/1); /* ?? */ ++ aufs_write_unlock(root); ++ ++out_mtx: ++ inode_unlock(inode); ++out_opts: ++ free_page((unsigned long)opts.opt); ++out: ++ err = cvt_err(err); ++ AuTraceErr(err); ++ return err; ++} ++ ++static const struct super_operations aufs_sop = { ++ .alloc_inode = aufs_alloc_inode, ++ .destroy_inode = aufs_destroy_inode, ++ .free_inode = aufs_free_inode, ++ /* always deleting, no clearing */ ++ .drop_inode = generic_delete_inode, ++ .show_options = aufs_show_options, ++ .statfs = aufs_statfs, ++ .put_super = aufs_put_super, ++ .sync_fs = aufs_sync_fs, ++ .remount_fs = aufs_remount_fs ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int alloc_root(struct super_block *sb) ++{ ++ int err; ++ struct inode *inode; ++ struct dentry *root; ++ ++ err = -ENOMEM; ++ inode = au_iget_locked(sb, AUFS_ROOT_INO); ++ err = PTR_ERR(inode); ++ if (IS_ERR(inode)) ++ goto out; ++ ++ inode->i_op = aufs_iop + AuIop_DIR; /* with getattr by default */ ++ inode->i_fop = &aufs_dir_fop; ++ inode->i_mode = S_IFDIR; ++ set_nlink(inode, 2); ++ unlock_new_inode(inode); ++ ++ root = d_make_root(inode); ++ if (unlikely(!root)) ++ goto out; ++ err = PTR_ERR(root); ++ if (IS_ERR(root)) ++ goto out; ++ ++ err = au_di_init(root); ++ if (!err) { ++ sb->s_root = root; ++ return 0; /* success */ ++ } ++ dput(root); ++ ++out: ++ return err; ++} ++ ++static int aufs_fill_super(struct super_block *sb, void *raw_data, ++ int silent __maybe_unused) ++{ ++ int err; ++ struct au_opts opts = { ++ .opt = NULL ++ }; ++ struct au_sbinfo *sbinfo; ++ struct dentry *root; ++ struct inode *inode; ++ char *arg = raw_data; ++ ++ if (unlikely(!arg || !*arg)) { ++ err = -EINVAL; ++ pr_err("no arg\n"); ++ goto out; ++ } ++ ++ err = -ENOMEM; ++ opts.opt = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!opts.opt)) ++ goto out; ++ opts.max_opt = PAGE_SIZE / sizeof(*opts.opt); ++ opts.sb_flags = sb->s_flags; ++ ++ err = au_si_alloc(sb); ++ if (unlikely(err)) ++ goto out_opts; ++ sbinfo = au_sbi(sb); ++ ++ /* all timestamps always follow the ones on the branch */ ++ sb->s_flags |= SB_NOATIME | SB_NODIRATIME; ++ sb->s_flags |= SB_I_VERSION; /* do we really need this? */ ++ sb->s_op = &aufs_sop; ++ sb->s_d_op = &aufs_dop; ++ sb->s_magic = AUFS_SUPER_MAGIC; ++ sb->s_maxbytes = 0; ++ sb->s_stack_depth = 1; ++ au_export_init(sb); ++ au_xattr_init(sb); ++ ++ err = alloc_root(sb); ++ if (unlikely(err)) { ++ si_write_unlock(sb); ++ goto out_info; ++ } ++ root = sb->s_root; ++ inode = d_inode(root); ++ ++ /* ++ * actually we can parse options regardless aufs lock here. ++ * but at remount time, parsing must be done before aufs lock. ++ * so we follow the same rule. ++ */ ++ ii_write_lock_parent(inode); ++ aufs_write_unlock(root); ++ err = au_opts_parse(sb, arg, &opts); ++ if (unlikely(err)) ++ goto out_root; ++ ++ /* lock vfs_inode first, then aufs. */ ++ inode_lock(inode); ++ aufs_write_lock(root); ++ err = au_opts_mount(sb, &opts); ++ au_opts_free(&opts); ++ if (!err && au_ftest_si(sbinfo, NO_DREVAL)) { ++ sb->s_d_op = &aufs_dop_noreval; ++ pr_info("%ps\n", sb->s_d_op); ++ au_refresh_dop(root, /*force_reval*/0); ++ sbinfo->si_iop_array = aufs_iop_nogetattr; ++ au_refresh_iop(inode, /*force_getattr*/0); ++ } ++ aufs_write_unlock(root); ++ inode_unlock(inode); ++ if (!err) ++ goto out_opts; /* success */ ++ ++out_root: ++ dput(root); ++ sb->s_root = NULL; ++out_info: ++ kobject_put(&sbinfo->si_kobj); ++ sb->s_fs_info = NULL; ++out_opts: ++ free_page((unsigned long)opts.opt); ++out: ++ AuTraceErr(err); ++ err = cvt_err(err); ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry *aufs_mount(struct file_system_type *fs_type, int flags, ++ const char *dev_name __maybe_unused, ++ void *raw_data) ++{ ++ struct dentry *root; ++ ++ /* all timestamps always follow the ones on the branch */ ++ /* mnt->mnt_flags |= MNT_NOATIME | MNT_NODIRATIME; */ ++ root = mount_nodev(fs_type, flags, raw_data, aufs_fill_super); ++ if (IS_ERR(root)) ++ goto out; ++ ++ au_sbilist_add(root->d_sb); ++ ++out: ++ return root; ++} ++ ++static void aufs_kill_sb(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ sbinfo = au_sbi(sb); ++ if (sbinfo) { ++ au_sbilist_del(sb); ++ aufs_write_lock(sb->s_root); ++ au_fhsm_fin(sb); ++ if (sbinfo->si_wbr_create_ops->fin) ++ sbinfo->si_wbr_create_ops->fin(sb); ++ if (au_opt_test(sbinfo->si_mntflags, UDBA_HNOTIFY)) { ++ au_opt_set_udba(sbinfo->si_mntflags, UDBA_NONE); ++ au_remount_refresh(sb, /*do_idop*/0); ++ } ++ if (au_opt_test(sbinfo->si_mntflags, PLINK)) ++ au_plink_put(sb, /*verbose*/1); ++ au_xino_clr(sb); ++ au_dr_opt_flush(sb); ++ sbinfo->si_sb = NULL; ++ aufs_write_unlock(sb->s_root); ++ au_nwt_flush(&sbinfo->si_nowait); ++ } ++ kill_anon_super(sb); ++} ++ ++struct file_system_type aufs_fs_type = { ++ .name = AUFS_FSTYPE, ++ /* a race between rename and others */ ++ .fs_flags = FS_RENAME_DOES_D_MOVE, ++ .mount = aufs_mount, ++ .kill_sb = aufs_kill_sb, ++ /* no need to __module_get() and module_put(). */ ++ .owner = THIS_MODULE, ++}; +diff -Nurp linux-5.4/fs/aufs/super.h linux-5.4-aufs/fs/aufs/super.h +--- linux-5.4/fs/aufs/super.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/super.h 2019-11-28 01:25:59.068925618 +0200 +@@ -0,0 +1,576 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * super_block operations ++ */ ++ ++#ifndef __AUFS_SUPER_H__ ++#define __AUFS_SUPER_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include "hbl.h" ++#include "lcnt.h" ++#include "rwsem.h" ++#include "wkq.h" ++ ++/* policies to select one among multiple writable branches */ ++struct au_wbr_copyup_operations { ++ int (*copyup)(struct dentry *dentry); ++}; ++ ++#define AuWbr_DIR 1 /* target is a dir */ ++#define AuWbr_PARENT (1 << 1) /* always require a parent */ ++ ++#define au_ftest_wbr(flags, name) ((flags) & AuWbr_##name) ++#define au_fset_wbr(flags, name) { (flags) |= AuWbr_##name; } ++#define au_fclr_wbr(flags, name) { (flags) &= ~AuWbr_##name; } ++ ++struct au_wbr_create_operations { ++ int (*create)(struct dentry *dentry, unsigned int flags); ++ int (*init)(struct super_block *sb); ++ int (*fin)(struct super_block *sb); ++}; ++ ++struct au_wbr_mfs { ++ struct mutex mfs_lock; /* protect this structure */ ++ unsigned long mfs_jiffy; ++ unsigned long mfs_expire; ++ aufs_bindex_t mfs_bindex; ++ ++ unsigned long long mfsrr_bytes; ++ unsigned long long mfsrr_watermark; ++}; ++ ++#define AuPlink_NHASH 100 ++static inline int au_plink_hash(ino_t ino) ++{ ++ return ino % AuPlink_NHASH; ++} ++ ++/* File-based Hierarchical Storage Management */ ++struct au_fhsm { ++#ifdef CONFIG_AUFS_FHSM ++ /* allow only one process who can receive the notification */ ++ spinlock_t fhsm_spin; ++ pid_t fhsm_pid; ++ wait_queue_head_t fhsm_wqh; ++ atomic_t fhsm_readable; ++ ++ /* these are protected by si_rwsem */ ++ unsigned long fhsm_expire; ++ aufs_bindex_t fhsm_bottom; ++#endif ++}; ++ ++struct au_branch; ++struct au_sbinfo { ++ /* nowait tasks in the system-wide workqueue */ ++ struct au_nowait_tasks si_nowait; ++ ++ /* ++ * tried sb->s_umount, but failed due to the dependency between i_mutex. ++ * rwsem for au_sbinfo is necessary. ++ */ ++ struct au_rwsem si_rwsem; ++ ++ /* ++ * dirty approach to protect sb->sb_inodes and ->s_files (gone) from ++ * remount. ++ */ ++ au_lcnt_t si_ninodes, si_nfiles; ++ ++ /* branch management */ ++ unsigned int si_generation; ++ ++ /* see AuSi_ flags */ ++ unsigned char au_si_status; ++ ++ aufs_bindex_t si_bbot; ++ ++ /* dirty trick to keep br_id plus */ ++ unsigned int si_last_br_id : ++ sizeof(aufs_bindex_t) * BITS_PER_BYTE - 1; ++ struct au_branch **si_branch; ++ ++ /* policy to select a writable branch */ ++ unsigned char si_wbr_copyup; ++ unsigned char si_wbr_create; ++ struct au_wbr_copyup_operations *si_wbr_copyup_ops; ++ struct au_wbr_create_operations *si_wbr_create_ops; ++ ++ /* round robin */ ++ atomic_t si_wbr_rr_next; ++ ++ /* most free space */ ++ struct au_wbr_mfs si_wbr_mfs; ++ ++ /* File-based Hierarchical Storage Management */ ++ struct au_fhsm si_fhsm; ++ ++ /* mount flags */ ++ /* include/asm-ia64/siginfo.h defines a macro named si_flags */ ++ unsigned int si_mntflags; ++ ++ /* external inode number (bitmap and translation table) */ ++ vfs_readf_t si_xread; ++ vfs_writef_t si_xwrite; ++ loff_t si_ximaxent; /* max entries in a xino */ ++ ++ struct file *si_xib; ++ struct mutex si_xib_mtx; /* protect xib members */ ++ unsigned long *si_xib_buf; ++ unsigned long si_xib_last_pindex; ++ int si_xib_next_bit; ++ ++ unsigned long si_xino_jiffy; ++ unsigned long si_xino_expire; ++ /* reserved for future use */ ++ /* unsigned long long si_xib_limit; */ /* Max xib file size */ ++ ++#ifdef CONFIG_AUFS_EXPORT ++ /* i_generation */ ++ /* todo: make xigen file an array to support many inode numbers */ ++ struct file *si_xigen; ++ atomic_t si_xigen_next; ++#endif ++ ++ /* dirty trick to support atomic_open */ ++ struct hlist_bl_head si_aopen; ++ ++ /* vdir parameters */ ++ unsigned long si_rdcache; /* max cache time in jiffies */ ++ unsigned int si_rdblk; /* deblk size */ ++ unsigned int si_rdhash; /* hash size */ ++ ++ /* ++ * If the number of whiteouts are larger than si_dirwh, leave all of ++ * them after au_whtmp_ren to reduce the cost of rmdir(2). ++ * future fsck.aufs or kernel thread will remove them later. ++ * Otherwise, remove all whiteouts and the dir in rmdir(2). ++ */ ++ unsigned int si_dirwh; ++ ++ /* pseudo_link list */ ++ struct hlist_bl_head si_plink[AuPlink_NHASH]; ++ wait_queue_head_t si_plink_wq; ++ spinlock_t si_plink_maint_lock; ++ pid_t si_plink_maint_pid; ++ ++ /* file list */ ++ struct hlist_bl_head si_files; ++ ++ /* with/without getattr, brother of sb->s_d_op */ ++ struct inode_operations *si_iop_array; ++ ++ /* ++ * sysfs and lifetime management. ++ * this is not a small structure and it may be a waste of memory in case ++ * of sysfs is disabled, particularly when many aufs-es are mounted. ++ * but using sysfs is majority. ++ */ ++ struct kobject si_kobj; ++#ifdef CONFIG_DEBUG_FS ++ struct dentry *si_dbgaufs; ++ struct dentry *si_dbgaufs_plink; ++ struct dentry *si_dbgaufs_xib; ++#ifdef CONFIG_AUFS_EXPORT ++ struct dentry *si_dbgaufs_xigen; ++#endif ++#endif ++ ++#ifdef CONFIG_AUFS_SBILIST ++ struct hlist_bl_node si_list; ++#endif ++ ++ /* dirty, necessary for unmounting, sysfs and sysrq */ ++ struct super_block *si_sb; ++}; ++ ++/* sbinfo status flags */ ++/* ++ * set true when refresh_dirs() failed at remount time. ++ * then try refreshing dirs at access time again. ++ * if it is false, refreshing dirs at access time is unnecessary ++ */ ++#define AuSi_FAILED_REFRESH_DIR 1 ++#define AuSi_FHSM (1 << 1) /* fhsm is active now */ ++#define AuSi_NO_DREVAL (1 << 2) /* disable all d_revalidate */ ++ ++#ifndef CONFIG_AUFS_FHSM ++#undef AuSi_FHSM ++#define AuSi_FHSM 0 ++#endif ++ ++static inline unsigned char au_do_ftest_si(struct au_sbinfo *sbi, ++ unsigned int flag) ++{ ++ AuRwMustAnyLock(&sbi->si_rwsem); ++ return sbi->au_si_status & flag; ++} ++#define au_ftest_si(sbinfo, name) au_do_ftest_si(sbinfo, AuSi_##name) ++#define au_fset_si(sbinfo, name) do { \ ++ AuRwMustWriteLock(&(sbinfo)->si_rwsem); \ ++ (sbinfo)->au_si_status |= AuSi_##name; \ ++} while (0) ++#define au_fclr_si(sbinfo, name) do { \ ++ AuRwMustWriteLock(&(sbinfo)->si_rwsem); \ ++ (sbinfo)->au_si_status &= ~AuSi_##name; \ ++} while (0) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policy to select one among writable branches */ ++#define AuWbrCopyup(sbinfo, ...) \ ++ ((sbinfo)->si_wbr_copyup_ops->copyup(__VA_ARGS__)) ++#define AuWbrCreate(sbinfo, ...) \ ++ ((sbinfo)->si_wbr_create_ops->create(__VA_ARGS__)) ++ ++/* flags for si_read_lock()/aufs_read_lock()/di_read_lock() */ ++#define AuLock_DW 1 /* write-lock dentry */ ++#define AuLock_IR (1 << 1) /* read-lock inode */ ++#define AuLock_IW (1 << 2) /* write-lock inode */ ++#define AuLock_FLUSH (1 << 3) /* wait for 'nowait' tasks */ ++#define AuLock_DIRS (1 << 4) /* target is a pair of dirs */ ++ /* except RENAME_EXCHANGE */ ++#define AuLock_NOPLM (1 << 5) /* return err in plm mode */ ++#define AuLock_NOPLMW (1 << 6) /* wait for plm mode ends */ ++#define AuLock_GEN (1 << 7) /* test digen/iigen */ ++#define au_ftest_lock(flags, name) ((flags) & AuLock_##name) ++#define au_fset_lock(flags, name) \ ++ do { (flags) |= AuLock_##name; } while (0) ++#define au_fclr_lock(flags, name) \ ++ do { (flags) &= ~AuLock_##name; } while (0) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* super.c */ ++extern struct file_system_type aufs_fs_type; ++struct inode *au_iget_locked(struct super_block *sb, ino_t ino); ++typedef unsigned long long (*au_arraycb_t)(struct super_block *sb, void *array, ++ unsigned long long max, void *arg); ++void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, ++ struct super_block *sb, void *arg); ++struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max); ++void au_iarray_free(struct inode **a, unsigned long long max); ++ ++/* sbinfo.c */ ++void au_si_free(struct kobject *kobj); ++int au_si_alloc(struct super_block *sb); ++int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr, int may_shrink); ++ ++unsigned int au_sigen_inc(struct super_block *sb); ++aufs_bindex_t au_new_br_id(struct super_block *sb); ++ ++int si_read_lock(struct super_block *sb, int flags); ++int si_write_lock(struct super_block *sb, int flags); ++int aufs_read_lock(struct dentry *dentry, int flags); ++void aufs_read_unlock(struct dentry *dentry, int flags); ++void aufs_write_lock(struct dentry *dentry); ++void aufs_write_unlock(struct dentry *dentry); ++int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags); ++void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2); ++ ++/* wbr_policy.c */ ++extern struct au_wbr_copyup_operations au_wbr_copyup_ops[]; ++extern struct au_wbr_create_operations au_wbr_create_ops[]; ++int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst); ++int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex); ++int au_wbr_do_copyup_bu(struct dentry *dentry, aufs_bindex_t btop); ++ ++/* mvdown.c */ ++int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *arg); ++ ++#ifdef CONFIG_AUFS_FHSM ++/* fhsm.c */ ++ ++static inline pid_t au_fhsm_pid(struct au_fhsm *fhsm) ++{ ++ pid_t pid; ++ ++ spin_lock(&fhsm->fhsm_spin); ++ pid = fhsm->fhsm_pid; ++ spin_unlock(&fhsm->fhsm_spin); ++ ++ return pid; ++} ++ ++void au_fhsm_wrote(struct super_block *sb, aufs_bindex_t bindex, int force); ++void au_fhsm_wrote_all(struct super_block *sb, int force); ++int au_fhsm_fd(struct super_block *sb, int oflags); ++int au_fhsm_br_alloc(struct au_branch *br); ++void au_fhsm_set_bottom(struct super_block *sb, aufs_bindex_t bindex); ++void au_fhsm_fin(struct super_block *sb); ++void au_fhsm_init(struct au_sbinfo *sbinfo); ++void au_fhsm_set(struct au_sbinfo *sbinfo, unsigned int sec); ++void au_fhsm_show(struct seq_file *seq, struct au_sbinfo *sbinfo); ++#else ++AuStubVoid(au_fhsm_wrote, struct super_block *sb, aufs_bindex_t bindex, ++ int force) ++AuStubVoid(au_fhsm_wrote_all, struct super_block *sb, int force) ++AuStub(int, au_fhsm_fd, return -EOPNOTSUPP, struct super_block *sb, int oflags) ++AuStub(pid_t, au_fhsm_pid, return 0, struct au_fhsm *fhsm) ++AuStubInt0(au_fhsm_br_alloc, struct au_branch *br) ++AuStubVoid(au_fhsm_set_bottom, struct super_block *sb, aufs_bindex_t bindex) ++AuStubVoid(au_fhsm_fin, struct super_block *sb) ++AuStubVoid(au_fhsm_init, struct au_sbinfo *sbinfo) ++AuStubVoid(au_fhsm_set, struct au_sbinfo *sbinfo, unsigned int sec) ++AuStubVoid(au_fhsm_show, struct seq_file *seq, struct au_sbinfo *sbinfo) ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_sbinfo *au_sbi(struct super_block *sb) ++{ ++ return sb->s_fs_info; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_EXPORT ++int au_test_nfsd(void); ++void au_export_init(struct super_block *sb); ++void au_xigen_inc(struct inode *inode); ++int au_xigen_new(struct inode *inode); ++int au_xigen_set(struct super_block *sb, struct path *path); ++void au_xigen_clr(struct super_block *sb); ++ ++static inline int au_busy_or_stale(void) ++{ ++ if (!au_test_nfsd()) ++ return -EBUSY; ++ return -ESTALE; ++} ++#else ++AuStubInt0(au_test_nfsd, void) ++AuStubVoid(au_export_init, struct super_block *sb) ++AuStubVoid(au_xigen_inc, struct inode *inode) ++AuStubInt0(au_xigen_new, struct inode *inode) ++AuStubInt0(au_xigen_set, struct super_block *sb, struct path *path) ++AuStubVoid(au_xigen_clr, struct super_block *sb) ++AuStub(int, au_busy_or_stale, return -EBUSY, void) ++#endif /* CONFIG_AUFS_EXPORT */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_SBILIST ++/* module.c */ ++extern struct hlist_bl_head au_sbilist; ++ ++static inline void au_sbilist_init(void) ++{ ++ INIT_HLIST_BL_HEAD(&au_sbilist); ++} ++ ++static inline void au_sbilist_add(struct super_block *sb) ++{ ++ au_hbl_add(&au_sbi(sb)->si_list, &au_sbilist); ++} ++ ++static inline void au_sbilist_del(struct super_block *sb) ++{ ++ au_hbl_del(&au_sbi(sb)->si_list, &au_sbilist); ++} ++ ++#ifdef CONFIG_AUFS_MAGIC_SYSRQ ++static inline void au_sbilist_lock(void) ++{ ++ hlist_bl_lock(&au_sbilist); ++} ++ ++static inline void au_sbilist_unlock(void) ++{ ++ hlist_bl_unlock(&au_sbilist); ++} ++#define AuGFP_SBILIST GFP_ATOMIC ++#else ++AuStubVoid(au_sbilist_lock, void) ++AuStubVoid(au_sbilist_unlock, void) ++#define AuGFP_SBILIST GFP_NOFS ++#endif /* CONFIG_AUFS_MAGIC_SYSRQ */ ++#else ++AuStubVoid(au_sbilist_init, void) ++AuStubVoid(au_sbilist_add, struct super_block *sb) ++AuStubVoid(au_sbilist_del, struct super_block *sb) ++AuStubVoid(au_sbilist_lock, void) ++AuStubVoid(au_sbilist_unlock, void) ++#define AuGFP_SBILIST GFP_NOFS ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline void dbgaufs_si_null(struct au_sbinfo *sbinfo) ++{ ++ /* ++ * This function is a dynamic '__init' function actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++#ifdef CONFIG_DEBUG_FS ++ sbinfo->si_dbgaufs = NULL; ++ sbinfo->si_dbgaufs_plink = NULL; ++ sbinfo->si_dbgaufs_xib = NULL; ++#ifdef CONFIG_AUFS_EXPORT ++ sbinfo->si_dbgaufs_xigen = NULL; ++#endif ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* current->atomic_flags */ ++/* this value should never corrupt the ones defined in linux/sched.h */ ++#define PFA_AUFS 0x10 ++ ++TASK_PFA_TEST(AUFS, test_aufs) /* task_test_aufs */ ++TASK_PFA_SET(AUFS, aufs) /* task_set_aufs */ ++TASK_PFA_CLEAR(AUFS, aufs) /* task_clear_aufs */ ++ ++static inline int si_pid_test(struct super_block *sb) ++{ ++ return !!task_test_aufs(current); ++} ++ ++static inline void si_pid_clr(struct super_block *sb) ++{ ++ AuDebugOn(!task_test_aufs(current)); ++ task_clear_aufs(current); ++} ++ ++static inline void si_pid_set(struct super_block *sb) ++{ ++ AuDebugOn(task_test_aufs(current)); ++ task_set_aufs(current); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock superblock. mainly for entry point functions */ ++#define __si_read_lock(sb) au_rw_read_lock(&au_sbi(sb)->si_rwsem) ++#define __si_write_lock(sb) au_rw_write_lock(&au_sbi(sb)->si_rwsem) ++#define __si_read_trylock(sb) au_rw_read_trylock(&au_sbi(sb)->si_rwsem) ++#define __si_write_trylock(sb) au_rw_write_trylock(&au_sbi(sb)->si_rwsem) ++/* ++#define __si_read_trylock_nested(sb) \ ++ au_rw_read_trylock_nested(&au_sbi(sb)->si_rwsem) ++#define __si_write_trylock_nested(sb) \ ++ au_rw_write_trylock_nested(&au_sbi(sb)->si_rwsem) ++*/ ++ ++#define __si_read_unlock(sb) au_rw_read_unlock(&au_sbi(sb)->si_rwsem) ++#define __si_write_unlock(sb) au_rw_write_unlock(&au_sbi(sb)->si_rwsem) ++#define __si_downgrade_lock(sb) au_rw_dgrade_lock(&au_sbi(sb)->si_rwsem) ++ ++#define SiMustNoWaiters(sb) AuRwMustNoWaiters(&au_sbi(sb)->si_rwsem) ++#define SiMustAnyLock(sb) AuRwMustAnyLock(&au_sbi(sb)->si_rwsem) ++#define SiMustWriteLock(sb) AuRwMustWriteLock(&au_sbi(sb)->si_rwsem) ++ ++static inline void si_noflush_read_lock(struct super_block *sb) ++{ ++ __si_read_lock(sb); ++ si_pid_set(sb); ++} ++ ++static inline int si_noflush_read_trylock(struct super_block *sb) ++{ ++ int locked; ++ ++ locked = __si_read_trylock(sb); ++ if (locked) ++ si_pid_set(sb); ++ return locked; ++} ++ ++static inline void si_noflush_write_lock(struct super_block *sb) ++{ ++ __si_write_lock(sb); ++ si_pid_set(sb); ++} ++ ++static inline int si_noflush_write_trylock(struct super_block *sb) ++{ ++ int locked; ++ ++ locked = __si_write_trylock(sb); ++ if (locked) ++ si_pid_set(sb); ++ return locked; ++} ++ ++#if 0 /* reserved */ ++static inline int si_read_trylock(struct super_block *sb, int flags) ++{ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ return si_noflush_read_trylock(sb); ++} ++#endif ++ ++static inline void si_read_unlock(struct super_block *sb) ++{ ++ si_pid_clr(sb); ++ __si_read_unlock(sb); ++} ++ ++#if 0 /* reserved */ ++static inline int si_write_trylock(struct super_block *sb, int flags) ++{ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ return si_noflush_write_trylock(sb); ++} ++#endif ++ ++static inline void si_write_unlock(struct super_block *sb) ++{ ++ si_pid_clr(sb); ++ __si_write_unlock(sb); ++} ++ ++#if 0 /* reserved */ ++static inline void si_downgrade_lock(struct super_block *sb) ++{ ++ __si_downgrade_lock(sb); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline aufs_bindex_t au_sbbot(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_bbot; ++} ++ ++static inline unsigned int au_mntflags(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_mntflags; ++} ++ ++static inline unsigned int au_sigen(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_generation; ++} ++ ++static inline struct au_branch *au_sbr(struct super_block *sb, ++ aufs_bindex_t bindex) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_branch[0 + bindex]; ++} ++ ++static inline loff_t au_xi_maxent(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_ximaxent; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_SUPER_H__ */ +diff -Nurp linux-5.4/fs/aufs/sysaufs.c linux-5.4-aufs/fs/aufs/sysaufs.c +--- linux-5.4/fs/aufs/sysaufs.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/sysaufs.c 2019-11-28 01:25:59.068925618 +0200 +@@ -0,0 +1,80 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * sysfs interface and lifetime management ++ * they are necessary regardless sysfs is disabled. ++ */ ++ ++#include ++#include "aufs.h" ++ ++unsigned long sysaufs_si_mask; ++struct kset *sysaufs_kset; ++ ++#define AuSiAttr(_name) { \ ++ .attr = { .name = __stringify(_name), .mode = 0444 }, \ ++ .show = sysaufs_si_##_name, \ ++} ++ ++static struct sysaufs_si_attr sysaufs_si_attr_xi_path = AuSiAttr(xi_path); ++struct attribute *sysaufs_si_attrs[] = { ++ &sysaufs_si_attr_xi_path.attr, ++ NULL, ++}; ++ ++static const struct sysfs_ops au_sbi_ops = { ++ .show = sysaufs_si_show ++}; ++ ++static struct kobj_type au_sbi_ktype = { ++ .release = au_si_free, ++ .sysfs_ops = &au_sbi_ops, ++ .default_attrs = sysaufs_si_attrs ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int sysaufs_si_init(struct au_sbinfo *sbinfo) ++{ ++ int err; ++ ++ sbinfo->si_kobj.kset = sysaufs_kset; ++ /* cf. sysaufs_name() */ ++ err = kobject_init_and_add ++ (&sbinfo->si_kobj, &au_sbi_ktype, /*&sysaufs_kset->kobj*/NULL, ++ SysaufsSiNamePrefix "%lx", sysaufs_si_id(sbinfo)); ++ ++ return err; ++} ++ ++void sysaufs_fin(void) ++{ ++ sysfs_remove_group(&sysaufs_kset->kobj, sysaufs_attr_group); ++ kset_unregister(sysaufs_kset); ++} ++ ++int __init sysaufs_init(void) ++{ ++ int err; ++ ++ do { ++ get_random_bytes(&sysaufs_si_mask, sizeof(sysaufs_si_mask)); ++ } while (!sysaufs_si_mask); ++ ++ err = -EINVAL; ++ sysaufs_kset = kset_create_and_add(AUFS_NAME, NULL, fs_kobj); ++ if (unlikely(!sysaufs_kset)) ++ goto out; ++ err = PTR_ERR(sysaufs_kset); ++ if (IS_ERR(sysaufs_kset)) ++ goto out; ++ err = sysfs_create_group(&sysaufs_kset->kobj, sysaufs_attr_group); ++ if (unlikely(err)) ++ kset_unregister(sysaufs_kset); ++ ++out: ++ return err; ++} +diff -Nurp linux-5.4/fs/aufs/sysaufs.h linux-5.4-aufs/fs/aufs/sysaufs.h +--- linux-5.4/fs/aufs/sysaufs.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/sysaufs.h 2019-11-28 01:25:59.068925618 +0200 +@@ -0,0 +1,89 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * sysfs interface and mount lifetime management ++ */ ++ ++#ifndef __SYSAUFS_H__ ++#define __SYSAUFS_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "module.h" ++ ++struct super_block; ++struct au_sbinfo; ++ ++struct sysaufs_si_attr { ++ struct attribute attr; ++ int (*show)(struct seq_file *seq, struct super_block *sb); ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* sysaufs.c */ ++extern unsigned long sysaufs_si_mask; ++extern struct kset *sysaufs_kset; ++extern struct attribute *sysaufs_si_attrs[]; ++int sysaufs_si_init(struct au_sbinfo *sbinfo); ++int __init sysaufs_init(void); ++void sysaufs_fin(void); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* some people doesn't like to show a pointer in kernel */ ++static inline unsigned long sysaufs_si_id(struct au_sbinfo *sbinfo) ++{ ++ return sysaufs_si_mask ^ (unsigned long)sbinfo; ++} ++ ++#define SysaufsSiNamePrefix "si_" ++#define SysaufsSiNameLen (sizeof(SysaufsSiNamePrefix) + 16) ++static inline void sysaufs_name(struct au_sbinfo *sbinfo, char *name) ++{ ++ snprintf(name, SysaufsSiNameLen, SysaufsSiNamePrefix "%lx", ++ sysaufs_si_id(sbinfo)); ++} ++ ++struct au_branch; ++#ifdef CONFIG_SYSFS ++/* sysfs.c */ ++extern struct attribute_group *sysaufs_attr_group; ++ ++int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb); ++ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, ++ char *buf); ++long au_brinfo_ioctl(struct file *file, unsigned long arg); ++#ifdef CONFIG_COMPAT ++long au_brinfo_compat_ioctl(struct file *file, unsigned long arg); ++#endif ++ ++void sysaufs_br_init(struct au_branch *br); ++void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex); ++void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex); ++ ++#define sysaufs_brs_init() do {} while (0) ++ ++#else ++#define sysaufs_attr_group NULL ++ ++AuStubInt0(sysaufs_si_xi_path, struct seq_file *seq, struct super_block *sb) ++AuStub(ssize_t, sysaufs_si_show, return 0, struct kobject *kobj, ++ struct attribute *attr, char *buf) ++AuStubVoid(sysaufs_br_init, struct au_branch *br) ++AuStubVoid(sysaufs_brs_add, struct super_block *sb, aufs_bindex_t bindex) ++AuStubVoid(sysaufs_brs_del, struct super_block *sb, aufs_bindex_t bindex) ++ ++static inline void sysaufs_brs_init(void) ++{ ++ sysaufs_brs = 0; ++} ++ ++#endif /* CONFIG_SYSFS */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __SYSAUFS_H__ */ +diff -Nurp linux-5.4/fs/aufs/sysfs.c linux-5.4-aufs/fs/aufs/sysfs.c +--- linux-5.4/fs/aufs/sysfs.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/sysfs.c 2019-11-28 01:25:59.068925618 +0200 +@@ -0,0 +1,338 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * sysfs interface ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++static struct attribute *au_attr[] = { ++ NULL, /* need to NULL terminate the list of attributes */ ++}; ++ ++static struct attribute_group sysaufs_attr_group_body = { ++ .attrs = au_attr ++}; ++ ++struct attribute_group *sysaufs_attr_group = &sysaufs_attr_group_body; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb) ++{ ++ int err; ++ ++ SiMustAnyLock(sb); ++ ++ err = 0; ++ if (au_opt_test(au_mntflags(sb), XINO)) { ++ err = au_xino_path(seq, au_sbi(sb)->si_xib); ++ seq_putc(seq, '\n'); ++ } ++ return err; ++} ++ ++/* ++ * the lifetime of branch is independent from the entry under sysfs. ++ * sysfs handles the lifetime of the entry, and never call ->show() after it is ++ * unlinked. ++ */ ++static int sysaufs_si_br(struct seq_file *seq, struct super_block *sb, ++ aufs_bindex_t bindex, int idx) ++{ ++ int err; ++ struct path path; ++ struct dentry *root; ++ struct au_branch *br; ++ au_br_perm_str_t perm; ++ ++ AuDbg("b%d\n", bindex); ++ ++ err = 0; ++ root = sb->s_root; ++ di_read_lock_parent(root, !AuLock_IR); ++ br = au_sbr(sb, bindex); ++ ++ switch (idx) { ++ case AuBrSysfs_BR: ++ path.mnt = au_br_mnt(br); ++ path.dentry = au_h_dptr(root, bindex); ++ err = au_seq_path(seq, &path); ++ if (!err) { ++ au_optstr_br_perm(&perm, br->br_perm); ++ seq_printf(seq, "=%s\n", perm.a); ++ } ++ break; ++ case AuBrSysfs_BRID: ++ seq_printf(seq, "%d\n", br->br_id); ++ break; ++ } ++ di_read_unlock(root, !AuLock_IR); ++ if (unlikely(err || seq_has_overflowed(seq))) ++ err = -E2BIG; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct seq_file *au_seq(char *p, ssize_t len) ++{ ++ struct seq_file *seq; ++ ++ seq = kzalloc(sizeof(*seq), GFP_NOFS); ++ if (seq) { ++ /* mutex_init(&seq.lock); */ ++ seq->buf = p; ++ seq->size = len; ++ return seq; /* success */ ++ } ++ ++ seq = ERR_PTR(-ENOMEM); ++ return seq; ++} ++ ++#define SysaufsBr_PREFIX "br" ++#define SysaufsBrid_PREFIX "brid" ++ ++/* todo: file size may exceed PAGE_SIZE */ ++ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, ++ char *buf) ++{ ++ ssize_t err; ++ int idx; ++ long l; ++ aufs_bindex_t bbot; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ struct seq_file *seq; ++ char *name; ++ struct attribute **cattr; ++ ++ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); ++ sb = sbinfo->si_sb; ++ ++ /* ++ * prevent a race condition between sysfs and aufs. ++ * for instance, sysfs_file_read() calls sysfs_get_active_two() which ++ * prohibits maintaining the sysfs entries. ++ * hew we acquire read lock after sysfs_get_active_two(). ++ * on the other hand, the remount process may maintain the sysfs/aufs ++ * entries after acquiring write lock. ++ * it can cause a deadlock. ++ * simply we gave up processing read here. ++ */ ++ err = -EBUSY; ++ if (unlikely(!si_noflush_read_trylock(sb))) ++ goto out; ++ ++ seq = au_seq(buf, PAGE_SIZE); ++ err = PTR_ERR(seq); ++ if (IS_ERR(seq)) ++ goto out_unlock; ++ ++ name = (void *)attr->name; ++ cattr = sysaufs_si_attrs; ++ while (*cattr) { ++ if (!strcmp(name, (*cattr)->name)) { ++ err = container_of(*cattr, struct sysaufs_si_attr, attr) ++ ->show(seq, sb); ++ goto out_seq; ++ } ++ cattr++; ++ } ++ ++ if (!strncmp(name, SysaufsBrid_PREFIX, ++ sizeof(SysaufsBrid_PREFIX) - 1)) { ++ idx = AuBrSysfs_BRID; ++ name += sizeof(SysaufsBrid_PREFIX) - 1; ++ } else if (!strncmp(name, SysaufsBr_PREFIX, ++ sizeof(SysaufsBr_PREFIX) - 1)) { ++ idx = AuBrSysfs_BR; ++ name += sizeof(SysaufsBr_PREFIX) - 1; ++ } else ++ BUG(); ++ ++ err = kstrtol(name, 10, &l); ++ if (!err) { ++ bbot = au_sbbot(sb); ++ if (l <= bbot) ++ err = sysaufs_si_br(seq, sb, (aufs_bindex_t)l, idx); ++ else ++ err = -ENOENT; ++ } ++ ++out_seq: ++ if (!err) { ++ err = seq->count; ++ /* sysfs limit */ ++ if (unlikely(err == PAGE_SIZE)) ++ err = -EFBIG; ++ } ++ au_kfree_rcu(seq); ++out_unlock: ++ si_read_unlock(sb); ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_brinfo(struct super_block *sb, union aufs_brinfo __user *arg) ++{ ++ int err; ++ int16_t brid; ++ aufs_bindex_t bindex, bbot; ++ size_t sz; ++ char *buf; ++ struct seq_file *seq; ++ struct au_branch *br; ++ ++ si_read_lock(sb, AuLock_FLUSH); ++ bbot = au_sbbot(sb); ++ err = bbot + 1; ++ if (!arg) ++ goto out; ++ ++ err = -ENOMEM; ++ buf = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!buf)) ++ goto out; ++ ++ seq = au_seq(buf, PAGE_SIZE); ++ err = PTR_ERR(seq); ++ if (IS_ERR(seq)) ++ goto out_buf; ++ ++ sz = sizeof(*arg) - offsetof(union aufs_brinfo, path); ++ for (bindex = 0; bindex <= bbot; bindex++, arg++) { ++ /* VERIFY_WRITE */ ++ err = !access_ok(arg, sizeof(*arg)); ++ if (unlikely(err)) ++ break; ++ ++ br = au_sbr(sb, bindex); ++ brid = br->br_id; ++ BUILD_BUG_ON(sizeof(brid) != sizeof(arg->id)); ++ err = __put_user(brid, &arg->id); ++ if (unlikely(err)) ++ break; ++ ++ BUILD_BUG_ON(sizeof(br->br_perm) != sizeof(arg->perm)); ++ err = __put_user(br->br_perm, &arg->perm); ++ if (unlikely(err)) ++ break; ++ ++ err = au_seq_path(seq, &br->br_path); ++ if (unlikely(err)) ++ break; ++ seq_putc(seq, '\0'); ++ if (!seq_has_overflowed(seq)) { ++ err = copy_to_user(arg->path, seq->buf, seq->count); ++ seq->count = 0; ++ if (unlikely(err)) ++ break; ++ } else { ++ err = -E2BIG; ++ goto out_seq; ++ } ++ } ++ if (unlikely(err)) ++ err = -EFAULT; ++ ++out_seq: ++ au_kfree_rcu(seq); ++out_buf: ++ free_page((unsigned long)buf); ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++long au_brinfo_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_brinfo(file->f_path.dentry->d_sb, (void __user *)arg); ++} ++ ++#ifdef CONFIG_COMPAT ++long au_brinfo_compat_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_brinfo(file->f_path.dentry->d_sb, compat_ptr(arg)); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++void sysaufs_br_init(struct au_branch *br) ++{ ++ int i; ++ struct au_brsysfs *br_sysfs; ++ struct attribute *attr; ++ ++ br_sysfs = br->br_sysfs; ++ for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { ++ attr = &br_sysfs->attr; ++ sysfs_attr_init(attr); ++ attr->name = br_sysfs->name; ++ attr->mode = 0444; ++ br_sysfs++; ++ } ++} ++ ++void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ struct au_branch *br; ++ struct kobject *kobj; ++ struct au_brsysfs *br_sysfs; ++ int i; ++ aufs_bindex_t bbot; ++ ++ if (!sysaufs_brs) ++ return; ++ ++ kobj = &au_sbi(sb)->si_kobj; ++ bbot = au_sbbot(sb); ++ for (; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ br_sysfs = br->br_sysfs; ++ for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { ++ sysfs_remove_file(kobj, &br_sysfs->attr); ++ br_sysfs++; ++ } ++ } ++} ++ ++void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ int err, i; ++ aufs_bindex_t bbot; ++ struct kobject *kobj; ++ struct au_branch *br; ++ struct au_brsysfs *br_sysfs; ++ ++ if (!sysaufs_brs) ++ return; ++ ++ kobj = &au_sbi(sb)->si_kobj; ++ bbot = au_sbbot(sb); ++ for (; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ br_sysfs = br->br_sysfs; ++ snprintf(br_sysfs[AuBrSysfs_BR].name, sizeof(br_sysfs->name), ++ SysaufsBr_PREFIX "%d", bindex); ++ snprintf(br_sysfs[AuBrSysfs_BRID].name, sizeof(br_sysfs->name), ++ SysaufsBrid_PREFIX "%d", bindex); ++ for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { ++ err = sysfs_create_file(kobj, &br_sysfs->attr); ++ if (unlikely(err)) ++ pr_warn("failed %s under sysfs(%d)\n", ++ br_sysfs->name, err); ++ br_sysfs++; ++ } ++ } ++} +diff -Nurp linux-5.4/fs/aufs/sysrq.c linux-5.4-aufs/fs/aufs/sysrq.c +--- linux-5.4/fs/aufs/sysrq.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/sysrq.c 2019-11-28 01:25:59.068925618 +0200 +@@ -0,0 +1,147 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * magic sysrq handler ++ */ ++ ++/* #include */ ++#include ++#include "aufs.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void sysrq_sb(struct super_block *sb) ++{ ++ char *plevel; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ struct hlist_bl_head *files; ++ struct hlist_bl_node *pos; ++ struct au_finfo *finfo; ++ ++ plevel = au_plevel; ++ au_plevel = KERN_WARNING; ++ ++ /* since we define pr_fmt, call printk directly */ ++#define pr(str) printk(KERN_WARNING AUFS_NAME ": " str) ++ ++ sbinfo = au_sbi(sb); ++ printk(KERN_WARNING "si=%lx\n", sysaufs_si_id(sbinfo)); ++ pr("superblock\n"); ++ au_dpri_sb(sb); ++ ++#if 0 ++ pr("root dentry\n"); ++ au_dpri_dentry(sb->s_root); ++ pr("root inode\n"); ++ au_dpri_inode(d_inode(sb->s_root)); ++#endif ++ ++#if 0 ++ do { ++ int err, i, j, ndentry; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ ++ err = au_dpages_init(&dpages, GFP_ATOMIC); ++ if (unlikely(err)) ++ break; ++ err = au_dcsub_pages(&dpages, sb->s_root, NULL, NULL); ++ if (!err) ++ for (i = 0; i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ ndentry = dpage->ndentry; ++ for (j = 0; j < ndentry; j++) ++ au_dpri_dentry(dpage->dentries[j]); ++ } ++ au_dpages_free(&dpages); ++ } while (0); ++#endif ++ ++#if 1 ++ { ++ struct inode *i; ++ ++ pr("isolated inode\n"); ++ spin_lock(&sb->s_inode_list_lock); ++ list_for_each_entry(i, &sb->s_inodes, i_sb_list) { ++ spin_lock(&i->i_lock); ++ if (1 || hlist_empty(&i->i_dentry)) ++ au_dpri_inode(i); ++ spin_unlock(&i->i_lock); ++ } ++ spin_unlock(&sb->s_inode_list_lock); ++ } ++#endif ++ pr("files\n"); ++ files = &au_sbi(sb)->si_files; ++ hlist_bl_lock(files); ++ hlist_bl_for_each_entry(finfo, pos, files, fi_hlist) { ++ umode_t mode; ++ ++ file = finfo->fi_file; ++ mode = file_inode(file)->i_mode; ++ if (!special_file(mode)) ++ au_dpri_file(file); ++ } ++ hlist_bl_unlock(files); ++ pr("done\n"); ++ ++#undef pr ++ au_plevel = plevel; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* module parameter */ ++static char *aufs_sysrq_key = "a"; ++module_param_named(sysrq, aufs_sysrq_key, charp, 0444); ++MODULE_PARM_DESC(sysrq, "MagicSysRq key for " AUFS_NAME); ++ ++static void au_sysrq(int key __maybe_unused) ++{ ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_node *pos; ++ ++ lockdep_off(); ++ au_sbilist_lock(); ++ hlist_bl_for_each_entry(sbinfo, pos, &au_sbilist, si_list) ++ sysrq_sb(sbinfo->si_sb); ++ au_sbilist_unlock(); ++ lockdep_on(); ++} ++ ++static struct sysrq_key_op au_sysrq_op = { ++ .handler = au_sysrq, ++ .help_msg = "Aufs", ++ .action_msg = "Aufs", ++ .enable_mask = SYSRQ_ENABLE_DUMP ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int __init au_sysrq_init(void) ++{ ++ int err; ++ char key; ++ ++ err = -1; ++ key = *aufs_sysrq_key; ++ if ('a' <= key && key <= 'z') ++ err = register_sysrq_key(key, &au_sysrq_op); ++ if (unlikely(err)) ++ pr_err("err %d, sysrq=%c\n", err, key); ++ return err; ++} ++ ++void au_sysrq_fin(void) ++{ ++ int err; ++ ++ err = unregister_sysrq_key(*aufs_sysrq_key, &au_sysrq_op); ++ if (unlikely(err)) ++ pr_err("err %d (ignored)\n", err); ++} +diff -Nurp linux-5.4/fs/aufs/wbr_policy.c linux-5.4-aufs/fs/aufs/wbr_policy.c +--- linux-5.4/fs/aufs/wbr_policy.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/wbr_policy.c 2019-11-28 01:25:59.068925618 +0200 +@@ -0,0 +1,817 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * policies for selecting one among multiple writable branches ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* subset of cpup_attr() */ ++static noinline_for_stack ++int au_cpdown_attr(struct path *h_path, struct dentry *h_src) ++{ ++ int err, sbits; ++ struct iattr ia; ++ struct inode *h_isrc; ++ ++ h_isrc = d_inode(h_src); ++ ia.ia_valid = ATTR_FORCE | ATTR_MODE | ATTR_UID | ATTR_GID; ++ ia.ia_mode = h_isrc->i_mode; ++ ia.ia_uid = h_isrc->i_uid; ++ ia.ia_gid = h_isrc->i_gid; ++ sbits = !!(ia.ia_mode & (S_ISUID | S_ISGID)); ++ au_cpup_attr_flags(d_inode(h_path->dentry), h_isrc->i_flags); ++ /* no delegation since it is just created */ ++ err = vfsub_sio_notify_change(h_path, &ia, /*delegated*/NULL); ++ ++ /* is this nfs only? */ ++ if (!err && sbits && au_test_nfs(h_path->dentry->d_sb)) { ++ ia.ia_valid = ATTR_FORCE | ATTR_MODE; ++ ia.ia_mode = h_isrc->i_mode; ++ err = vfsub_sio_notify_change(h_path, &ia, /*delegated*/NULL); ++ } ++ ++ return err; ++} ++ ++#define AuCpdown_PARENT_OPQ 1 ++#define AuCpdown_WHED (1 << 1) ++#define AuCpdown_MADE_DIR (1 << 2) ++#define AuCpdown_DIROPQ (1 << 3) ++#define au_ftest_cpdown(flags, name) ((flags) & AuCpdown_##name) ++#define au_fset_cpdown(flags, name) \ ++ do { (flags) |= AuCpdown_##name; } while (0) ++#define au_fclr_cpdown(flags, name) \ ++ do { (flags) &= ~AuCpdown_##name; } while (0) ++ ++static int au_cpdown_dir_opq(struct dentry *dentry, aufs_bindex_t bdst, ++ unsigned int *flags) ++{ ++ int err; ++ struct dentry *opq_dentry; ++ ++ opq_dentry = au_diropq_create(dentry, bdst); ++ err = PTR_ERR(opq_dentry); ++ if (IS_ERR(opq_dentry)) ++ goto out; ++ dput(opq_dentry); ++ au_fset_cpdown(*flags, DIROPQ); ++ ++out: ++ return err; ++} ++ ++static int au_cpdown_dir_wh(struct dentry *dentry, struct dentry *h_parent, ++ struct inode *dir, aufs_bindex_t bdst) ++{ ++ int err; ++ struct path h_path; ++ struct au_branch *br; ++ ++ br = au_sbr(dentry->d_sb, bdst); ++ h_path.dentry = au_wh_lkup(h_parent, &dentry->d_name, br); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) ++ goto out; ++ ++ err = 0; ++ if (d_is_positive(h_path.dentry)) { ++ h_path.mnt = au_br_mnt(br); ++ err = au_wh_unlink_dentry(au_h_iptr(dir, bdst), &h_path, ++ dentry); ++ } ++ dput(h_path.dentry); ++ ++out: ++ return err; ++} ++ ++static int au_cpdown_dir(struct dentry *dentry, aufs_bindex_t bdst, ++ struct au_pin *pin, ++ struct dentry *h_parent, void *arg) ++{ ++ int err, rerr; ++ aufs_bindex_t bopq, btop; ++ struct path h_path; ++ struct dentry *parent; ++ struct inode *h_dir, *h_inode, *inode, *dir; ++ unsigned int *flags = arg; ++ ++ btop = au_dbtop(dentry); ++ /* dentry is di-locked */ ++ parent = dget_parent(dentry); ++ dir = d_inode(parent); ++ h_dir = d_inode(h_parent); ++ AuDebugOn(h_dir != au_h_iptr(dir, bdst)); ++ IMustLock(h_dir); ++ ++ err = au_lkup_neg(dentry, bdst, /*wh*/0); ++ if (unlikely(err < 0)) ++ goto out; ++ h_path.dentry = au_h_dptr(dentry, bdst); ++ h_path.mnt = au_sbr_mnt(dentry->d_sb, bdst); ++ err = vfsub_sio_mkdir(au_h_iptr(dir, bdst), &h_path, 0755); ++ if (unlikely(err)) ++ goto out_put; ++ au_fset_cpdown(*flags, MADE_DIR); ++ ++ bopq = au_dbdiropq(dentry); ++ au_fclr_cpdown(*flags, WHED); ++ au_fclr_cpdown(*flags, DIROPQ); ++ if (au_dbwh(dentry) == bdst) ++ au_fset_cpdown(*flags, WHED); ++ if (!au_ftest_cpdown(*flags, PARENT_OPQ) && bopq <= bdst) ++ au_fset_cpdown(*flags, PARENT_OPQ); ++ h_inode = d_inode(h_path.dentry); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ if (au_ftest_cpdown(*flags, WHED)) { ++ err = au_cpdown_dir_opq(dentry, bdst, flags); ++ if (unlikely(err)) { ++ inode_unlock(h_inode); ++ goto out_dir; ++ } ++ } ++ ++ err = au_cpdown_attr(&h_path, au_h_dptr(dentry, btop)); ++ inode_unlock(h_inode); ++ if (unlikely(err)) ++ goto out_opq; ++ ++ if (au_ftest_cpdown(*flags, WHED)) { ++ err = au_cpdown_dir_wh(dentry, h_parent, dir, bdst); ++ if (unlikely(err)) ++ goto out_opq; ++ } ++ ++ inode = d_inode(dentry); ++ if (au_ibbot(inode) < bdst) ++ au_set_ibbot(inode, bdst); ++ au_set_h_iptr(inode, bdst, au_igrab(h_inode), ++ au_hi_flags(inode, /*isdir*/1)); ++ au_fhsm_wrote(dentry->d_sb, bdst, /*force*/0); ++ goto out; /* success */ ++ ++ /* revert */ ++out_opq: ++ if (au_ftest_cpdown(*flags, DIROPQ)) { ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ rerr = au_diropq_remove(dentry, bdst); ++ inode_unlock(h_inode); ++ if (unlikely(rerr)) { ++ AuIOErr("failed removing diropq for %pd b%d (%d)\n", ++ dentry, bdst, rerr); ++ err = -EIO; ++ goto out; ++ } ++ } ++out_dir: ++ if (au_ftest_cpdown(*flags, MADE_DIR)) { ++ rerr = vfsub_sio_rmdir(au_h_iptr(dir, bdst), &h_path); ++ if (unlikely(rerr)) { ++ AuIOErr("failed removing %pd b%d (%d)\n", ++ dentry, bdst, rerr); ++ err = -EIO; ++ } ++ } ++out_put: ++ au_set_h_dptr(dentry, bdst, NULL); ++ if (au_dbbot(dentry) == bdst) ++ au_update_dbbot(dentry); ++out: ++ dput(parent); ++ return err; ++} ++ ++int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst) ++{ ++ int err; ++ unsigned int flags; ++ ++ flags = 0; ++ err = au_cp_dirs(dentry, bdst, au_cpdown_dir, &flags); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policies for create */ ++ ++int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ int err, i, j, ndentry; ++ aufs_bindex_t bopq; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries, *parent, *d; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ parent = dget_parent(dentry); ++ err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/0); ++ if (unlikely(err)) ++ goto out_free; ++ ++ err = bindex; ++ for (i = 0; i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ ndentry = dpage->ndentry; ++ for (j = 0; j < ndentry; j++) { ++ d = dentries[j]; ++ di_read_lock_parent2(d, !AuLock_IR); ++ bopq = au_dbdiropq(d); ++ di_read_unlock(d, !AuLock_IR); ++ if (bopq >= 0 && bopq < err) ++ err = bopq; ++ } ++ } ++ ++out_free: ++ dput(parent); ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++static int au_wbr_bu(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ for (; bindex >= 0; bindex--) ++ if (!au_br_rdonly(au_sbr(sb, bindex))) ++ return bindex; ++ return -EROFS; ++} ++ ++/* top down parent */ ++static int au_wbr_create_tdp(struct dentry *dentry, ++ unsigned int flags __maybe_unused) ++{ ++ int err; ++ aufs_bindex_t btop, bindex; ++ struct super_block *sb; ++ struct dentry *parent, *h_parent; ++ ++ sb = dentry->d_sb; ++ btop = au_dbtop(dentry); ++ err = btop; ++ if (!au_br_rdonly(au_sbr(sb, btop))) ++ goto out; ++ ++ err = -EROFS; ++ parent = dget_parent(dentry); ++ for (bindex = au_dbtop(parent); bindex < btop; bindex++) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || d_is_negative(h_parent)) ++ continue; ++ ++ if (!au_br_rdonly(au_sbr(sb, bindex))) { ++ err = bindex; ++ break; ++ } ++ } ++ dput(parent); ++ ++ /* bottom up here */ ++ if (unlikely(err < 0)) { ++ err = au_wbr_bu(sb, btop - 1); ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ } ++ ++out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* an exception for the policy other than tdp */ ++static int au_wbr_create_exp(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bwh, bdiropq; ++ struct dentry *parent; ++ ++ err = -1; ++ bwh = au_dbwh(dentry); ++ parent = dget_parent(dentry); ++ bdiropq = au_dbdiropq(parent); ++ if (bwh >= 0) { ++ if (bdiropq >= 0) ++ err = min(bdiropq, bwh); ++ else ++ err = bwh; ++ AuDbg("%d\n", err); ++ } else if (bdiropq >= 0) { ++ err = bdiropq; ++ AuDbg("%d\n", err); ++ } ++ dput(parent); ++ ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ ++ if (err >= 0 && au_br_rdonly(au_sbr(dentry->d_sb, err))) ++ err = -1; ++ ++ AuDbg("%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* round robin */ ++static int au_wbr_create_init_rr(struct super_block *sb) ++{ ++ int err; ++ ++ err = au_wbr_bu(sb, au_sbbot(sb)); ++ atomic_set(&au_sbi(sb)->si_wbr_rr_next, -err); /* less important */ ++ /* smp_mb(); */ ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_create_rr(struct dentry *dentry, unsigned int flags) ++{ ++ int err, nbr; ++ unsigned int u; ++ aufs_bindex_t bindex, bbot; ++ struct super_block *sb; ++ atomic_t *next; ++ ++ err = au_wbr_create_exp(dentry); ++ if (err >= 0) ++ goto out; ++ ++ sb = dentry->d_sb; ++ next = &au_sbi(sb)->si_wbr_rr_next; ++ bbot = au_sbbot(sb); ++ nbr = bbot + 1; ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ if (!au_ftest_wbr(flags, DIR)) { ++ err = atomic_dec_return(next) + 1; ++ /* modulo for 0 is meaningless */ ++ if (unlikely(!err)) ++ err = atomic_dec_return(next) + 1; ++ } else ++ err = atomic_read(next); ++ AuDbg("%d\n", err); ++ u = err; ++ err = u % nbr; ++ AuDbg("%d\n", err); ++ if (!au_br_rdonly(au_sbr(sb, err))) ++ break; ++ err = -EROFS; ++ } ++ ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ ++out: ++ AuDbg("%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* most free space */ ++static void au_mfs(struct dentry *dentry, struct dentry *parent) ++{ ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_wbr_mfs *mfs; ++ struct dentry *h_parent; ++ aufs_bindex_t bindex, bbot; ++ int err; ++ unsigned long long b, bavail; ++ struct path h_path; ++ /* reduce the stack usage */ ++ struct kstatfs *st; ++ ++ st = kmalloc(sizeof(*st), GFP_NOFS); ++ if (unlikely(!st)) { ++ AuWarn1("failed updating mfs(%d), ignored\n", -ENOMEM); ++ return; ++ } ++ ++ bavail = 0; ++ sb = dentry->d_sb; ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ MtxMustLock(&mfs->mfs_lock); ++ mfs->mfs_bindex = -EROFS; ++ mfs->mfsrr_bytes = 0; ++ if (!parent) { ++ bindex = 0; ++ bbot = au_sbbot(sb); ++ } else { ++ bindex = au_dbtop(parent); ++ bbot = au_dbtaildir(parent); ++ } ++ ++ for (; bindex <= bbot; bindex++) { ++ if (parent) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || d_is_negative(h_parent)) ++ continue; ++ } ++ br = au_sbr(sb, bindex); ++ if (au_br_rdonly(br)) ++ continue; ++ ++ /* sb->s_root for NFS is unreliable */ ++ h_path.mnt = au_br_mnt(br); ++ h_path.dentry = h_path.mnt->mnt_root; ++ err = vfs_statfs(&h_path, st); ++ if (unlikely(err)) { ++ AuWarn1("failed statfs, b%d, %d\n", bindex, err); ++ continue; ++ } ++ ++ /* when the available size is equal, select the lower one */ ++ BUILD_BUG_ON(sizeof(b) < sizeof(st->f_bavail) ++ || sizeof(b) < sizeof(st->f_bsize)); ++ b = st->f_bavail * st->f_bsize; ++ br->br_wbr->wbr_bytes = b; ++ if (b >= bavail) { ++ bavail = b; ++ mfs->mfs_bindex = bindex; ++ mfs->mfs_jiffy = jiffies; ++ } ++ } ++ ++ mfs->mfsrr_bytes = bavail; ++ AuDbg("b%d\n", mfs->mfs_bindex); ++ au_kfree_rcu(st); ++} ++ ++static int au_wbr_create_mfs(struct dentry *dentry, unsigned int flags) ++{ ++ int err; ++ struct dentry *parent; ++ struct super_block *sb; ++ struct au_wbr_mfs *mfs; ++ ++ err = au_wbr_create_exp(dentry); ++ if (err >= 0) ++ goto out; ++ ++ sb = dentry->d_sb; ++ parent = NULL; ++ if (au_ftest_wbr(flags, PARENT)) ++ parent = dget_parent(dentry); ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ mutex_lock(&mfs->mfs_lock); ++ if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire) ++ || mfs->mfs_bindex < 0 ++ || au_br_rdonly(au_sbr(sb, mfs->mfs_bindex))) ++ au_mfs(dentry, parent); ++ mutex_unlock(&mfs->mfs_lock); ++ err = mfs->mfs_bindex; ++ dput(parent); ++ ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ ++out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_create_init_mfs(struct super_block *sb) ++{ ++ struct au_wbr_mfs *mfs; ++ ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ mutex_init(&mfs->mfs_lock); ++ mfs->mfs_jiffy = 0; ++ mfs->mfs_bindex = -EROFS; ++ ++ return 0; ++} ++ ++static int au_wbr_create_fin_mfs(struct super_block *sb __maybe_unused) ++{ ++ mutex_destroy(&au_sbi(sb)->si_wbr_mfs.mfs_lock); ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* top down regardless parent, and then mfs */ ++static int au_wbr_create_tdmfs(struct dentry *dentry, ++ unsigned int flags __maybe_unused) ++{ ++ int err; ++ aufs_bindex_t bwh, btail, bindex, bfound, bmfs; ++ unsigned long long watermark; ++ struct super_block *sb; ++ struct au_wbr_mfs *mfs; ++ struct au_branch *br; ++ struct dentry *parent; ++ ++ sb = dentry->d_sb; ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ mutex_lock(&mfs->mfs_lock); ++ if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire) ++ || mfs->mfs_bindex < 0) ++ au_mfs(dentry, /*parent*/NULL); ++ watermark = mfs->mfsrr_watermark; ++ bmfs = mfs->mfs_bindex; ++ mutex_unlock(&mfs->mfs_lock); ++ ++ /* another style of au_wbr_create_exp() */ ++ bwh = au_dbwh(dentry); ++ parent = dget_parent(dentry); ++ btail = au_dbtaildir(parent); ++ if (bwh >= 0 && bwh < btail) ++ btail = bwh; ++ ++ err = au_wbr_nonopq(dentry, btail); ++ if (unlikely(err < 0)) ++ goto out; ++ btail = err; ++ bfound = -1; ++ for (bindex = 0; bindex <= btail; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_rdonly(br)) ++ continue; ++ if (br->br_wbr->wbr_bytes > watermark) { ++ bfound = bindex; ++ break; ++ } ++ } ++ err = bfound; ++ if (err < 0) ++ err = bmfs; ++ ++out: ++ dput(parent); ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* most free space and then round robin */ ++static int au_wbr_create_mfsrr(struct dentry *dentry, unsigned int flags) ++{ ++ int err; ++ struct au_wbr_mfs *mfs; ++ ++ err = au_wbr_create_mfs(dentry, flags); ++ if (err >= 0) { ++ mfs = &au_sbi(dentry->d_sb)->si_wbr_mfs; ++ mutex_lock(&mfs->mfs_lock); ++ if (mfs->mfsrr_bytes < mfs->mfsrr_watermark) ++ err = au_wbr_create_rr(dentry, flags); ++ mutex_unlock(&mfs->mfs_lock); ++ } ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_create_init_mfsrr(struct super_block *sb) ++{ ++ int err; ++ ++ au_wbr_create_init_mfs(sb); /* ignore */ ++ err = au_wbr_create_init_rr(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* top down parent and most free space */ ++static int au_wbr_create_pmfs(struct dentry *dentry, unsigned int flags) ++{ ++ int err, e2; ++ unsigned long long b; ++ aufs_bindex_t bindex, btop, bbot; ++ struct super_block *sb; ++ struct dentry *parent, *h_parent; ++ struct au_branch *br; ++ ++ err = au_wbr_create_tdp(dentry, flags); ++ if (unlikely(err < 0)) ++ goto out; ++ parent = dget_parent(dentry); ++ btop = au_dbtop(parent); ++ bbot = au_dbtaildir(parent); ++ if (btop == bbot) ++ goto out_parent; /* success */ ++ ++ e2 = au_wbr_create_mfs(dentry, flags); ++ if (e2 < 0) ++ goto out_parent; /* success */ ++ ++ /* when the available size is equal, select upper one */ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, err); ++ b = br->br_wbr->wbr_bytes; ++ AuDbg("b%d, %llu\n", err, b); ++ ++ for (bindex = btop; bindex <= bbot; bindex++) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || d_is_negative(h_parent)) ++ continue; ++ ++ br = au_sbr(sb, bindex); ++ if (!au_br_rdonly(br) && br->br_wbr->wbr_bytes > b) { ++ b = br->br_wbr->wbr_bytes; ++ err = bindex; ++ AuDbg("b%d, %llu\n", err, b); ++ } ++ } ++ ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ ++out_parent: ++ dput(parent); ++out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * - top down parent ++ * - most free space with parent ++ * - most free space round-robin regardless parent ++ */ ++static int au_wbr_create_pmfsrr(struct dentry *dentry, unsigned int flags) ++{ ++ int err; ++ unsigned long long watermark; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_wbr_mfs *mfs; ++ ++ err = au_wbr_create_pmfs(dentry, flags | AuWbr_PARENT); ++ if (unlikely(err < 0)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, err); ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ mutex_lock(&mfs->mfs_lock); ++ watermark = mfs->mfsrr_watermark; ++ mutex_unlock(&mfs->mfs_lock); ++ if (br->br_wbr->wbr_bytes < watermark) ++ /* regardless the parent dir */ ++ err = au_wbr_create_mfsrr(dentry, flags); ++ ++out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policies for copyup */ ++ ++/* top down parent */ ++static int au_wbr_copyup_tdp(struct dentry *dentry) ++{ ++ return au_wbr_create_tdp(dentry, /*flags, anything is ok*/0); ++} ++ ++/* bottom up parent */ ++static int au_wbr_copyup_bup(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bindex, btop; ++ struct dentry *parent, *h_parent; ++ struct super_block *sb; ++ ++ err = -EROFS; ++ sb = dentry->d_sb; ++ parent = dget_parent(dentry); ++ btop = au_dbtop(parent); ++ for (bindex = au_dbtop(dentry); bindex >= btop; bindex--) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || d_is_negative(h_parent)) ++ continue; ++ ++ if (!au_br_rdonly(au_sbr(sb, bindex))) { ++ err = bindex; ++ break; ++ } ++ } ++ dput(parent); ++ ++ /* bottom up here */ ++ if (unlikely(err < 0)) ++ err = au_wbr_bu(sb, btop - 1); ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* bottom up */ ++int au_wbr_do_copyup_bu(struct dentry *dentry, aufs_bindex_t btop) ++{ ++ int err; ++ ++ err = au_wbr_bu(dentry->d_sb, btop); ++ AuDbg("b%d\n", err); ++ if (err > btop) ++ err = au_wbr_nonopq(dentry, err); ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_copyup_bu(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t btop; ++ ++ btop = au_dbtop(dentry); ++ err = au_wbr_do_copyup_bu(dentry, btop); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_wbr_copyup_operations au_wbr_copyup_ops[] = { ++ [AuWbrCopyup_TDP] = { ++ .copyup = au_wbr_copyup_tdp ++ }, ++ [AuWbrCopyup_BUP] = { ++ .copyup = au_wbr_copyup_bup ++ }, ++ [AuWbrCopyup_BU] = { ++ .copyup = au_wbr_copyup_bu ++ } ++}; ++ ++struct au_wbr_create_operations au_wbr_create_ops[] = { ++ [AuWbrCreate_TDP] = { ++ .create = au_wbr_create_tdp ++ }, ++ [AuWbrCreate_RR] = { ++ .create = au_wbr_create_rr, ++ .init = au_wbr_create_init_rr ++ }, ++ [AuWbrCreate_MFS] = { ++ .create = au_wbr_create_mfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_MFSV] = { ++ .create = au_wbr_create_mfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_MFSRR] = { ++ .create = au_wbr_create_mfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_MFSRRV] = { ++ .create = au_wbr_create_mfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_TDMFS] = { ++ .create = au_wbr_create_tdmfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_TDMFSV] = { ++ .create = au_wbr_create_tdmfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFS] = { ++ .create = au_wbr_create_pmfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFSV] = { ++ .create = au_wbr_create_pmfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFSRR] = { ++ .create = au_wbr_create_pmfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFSRRV] = { ++ .create = au_wbr_create_pmfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ } ++}; +diff -Nurp linux-5.4/fs/aufs/vdir.c linux-5.4-aufs/fs/aufs/vdir.c +--- linux-5.4/fs/aufs/vdir.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/vdir.c 2019-11-28 01:25:59.068925618 +0200 +@@ -0,0 +1,883 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * virtual or vertical directory ++ */ ++ ++#include ++#include "aufs.h" ++ ++static unsigned int calc_size(int nlen) ++{ ++ return ALIGN(sizeof(struct au_vdir_de) + nlen, sizeof(ino_t)); ++} ++ ++static int set_deblk_end(union au_vdir_deblk_p *p, ++ union au_vdir_deblk_p *deblk_end) ++{ ++ if (calc_size(0) <= deblk_end->deblk - p->deblk) { ++ p->de->de_str.len = 0; ++ /* smp_mb(); */ ++ return 0; ++ } ++ return -1; /* error */ ++} ++ ++/* returns true or false */ ++static int is_deblk_end(union au_vdir_deblk_p *p, ++ union au_vdir_deblk_p *deblk_end) ++{ ++ if (calc_size(0) <= deblk_end->deblk - p->deblk) ++ return !p->de->de_str.len; ++ return 1; ++} ++ ++static unsigned char *last_deblk(struct au_vdir *vdir) ++{ ++ return vdir->vd_deblk[vdir->vd_nblk - 1]; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* estimate the appropriate size for name hash table */ ++unsigned int au_rdhash_est(loff_t sz) ++{ ++ unsigned int n; ++ ++ n = UINT_MAX; ++ sz >>= 10; ++ if (sz < n) ++ n = sz; ++ if (sz < AUFS_RDHASH_DEF) ++ n = AUFS_RDHASH_DEF; ++ /* pr_info("n %u\n", n); */ ++ return n; ++} ++ ++/* ++ * the allocated memory has to be freed by ++ * au_nhash_wh_free() or au_nhash_de_free(). ++ */ ++int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp) ++{ ++ struct hlist_head *head; ++ unsigned int u; ++ size_t sz; ++ ++ sz = sizeof(*nhash->nh_head) * num_hash; ++ head = kmalloc(sz, gfp); ++ if (head) { ++ nhash->nh_num = num_hash; ++ nhash->nh_head = head; ++ for (u = 0; u < num_hash; u++) ++ INIT_HLIST_HEAD(head++); ++ return 0; /* success */ ++ } ++ ++ return -ENOMEM; ++} ++ ++static void nhash_count(struct hlist_head *head) ++{ ++#if 0 ++ unsigned long n; ++ struct hlist_node *pos; ++ ++ n = 0; ++ hlist_for_each(pos, head) ++ n++; ++ pr_info("%lu\n", n); ++#endif ++} ++ ++static void au_nhash_wh_do_free(struct hlist_head *head) ++{ ++ struct au_vdir_wh *pos; ++ struct hlist_node *node; ++ ++ hlist_for_each_entry_safe(pos, node, head, wh_hash) ++ au_kfree_rcu(pos); ++} ++ ++static void au_nhash_de_do_free(struct hlist_head *head) ++{ ++ struct au_vdir_dehstr *pos; ++ struct hlist_node *node; ++ ++ hlist_for_each_entry_safe(pos, node, head, hash) ++ au_cache_free_vdir_dehstr(pos); ++} ++ ++static void au_nhash_do_free(struct au_nhash *nhash, ++ void (*free)(struct hlist_head *head)) ++{ ++ unsigned int n; ++ struct hlist_head *head; ++ ++ n = nhash->nh_num; ++ if (!n) ++ return; ++ ++ head = nhash->nh_head; ++ while (n-- > 0) { ++ nhash_count(head); ++ free(head++); ++ } ++ au_kfree_try_rcu(nhash->nh_head); ++} ++ ++void au_nhash_wh_free(struct au_nhash *whlist) ++{ ++ au_nhash_do_free(whlist, au_nhash_wh_do_free); ++} ++ ++static void au_nhash_de_free(struct au_nhash *delist) ++{ ++ au_nhash_do_free(delist, au_nhash_de_do_free); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt, ++ int limit) ++{ ++ int num; ++ unsigned int u, n; ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ ++ num = 0; ++ n = whlist->nh_num; ++ head = whlist->nh_head; ++ for (u = 0; u < n; u++, head++) ++ hlist_for_each_entry(pos, head, wh_hash) ++ if (pos->wh_bindex == btgt && ++num > limit) ++ return 1; ++ return 0; ++} ++ ++static struct hlist_head *au_name_hash(struct au_nhash *nhash, ++ unsigned char *name, ++ unsigned int len) ++{ ++ unsigned int v; ++ /* const unsigned int magic_bit = 12; */ ++ ++ AuDebugOn(!nhash->nh_num || !nhash->nh_head); ++ ++ v = 0; ++ if (len > 8) ++ len = 8; ++ while (len--) ++ v += *name++; ++ /* v = hash_long(v, magic_bit); */ ++ v %= nhash->nh_num; ++ return nhash->nh_head + v; ++} ++ ++static int au_nhash_test_name(struct au_vdir_destr *str, const char *name, ++ int nlen) ++{ ++ return str->len == nlen && !memcmp(str->name, name, nlen); ++} ++ ++/* returns found or not */ ++int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen) ++{ ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ struct au_vdir_destr *str; ++ ++ head = au_name_hash(whlist, name, nlen); ++ hlist_for_each_entry(pos, head, wh_hash) { ++ str = &pos->wh_str; ++ AuDbg("%.*s\n", str->len, str->name); ++ if (au_nhash_test_name(str, name, nlen)) ++ return 1; ++ } ++ return 0; ++} ++ ++/* returns found(true) or not */ ++static int test_known(struct au_nhash *delist, char *name, int nlen) ++{ ++ struct hlist_head *head; ++ struct au_vdir_dehstr *pos; ++ struct au_vdir_destr *str; ++ ++ head = au_name_hash(delist, name, nlen); ++ hlist_for_each_entry(pos, head, hash) { ++ str = pos->str; ++ AuDbg("%.*s\n", str->len, str->name); ++ if (au_nhash_test_name(str, name, nlen)) ++ return 1; ++ } ++ return 0; ++} ++ ++static void au_shwh_init_wh(struct au_vdir_wh *wh, ino_t ino, ++ unsigned char d_type) ++{ ++#ifdef CONFIG_AUFS_SHWH ++ wh->wh_ino = ino; ++ wh->wh_type = d_type; ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino, ++ unsigned int d_type, aufs_bindex_t bindex, ++ unsigned char shwh) ++{ ++ int err; ++ struct au_vdir_destr *str; ++ struct au_vdir_wh *wh; ++ ++ AuDbg("%.*s\n", nlen, name); ++ AuDebugOn(!whlist->nh_num || !whlist->nh_head); ++ ++ err = -ENOMEM; ++ wh = kmalloc(sizeof(*wh) + nlen, GFP_NOFS); ++ if (unlikely(!wh)) ++ goto out; ++ ++ err = 0; ++ wh->wh_bindex = bindex; ++ if (shwh) ++ au_shwh_init_wh(wh, ino, d_type); ++ str = &wh->wh_str; ++ str->len = nlen; ++ memcpy(str->name, name, nlen); ++ hlist_add_head(&wh->wh_hash, au_name_hash(whlist, name, nlen)); ++ /* smp_mb(); */ ++ ++out: ++ return err; ++} ++ ++static int append_deblk(struct au_vdir *vdir) ++{ ++ int err; ++ unsigned long ul; ++ const unsigned int deblk_sz = vdir->vd_deblk_sz; ++ union au_vdir_deblk_p p, deblk_end; ++ unsigned char **o; ++ ++ err = -ENOMEM; ++ o = au_krealloc(vdir->vd_deblk, sizeof(*o) * (vdir->vd_nblk + 1), ++ GFP_NOFS, /*may_shrink*/0); ++ if (unlikely(!o)) ++ goto out; ++ ++ vdir->vd_deblk = o; ++ p.deblk = kmalloc(deblk_sz, GFP_NOFS); ++ if (p.deblk) { ++ ul = vdir->vd_nblk++; ++ vdir->vd_deblk[ul] = p.deblk; ++ vdir->vd_last.ul = ul; ++ vdir->vd_last.p.deblk = p.deblk; ++ deblk_end.deblk = p.deblk + deblk_sz; ++ err = set_deblk_end(&p, &deblk_end); ++ } ++ ++out: ++ return err; ++} ++ ++static int append_de(struct au_vdir *vdir, char *name, int nlen, ino_t ino, ++ unsigned int d_type, struct au_nhash *delist) ++{ ++ int err; ++ unsigned int sz; ++ const unsigned int deblk_sz = vdir->vd_deblk_sz; ++ union au_vdir_deblk_p p, *room, deblk_end; ++ struct au_vdir_dehstr *dehstr; ++ ++ p.deblk = last_deblk(vdir); ++ deblk_end.deblk = p.deblk + deblk_sz; ++ room = &vdir->vd_last.p; ++ AuDebugOn(room->deblk < p.deblk || deblk_end.deblk <= room->deblk ++ || !is_deblk_end(room, &deblk_end)); ++ ++ sz = calc_size(nlen); ++ if (unlikely(sz > deblk_end.deblk - room->deblk)) { ++ err = append_deblk(vdir); ++ if (unlikely(err)) ++ goto out; ++ ++ p.deblk = last_deblk(vdir); ++ deblk_end.deblk = p.deblk + deblk_sz; ++ /* smp_mb(); */ ++ AuDebugOn(room->deblk != p.deblk); ++ } ++ ++ err = -ENOMEM; ++ dehstr = au_cache_alloc_vdir_dehstr(); ++ if (unlikely(!dehstr)) ++ goto out; ++ ++ dehstr->str = &room->de->de_str; ++ hlist_add_head(&dehstr->hash, au_name_hash(delist, name, nlen)); ++ room->de->de_ino = ino; ++ room->de->de_type = d_type; ++ room->de->de_str.len = nlen; ++ memcpy(room->de->de_str.name, name, nlen); ++ ++ err = 0; ++ room->deblk += sz; ++ if (unlikely(set_deblk_end(room, &deblk_end))) ++ err = append_deblk(vdir); ++ /* smp_mb(); */ ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_vdir_free(struct au_vdir *vdir) ++{ ++ unsigned char **deblk; ++ ++ deblk = vdir->vd_deblk; ++ while (vdir->vd_nblk--) ++ au_kfree_try_rcu(*deblk++); ++ au_kfree_try_rcu(vdir->vd_deblk); ++ au_cache_free_vdir(vdir); ++} ++ ++static struct au_vdir *alloc_vdir(struct file *file) ++{ ++ struct au_vdir *vdir; ++ struct super_block *sb; ++ int err; ++ ++ sb = file->f_path.dentry->d_sb; ++ SiMustAnyLock(sb); ++ ++ err = -ENOMEM; ++ vdir = au_cache_alloc_vdir(); ++ if (unlikely(!vdir)) ++ goto out; ++ ++ vdir->vd_deblk = kzalloc(sizeof(*vdir->vd_deblk), GFP_NOFS); ++ if (unlikely(!vdir->vd_deblk)) ++ goto out_free; ++ ++ vdir->vd_deblk_sz = au_sbi(sb)->si_rdblk; ++ if (!vdir->vd_deblk_sz) { ++ /* estimate the appropriate size for deblk */ ++ vdir->vd_deblk_sz = au_dir_size(file, /*dentry*/NULL); ++ /* pr_info("vd_deblk_sz %u\n", vdir->vd_deblk_sz); */ ++ } ++ vdir->vd_nblk = 0; ++ vdir->vd_version = 0; ++ vdir->vd_jiffy = 0; ++ err = append_deblk(vdir); ++ if (!err) ++ return vdir; /* success */ ++ ++ au_kfree_try_rcu(vdir->vd_deblk); ++ ++out_free: ++ au_cache_free_vdir(vdir); ++out: ++ vdir = ERR_PTR(err); ++ return vdir; ++} ++ ++static int reinit_vdir(struct au_vdir *vdir) ++{ ++ int err; ++ union au_vdir_deblk_p p, deblk_end; ++ ++ while (vdir->vd_nblk > 1) { ++ au_kfree_try_rcu(vdir->vd_deblk[vdir->vd_nblk - 1]); ++ /* vdir->vd_deblk[vdir->vd_nblk - 1] = NULL; */ ++ vdir->vd_nblk--; ++ } ++ p.deblk = vdir->vd_deblk[0]; ++ deblk_end.deblk = p.deblk + vdir->vd_deblk_sz; ++ err = set_deblk_end(&p, &deblk_end); ++ /* keep vd_dblk_sz */ ++ vdir->vd_last.ul = 0; ++ vdir->vd_last.p.deblk = vdir->vd_deblk[0]; ++ vdir->vd_version = 0; ++ vdir->vd_jiffy = 0; ++ /* smp_mb(); */ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AuFillVdir_CALLED 1 ++#define AuFillVdir_WHABLE (1 << 1) ++#define AuFillVdir_SHWH (1 << 2) ++#define au_ftest_fillvdir(flags, name) ((flags) & AuFillVdir_##name) ++#define au_fset_fillvdir(flags, name) \ ++ do { (flags) |= AuFillVdir_##name; } while (0) ++#define au_fclr_fillvdir(flags, name) \ ++ do { (flags) &= ~AuFillVdir_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_SHWH ++#undef AuFillVdir_SHWH ++#define AuFillVdir_SHWH 0 ++#endif ++ ++struct fillvdir_arg { ++ struct dir_context ctx; ++ struct file *file; ++ struct au_vdir *vdir; ++ struct au_nhash delist; ++ struct au_nhash whlist; ++ aufs_bindex_t bindex; ++ unsigned int flags; ++ int err; ++}; ++ ++static int fillvdir(struct dir_context *ctx, const char *__name, int nlen, ++ loff_t offset __maybe_unused, u64 h_ino, ++ unsigned int d_type) ++{ ++ struct fillvdir_arg *arg = container_of(ctx, struct fillvdir_arg, ctx); ++ char *name = (void *)__name; ++ struct super_block *sb; ++ ino_t ino; ++ const unsigned char shwh = !!au_ftest_fillvdir(arg->flags, SHWH); ++ ++ arg->err = 0; ++ sb = arg->file->f_path.dentry->d_sb; ++ au_fset_fillvdir(arg->flags, CALLED); ++ /* smp_mb(); */ ++ if (nlen <= AUFS_WH_PFX_LEN ++ || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { ++ if (test_known(&arg->delist, name, nlen) ++ || au_nhash_test_known_wh(&arg->whlist, name, nlen)) ++ goto out; /* already exists or whiteouted */ ++ ++ arg->err = au_ino(sb, arg->bindex, h_ino, d_type, &ino); ++ if (!arg->err) { ++ if (unlikely(nlen > AUFS_MAX_NAMELEN)) ++ d_type = DT_UNKNOWN; ++ arg->err = append_de(arg->vdir, name, nlen, ino, ++ d_type, &arg->delist); ++ } ++ } else if (au_ftest_fillvdir(arg->flags, WHABLE)) { ++ name += AUFS_WH_PFX_LEN; ++ nlen -= AUFS_WH_PFX_LEN; ++ if (au_nhash_test_known_wh(&arg->whlist, name, nlen)) ++ goto out; /* already whiteouted */ ++ ++ ino = 0; /* just to suppress a warning */ ++ if (shwh) ++ arg->err = au_wh_ino(sb, arg->bindex, h_ino, d_type, ++ &ino); ++ if (!arg->err) { ++ if (nlen <= AUFS_MAX_NAMELEN + AUFS_WH_PFX_LEN) ++ d_type = DT_UNKNOWN; ++ arg->err = au_nhash_append_wh ++ (&arg->whlist, name, nlen, ino, d_type, ++ arg->bindex, shwh); ++ } ++ } ++ ++out: ++ if (!arg->err) ++ arg->vdir->vd_jiffy = jiffies; ++ /* smp_mb(); */ ++ AuTraceErr(arg->err); ++ return arg->err; ++} ++ ++static int au_handle_shwh(struct super_block *sb, struct au_vdir *vdir, ++ struct au_nhash *whlist, struct au_nhash *delist) ++{ ++#ifdef CONFIG_AUFS_SHWH ++ int err; ++ unsigned int nh, u; ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ struct hlist_node *n; ++ char *p, *o; ++ struct au_vdir_destr *destr; ++ ++ AuDebugOn(!au_opt_test(au_mntflags(sb), SHWH)); ++ ++ err = -ENOMEM; ++ o = p = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!p)) ++ goto out; ++ ++ err = 0; ++ nh = whlist->nh_num; ++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); ++ p += AUFS_WH_PFX_LEN; ++ for (u = 0; u < nh; u++) { ++ head = whlist->nh_head + u; ++ hlist_for_each_entry_safe(pos, n, head, wh_hash) { ++ destr = &pos->wh_str; ++ memcpy(p, destr->name, destr->len); ++ err = append_de(vdir, o, destr->len + AUFS_WH_PFX_LEN, ++ pos->wh_ino, pos->wh_type, delist); ++ if (unlikely(err)) ++ break; ++ } ++ } ++ ++ free_page((unsigned long)o); ++ ++out: ++ AuTraceErr(err); ++ return err; ++#else ++ return 0; ++#endif ++} ++ ++static int au_do_read_vdir(struct fillvdir_arg *arg) ++{ ++ int err; ++ unsigned int rdhash; ++ loff_t offset; ++ aufs_bindex_t bbot, bindex, btop; ++ unsigned char shwh; ++ struct file *hf, *file; ++ struct super_block *sb; ++ ++ file = arg->file; ++ sb = file->f_path.dentry->d_sb; ++ SiMustAnyLock(sb); ++ ++ rdhash = au_sbi(sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(file, /*dentry*/NULL)); ++ err = au_nhash_alloc(&arg->delist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_nhash_alloc(&arg->whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out_delist; ++ ++ err = 0; ++ arg->flags = 0; ++ shwh = 0; ++ if (au_opt_test(au_mntflags(sb), SHWH)) { ++ shwh = 1; ++ au_fset_fillvdir(arg->flags, SHWH); ++ } ++ btop = au_fbtop(file); ++ bbot = au_fbbot_dir(file); ++ for (bindex = btop; !err && bindex <= bbot; bindex++) { ++ hf = au_hf_dir(file, bindex); ++ if (!hf) ++ continue; ++ ++ offset = vfsub_llseek(hf, 0, SEEK_SET); ++ err = offset; ++ if (unlikely(offset)) ++ break; ++ ++ arg->bindex = bindex; ++ au_fclr_fillvdir(arg->flags, WHABLE); ++ if (shwh ++ || (bindex != bbot ++ && au_br_whable(au_sbr_perm(sb, bindex)))) ++ au_fset_fillvdir(arg->flags, WHABLE); ++ do { ++ arg->err = 0; ++ au_fclr_fillvdir(arg->flags, CALLED); ++ /* smp_mb(); */ ++ err = vfsub_iterate_dir(hf, &arg->ctx); ++ if (err >= 0) ++ err = arg->err; ++ } while (!err && au_ftest_fillvdir(arg->flags, CALLED)); ++ ++ /* ++ * dir_relax() may be good for concurrency, but aufs should not ++ * use it since it will cause a lockdep problem. ++ */ ++ } ++ ++ if (!err && shwh) ++ err = au_handle_shwh(sb, arg->vdir, &arg->whlist, &arg->delist); ++ ++ au_nhash_wh_free(&arg->whlist); ++ ++out_delist: ++ au_nhash_de_free(&arg->delist); ++out: ++ return err; ++} ++ ++static int read_vdir(struct file *file, int may_read) ++{ ++ int err; ++ unsigned long expire; ++ unsigned char do_read; ++ struct fillvdir_arg arg = { ++ .ctx = { ++ .actor = fillvdir ++ } ++ }; ++ struct inode *inode; ++ struct au_vdir *vdir, *allocated; ++ ++ err = 0; ++ inode = file_inode(file); ++ IMustLock(inode); ++ IiMustWriteLock(inode); ++ SiMustAnyLock(inode->i_sb); ++ ++ allocated = NULL; ++ do_read = 0; ++ expire = au_sbi(inode->i_sb)->si_rdcache; ++ vdir = au_ivdir(inode); ++ if (!vdir) { ++ do_read = 1; ++ vdir = alloc_vdir(file); ++ err = PTR_ERR(vdir); ++ if (IS_ERR(vdir)) ++ goto out; ++ err = 0; ++ allocated = vdir; ++ } else if (may_read ++ && (!inode_eq_iversion(inode, vdir->vd_version) ++ || time_after(jiffies, vdir->vd_jiffy + expire))) { ++ do_read = 1; ++ err = reinit_vdir(vdir); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ if (!do_read) ++ return 0; /* success */ ++ ++ arg.file = file; ++ arg.vdir = vdir; ++ err = au_do_read_vdir(&arg); ++ if (!err) { ++ /* file->f_pos = 0; */ /* todo: ctx->pos? */ ++ vdir->vd_version = inode_query_iversion(inode); ++ vdir->vd_last.ul = 0; ++ vdir->vd_last.p.deblk = vdir->vd_deblk[0]; ++ if (allocated) ++ au_set_ivdir(inode, allocated); ++ } else if (allocated) ++ au_vdir_free(allocated); ++ ++out: ++ return err; ++} ++ ++static int copy_vdir(struct au_vdir *tgt, struct au_vdir *src) ++{ ++ int err, rerr; ++ unsigned long ul, n; ++ const unsigned int deblk_sz = src->vd_deblk_sz; ++ ++ AuDebugOn(tgt->vd_nblk != 1); ++ ++ err = -ENOMEM; ++ if (tgt->vd_nblk < src->vd_nblk) { ++ unsigned char **p; ++ ++ p = au_krealloc(tgt->vd_deblk, sizeof(*p) * src->vd_nblk, ++ GFP_NOFS, /*may_shrink*/0); ++ if (unlikely(!p)) ++ goto out; ++ tgt->vd_deblk = p; ++ } ++ ++ if (tgt->vd_deblk_sz != deblk_sz) { ++ unsigned char *p; ++ ++ tgt->vd_deblk_sz = deblk_sz; ++ p = au_krealloc(tgt->vd_deblk[0], deblk_sz, GFP_NOFS, ++ /*may_shrink*/1); ++ if (unlikely(!p)) ++ goto out; ++ tgt->vd_deblk[0] = p; ++ } ++ memcpy(tgt->vd_deblk[0], src->vd_deblk[0], deblk_sz); ++ tgt->vd_version = src->vd_version; ++ tgt->vd_jiffy = src->vd_jiffy; ++ ++ n = src->vd_nblk; ++ for (ul = 1; ul < n; ul++) { ++ tgt->vd_deblk[ul] = kmemdup(src->vd_deblk[ul], deblk_sz, ++ GFP_NOFS); ++ if (unlikely(!tgt->vd_deblk[ul])) ++ goto out; ++ tgt->vd_nblk++; ++ } ++ tgt->vd_nblk = n; ++ tgt->vd_last.ul = tgt->vd_last.ul; ++ tgt->vd_last.p.deblk = tgt->vd_deblk[tgt->vd_last.ul]; ++ tgt->vd_last.p.deblk += src->vd_last.p.deblk ++ - src->vd_deblk[src->vd_last.ul]; ++ /* smp_mb(); */ ++ return 0; /* success */ ++ ++out: ++ rerr = reinit_vdir(tgt); ++ BUG_ON(rerr); ++ return err; ++} ++ ++int au_vdir_init(struct file *file) ++{ ++ int err; ++ struct inode *inode; ++ struct au_vdir *vdir_cache, *allocated; ++ ++ /* test file->f_pos here instead of ctx->pos */ ++ err = read_vdir(file, !file->f_pos); ++ if (unlikely(err)) ++ goto out; ++ ++ allocated = NULL; ++ vdir_cache = au_fvdir_cache(file); ++ if (!vdir_cache) { ++ vdir_cache = alloc_vdir(file); ++ err = PTR_ERR(vdir_cache); ++ if (IS_ERR(vdir_cache)) ++ goto out; ++ allocated = vdir_cache; ++ } else if (!file->f_pos && vdir_cache->vd_version != file->f_version) { ++ /* test file->f_pos here instead of ctx->pos */ ++ err = reinit_vdir(vdir_cache); ++ if (unlikely(err)) ++ goto out; ++ } else ++ return 0; /* success */ ++ ++ inode = file_inode(file); ++ err = copy_vdir(vdir_cache, au_ivdir(inode)); ++ if (!err) { ++ file->f_version = inode_query_iversion(inode); ++ if (allocated) ++ au_set_fvdir_cache(file, allocated); ++ } else if (allocated) ++ au_vdir_free(allocated); ++ ++out: ++ return err; ++} ++ ++static loff_t calc_offset(struct au_vdir *vdir) ++{ ++ loff_t offset; ++ union au_vdir_deblk_p p; ++ ++ p.deblk = vdir->vd_deblk[vdir->vd_last.ul]; ++ offset = vdir->vd_last.p.deblk - p.deblk; ++ offset += vdir->vd_deblk_sz * vdir->vd_last.ul; ++ return offset; ++} ++ ++/* returns true or false */ ++static int seek_vdir(struct file *file, struct dir_context *ctx) ++{ ++ int valid; ++ unsigned int deblk_sz; ++ unsigned long ul, n; ++ loff_t offset; ++ union au_vdir_deblk_p p, deblk_end; ++ struct au_vdir *vdir_cache; ++ ++ valid = 1; ++ vdir_cache = au_fvdir_cache(file); ++ offset = calc_offset(vdir_cache); ++ AuDbg("offset %lld\n", offset); ++ if (ctx->pos == offset) ++ goto out; ++ ++ vdir_cache->vd_last.ul = 0; ++ vdir_cache->vd_last.p.deblk = vdir_cache->vd_deblk[0]; ++ if (!ctx->pos) ++ goto out; ++ ++ valid = 0; ++ deblk_sz = vdir_cache->vd_deblk_sz; ++ ul = div64_u64(ctx->pos, deblk_sz); ++ AuDbg("ul %lu\n", ul); ++ if (ul >= vdir_cache->vd_nblk) ++ goto out; ++ ++ n = vdir_cache->vd_nblk; ++ for (; ul < n; ul++) { ++ p.deblk = vdir_cache->vd_deblk[ul]; ++ deblk_end.deblk = p.deblk + deblk_sz; ++ offset = ul; ++ offset *= deblk_sz; ++ while (!is_deblk_end(&p, &deblk_end) && offset < ctx->pos) { ++ unsigned int l; ++ ++ l = calc_size(p.de->de_str.len); ++ offset += l; ++ p.deblk += l; ++ } ++ if (!is_deblk_end(&p, &deblk_end)) { ++ valid = 1; ++ vdir_cache->vd_last.ul = ul; ++ vdir_cache->vd_last.p = p; ++ break; ++ } ++ } ++ ++out: ++ /* smp_mb(); */ ++ if (!valid) ++ AuDbg("valid %d\n", !valid); ++ return valid; ++} ++ ++int au_vdir_fill_de(struct file *file, struct dir_context *ctx) ++{ ++ unsigned int l, deblk_sz; ++ union au_vdir_deblk_p deblk_end; ++ struct au_vdir *vdir_cache; ++ struct au_vdir_de *de; ++ ++ if (!seek_vdir(file, ctx)) ++ return 0; ++ ++ vdir_cache = au_fvdir_cache(file); ++ deblk_sz = vdir_cache->vd_deblk_sz; ++ while (1) { ++ deblk_end.deblk = vdir_cache->vd_deblk[vdir_cache->vd_last.ul]; ++ deblk_end.deblk += deblk_sz; ++ while (!is_deblk_end(&vdir_cache->vd_last.p, &deblk_end)) { ++ de = vdir_cache->vd_last.p.de; ++ AuDbg("%.*s, off%lld, i%lu, dt%d\n", ++ de->de_str.len, de->de_str.name, ctx->pos, ++ (unsigned long)de->de_ino, de->de_type); ++ if (unlikely(!dir_emit(ctx, de->de_str.name, ++ de->de_str.len, de->de_ino, ++ de->de_type))) { ++ /* todo: ignore the error caused by udba? */ ++ /* return err; */ ++ return 0; ++ } ++ ++ l = calc_size(de->de_str.len); ++ vdir_cache->vd_last.p.deblk += l; ++ ctx->pos += l; ++ } ++ if (vdir_cache->vd_last.ul < vdir_cache->vd_nblk - 1) { ++ vdir_cache->vd_last.ul++; ++ vdir_cache->vd_last.p.deblk ++ = vdir_cache->vd_deblk[vdir_cache->vd_last.ul]; ++ ctx->pos = deblk_sz * vdir_cache->vd_last.ul; ++ continue; ++ } ++ break; ++ } ++ ++ /* smp_mb(); */ ++ return 0; ++} +diff -Nurp linux-5.4/fs/aufs/vfsub.c linux-5.4-aufs/fs/aufs/vfsub.c +--- linux-5.4/fs/aufs/vfsub.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/vfsub.c 2019-11-28 01:25:59.068925618 +0200 +@@ -0,0 +1,889 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * sub-routines for VFS ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++#ifdef CONFIG_AUFS_BR_FUSE ++int vfsub_test_mntns(struct vfsmount *mnt, struct super_block *h_sb) ++{ ++ if (!au_test_fuse(h_sb) || !au_userns) ++ return 0; ++ ++ return is_current_mnt_ns(mnt) ? 0 : -EACCES; ++} ++#endif ++ ++int vfsub_sync_filesystem(struct super_block *h_sb, int wait) ++{ ++ int err; ++ ++ lockdep_off(); ++ down_read(&h_sb->s_umount); ++ err = __sync_filesystem(h_sb, wait); ++ up_read(&h_sb->s_umount); ++ lockdep_on(); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_update_h_iattr(struct path *h_path, int *did) ++{ ++ int err; ++ struct kstat st; ++ struct super_block *h_sb; ++ ++ /* for remote fs, leave work for its getattr or d_revalidate */ ++ /* for bad i_attr fs, handle them in aufs_getattr() */ ++ /* still some fs may acquire i_mutex. we need to skip them */ ++ err = 0; ++ if (!did) ++ did = &err; ++ h_sb = h_path->dentry->d_sb; ++ *did = (!au_test_fs_remote(h_sb) && au_test_fs_refresh_iattr(h_sb)); ++ if (*did) ++ err = vfsub_getattr(h_path, &st); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct file *vfsub_dentry_open(struct path *path, int flags) ++{ ++ struct file *file; ++ ++ file = dentry_open(path, flags /* | __FMODE_NONOTIFY */, ++ current_cred()); ++ if (!IS_ERR_OR_NULL(file) ++ && (file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) ++ i_readcount_inc(d_inode(path->dentry)); ++ ++ return file; ++} ++ ++struct file *vfsub_filp_open(const char *path, int oflags, int mode) ++{ ++ struct file *file; ++ ++ lockdep_off(); ++ file = filp_open(path, ++ oflags /* | __FMODE_NONOTIFY */, ++ mode); ++ lockdep_on(); ++ if (IS_ERR(file)) ++ goto out; ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ ++out: ++ return file; ++} ++ ++/* ++ * Ideally this function should call VFS:do_last() in order to keep all its ++ * checkings. But it is very hard for aufs to regenerate several VFS internal ++ * structure such as nameidata. This is a second (or third) best approach. ++ * cf. linux/fs/namei.c:do_last(), lookup_open() and atomic_open(). ++ */ ++int vfsub_atomic_open(struct inode *dir, struct dentry *dentry, ++ struct vfsub_aopen_args *args) ++{ ++ int err; ++ struct au_branch *br = args->br; ++ struct file *file = args->file; ++ /* copied from linux/fs/namei.c:atomic_open() */ ++ struct dentry *const DENTRY_NOT_SET = (void *)-1UL; ++ ++ IMustLock(dir); ++ AuDebugOn(!dir->i_op->atomic_open); ++ ++ err = au_br_test_oflag(args->open_flag, br); ++ if (unlikely(err)) ++ goto out; ++ ++ au_lcnt_inc(&br->br_nfiles); ++ file->f_path.dentry = DENTRY_NOT_SET; ++ file->f_path.mnt = au_br_mnt(br); ++ AuDbg("%ps\n", dir->i_op->atomic_open); ++ err = dir->i_op->atomic_open(dir, dentry, file, args->open_flag, ++ args->create_mode); ++ if (unlikely(err < 0)) { ++ au_lcnt_dec(&br->br_nfiles); ++ goto out; ++ } ++ ++ /* temporary workaround for nfsv4 branch */ ++ if (au_test_nfs(dir->i_sb)) ++ nfs_mark_for_revalidate(dir); ++ ++ if (file->f_mode & FMODE_CREATED) ++ fsnotify_create(dir, dentry); ++ if (!(file->f_mode & FMODE_OPENED)) { ++ au_lcnt_dec(&br->br_nfiles); ++ goto out; ++ } ++ ++ /* todo: call VFS:may_open() here */ ++ /* todo: ima_file_check() too? */ ++ if (!err && (args->open_flag & __FMODE_EXEC)) ++ err = deny_write_access(file); ++ if (!err) ++ fsnotify_open(file); ++ else ++ au_lcnt_dec(&br->br_nfiles); ++ /* note that the file is created and still opened */ ++ ++out: ++ return err; ++} ++ ++int vfsub_kern_path(const char *name, unsigned int flags, struct path *path) ++{ ++ int err; ++ ++ err = kern_path(name, flags, path); ++ if (!err && d_is_positive(path->dentry)) ++ vfsub_update_h_iattr(path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++struct dentry *vfsub_lookup_one_len_unlocked(const char *name, ++ struct dentry *parent, int len) ++{ ++ struct path path = { ++ .mnt = NULL ++ }; ++ ++ path.dentry = lookup_one_len_unlocked(name, parent, len); ++ if (IS_ERR(path.dentry)) ++ goto out; ++ if (d_is_positive(path.dentry)) ++ vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/ ++ ++out: ++ AuTraceErrPtr(path.dentry); ++ return path.dentry; ++} ++ ++struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent, ++ int len) ++{ ++ struct path path = { ++ .mnt = NULL ++ }; ++ ++ /* VFS checks it too, but by WARN_ON_ONCE() */ ++ IMustLock(d_inode(parent)); ++ ++ path.dentry = lookup_one_len(name, parent, len); ++ if (IS_ERR(path.dentry)) ++ goto out; ++ if (d_is_positive(path.dentry)) ++ vfsub_update_h_iattr(&path, /*did*/NULL); /*ignore*/ ++ ++out: ++ AuTraceErrPtr(path.dentry); ++ return path.dentry; ++} ++ ++void vfsub_call_lkup_one(void *args) ++{ ++ struct vfsub_lkup_one_args *a = args; ++ *a->errp = vfsub_lkup_one(a->name, a->parent); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2) ++{ ++ struct dentry *d; ++ ++ lockdep_off(); ++ d = lock_rename(d1, d2); ++ lockdep_on(); ++ au_hn_suspend(hdir1); ++ if (hdir1 != hdir2) ++ au_hn_suspend(hdir2); ++ ++ return d; ++} ++ ++void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2) ++{ ++ au_hn_resume(hdir1); ++ if (hdir1 != hdir2) ++ au_hn_resume(hdir2); ++ lockdep_off(); ++ unlock_rename(d1, d2); ++ lockdep_on(); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_create(struct inode *dir, struct path *path, int mode, bool want_excl) ++{ ++ int err; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_mknod(path, d, mode, 0); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ lockdep_off(); ++ err = vfs_create(dir, path->dentry, mode, want_excl); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_symlink(struct inode *dir, struct path *path, const char *symname) ++{ ++ int err; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_symlink(path, d, symname); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ lockdep_off(); ++ err = vfs_symlink(dir, path->dentry, symname); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev) ++{ ++ int err; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_mknod(path, d, mode, new_encode_dev(dev)); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ lockdep_off(); ++ err = vfs_mknod(dir, path->dentry, mode, dev); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++static int au_test_nlink(struct inode *inode) ++{ ++ const unsigned int link_max = UINT_MAX >> 1; /* rough margin */ ++ ++ if (!au_test_fs_no_limit_nlink(inode->i_sb) ++ || inode->i_nlink < link_max) ++ return 0; ++ return -EMLINK; ++} ++ ++int vfsub_link(struct dentry *src_dentry, struct inode *dir, struct path *path, ++ struct inode **delegated_inode) ++{ ++ int err; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ ++ err = au_test_nlink(d_inode(src_dentry)); ++ if (unlikely(err)) ++ return err; ++ ++ /* we don't call may_linkat() */ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_link(src_dentry, path, d); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ lockdep_off(); ++ err = vfs_link(src_dentry, dir, path->dentry, delegated_inode); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ /* fuse has different memory inode for the same inumber */ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ tmp.dentry = src_dentry; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_rename(struct inode *src_dir, struct dentry *src_dentry, ++ struct inode *dir, struct path *path, ++ struct inode **delegated_inode, unsigned int flags) ++{ ++ int err; ++ struct path tmp = { ++ .mnt = path->mnt ++ }; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ IMustLock(src_dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ tmp.dentry = src_dentry->d_parent; ++ err = security_path_rename(&tmp, src_dentry, path, d, /*flags*/0); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ lockdep_off(); ++ err = vfs_rename(src_dir, src_dentry, dir, path->dentry, ++ delegated_inode, flags); ++ lockdep_on(); ++ if (!err) { ++ int did; ++ ++ tmp.dentry = d->d_parent; ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = src_dentry; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ tmp.dentry = src_dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_mkdir(struct inode *dir, struct path *path, int mode) ++{ ++ int err; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_mkdir(path, d, mode); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ lockdep_off(); ++ err = vfs_mkdir(dir, path->dentry, mode); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = *path; ++ int did; ++ ++ vfsub_update_h_iattr(&tmp, &did); ++ if (did) { ++ tmp.dentry = path->dentry->d_parent; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); ++ } ++ /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++int vfsub_rmdir(struct inode *dir, struct path *path) ++{ ++ int err; ++ struct dentry *d; ++ ++ IMustLock(dir); ++ ++ d = path->dentry; ++ path->dentry = d->d_parent; ++ err = security_path_rmdir(path, d); ++ path->dentry = d; ++ if (unlikely(err)) ++ goto out; ++ ++ lockdep_off(); ++ err = vfs_rmdir(dir, path->dentry); ++ lockdep_on(); ++ if (!err) { ++ struct path tmp = { ++ .dentry = path->dentry->d_parent, ++ .mnt = path->mnt ++ }; ++ ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/ ++ } ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* todo: support mmap_sem? */ ++ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ ++ lockdep_off(); ++ err = vfs_read(file, ubuf, count, ppos); ++ lockdep_on(); ++ if (err >= 0) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++/* todo: kernel_read()? */ ++ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ mm_segment_t oldfs; ++ union { ++ void *k; ++ char __user *u; ++ } buf; ++ ++ buf.k = kbuf; ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ err = vfsub_read_u(file, buf.u, count, ppos); ++ set_fs(oldfs); ++ return err; ++} ++ ++ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ ++ lockdep_off(); ++ err = vfs_write(file, ubuf, count, ppos); ++ lockdep_on(); ++ if (err >= 0) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, loff_t *ppos) ++{ ++ ssize_t err; ++ mm_segment_t oldfs; ++ union { ++ void *k; ++ const char __user *u; ++ } buf; ++ ++ buf.k = kbuf; ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ err = vfsub_write_u(file, buf.u, count, ppos); ++ set_fs(oldfs); ++ return err; ++} ++ ++int vfsub_flush(struct file *file, fl_owner_t id) ++{ ++ int err; ++ ++ err = 0; ++ if (file->f_op->flush) { ++ if (!au_test_nfs(file->f_path.dentry->d_sb)) ++ err = file->f_op->flush(file, id); ++ else { ++ lockdep_off(); ++ err = file->f_op->flush(file, id); ++ lockdep_on(); ++ } ++ if (!err) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); ++ /*ignore*/ ++ } ++ return err; ++} ++ ++int vfsub_iterate_dir(struct file *file, struct dir_context *ctx) ++{ ++ int err; ++ ++ AuDbg("%pD, ctx{%ps, %llu}\n", file, ctx->actor, ctx->pos); ++ ++ lockdep_off(); ++ err = iterate_dir(file, ctx); ++ lockdep_on(); ++ if (err >= 0) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ ++ return err; ++} ++ ++long vfsub_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags) ++{ ++ long err; ++ ++ lockdep_off(); ++ err = do_splice_to(in, ppos, pipe, len, flags); ++ lockdep_on(); ++ file_accessed(in); ++ if (err >= 0) ++ vfsub_update_h_iattr(&in->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags) ++{ ++ long err; ++ ++ lockdep_off(); ++ err = do_splice_from(pipe, out, ppos, len, flags); ++ lockdep_on(); ++ if (err >= 0) ++ vfsub_update_h_iattr(&out->f_path, /*did*/NULL); /*ignore*/ ++ return err; ++} ++ ++int vfsub_fsync(struct file *file, struct path *path, int datasync) ++{ ++ int err; ++ ++ /* file can be NULL */ ++ lockdep_off(); ++ err = vfs_fsync(file, datasync); ++ lockdep_on(); ++ if (!err) { ++ if (!path) { ++ AuDebugOn(!file); ++ path = &file->f_path; ++ } ++ vfsub_update_h_iattr(path, /*did*/NULL); /*ignore*/ ++ } ++ return err; ++} ++ ++/* cf. open.c:do_sys_truncate() and do_sys_ftruncate() */ ++int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr, ++ struct file *h_file) ++{ ++ int err; ++ struct inode *h_inode; ++ struct super_block *h_sb; ++ ++ if (!h_file) { ++ err = vfsub_truncate(h_path, length); ++ goto out; ++ } ++ ++ h_inode = d_inode(h_path->dentry); ++ h_sb = h_inode->i_sb; ++ lockdep_off(); ++ sb_start_write(h_sb); ++ lockdep_on(); ++ err = locks_verify_truncate(h_inode, h_file, length); ++ if (!err) ++ err = security_path_truncate(h_path); ++ if (!err) { ++ lockdep_off(); ++ err = do_truncate(h_path->dentry, length, attr, h_file); ++ lockdep_on(); ++ } ++ lockdep_off(); ++ sb_end_write(h_sb); ++ lockdep_on(); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_vfsub_mkdir_args { ++ int *errp; ++ struct inode *dir; ++ struct path *path; ++ int mode; ++}; ++ ++static void au_call_vfsub_mkdir(void *args) ++{ ++ struct au_vfsub_mkdir_args *a = args; ++ *a->errp = vfsub_mkdir(a->dir, a->path, a->mode); ++} ++ ++int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode) ++{ ++ int err, do_sio, wkq_err; ++ ++ do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE); ++ if (!do_sio) { ++ lockdep_off(); ++ err = vfsub_mkdir(dir, path, mode); ++ lockdep_on(); ++ } else { ++ struct au_vfsub_mkdir_args args = { ++ .errp = &err, ++ .dir = dir, ++ .path = path, ++ .mode = mode ++ }; ++ wkq_err = au_wkq_wait(au_call_vfsub_mkdir, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} ++ ++struct au_vfsub_rmdir_args { ++ int *errp; ++ struct inode *dir; ++ struct path *path; ++}; ++ ++static void au_call_vfsub_rmdir(void *args) ++{ ++ struct au_vfsub_rmdir_args *a = args; ++ *a->errp = vfsub_rmdir(a->dir, a->path); ++} ++ ++int vfsub_sio_rmdir(struct inode *dir, struct path *path) ++{ ++ int err, do_sio, wkq_err; ++ ++ do_sio = au_test_h_perm_sio(dir, MAY_EXEC | MAY_WRITE); ++ if (!do_sio) { ++ lockdep_off(); ++ err = vfsub_rmdir(dir, path); ++ lockdep_on(); ++ } else { ++ struct au_vfsub_rmdir_args args = { ++ .errp = &err, ++ .dir = dir, ++ .path = path ++ }; ++ wkq_err = au_wkq_wait(au_call_vfsub_rmdir, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct notify_change_args { ++ int *errp; ++ struct path *path; ++ struct iattr *ia; ++ struct inode **delegated_inode; ++}; ++ ++static void call_notify_change(void *args) ++{ ++ struct notify_change_args *a = args; ++ struct inode *h_inode; ++ ++ h_inode = d_inode(a->path->dentry); ++ IMustLock(h_inode); ++ ++ *a->errp = -EPERM; ++ if (!IS_IMMUTABLE(h_inode) && !IS_APPEND(h_inode)) { ++ lockdep_off(); ++ *a->errp = notify_change(a->path->dentry, a->ia, ++ a->delegated_inode); ++ lockdep_on(); ++ if (!*a->errp) ++ vfsub_update_h_iattr(a->path, /*did*/NULL); /*ignore*/ ++ } ++ AuTraceErr(*a->errp); ++} ++ ++int vfsub_notify_change(struct path *path, struct iattr *ia, ++ struct inode **delegated_inode) ++{ ++ int err; ++ struct notify_change_args args = { ++ .errp = &err, ++ .path = path, ++ .ia = ia, ++ .delegated_inode = delegated_inode ++ }; ++ ++ call_notify_change(&args); ++ ++ return err; ++} ++ ++int vfsub_sio_notify_change(struct path *path, struct iattr *ia, ++ struct inode **delegated_inode) ++{ ++ int err, wkq_err; ++ struct notify_change_args args = { ++ .errp = &err, ++ .path = path, ++ .ia = ia, ++ .delegated_inode = delegated_inode ++ }; ++ ++ wkq_err = au_wkq_wait(call_notify_change, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct unlink_args { ++ int *errp; ++ struct inode *dir; ++ struct path *path; ++ struct inode **delegated_inode; ++}; ++ ++static void call_unlink(void *args) ++{ ++ struct unlink_args *a = args; ++ struct dentry *d = a->path->dentry; ++ struct inode *h_inode; ++ const int stop_sillyrename = (au_test_nfs(d->d_sb) ++ && au_dcount(d) == 1); ++ ++ IMustLock(a->dir); ++ ++ a->path->dentry = d->d_parent; ++ *a->errp = security_path_unlink(a->path, d); ++ a->path->dentry = d; ++ if (unlikely(*a->errp)) ++ return; ++ ++ if (!stop_sillyrename) ++ dget(d); ++ h_inode = NULL; ++ if (d_is_positive(d)) { ++ h_inode = d_inode(d); ++ ihold(h_inode); ++ } ++ ++ lockdep_off(); ++ *a->errp = vfs_unlink(a->dir, d, a->delegated_inode); ++ lockdep_on(); ++ if (!*a->errp) { ++ struct path tmp = { ++ .dentry = d->d_parent, ++ .mnt = a->path->mnt ++ }; ++ vfsub_update_h_iattr(&tmp, /*did*/NULL); /*ignore*/ ++ } ++ ++ if (!stop_sillyrename) ++ dput(d); ++ if (h_inode) ++ iput(h_inode); ++ ++ AuTraceErr(*a->errp); ++} ++ ++/* ++ * @dir: must be locked. ++ * @dentry: target dentry. ++ */ ++int vfsub_unlink(struct inode *dir, struct path *path, ++ struct inode **delegated_inode, int force) ++{ ++ int err; ++ struct unlink_args args = { ++ .errp = &err, ++ .dir = dir, ++ .path = path, ++ .delegated_inode = delegated_inode ++ }; ++ ++ if (!force) ++ call_unlink(&args); ++ else { ++ int wkq_err; ++ ++ wkq_err = au_wkq_wait(call_unlink, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} +diff -Nurp linux-5.4/fs/aufs/vfsub.h linux-5.4-aufs/fs/aufs/vfsub.h +--- linux-5.4/fs/aufs/vfsub.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/vfsub.h 2019-11-28 01:25:59.068925618 +0200 +@@ -0,0 +1,341 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * sub-routines for VFS ++ */ ++ ++#ifndef __AUFS_VFSUB_H__ ++#define __AUFS_VFSUB_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++#include "debug.h" ++ ++/* copied from linux/fs/internal.h */ ++/* todo: BAD approach!! */ ++extern void __mnt_drop_write(struct vfsmount *); ++extern struct file *alloc_empty_file(int, const struct cred *); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for lower inode */ ++/* default MAX_LOCKDEP_SUBCLASSES(8) is not enough */ ++/* reduce? gave up. */ ++enum { ++ AuLsc_I_Begin = I_MUTEX_PARENT2, /* 5 */ ++ AuLsc_I_PARENT, /* lower inode, parent first */ ++ AuLsc_I_PARENT2, /* copyup dirs */ ++ AuLsc_I_PARENT3, /* copyup wh */ ++ AuLsc_I_CHILD, ++ AuLsc_I_CHILD2, ++ AuLsc_I_End ++}; ++ ++/* to debug easier, do not make them inlined functions */ ++#define MtxMustLock(mtx) AuDebugOn(!mutex_is_locked(mtx)) ++#define IMustLock(i) AuDebugOn(!inode_is_locked(i)) ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline void vfsub_drop_nlink(struct inode *inode) ++{ ++ AuDebugOn(!inode->i_nlink); ++ drop_nlink(inode); ++} ++ ++static inline void vfsub_dead_dir(struct inode *inode) ++{ ++ AuDebugOn(!S_ISDIR(inode->i_mode)); ++ inode->i_flags |= S_DEAD; ++ clear_nlink(inode); ++} ++ ++static inline int vfsub_native_ro(struct inode *inode) ++{ ++ return sb_rdonly(inode->i_sb) ++ || IS_RDONLY(inode) ++ /* || IS_APPEND(inode) */ ++ || IS_IMMUTABLE(inode); ++} ++ ++#ifdef CONFIG_AUFS_BR_FUSE ++int vfsub_test_mntns(struct vfsmount *mnt, struct super_block *h_sb); ++#else ++AuStubInt0(vfsub_test_mntns, struct vfsmount *mnt, struct super_block *h_sb); ++#endif ++ ++int vfsub_sync_filesystem(struct super_block *h_sb, int wait); ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_update_h_iattr(struct path *h_path, int *did); ++struct file *vfsub_dentry_open(struct path *path, int flags); ++struct file *vfsub_filp_open(const char *path, int oflags, int mode); ++struct au_branch; ++struct vfsub_aopen_args { ++ struct file *file; ++ unsigned int open_flag; ++ umode_t create_mode; ++ struct au_branch *br; ++}; ++int vfsub_atomic_open(struct inode *dir, struct dentry *dentry, ++ struct vfsub_aopen_args *args); ++int vfsub_kern_path(const char *name, unsigned int flags, struct path *path); ++ ++struct dentry *vfsub_lookup_one_len_unlocked(const char *name, ++ struct dentry *parent, int len); ++struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent, ++ int len); ++ ++struct vfsub_lkup_one_args { ++ struct dentry **errp; ++ struct qstr *name; ++ struct dentry *parent; ++}; ++ ++static inline struct dentry *vfsub_lkup_one(struct qstr *name, ++ struct dentry *parent) ++{ ++ return vfsub_lookup_one_len(name->name, parent, name->len); ++} ++ ++void vfsub_call_lkup_one(void *args); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int vfsub_mnt_want_write(struct vfsmount *mnt) ++{ ++ int err; ++ ++ lockdep_off(); ++ err = mnt_want_write(mnt); ++ lockdep_on(); ++ return err; ++} ++ ++static inline void vfsub_mnt_drop_write(struct vfsmount *mnt) ++{ ++ lockdep_off(); ++ mnt_drop_write(mnt); ++ lockdep_on(); ++} ++ ++#if 0 /* reserved */ ++static inline void vfsub_mnt_drop_write_file(struct file *file) ++{ ++ lockdep_off(); ++ mnt_drop_write_file(file); ++ lockdep_on(); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_hinode; ++struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2); ++void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2); ++ ++int vfsub_create(struct inode *dir, struct path *path, int mode, ++ bool want_excl); ++int vfsub_symlink(struct inode *dir, struct path *path, ++ const char *symname); ++int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev); ++int vfsub_link(struct dentry *src_dentry, struct inode *dir, ++ struct path *path, struct inode **delegated_inode); ++int vfsub_rename(struct inode *src_hdir, struct dentry *src_dentry, ++ struct inode *hdir, struct path *path, ++ struct inode **delegated_inode, unsigned int flags); ++int vfsub_mkdir(struct inode *dir, struct path *path, int mode); ++int vfsub_rmdir(struct inode *dir, struct path *path); ++ ++/* ---------------------------------------------------------------------- */ ++ ++ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, ++ loff_t *ppos); ++ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, ++ loff_t *ppos); ++ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, ++ loff_t *ppos); ++ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, ++ loff_t *ppos); ++int vfsub_flush(struct file *file, fl_owner_t id); ++int vfsub_iterate_dir(struct file *file, struct dir_context *ctx); ++ ++static inline loff_t vfsub_f_size_read(struct file *file) ++{ ++ return i_size_read(file_inode(file)); ++} ++ ++static inline unsigned int vfsub_file_flags(struct file *file) ++{ ++ unsigned int flags; ++ ++ spin_lock(&file->f_lock); ++ flags = file->f_flags; ++ spin_unlock(&file->f_lock); ++ ++ return flags; ++} ++ ++static inline int vfsub_file_execed(struct file *file) ++{ ++ /* todo: direct access f_flags */ ++ return !!(vfsub_file_flags(file) & __FMODE_EXEC); ++} ++ ++#if 0 /* reserved */ ++static inline void vfsub_file_accessed(struct file *h_file) ++{ ++ file_accessed(h_file); ++ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); /*ignore*/ ++} ++#endif ++ ++#if 0 /* reserved */ ++static inline void vfsub_touch_atime(struct vfsmount *h_mnt, ++ struct dentry *h_dentry) ++{ ++ struct path h_path = { ++ .dentry = h_dentry, ++ .mnt = h_mnt ++ }; ++ touch_atime(&h_path); ++ vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/ ++} ++#endif ++ ++static inline int vfsub_update_time(struct inode *h_inode, ++ struct timespec64 *ts, int flags) ++{ ++ return update_time(h_inode, ts, flags); ++ /* no vfsub_update_h_iattr() since we don't have struct path */ ++} ++ ++#ifdef CONFIG_FS_POSIX_ACL ++static inline int vfsub_acl_chmod(struct inode *h_inode, umode_t h_mode) ++{ ++ int err; ++ ++ err = posix_acl_chmod(h_inode, h_mode); ++ if (err == -EOPNOTSUPP) ++ err = 0; ++ return err; ++} ++#else ++AuStubInt0(vfsub_acl_chmod, struct inode *h_inode, umode_t h_mode); ++#endif ++ ++long vfsub_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags); ++long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags); ++ ++static inline long vfsub_truncate(struct path *path, loff_t length) ++{ ++ long err; ++ ++ lockdep_off(); ++ err = vfs_truncate(path, length); ++ lockdep_on(); ++ return err; ++} ++ ++int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr, ++ struct file *h_file); ++int vfsub_fsync(struct file *file, struct path *path, int datasync); ++ ++/* ++ * re-use branch fs's ioctl(FICLONE) while aufs itself doesn't support such ++ * ioctl. ++ */ ++static inline loff_t vfsub_clone_file_range(struct file *src, struct file *dst, ++ loff_t len) ++{ ++ loff_t err; ++ ++ lockdep_off(); ++ err = vfs_clone_file_range(src, 0, dst, 0, len, /*remap_flags*/0); ++ lockdep_on(); ++ ++ return err; ++} ++ ++/* copy_file_range(2) is a systemcall */ ++static inline ssize_t vfsub_copy_file_range(struct file *src, loff_t src_pos, ++ struct file *dst, loff_t dst_pos, ++ size_t len, unsigned int flags) ++{ ++ ssize_t ssz; ++ ++ lockdep_off(); ++ ssz = vfs_copy_file_range(src, src_pos, dst, dst_pos, len, flags); ++ lockdep_on(); ++ ++ return ssz; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline loff_t vfsub_llseek(struct file *file, loff_t offset, int origin) ++{ ++ loff_t err; ++ ++ lockdep_off(); ++ err = vfs_llseek(file, offset, origin); ++ lockdep_on(); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode); ++int vfsub_sio_rmdir(struct inode *dir, struct path *path); ++int vfsub_sio_notify_change(struct path *path, struct iattr *ia, ++ struct inode **delegated_inode); ++int vfsub_notify_change(struct path *path, struct iattr *ia, ++ struct inode **delegated_inode); ++int vfsub_unlink(struct inode *dir, struct path *path, ++ struct inode **delegated_inode, int force); ++ ++static inline int vfsub_getattr(const struct path *path, struct kstat *st) ++{ ++ return vfs_getattr(path, st, STATX_BASIC_STATS, AT_STATX_SYNC_AS_STAT); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int vfsub_setxattr(struct dentry *dentry, const char *name, ++ const void *value, size_t size, int flags) ++{ ++ int err; ++ ++ lockdep_off(); ++ err = vfs_setxattr(dentry, name, value, size, flags); ++ lockdep_on(); ++ ++ return err; ++} ++ ++static inline int vfsub_removexattr(struct dentry *dentry, const char *name) ++{ ++ int err; ++ ++ lockdep_off(); ++ err = vfs_removexattr(dentry, name); ++ lockdep_on(); ++ ++ return err; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_VFSUB_H__ */ +diff -Nurp linux-5.4/fs/aufs/whout.c linux-5.4-aufs/fs/aufs/whout.c +--- linux-5.4/fs/aufs/whout.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/whout.c 2019-11-28 01:25:59.069925618 +0200 +@@ -0,0 +1,1049 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * whiteout for logical deletion and opaque directory ++ */ ++ ++#include "aufs.h" ++ ++#define WH_MASK 0444 ++ ++/* ++ * If a directory contains this file, then it is opaque. We start with the ++ * .wh. flag so that it is blocked by lookup. ++ */ ++static struct qstr diropq_name = QSTR_INIT(AUFS_WH_DIROPQ, ++ sizeof(AUFS_WH_DIROPQ) - 1); ++ ++/* ++ * generate whiteout name, which is NOT terminated by NULL. ++ * @name: original d_name.name ++ * @len: original d_name.len ++ * @wh: whiteout qstr ++ * returns zero when succeeds, otherwise error. ++ * succeeded value as wh->name should be freed by kfree(). ++ */ ++int au_wh_name_alloc(struct qstr *wh, const struct qstr *name) ++{ ++ char *p; ++ ++ if (unlikely(name->len > PATH_MAX - AUFS_WH_PFX_LEN)) ++ return -ENAMETOOLONG; ++ ++ wh->len = name->len + AUFS_WH_PFX_LEN; ++ p = kmalloc(wh->len, GFP_NOFS); ++ wh->name = p; ++ if (p) { ++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); ++ memcpy(p + AUFS_WH_PFX_LEN, name->name, name->len); ++ /* smp_mb(); */ ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * test if the @wh_name exists under @h_parent. ++ * @try_sio specifies the necessary of super-io. ++ */ ++int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, int try_sio) ++{ ++ int err; ++ struct dentry *wh_dentry; ++ ++ if (!try_sio) ++ wh_dentry = vfsub_lkup_one(wh_name, h_parent); ++ else ++ wh_dentry = au_sio_lkup_one(wh_name, h_parent); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) { ++ if (err == -ENAMETOOLONG) ++ err = 0; ++ goto out; ++ } ++ ++ err = 0; ++ if (d_is_negative(wh_dentry)) ++ goto out_wh; /* success */ ++ ++ err = 1; ++ if (d_is_reg(wh_dentry)) ++ goto out_wh; /* success */ ++ ++ err = -EIO; ++ AuIOErr("%pd Invalid whiteout entry type 0%o.\n", ++ wh_dentry, d_inode(wh_dentry)->i_mode); ++ ++out_wh: ++ dput(wh_dentry); ++out: ++ return err; ++} ++ ++/* ++ * test if the @h_dentry sets opaque or not. ++ */ ++int au_diropq_test(struct dentry *h_dentry) ++{ ++ int err; ++ struct inode *h_dir; ++ ++ h_dir = d_inode(h_dentry); ++ err = au_wh_test(h_dentry, &diropq_name, ++ au_test_h_perm_sio(h_dir, MAY_EXEC)); ++ return err; ++} ++ ++/* ++ * returns a negative dentry whose name is unique and temporary. ++ */ ++struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br, ++ struct qstr *prefix) ++{ ++ struct dentry *dentry; ++ int i; ++ char defname[NAME_MAX - AUFS_MAX_NAMELEN + DNAME_INLINE_LEN + 1], ++ *name, *p; ++ /* strict atomic_t is unnecessary here */ ++ static unsigned short cnt; ++ struct qstr qs; ++ ++ BUILD_BUG_ON(sizeof(cnt) * 2 > AUFS_WH_TMP_LEN); ++ ++ name = defname; ++ qs.len = sizeof(defname) - DNAME_INLINE_LEN + prefix->len - 1; ++ if (unlikely(prefix->len > DNAME_INLINE_LEN)) { ++ dentry = ERR_PTR(-ENAMETOOLONG); ++ if (unlikely(qs.len > NAME_MAX)) ++ goto out; ++ dentry = ERR_PTR(-ENOMEM); ++ name = kmalloc(qs.len + 1, GFP_NOFS); ++ if (unlikely(!name)) ++ goto out; ++ } ++ ++ /* doubly whiteout-ed */ ++ memcpy(name, AUFS_WH_PFX AUFS_WH_PFX, AUFS_WH_PFX_LEN * 2); ++ p = name + AUFS_WH_PFX_LEN * 2; ++ memcpy(p, prefix->name, prefix->len); ++ p += prefix->len; ++ *p++ = '.'; ++ AuDebugOn(name + qs.len + 1 - p <= AUFS_WH_TMP_LEN); ++ ++ qs.name = name; ++ for (i = 0; i < 3; i++) { ++ sprintf(p, "%.*x", AUFS_WH_TMP_LEN, cnt++); ++ dentry = au_sio_lkup_one(&qs, h_parent); ++ if (IS_ERR(dentry) || d_is_negative(dentry)) ++ goto out_name; ++ dput(dentry); ++ } ++ /* pr_warn("could not get random name\n"); */ ++ dentry = ERR_PTR(-EEXIST); ++ AuDbg("%.*s\n", AuLNPair(&qs)); ++ BUG(); ++ ++out_name: ++ if (name != defname) ++ au_kfree_try_rcu(name); ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ++ * rename the @h_dentry on @br to the whiteouted temporary name. ++ */ ++int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br) ++{ ++ int err; ++ struct path h_path = { ++ .mnt = au_br_mnt(br) ++ }; ++ struct inode *h_dir, *delegated; ++ struct dentry *h_parent; ++ ++ h_parent = h_dentry->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ ++ h_path.dentry = au_whtmp_lkup(h_parent, br, &h_dentry->d_name); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) ++ goto out; ++ ++ /* under the same dir, no need to lock_rename() */ ++ delegated = NULL; ++ err = vfsub_rename(h_dir, h_dentry, h_dir, &h_path, &delegated, ++ /*flags*/0); ++ AuTraceErr(err); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ dput(h_path.dentry); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * functions for removing a whiteout ++ */ ++ ++static int do_unlink_wh(struct inode *h_dir, struct path *h_path) ++{ ++ int err, force; ++ struct inode *delegated; ++ ++ /* ++ * forces superio when the dir has a sticky bit. ++ * this may be a violation of unix fs semantics. ++ */ ++ force = (h_dir->i_mode & S_ISVTX) ++ && !uid_eq(current_fsuid(), d_inode(h_path->dentry)->i_uid); ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, h_path, &delegated, force); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ return err; ++} ++ ++int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path, ++ struct dentry *dentry) ++{ ++ int err; ++ ++ err = do_unlink_wh(h_dir, h_path); ++ if (!err && dentry) ++ au_set_dbwh(dentry, -1); ++ ++ return err; ++} ++ ++static int unlink_wh_name(struct dentry *h_parent, struct qstr *wh, ++ struct au_branch *br) ++{ ++ int err; ++ struct path h_path = { ++ .mnt = au_br_mnt(br) ++ }; ++ ++ err = 0; ++ h_path.dentry = vfsub_lkup_one(wh, h_parent); ++ if (IS_ERR(h_path.dentry)) ++ err = PTR_ERR(h_path.dentry); ++ else { ++ if (d_is_reg(h_path.dentry)) ++ err = do_unlink_wh(d_inode(h_parent), &h_path); ++ dput(h_path.dentry); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * initialize/clean whiteout for a branch ++ */ ++ ++static void au_wh_clean(struct inode *h_dir, struct path *whpath, ++ const int isdir) ++{ ++ int err; ++ struct inode *delegated; ++ ++ if (d_is_negative(whpath->dentry)) ++ return; ++ ++ if (isdir) ++ err = vfsub_rmdir(h_dir, whpath); ++ else { ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, whpath, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ } ++ if (unlikely(err)) ++ pr_warn("failed removing %pd (%d), ignored.\n", ++ whpath->dentry, err); ++} ++ ++static int test_linkable(struct dentry *h_root) ++{ ++ struct inode *h_dir = d_inode(h_root); ++ ++ if (h_dir->i_op->link) ++ return 0; ++ ++ pr_err("%pd (%s) doesn't support link(2), use noplink and rw+nolwh\n", ++ h_root, au_sbtype(h_root->d_sb)); ++ return -ENOSYS; ++} ++ ++/* todo: should this mkdir be done in /sbin/mount.aufs helper? */ ++static int au_whdir(struct inode *h_dir, struct path *path) ++{ ++ int err; ++ ++ err = -EEXIST; ++ if (d_is_negative(path->dentry)) { ++ int mode = 0700; ++ ++ if (au_test_nfs(path->dentry->d_sb)) ++ mode |= 0111; ++ err = vfsub_mkdir(h_dir, path, mode); ++ } else if (d_is_dir(path->dentry)) ++ err = 0; ++ else ++ pr_err("unknown %pd exists\n", path->dentry); ++ ++ return err; ++} ++ ++struct au_wh_base { ++ const struct qstr *name; ++ struct dentry *dentry; ++}; ++ ++static void au_wh_init_ro(struct inode *h_dir, struct au_wh_base base[], ++ struct path *h_path) ++{ ++ h_path->dentry = base[AuBrWh_BASE].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/0); ++ h_path->dentry = base[AuBrWh_PLINK].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++ h_path->dentry = base[AuBrWh_ORPH].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++} ++ ++/* ++ * returns tri-state, ++ * minus: error, caller should print the message ++ * zero: success ++ * plus: error, caller should NOT print the message ++ */ ++static int au_wh_init_rw_nolink(struct dentry *h_root, struct au_wbr *wbr, ++ int do_plink, struct au_wh_base base[], ++ struct path *h_path) ++{ ++ int err; ++ struct inode *h_dir; ++ ++ h_dir = d_inode(h_root); ++ h_path->dentry = base[AuBrWh_BASE].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/0); ++ h_path->dentry = base[AuBrWh_PLINK].dentry; ++ if (do_plink) { ++ err = test_linkable(h_root); ++ if (unlikely(err)) { ++ err = 1; ++ goto out; ++ } ++ ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry); ++ } else ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++ h_path->dentry = base[AuBrWh_ORPH].dentry; ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry); ++ ++out: ++ return err; ++} ++ ++/* ++ * for the moment, aufs supports the branch filesystem which does not support ++ * link(2). testing on FAT which does not support i_op->setattr() fully either, ++ * copyup failed. finally, such filesystem will not be used as the writable ++ * branch. ++ * ++ * returns tri-state, see above. ++ */ ++static int au_wh_init_rw(struct dentry *h_root, struct au_wbr *wbr, ++ int do_plink, struct au_wh_base base[], ++ struct path *h_path) ++{ ++ int err; ++ struct inode *h_dir; ++ ++ WbrWhMustWriteLock(wbr); ++ ++ err = test_linkable(h_root); ++ if (unlikely(err)) { ++ err = 1; ++ goto out; ++ } ++ ++ /* ++ * todo: should this create be done in /sbin/mount.aufs helper? ++ */ ++ err = -EEXIST; ++ h_dir = d_inode(h_root); ++ if (d_is_negative(base[AuBrWh_BASE].dentry)) { ++ h_path->dentry = base[AuBrWh_BASE].dentry; ++ err = vfsub_create(h_dir, h_path, WH_MASK, /*want_excl*/true); ++ } else if (d_is_reg(base[AuBrWh_BASE].dentry)) ++ err = 0; ++ else ++ pr_err("unknown %pd2 exists\n", base[AuBrWh_BASE].dentry); ++ if (unlikely(err)) ++ goto out; ++ ++ h_path->dentry = base[AuBrWh_PLINK].dentry; ++ if (do_plink) { ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry); ++ } else ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++ wbr->wbr_whbase = dget(base[AuBrWh_BASE].dentry); ++ ++ h_path->dentry = base[AuBrWh_ORPH].dentry; ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry); ++ ++out: ++ return err; ++} ++ ++/* ++ * initialize the whiteout base file/dir for @br. ++ */ ++int au_wh_init(struct au_branch *br, struct super_block *sb) ++{ ++ int err, i; ++ const unsigned char do_plink ++ = !!au_opt_test(au_mntflags(sb), PLINK); ++ struct inode *h_dir; ++ struct path path = br->br_path; ++ struct dentry *h_root = path.dentry; ++ struct au_wbr *wbr = br->br_wbr; ++ static const struct qstr base_name[] = { ++ [AuBrWh_BASE] = QSTR_INIT(AUFS_BASE_NAME, ++ sizeof(AUFS_BASE_NAME) - 1), ++ [AuBrWh_PLINK] = QSTR_INIT(AUFS_PLINKDIR_NAME, ++ sizeof(AUFS_PLINKDIR_NAME) - 1), ++ [AuBrWh_ORPH] = QSTR_INIT(AUFS_ORPHDIR_NAME, ++ sizeof(AUFS_ORPHDIR_NAME) - 1) ++ }; ++ struct au_wh_base base[] = { ++ [AuBrWh_BASE] = { ++ .name = base_name + AuBrWh_BASE, ++ .dentry = NULL ++ }, ++ [AuBrWh_PLINK] = { ++ .name = base_name + AuBrWh_PLINK, ++ .dentry = NULL ++ }, ++ [AuBrWh_ORPH] = { ++ .name = base_name + AuBrWh_ORPH, ++ .dentry = NULL ++ } ++ }; ++ ++ if (wbr) ++ WbrWhMustWriteLock(wbr); ++ ++ for (i = 0; i < AuBrWh_Last; i++) { ++ /* doubly whiteouted */ ++ struct dentry *d; ++ ++ d = au_wh_lkup(h_root, (void *)base[i].name, br); ++ err = PTR_ERR(d); ++ if (IS_ERR(d)) ++ goto out; ++ ++ base[i].dentry = d; ++ AuDebugOn(wbr ++ && wbr->wbr_wh[i] ++ && wbr->wbr_wh[i] != base[i].dentry); ++ } ++ ++ if (wbr) ++ for (i = 0; i < AuBrWh_Last; i++) { ++ dput(wbr->wbr_wh[i]); ++ wbr->wbr_wh[i] = NULL; ++ } ++ ++ err = 0; ++ if (!au_br_writable(br->br_perm)) { ++ h_dir = d_inode(h_root); ++ au_wh_init_ro(h_dir, base, &path); ++ } else if (!au_br_wh_linkable(br->br_perm)) { ++ err = au_wh_init_rw_nolink(h_root, wbr, do_plink, base, &path); ++ if (err > 0) ++ goto out; ++ else if (err) ++ goto out_err; ++ } else { ++ err = au_wh_init_rw(h_root, wbr, do_plink, base, &path); ++ if (err > 0) ++ goto out; ++ else if (err) ++ goto out_err; ++ } ++ goto out; /* success */ ++ ++out_err: ++ pr_err("an error(%d) on the writable branch %pd(%s)\n", ++ err, h_root, au_sbtype(h_root->d_sb)); ++out: ++ for (i = 0; i < AuBrWh_Last; i++) ++ dput(base[i].dentry); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * whiteouts are all hard-linked usually. ++ * when its link count reaches a ceiling, we create a new whiteout base ++ * asynchronously. ++ */ ++ ++struct reinit_br_wh { ++ struct super_block *sb; ++ struct au_branch *br; ++}; ++ ++static void reinit_br_wh(void *arg) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct path h_path; ++ struct reinit_br_wh *a = arg; ++ struct au_wbr *wbr; ++ struct inode *dir, *delegated; ++ struct dentry *h_root; ++ struct au_hinode *hdir; ++ ++ err = 0; ++ wbr = a->br->br_wbr; ++ /* big aufs lock */ ++ si_noflush_write_lock(a->sb); ++ if (!au_br_writable(a->br->br_perm)) ++ goto out; ++ bindex = au_br_index(a->sb, a->br->br_id); ++ if (unlikely(bindex < 0)) ++ goto out; ++ ++ di_read_lock_parent(a->sb->s_root, AuLock_IR); ++ dir = d_inode(a->sb->s_root); ++ hdir = au_hi(dir, bindex); ++ h_root = au_h_dptr(a->sb->s_root, bindex); ++ AuDebugOn(h_root != au_br_dentry(a->br)); ++ ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ wbr_wh_write_lock(wbr); ++ err = au_h_verify(wbr->wbr_whbase, au_opt_udba(a->sb), hdir->hi_inode, ++ h_root, a->br); ++ if (!err) { ++ h_path.dentry = wbr->wbr_whbase; ++ h_path.mnt = au_br_mnt(a->br); ++ delegated = NULL; ++ err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated, ++ /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ } else { ++ pr_warn("%pd is moved, ignored\n", wbr->wbr_whbase); ++ err = 0; ++ } ++ dput(wbr->wbr_whbase); ++ wbr->wbr_whbase = NULL; ++ if (!err) ++ err = au_wh_init(a->br, a->sb); ++ wbr_wh_write_unlock(wbr); ++ au_hn_inode_unlock(hdir); ++ di_read_unlock(a->sb->s_root, AuLock_IR); ++ if (!err) ++ au_fhsm_wrote(a->sb, bindex, /*force*/0); ++ ++out: ++ if (wbr) ++ atomic_dec(&wbr->wbr_wh_running); ++ au_lcnt_dec(&a->br->br_count); ++ si_write_unlock(a->sb); ++ au_nwt_done(&au_sbi(a->sb)->si_nowait); ++ au_kfree_rcu(a); ++ if (unlikely(err)) ++ AuIOErr("err %d\n", err); ++} ++ ++static void kick_reinit_br_wh(struct super_block *sb, struct au_branch *br) ++{ ++ int do_dec, wkq_err; ++ struct reinit_br_wh *arg; ++ ++ do_dec = 1; ++ if (atomic_inc_return(&br->br_wbr->wbr_wh_running) != 1) ++ goto out; ++ ++ /* ignore ENOMEM */ ++ arg = kmalloc(sizeof(*arg), GFP_NOFS); ++ if (arg) { ++ /* ++ * dec(wh_running), kfree(arg) and dec(br_count) ++ * in reinit function ++ */ ++ arg->sb = sb; ++ arg->br = br; ++ au_lcnt_inc(&br->br_count); ++ wkq_err = au_wkq_nowait(reinit_br_wh, arg, sb, /*flags*/0); ++ if (unlikely(wkq_err)) { ++ atomic_dec(&br->br_wbr->wbr_wh_running); ++ au_lcnt_dec(&br->br_count); ++ au_kfree_rcu(arg); ++ } ++ do_dec = 0; ++ } ++ ++out: ++ if (do_dec) ++ atomic_dec(&br->br_wbr->wbr_wh_running); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create the whiteout @wh. ++ */ ++static int link_or_create_wh(struct super_block *sb, aufs_bindex_t bindex, ++ struct dentry *wh) ++{ ++ int err; ++ struct path h_path = { ++ .dentry = wh ++ }; ++ struct au_branch *br; ++ struct au_wbr *wbr; ++ struct dentry *h_parent; ++ struct inode *h_dir, *delegated; ++ ++ h_parent = wh->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ ++ br = au_sbr(sb, bindex); ++ h_path.mnt = au_br_mnt(br); ++ wbr = br->br_wbr; ++ wbr_wh_read_lock(wbr); ++ if (wbr->wbr_whbase) { ++ delegated = NULL; ++ err = vfsub_link(wbr->wbr_whbase, h_dir, &h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ if (!err || err != -EMLINK) ++ goto out; ++ ++ /* link count full. re-initialize br_whbase. */ ++ kick_reinit_br_wh(sb, br); ++ } ++ ++ /* return this error in this context */ ++ err = vfsub_create(h_dir, &h_path, WH_MASK, /*want_excl*/true); ++ if (!err) ++ au_fhsm_wrote(sb, bindex, /*force*/0); ++ ++out: ++ wbr_wh_read_unlock(wbr); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create or remove the diropq. ++ */ ++static struct dentry *do_diropq(struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int flags) ++{ ++ struct dentry *opq_dentry, *h_dentry; ++ struct super_block *sb; ++ struct au_branch *br; ++ int err; ++ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, bindex); ++ h_dentry = au_h_dptr(dentry, bindex); ++ opq_dentry = vfsub_lkup_one(&diropq_name, h_dentry); ++ if (IS_ERR(opq_dentry)) ++ goto out; ++ ++ if (au_ftest_diropq(flags, CREATE)) { ++ err = link_or_create_wh(sb, bindex, opq_dentry); ++ if (!err) { ++ au_set_dbdiropq(dentry, bindex); ++ goto out; /* success */ ++ } ++ } else { ++ struct path tmp = { ++ .dentry = opq_dentry, ++ .mnt = au_br_mnt(br) ++ }; ++ err = do_unlink_wh(au_h_iptr(d_inode(dentry), bindex), &tmp); ++ if (!err) ++ au_set_dbdiropq(dentry, -1); ++ } ++ dput(opq_dentry); ++ opq_dentry = ERR_PTR(err); ++ ++out: ++ return opq_dentry; ++} ++ ++struct do_diropq_args { ++ struct dentry **errp; ++ struct dentry *dentry; ++ aufs_bindex_t bindex; ++ unsigned int flags; ++}; ++ ++static void call_do_diropq(void *args) ++{ ++ struct do_diropq_args *a = args; ++ *a->errp = do_diropq(a->dentry, a->bindex, a->flags); ++} ++ ++struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int flags) ++{ ++ struct dentry *diropq, *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!au_test_h_perm_sio(d_inode(h_dentry), MAY_EXEC | MAY_WRITE)) ++ diropq = do_diropq(dentry, bindex, flags); ++ else { ++ int wkq_err; ++ struct do_diropq_args args = { ++ .errp = &diropq, ++ .dentry = dentry, ++ .bindex = bindex, ++ .flags = flags ++ }; ++ ++ wkq_err = au_wkq_wait(call_do_diropq, &args); ++ if (unlikely(wkq_err)) ++ diropq = ERR_PTR(wkq_err); ++ } ++ ++ return diropq; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * lookup whiteout dentry. ++ * @h_parent: lower parent dentry which must exist and be locked ++ * @base_name: name of dentry which will be whiteouted ++ * returns dentry for whiteout. ++ */ ++struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name, ++ struct au_branch *br) ++{ ++ int err; ++ struct qstr wh_name; ++ struct dentry *wh_dentry; ++ ++ err = au_wh_name_alloc(&wh_name, base_name); ++ wh_dentry = ERR_PTR(err); ++ if (!err) { ++ wh_dentry = vfsub_lkup_one(&wh_name, h_parent); ++ au_kfree_try_rcu(wh_name.name); ++ } ++ return wh_dentry; ++} ++ ++/* ++ * link/create a whiteout for @dentry on @bindex. ++ */ ++struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent) ++{ ++ struct dentry *wh_dentry; ++ struct super_block *sb; ++ int err; ++ ++ sb = dentry->d_sb; ++ wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, au_sbr(sb, bindex)); ++ if (!IS_ERR(wh_dentry) && d_is_negative(wh_dentry)) { ++ err = link_or_create_wh(sb, bindex, wh_dentry); ++ if (!err) { ++ au_set_dbwh(dentry, bindex); ++ au_fhsm_wrote(sb, bindex, /*force*/0); ++ } else { ++ dput(wh_dentry); ++ wh_dentry = ERR_PTR(err); ++ } ++ } ++ ++ return wh_dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Delete all whiteouts in this directory on branch bindex. */ ++static int del_wh_children(struct dentry *h_dentry, struct au_nhash *whlist, ++ aufs_bindex_t bindex, struct au_branch *br) ++{ ++ int err; ++ unsigned long ul, n; ++ struct qstr wh_name; ++ char *p; ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ struct au_vdir_destr *str; ++ ++ err = -ENOMEM; ++ p = (void *)__get_free_page(GFP_NOFS); ++ wh_name.name = p; ++ if (unlikely(!wh_name.name)) ++ goto out; ++ ++ err = 0; ++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); ++ p += AUFS_WH_PFX_LEN; ++ n = whlist->nh_num; ++ head = whlist->nh_head; ++ for (ul = 0; !err && ul < n; ul++, head++) { ++ hlist_for_each_entry(pos, head, wh_hash) { ++ if (pos->wh_bindex != bindex) ++ continue; ++ ++ str = &pos->wh_str; ++ if (str->len + AUFS_WH_PFX_LEN <= PATH_MAX) { ++ memcpy(p, str->name, str->len); ++ wh_name.len = AUFS_WH_PFX_LEN + str->len; ++ err = unlink_wh_name(h_dentry, &wh_name, br); ++ if (!err) ++ continue; ++ break; ++ } ++ AuIOErr("whiteout name too long %.*s\n", ++ str->len, str->name); ++ err = -EIO; ++ break; ++ } ++ } ++ free_page((unsigned long)wh_name.name); ++ ++out: ++ return err; ++} ++ ++struct del_wh_children_args { ++ int *errp; ++ struct dentry *h_dentry; ++ struct au_nhash *whlist; ++ aufs_bindex_t bindex; ++ struct au_branch *br; ++}; ++ ++static void call_del_wh_children(void *args) ++{ ++ struct del_wh_children_args *a = args; ++ *a->errp = del_wh_children(a->h_dentry, a->whlist, a->bindex, a->br); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp) ++{ ++ struct au_whtmp_rmdir *whtmp; ++ int err; ++ unsigned int rdhash; ++ ++ SiMustAnyLock(sb); ++ ++ whtmp = kzalloc(sizeof(*whtmp), gfp); ++ if (unlikely(!whtmp)) { ++ whtmp = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ ++ /* no estimation for dir size */ ++ rdhash = au_sbi(sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = AUFS_RDHASH_DEF; ++ err = au_nhash_alloc(&whtmp->whlist, rdhash, gfp); ++ if (unlikely(err)) { ++ au_kfree_rcu(whtmp); ++ whtmp = ERR_PTR(err); ++ } ++ ++out: ++ return whtmp; ++} ++ ++void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp) ++{ ++ if (whtmp->br) ++ au_lcnt_dec(&whtmp->br->br_count); ++ dput(whtmp->wh_dentry); ++ iput(whtmp->dir); ++ au_nhash_wh_free(&whtmp->whlist); ++ au_kfree_rcu(whtmp); ++} ++ ++/* ++ * rmdir the whiteouted temporary named dir @h_dentry. ++ * @whlist: whiteouted children. ++ */ ++int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_nhash *whlist) ++{ ++ int err; ++ unsigned int h_nlink; ++ struct path h_tmp; ++ struct inode *wh_inode, *h_dir; ++ struct au_branch *br; ++ ++ h_dir = d_inode(wh_dentry->d_parent); /* dir inode is locked */ ++ IMustLock(h_dir); ++ ++ br = au_sbr(dir->i_sb, bindex); ++ wh_inode = d_inode(wh_dentry); ++ inode_lock_nested(wh_inode, AuLsc_I_CHILD); ++ ++ /* ++ * someone else might change some whiteouts while we were sleeping. ++ * it means this whlist may have an obsoleted entry. ++ */ ++ if (!au_test_h_perm_sio(wh_inode, MAY_EXEC | MAY_WRITE)) ++ err = del_wh_children(wh_dentry, whlist, bindex, br); ++ else { ++ int wkq_err; ++ struct del_wh_children_args args = { ++ .errp = &err, ++ .h_dentry = wh_dentry, ++ .whlist = whlist, ++ .bindex = bindex, ++ .br = br ++ }; ++ ++ wkq_err = au_wkq_wait(call_del_wh_children, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ inode_unlock(wh_inode); ++ ++ if (!err) { ++ h_tmp.dentry = wh_dentry; ++ h_tmp.mnt = au_br_mnt(br); ++ h_nlink = h_dir->i_nlink; ++ err = vfsub_rmdir(h_dir, &h_tmp); ++ /* some fs doesn't change the parent nlink in some cases */ ++ h_nlink -= h_dir->i_nlink; ++ } ++ ++ if (!err) { ++ if (au_ibtop(dir) == bindex) { ++ /* todo: dir->i_mutex is necessary */ ++ au_cpup_attr_timesizes(dir); ++ if (h_nlink) ++ vfsub_drop_nlink(dir); ++ } ++ return 0; /* success */ ++ } ++ ++ pr_warn("failed removing %pd(%d), ignored\n", wh_dentry, err); ++ return err; ++} ++ ++static void call_rmdir_whtmp(void *args) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct au_whtmp_rmdir *a = args; ++ struct super_block *sb; ++ struct dentry *h_parent; ++ struct inode *h_dir; ++ struct au_hinode *hdir; ++ ++ /* rmdir by nfsd may cause deadlock with this i_mutex */ ++ /* inode_lock(a->dir); */ ++ err = -EROFS; ++ sb = a->dir->i_sb; ++ si_read_lock(sb, !AuLock_FLUSH); ++ if (!au_br_writable(a->br->br_perm)) ++ goto out; ++ bindex = au_br_index(sb, a->br->br_id); ++ if (unlikely(bindex < 0)) ++ goto out; ++ ++ err = -EIO; ++ ii_write_lock_parent(a->dir); ++ h_parent = dget_parent(a->wh_dentry); ++ h_dir = d_inode(h_parent); ++ hdir = au_hi(a->dir, bindex); ++ err = vfsub_mnt_want_write(au_br_mnt(a->br)); ++ if (unlikely(err)) ++ goto out_mnt; ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ err = au_h_verify(a->wh_dentry, au_opt_udba(sb), h_dir, h_parent, ++ a->br); ++ if (!err) ++ err = au_whtmp_rmdir(a->dir, bindex, a->wh_dentry, &a->whlist); ++ au_hn_inode_unlock(hdir); ++ vfsub_mnt_drop_write(au_br_mnt(a->br)); ++ ++out_mnt: ++ dput(h_parent); ++ ii_write_unlock(a->dir); ++out: ++ /* inode_unlock(a->dir); */ ++ au_whtmp_rmdir_free(a); ++ si_read_unlock(sb); ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ if (unlikely(err)) ++ AuIOErr("err %d\n", err); ++} ++ ++void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_whtmp_rmdir *args) ++{ ++ int wkq_err; ++ struct super_block *sb; ++ ++ IMustLock(dir); ++ ++ /* all post-process will be done in do_rmdir_whtmp(). */ ++ sb = dir->i_sb; ++ args->dir = au_igrab(dir); ++ args->br = au_sbr(sb, bindex); ++ au_lcnt_inc(&args->br->br_count); ++ args->wh_dentry = dget(wh_dentry); ++ wkq_err = au_wkq_nowait(call_rmdir_whtmp, args, sb, /*flags*/0); ++ if (unlikely(wkq_err)) { ++ pr_warn("rmdir error %pd (%d), ignored\n", wh_dentry, wkq_err); ++ au_whtmp_rmdir_free(args); ++ } ++} +diff -Nurp linux-5.4/fs/aufs/whout.h linux-5.4-aufs/fs/aufs/whout.h +--- linux-5.4/fs/aufs/whout.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/whout.h 2019-11-28 01:25:59.069925618 +0200 +@@ -0,0 +1,73 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * whiteout for logical deletion and opaque directory ++ */ ++ ++#ifndef __AUFS_WHOUT_H__ ++#define __AUFS_WHOUT_H__ ++ ++#ifdef __KERNEL__ ++ ++#include "dir.h" ++ ++/* whout.c */ ++int au_wh_name_alloc(struct qstr *wh, const struct qstr *name); ++int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, int try_sio); ++int au_diropq_test(struct dentry *h_dentry); ++struct au_branch; ++struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br, ++ struct qstr *prefix); ++int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br); ++int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path, ++ struct dentry *dentry); ++int au_wh_init(struct au_branch *br, struct super_block *sb); ++ ++/* diropq flags */ ++#define AuDiropq_CREATE 1 ++#define au_ftest_diropq(flags, name) ((flags) & AuDiropq_##name) ++#define au_fset_diropq(flags, name) \ ++ do { (flags) |= AuDiropq_##name; } while (0) ++#define au_fclr_diropq(flags, name) \ ++ do { (flags) &= ~AuDiropq_##name; } while (0) ++ ++struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int flags); ++struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name, ++ struct au_branch *br); ++struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent); ++ ++/* real rmdir for the whiteout-ed dir */ ++struct au_whtmp_rmdir { ++ struct inode *dir; ++ struct au_branch *br; ++ struct dentry *wh_dentry; ++ struct au_nhash whlist; ++}; ++ ++struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp); ++void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp); ++int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_nhash *whlist); ++void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_whtmp_rmdir *args); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct dentry *au_diropq_create(struct dentry *dentry, ++ aufs_bindex_t bindex) ++{ ++ return au_diropq_sio(dentry, bindex, AuDiropq_CREATE); ++} ++ ++static inline int au_diropq_remove(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ return PTR_ERR(au_diropq_sio(dentry, bindex, !AuDiropq_CREATE)); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_WHOUT_H__ */ +diff -Nurp linux-5.4/fs/aufs/wkq.c linux-5.4-aufs/fs/aufs/wkq.c +--- linux-5.4/fs/aufs/wkq.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/wkq.c 2019-11-28 01:25:59.069925618 +0200 +@@ -0,0 +1,379 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * workqueue for asynchronous/super-io operations ++ * todo: try new credential scheme ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* internal workqueue named AUFS_WKQ_NAME */ ++ ++static struct workqueue_struct *au_wkq; ++ ++struct au_wkinfo { ++ struct work_struct wk; ++ struct kobject *kobj; ++ ++ unsigned int flags; /* see wkq.h */ ++ ++ au_wkq_func_t func; ++ void *args; ++ ++#ifdef CONFIG_LOCKDEP ++ int dont_check; ++ struct held_lock **hlock; ++#endif ++ ++ struct completion *comp; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * Aufs passes some operations to the workqueue such as the internal copyup. ++ * This scheme looks rather unnatural for LOCKDEP debugging feature, since the ++ * job run by workqueue depends upon the locks acquired in the other task. ++ * Delegating a small operation to the workqueue, aufs passes its lockdep ++ * information too. And the job in the workqueue restores the info in order to ++ * pretend as if it acquired those locks. This is just to make LOCKDEP work ++ * correctly and expectedly. ++ */ ++ ++#ifndef CONFIG_LOCKDEP ++AuStubInt0(au_wkq_lockdep_alloc, struct au_wkinfo *wkinfo); ++AuStubVoid(au_wkq_lockdep_free, struct au_wkinfo *wkinfo); ++AuStubVoid(au_wkq_lockdep_pre, struct au_wkinfo *wkinfo); ++AuStubVoid(au_wkq_lockdep_post, struct au_wkinfo *wkinfo); ++AuStubVoid(au_wkq_lockdep_init, struct au_wkinfo *wkinfo); ++#else ++static void au_wkq_lockdep_init(struct au_wkinfo *wkinfo) ++{ ++ wkinfo->hlock = NULL; ++ wkinfo->dont_check = 0; ++} ++ ++/* ++ * 1: matched ++ * 0: unmatched ++ */ ++static int au_wkq_lockdep_test(struct lock_class_key *key, const char *name) ++{ ++ static DEFINE_SPINLOCK(spin); ++ static struct { ++ char *name; ++ struct lock_class_key *key; ++ } a[] = { ++ { .name = "&sbinfo->si_rwsem" }, ++ { .name = "&finfo->fi_rwsem" }, ++ { .name = "&dinfo->di_rwsem" }, ++ { .name = "&iinfo->ii_rwsem" } ++ }; ++ static int set; ++ int i; ++ ++ /* lockless read from 'set.' see below */ ++ if (set == ARRAY_SIZE(a)) { ++ for (i = 0; i < ARRAY_SIZE(a); i++) ++ if (a[i].key == key) ++ goto match; ++ goto unmatch; ++ } ++ ++ spin_lock(&spin); ++ if (set) ++ for (i = 0; i < ARRAY_SIZE(a); i++) ++ if (a[i].key == key) { ++ spin_unlock(&spin); ++ goto match; ++ } ++ for (i = 0; i < ARRAY_SIZE(a); i++) { ++ if (a[i].key) { ++ if (unlikely(a[i].key == key)) { /* rare but possible */ ++ spin_unlock(&spin); ++ goto match; ++ } else ++ continue; ++ } ++ if (strstr(a[i].name, name)) { ++ /* ++ * the order of these three lines is important for the ++ * lockless read above. ++ */ ++ a[i].key = key; ++ spin_unlock(&spin); ++ set++; ++ /* AuDbg("%d, %s\n", set, name); */ ++ goto match; ++ } ++ } ++ spin_unlock(&spin); ++ goto unmatch; ++ ++match: ++ return 1; ++unmatch: ++ return 0; ++} ++ ++static int au_wkq_lockdep_alloc(struct au_wkinfo *wkinfo) ++{ ++ int err, n; ++ struct task_struct *curr; ++ struct held_lock **hl, *held_locks, *p; ++ ++ err = 0; ++ curr = current; ++ wkinfo->dont_check = lockdep_recursing(curr); ++ if (wkinfo->dont_check) ++ goto out; ++ n = curr->lockdep_depth; ++ if (!n) ++ goto out; ++ ++ err = -ENOMEM; ++ wkinfo->hlock = kmalloc_array(n + 1, sizeof(*wkinfo->hlock), GFP_NOFS); ++ if (unlikely(!wkinfo->hlock)) ++ goto out; ++ ++ err = 0; ++#if 0 ++ if (0 && au_debug_test()) /* left for debugging */ ++ lockdep_print_held_locks(curr); ++#endif ++ held_locks = curr->held_locks; ++ hl = wkinfo->hlock; ++ while (n--) { ++ p = held_locks++; ++ if (au_wkq_lockdep_test(p->instance->key, p->instance->name)) ++ *hl++ = p; ++ } ++ *hl = NULL; ++ ++out: ++ return err; ++} ++ ++static void au_wkq_lockdep_free(struct au_wkinfo *wkinfo) ++{ ++ au_kfree_try_rcu(wkinfo->hlock); ++} ++ ++static void au_wkq_lockdep_pre(struct au_wkinfo *wkinfo) ++{ ++ struct held_lock *p, **hl = wkinfo->hlock; ++ int subclass; ++ ++ if (wkinfo->dont_check) ++ lockdep_off(); ++ if (!hl) ++ return; ++ while ((p = *hl++)) { /* assignment */ ++ subclass = lockdep_hlock_class(p)->subclass; ++ /* AuDbg("%s, %d\n", p->instance->name, subclass); */ ++ if (p->read) ++ rwsem_acquire_read(p->instance, subclass, 0, ++ /*p->acquire_ip*/_RET_IP_); ++ else ++ rwsem_acquire(p->instance, subclass, 0, ++ /*p->acquire_ip*/_RET_IP_); ++ } ++} ++ ++static void au_wkq_lockdep_post(struct au_wkinfo *wkinfo) ++{ ++ struct held_lock *p, **hl = wkinfo->hlock; ++ ++ if (wkinfo->dont_check) ++ lockdep_on(); ++ if (!hl) ++ return; ++ while ((p = *hl++)) /* assignment */ ++ rwsem_release(p->instance, 0, /*p->acquire_ip*/_RET_IP_); ++} ++#endif ++ ++static void wkq_func(struct work_struct *wk) ++{ ++ struct au_wkinfo *wkinfo = container_of(wk, struct au_wkinfo, wk); ++ ++ AuDebugOn(!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)); ++ AuDebugOn(rlimit(RLIMIT_FSIZE) != RLIM_INFINITY); ++ ++ au_wkq_lockdep_pre(wkinfo); ++ wkinfo->func(wkinfo->args); ++ au_wkq_lockdep_post(wkinfo); ++ if (au_ftest_wkq(wkinfo->flags, WAIT)) ++ complete(wkinfo->comp); ++ else { ++ kobject_put(wkinfo->kobj); ++ module_put(THIS_MODULE); /* todo: ?? */ ++ au_kfree_rcu(wkinfo); ++ } ++} ++ ++/* ++ * Since struct completion is large, try allocating it dynamically. ++ */ ++#if 1 /* defined(CONFIG_4KSTACKS) || defined(AuTest4KSTACKS) */ ++#define AuWkqCompDeclare(name) struct completion *comp = NULL ++ ++static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp) ++{ ++ *comp = kmalloc(sizeof(**comp), GFP_NOFS); ++ if (*comp) { ++ init_completion(*comp); ++ wkinfo->comp = *comp; ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++static void au_wkq_comp_free(struct completion *comp) ++{ ++ au_kfree_rcu(comp); ++} ++ ++#else ++ ++/* no braces */ ++#define AuWkqCompDeclare(name) \ ++ DECLARE_COMPLETION_ONSTACK(_ ## name); \ ++ struct completion *comp = &_ ## name ++ ++static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp) ++{ ++ wkinfo->comp = *comp; ++ return 0; ++} ++ ++static void au_wkq_comp_free(struct completion *comp __maybe_unused) ++{ ++ /* empty */ ++} ++#endif /* 4KSTACKS */ ++ ++static void au_wkq_run(struct au_wkinfo *wkinfo) ++{ ++ if (au_ftest_wkq(wkinfo->flags, NEST)) { ++ if (au_wkq_test()) { ++ AuWarn1("wkq from wkq, unless silly-rename on NFS," ++ " due to a dead dir by UDBA," ++ " or async xino write?\n"); ++ AuDebugOn(au_ftest_wkq(wkinfo->flags, WAIT)); ++ } ++ } else ++ au_dbg_verify_kthread(); ++ ++ if (au_ftest_wkq(wkinfo->flags, WAIT)) { ++ INIT_WORK_ONSTACK(&wkinfo->wk, wkq_func); ++ queue_work(au_wkq, &wkinfo->wk); ++ } else { ++ INIT_WORK(&wkinfo->wk, wkq_func); ++ schedule_work(&wkinfo->wk); ++ } ++} ++ ++/* ++ * Be careful. It is easy to make deadlock happen. ++ * processA: lock, wkq and wait ++ * processB: wkq and wait, lock in wkq ++ * --> deadlock ++ */ ++int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args) ++{ ++ int err; ++ AuWkqCompDeclare(comp); ++ struct au_wkinfo wkinfo = { ++ .flags = flags, ++ .func = func, ++ .args = args ++ }; ++ ++ err = au_wkq_comp_alloc(&wkinfo, &comp); ++ if (unlikely(err)) ++ goto out; ++ err = au_wkq_lockdep_alloc(&wkinfo); ++ if (unlikely(err)) ++ goto out_comp; ++ if (!err) { ++ au_wkq_run(&wkinfo); ++ /* no timeout, no interrupt */ ++ wait_for_completion(wkinfo.comp); ++ } ++ au_wkq_lockdep_free(&wkinfo); ++ ++out_comp: ++ au_wkq_comp_free(comp); ++out: ++ destroy_work_on_stack(&wkinfo.wk); ++ return err; ++} ++ ++/* ++ * Note: dget/dput() in func for aufs dentries are not supported. It will be a ++ * problem in a concurrent umounting. ++ */ ++int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb, ++ unsigned int flags) ++{ ++ int err; ++ struct au_wkinfo *wkinfo; ++ ++ atomic_inc(&au_sbi(sb)->si_nowait.nw_len); ++ ++ /* ++ * wkq_func() must free this wkinfo. ++ * it highly depends upon the implementation of workqueue. ++ */ ++ err = 0; ++ wkinfo = kmalloc(sizeof(*wkinfo), GFP_NOFS); ++ if (wkinfo) { ++ wkinfo->kobj = &au_sbi(sb)->si_kobj; ++ wkinfo->flags = flags & ~AuWkq_WAIT; ++ wkinfo->func = func; ++ wkinfo->args = args; ++ wkinfo->comp = NULL; ++ au_wkq_lockdep_init(wkinfo); ++ kobject_get(wkinfo->kobj); ++ __module_get(THIS_MODULE); /* todo: ?? */ ++ ++ au_wkq_run(wkinfo); ++ } else { ++ err = -ENOMEM; ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_nwt_init(struct au_nowait_tasks *nwt) ++{ ++ atomic_set(&nwt->nw_len, 0); ++ /* smp_mb(); */ /* atomic_set */ ++ init_waitqueue_head(&nwt->nw_wq); ++} ++ ++void au_wkq_fin(void) ++{ ++ destroy_workqueue(au_wkq); ++} ++ ++int __init au_wkq_init(void) ++{ ++ int err; ++ ++ err = 0; ++ au_wkq = alloc_workqueue(AUFS_WKQ_NAME, 0, WQ_DFL_ACTIVE); ++ if (IS_ERR(au_wkq)) ++ err = PTR_ERR(au_wkq); ++ else if (!au_wkq) ++ err = -ENOMEM; ++ ++ return err; ++} +diff -Nurp linux-5.4/fs/aufs/wkq.h linux-5.4-aufs/fs/aufs/wkq.h +--- linux-5.4/fs/aufs/wkq.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/wkq.h 2019-11-28 01:25:59.069925618 +0200 +@@ -0,0 +1,76 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * workqueue for asynchronous/super-io operations ++ * todo: try new credentials management scheme ++ */ ++ ++#ifndef __AUFS_WKQ_H__ ++#define __AUFS_WKQ_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++struct super_block; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * in the next operation, wait for the 'nowait' tasks in system-wide workqueue ++ */ ++struct au_nowait_tasks { ++ atomic_t nw_len; ++ wait_queue_head_t nw_wq; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++typedef void (*au_wkq_func_t)(void *args); ++ ++/* wkq flags */ ++#define AuWkq_WAIT 1 ++#define AuWkq_NEST (1 << 1) ++#define au_ftest_wkq(flags, name) ((flags) & AuWkq_##name) ++#define au_fset_wkq(flags, name) \ ++ do { (flags) |= AuWkq_##name; } while (0) ++#define au_fclr_wkq(flags, name) \ ++ do { (flags) &= ~AuWkq_##name; } while (0) ++ ++/* wkq.c */ ++int au_wkq_do_wait(unsigned int flags, au_wkq_func_t func, void *args); ++int au_wkq_nowait(au_wkq_func_t func, void *args, struct super_block *sb, ++ unsigned int flags); ++void au_nwt_init(struct au_nowait_tasks *nwt); ++int __init au_wkq_init(void); ++void au_wkq_fin(void); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int au_wkq_test(void) ++{ ++ return current->flags & PF_WQ_WORKER; ++} ++ ++static inline int au_wkq_wait(au_wkq_func_t func, void *args) ++{ ++ return au_wkq_do_wait(AuWkq_WAIT, func, args); ++} ++ ++static inline void au_nwt_done(struct au_nowait_tasks *nwt) ++{ ++ if (atomic_dec_and_test(&nwt->nw_len)) ++ wake_up_all(&nwt->nw_wq); ++} ++ ++static inline int au_nwt_flush(struct au_nowait_tasks *nwt) ++{ ++ wait_event(nwt->nw_wq, !atomic_read(&nwt->nw_len)); ++ return 0; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_WKQ_H__ */ +diff -Nurp linux-5.4/fs/aufs/xattr.c linux-5.4-aufs/fs/aufs/xattr.c +--- linux-5.4/fs/aufs/xattr.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/xattr.c 2019-11-28 01:25:59.069925618 +0200 +@@ -0,0 +1,343 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2014-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * handling xattr functions ++ */ ++ ++#include ++#include ++#include ++#include "aufs.h" ++ ++static int au_xattr_ignore(int err, char *name, unsigned int ignore_flags) ++{ ++ if (!ignore_flags) ++ goto out; ++ switch (err) { ++ case -ENOMEM: ++ case -EDQUOT: ++ goto out; ++ } ++ ++ if ((ignore_flags & AuBrAttr_ICEX) == AuBrAttr_ICEX) { ++ err = 0; ++ goto out; ++ } ++ ++#define cmp(brattr, prefix) do { \ ++ if (!strncmp(name, XATTR_##prefix##_PREFIX, \ ++ XATTR_##prefix##_PREFIX_LEN)) { \ ++ if (ignore_flags & AuBrAttr_ICEX_##brattr) \ ++ err = 0; \ ++ goto out; \ ++ } \ ++ } while (0) ++ ++ cmp(SEC, SECURITY); ++ cmp(SYS, SYSTEM); ++ cmp(TR, TRUSTED); ++ cmp(USR, USER); ++#undef cmp ++ ++ if (ignore_flags & AuBrAttr_ICEX_OTH) ++ err = 0; ++ ++out: ++ return err; ++} ++ ++static const int au_xattr_out_of_list = AuBrAttr_ICEX_OTH << 1; ++ ++static int au_do_cpup_xattr(struct dentry *h_dst, struct dentry *h_src, ++ char *name, char **buf, unsigned int ignore_flags, ++ unsigned int verbose) ++{ ++ int err; ++ ssize_t ssz; ++ struct inode *h_idst; ++ ++ ssz = vfs_getxattr_alloc(h_src, name, buf, 0, GFP_NOFS); ++ err = ssz; ++ if (unlikely(err <= 0)) { ++ if (err == -ENODATA ++ || (err == -EOPNOTSUPP ++ && ((ignore_flags & au_xattr_out_of_list) ++ || (au_test_nfs_noacl(d_inode(h_src)) ++ && (!strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS) ++ || !strcmp(name, ++ XATTR_NAME_POSIX_ACL_DEFAULT)))) ++ )) ++ err = 0; ++ if (err && (verbose || au_debug_test())) ++ pr_err("%s, err %d\n", name, err); ++ goto out; ++ } ++ ++ /* unlock it temporary */ ++ h_idst = d_inode(h_dst); ++ inode_unlock(h_idst); ++ err = vfsub_setxattr(h_dst, name, *buf, ssz, /*flags*/0); ++ inode_lock_nested(h_idst, AuLsc_I_CHILD2); ++ if (unlikely(err)) { ++ if (verbose || au_debug_test()) ++ pr_err("%s, err %d\n", name, err); ++ err = au_xattr_ignore(err, name, ignore_flags); ++ } ++ ++out: ++ return err; ++} ++ ++int au_cpup_xattr(struct dentry *h_dst, struct dentry *h_src, int ignore_flags, ++ unsigned int verbose) ++{ ++ int err, unlocked, acl_access, acl_default; ++ ssize_t ssz; ++ struct inode *h_isrc, *h_idst; ++ char *value, *p, *o, *e; ++ ++ /* try stopping to update the source inode while we are referencing */ ++ /* there should not be the parent-child relationship between them */ ++ h_isrc = d_inode(h_src); ++ h_idst = d_inode(h_dst); ++ inode_unlock(h_idst); ++ inode_lock_shared_nested(h_isrc, AuLsc_I_CHILD); ++ inode_lock_nested(h_idst, AuLsc_I_CHILD2); ++ unlocked = 0; ++ ++ /* some filesystems don't list POSIX ACL, for example tmpfs */ ++ ssz = vfs_listxattr(h_src, NULL, 0); ++ err = ssz; ++ if (unlikely(err < 0)) { ++ AuTraceErr(err); ++ if (err == -ENODATA ++ || err == -EOPNOTSUPP) ++ err = 0; /* ignore */ ++ goto out; ++ } ++ ++ err = 0; ++ p = NULL; ++ o = NULL; ++ if (ssz) { ++ err = -ENOMEM; ++ p = kmalloc(ssz, GFP_NOFS); ++ o = p; ++ if (unlikely(!p)) ++ goto out; ++ err = vfs_listxattr(h_src, p, ssz); ++ } ++ inode_unlock_shared(h_isrc); ++ unlocked = 1; ++ AuDbg("err %d, ssz %zd\n", err, ssz); ++ if (unlikely(err < 0)) ++ goto out_free; ++ ++ err = 0; ++ e = p + ssz; ++ value = NULL; ++ acl_access = 0; ++ acl_default = 0; ++ while (!err && p < e) { ++ acl_access |= !strncmp(p, XATTR_NAME_POSIX_ACL_ACCESS, ++ sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1); ++ acl_default |= !strncmp(p, XATTR_NAME_POSIX_ACL_DEFAULT, ++ sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) ++ - 1); ++ err = au_do_cpup_xattr(h_dst, h_src, p, &value, ignore_flags, ++ verbose); ++ p += strlen(p) + 1; ++ } ++ AuTraceErr(err); ++ ignore_flags |= au_xattr_out_of_list; ++ if (!err && !acl_access) { ++ err = au_do_cpup_xattr(h_dst, h_src, ++ XATTR_NAME_POSIX_ACL_ACCESS, &value, ++ ignore_flags, verbose); ++ AuTraceErr(err); ++ } ++ if (!err && !acl_default) { ++ err = au_do_cpup_xattr(h_dst, h_src, ++ XATTR_NAME_POSIX_ACL_DEFAULT, &value, ++ ignore_flags, verbose); ++ AuTraceErr(err); ++ } ++ ++ au_kfree_try_rcu(value); ++ ++out_free: ++ au_kfree_try_rcu(o); ++out: ++ if (!unlocked) ++ inode_unlock_shared(h_isrc); ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_smack_reentering(struct super_block *sb) ++{ ++#if IS_ENABLED(CONFIG_SECURITY_SMACK) ++ /* ++ * as a part of lookup, smack_d_instantiate() is called, and it calls ++ * i_op->getxattr(). ouch. ++ */ ++ return si_pid_test(sb); ++#else ++ return 0; ++#endif ++} ++ ++enum { ++ AU_XATTR_LIST, ++ AU_XATTR_GET ++}; ++ ++struct au_lgxattr { ++ int type; ++ union { ++ struct { ++ char *list; ++ size_t size; ++ } list; ++ struct { ++ const char *name; ++ void *value; ++ size_t size; ++ } get; ++ } u; ++}; ++ ++static ssize_t au_lgxattr(struct dentry *dentry, struct au_lgxattr *arg) ++{ ++ ssize_t err; ++ int reenter; ++ struct path h_path; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ reenter = au_smack_reentering(sb); ++ if (!reenter) { ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out; ++ } ++ err = au_h_path_getattr(dentry, /*force*/1, &h_path, reenter); ++ if (unlikely(err)) ++ goto out_si; ++ if (unlikely(!h_path.dentry)) ++ /* illegally overlapped or something */ ++ goto out_di; /* pretending success */ ++ ++ /* always topmost entry only */ ++ switch (arg->type) { ++ case AU_XATTR_LIST: ++ err = vfs_listxattr(h_path.dentry, ++ arg->u.list.list, arg->u.list.size); ++ break; ++ case AU_XATTR_GET: ++ AuDebugOn(d_is_negative(h_path.dentry)); ++ err = vfs_getxattr(h_path.dentry, ++ arg->u.get.name, arg->u.get.value, ++ arg->u.get.size); ++ break; ++ } ++ ++out_di: ++ if (!reenter) ++ di_read_unlock(dentry, AuLock_IR); ++out_si: ++ if (!reenter) ++ si_read_unlock(sb); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++ssize_t aufs_listxattr(struct dentry *dentry, char *list, size_t size) ++{ ++ struct au_lgxattr arg = { ++ .type = AU_XATTR_LIST, ++ .u.list = { ++ .list = list, ++ .size = size ++ }, ++ }; ++ ++ return au_lgxattr(dentry, &arg); ++} ++ ++static ssize_t au_getxattr(struct dentry *dentry, ++ struct inode *inode __maybe_unused, ++ const char *name, void *value, size_t size) ++{ ++ struct au_lgxattr arg = { ++ .type = AU_XATTR_GET, ++ .u.get = { ++ .name = name, ++ .value = value, ++ .size = size ++ }, ++ }; ++ ++ return au_lgxattr(dentry, &arg); ++} ++ ++static int au_setxattr(struct dentry *dentry, struct inode *inode, ++ const char *name, const void *value, size_t size, ++ int flags) ++{ ++ struct au_sxattr arg = { ++ .type = AU_XATTR_SET, ++ .u.set = { ++ .name = name, ++ .value = value, ++ .size = size, ++ .flags = flags ++ }, ++ }; ++ ++ return au_sxattr(dentry, inode, &arg); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_xattr_get(const struct xattr_handler *handler, ++ struct dentry *dentry, struct inode *inode, ++ const char *name, void *buffer, size_t size) ++{ ++ return au_getxattr(dentry, inode, name, buffer, size); ++} ++ ++static int au_xattr_set(const struct xattr_handler *handler, ++ struct dentry *dentry, struct inode *inode, ++ const char *name, const void *value, size_t size, ++ int flags) ++{ ++ return au_setxattr(dentry, inode, name, value, size, flags); ++} ++ ++static const struct xattr_handler au_xattr_handler = { ++ .name = "", ++ .prefix = "", ++ .get = au_xattr_get, ++ .set = au_xattr_set ++}; ++ ++static const struct xattr_handler *au_xattr_handlers[] = { ++#ifdef CONFIG_FS_POSIX_ACL ++ &posix_acl_access_xattr_handler, ++ &posix_acl_default_xattr_handler, ++#endif ++ &au_xattr_handler, /* must be last */ ++ NULL ++}; ++ ++void au_xattr_init(struct super_block *sb) ++{ ++ sb->s_xattr = au_xattr_handlers; ++} +diff -Nurp linux-5.4/fs/aufs/xino.c linux-5.4-aufs/fs/aufs/xino.c +--- linux-5.4/fs/aufs/xino.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/fs/aufs/xino.c 2019-11-28 01:25:59.069925618 +0200 +@@ -0,0 +1,1952 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++/* ++ * external inode number translation table and bitmap ++ * ++ * things to consider ++ * - the lifetime ++ * + au_xino object ++ * + XINO files (xino, xib, xigen) ++ * + dynamic debugfs entries (xiN) ++ * + static debugfs entries (xib, xigen) ++ * + static sysfs entry (xi_path) ++ * - several entry points to handle them. ++ * + mount(2) without xino option (default) ++ * + mount(2) with xino option ++ * + mount(2) with noxino option ++ * + umount(2) ++ * + remount with add/del branches ++ * + remount with xino/noxino options ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++static aufs_bindex_t sbr_find_shared(struct super_block *sb, aufs_bindex_t btop, ++ aufs_bindex_t bbot, ++ struct super_block *h_sb) ++{ ++ /* todo: try binary-search if the branches are many */ ++ for (; btop <= bbot; btop++) ++ if (h_sb == au_sbr_sb(sb, btop)) ++ return btop; ++ return -1; ++} ++ ++/* ++ * find another branch who is on the same filesystem of the specified ++ * branch{@btgt}. search until @bbot. ++ */ ++static aufs_bindex_t is_sb_shared(struct super_block *sb, aufs_bindex_t btgt, ++ aufs_bindex_t bbot) ++{ ++ aufs_bindex_t bindex; ++ struct super_block *tgt_sb; ++ ++ tgt_sb = au_sbr_sb(sb, btgt); ++ bindex = sbr_find_shared(sb, /*btop*/0, btgt - 1, tgt_sb); ++ if (bindex < 0) ++ bindex = sbr_find_shared(sb, btgt + 1, bbot, tgt_sb); ++ ++ return bindex; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * stop unnecessary notify events at creating xino files ++ */ ++ ++aufs_bindex_t au_xi_root(struct super_block *sb, struct dentry *dentry) ++{ ++ aufs_bindex_t bfound, bindex, bbot; ++ struct dentry *parent; ++ struct au_branch *br; ++ ++ bfound = -1; ++ parent = dentry->d_parent; /* safe d_parent access */ ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_dentry(br) == parent) { ++ bfound = bindex; ++ break; ++ } ++ } ++ ++ AuDbg("bfound b%d\n", bfound); ++ return bfound; ++} ++ ++struct au_xino_lock_dir { ++ struct au_hinode *hdir; ++ struct dentry *parent; ++ struct inode *dir; ++}; ++ ++static struct dentry *au_dget_parent_lock(struct dentry *dentry, ++ unsigned int lsc) ++{ ++ struct dentry *parent; ++ struct inode *dir; ++ ++ parent = dget_parent(dentry); ++ dir = d_inode(parent); ++ inode_lock_nested(dir, lsc); ++#if 0 /* it should not happen */ ++ spin_lock(&dentry->d_lock); ++ if (unlikely(dentry->d_parent != parent)) { ++ spin_unlock(&dentry->d_lock); ++ inode_unlock(dir); ++ dput(parent); ++ parent = NULL; ++ goto out; ++ } ++ spin_unlock(&dentry->d_lock); ++ ++out: ++#endif ++ return parent; ++} ++ ++static void au_xino_lock_dir(struct super_block *sb, struct path *xipath, ++ struct au_xino_lock_dir *ldir) ++{ ++ aufs_bindex_t bindex; ++ ++ ldir->hdir = NULL; ++ bindex = au_xi_root(sb, xipath->dentry); ++ if (bindex >= 0) { ++ /* rw branch root */ ++ ldir->hdir = au_hi(d_inode(sb->s_root), bindex); ++ au_hn_inode_lock_nested(ldir->hdir, AuLsc_I_PARENT); ++ } else { ++ /* other */ ++ ldir->parent = au_dget_parent_lock(xipath->dentry, ++ AuLsc_I_PARENT); ++ ldir->dir = d_inode(ldir->parent); ++ } ++} ++ ++static void au_xino_unlock_dir(struct au_xino_lock_dir *ldir) ++{ ++ if (ldir->hdir) ++ au_hn_inode_unlock(ldir->hdir); ++ else { ++ inode_unlock(ldir->dir); ++ dput(ldir->parent); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create and set a new xino file ++ */ ++struct file *au_xino_create(struct super_block *sb, char *fpath, int silent, ++ int wbrtop) ++{ ++ struct file *file; ++ struct dentry *h_parent, *d; ++ struct inode *h_dir, *inode; ++ int err; ++ static DEFINE_MUTEX(mtx); ++ ++ /* ++ * at mount-time, and the xino file is the default path, ++ * hnotify is disabled so we have no notify events to ignore. ++ * when a user specified the xino, we cannot get au_hdir to be ignored. ++ */ ++ if (!wbrtop) ++ mutex_lock(&mtx); ++ file = vfsub_filp_open(fpath, O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE ++ /* | __FMODE_NONOTIFY */, ++ 0666); ++ if (IS_ERR(file)) { ++ if (!wbrtop) ++ mutex_unlock(&mtx); ++ if (!silent) ++ pr_err("open %s(%ld)\n", fpath, PTR_ERR(file)); ++ return file; ++ } ++ ++ /* keep file count */ ++ err = 0; ++ d = file->f_path.dentry; ++ h_parent = au_dget_parent_lock(d, AuLsc_I_PARENT); ++ if (!wbrtop) ++ mutex_unlock(&mtx); ++ /* mnt_want_write() is unnecessary here */ ++ h_dir = d_inode(h_parent); ++ inode = file_inode(file); ++ /* no delegation since it is just created */ ++ if (inode->i_nlink) ++ err = vfsub_unlink(h_dir, &file->f_path, /*delegated*/NULL, ++ /*force*/0); ++ inode_unlock(h_dir); ++ dput(h_parent); ++ if (unlikely(err)) { ++ if (!silent) ++ pr_err("unlink %s(%d)\n", fpath, err); ++ goto out; ++ } ++ ++ err = -EINVAL; ++ if (unlikely(sb == d->d_sb)) { ++ if (!silent) ++ pr_err("%s must be outside\n", fpath); ++ goto out; ++ } ++ if (unlikely(au_test_fs_bad_xino(d->d_sb))) { ++ if (!silent) ++ pr_err("xino doesn't support %s(%s)\n", ++ fpath, au_sbtype(d->d_sb)); ++ goto out; ++ } ++ return file; /* success */ ++ ++out: ++ fput(file); ++ file = ERR_PTR(err); ++ return file; ++} ++ ++/* ++ * create a new xinofile at the same place/path as @base. ++ */ ++struct file *au_xino_create2(struct super_block *sb, struct path *base, ++ struct file *copy_src) ++{ ++ struct file *file; ++ struct dentry *dentry, *parent; ++ struct inode *dir, *delegated; ++ struct qstr *name; ++ struct path path; ++ int err, do_unlock; ++ struct au_xino_lock_dir ldir; ++ ++ do_unlock = 1; ++ au_xino_lock_dir(sb, base, &ldir); ++ dentry = base->dentry; ++ parent = dentry->d_parent; /* dir inode is locked */ ++ dir = d_inode(parent); ++ IMustLock(dir); ++ ++ name = &dentry->d_name; ++ path.dentry = vfsub_lookup_one_len(name->name, parent, name->len); ++ if (IS_ERR(path.dentry)) { ++ file = (void *)path.dentry; ++ pr_err("%pd lookup err %ld\n", dentry, PTR_ERR(path.dentry)); ++ goto out; ++ } ++ ++ /* no need to mnt_want_write() since we call dentry_open() later */ ++ err = vfs_create(dir, path.dentry, 0666, NULL); ++ if (unlikely(err)) { ++ file = ERR_PTR(err); ++ pr_err("%pd create err %d\n", dentry, err); ++ goto out_dput; ++ } ++ ++ path.mnt = base->mnt; ++ file = vfsub_dentry_open(&path, ++ O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE ++ /* | __FMODE_NONOTIFY */); ++ if (IS_ERR(file)) { ++ pr_err("%pd open err %ld\n", dentry, PTR_ERR(file)); ++ goto out_dput; ++ } ++ ++ delegated = NULL; ++ err = vfsub_unlink(dir, &file->f_path, &delegated, /*force*/0); ++ au_xino_unlock_dir(&ldir); ++ do_unlock = 0; ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) { ++ pr_err("%pd unlink err %d\n", dentry, err); ++ goto out_fput; ++ } ++ ++ if (copy_src) { ++ /* no one can touch copy_src xino */ ++ err = au_copy_file(file, copy_src, vfsub_f_size_read(copy_src)); ++ if (unlikely(err)) { ++ pr_err("%pd copy err %d\n", dentry, err); ++ goto out_fput; ++ } ++ } ++ goto out_dput; /* success */ ++ ++out_fput: ++ fput(file); ++ file = ERR_PTR(err); ++out_dput: ++ dput(path.dentry); ++out: ++ if (do_unlock) ++ au_xino_unlock_dir(&ldir); ++ return file; ++} ++ ++struct file *au_xino_file1(struct au_xino *xi) ++{ ++ struct file *file; ++ unsigned int u, nfile; ++ ++ file = NULL; ++ nfile = xi->xi_nfile; ++ for (u = 0; u < nfile; u++) { ++ file = xi->xi_file[u]; ++ if (file) ++ break; ++ } ++ ++ return file; ++} ++ ++static int au_xino_file_set(struct au_xino *xi, int idx, struct file *file) ++{ ++ int err; ++ struct file *f; ++ void *p; ++ ++ if (file) ++ get_file(file); ++ ++ err = 0; ++ f = NULL; ++ if (idx < xi->xi_nfile) { ++ f = xi->xi_file[idx]; ++ if (f) ++ fput(f); ++ } else { ++ p = au_kzrealloc(xi->xi_file, ++ sizeof(*xi->xi_file) * xi->xi_nfile, ++ sizeof(*xi->xi_file) * (idx + 1), ++ GFP_NOFS, /*may_shrink*/0); ++ if (p) { ++ MtxMustLock(&xi->xi_mtx); ++ xi->xi_file = p; ++ xi->xi_nfile = idx + 1; ++ } else { ++ err = -ENOMEM; ++ if (file) ++ fput(file); ++ goto out; ++ } ++ } ++ xi->xi_file[idx] = file; ++ ++out: ++ return err; ++} ++ ++/* ++ * if @xinew->xi is not set, then create new xigen file. ++ */ ++struct file *au_xi_new(struct super_block *sb, struct au_xi_new *xinew) ++{ ++ struct file *file; ++ int err; ++ ++ SiMustAnyLock(sb); ++ ++ file = au_xino_create2(sb, xinew->base, xinew->copy_src); ++ if (IS_ERR(file)) { ++ err = PTR_ERR(file); ++ pr_err("%s[%d], err %d\n", ++ xinew->xi ? "xino" : "xigen", ++ xinew->idx, err); ++ goto out; ++ } ++ ++ if (xinew->xi) ++ err = au_xino_file_set(xinew->xi, xinew->idx, file); ++ else { ++ BUG(); ++ /* todo: make xigen file an array */ ++ /* err = au_xigen_file_set(sb, xinew->idx, file); */ ++ } ++ fput(file); ++ if (unlikely(err)) ++ file = ERR_PTR(err); ++ ++out: ++ return file; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * truncate xino files ++ */ ++static int au_xino_do_trunc(struct super_block *sb, aufs_bindex_t bindex, ++ int idx, struct kstatfs *st) ++{ ++ int err; ++ blkcnt_t blocks; ++ struct file *file, *new_xino; ++ struct au_xi_new xinew = { ++ .idx = idx ++ }; ++ ++ err = 0; ++ xinew.xi = au_sbr(sb, bindex)->br_xino; ++ file = au_xino_file(xinew.xi, idx); ++ if (!file) ++ goto out; ++ ++ xinew.base = &file->f_path; ++ err = vfs_statfs(xinew.base, st); ++ if (unlikely(err)) { ++ AuErr1("statfs err %d, ignored\n", err); ++ err = 0; ++ goto out; ++ } ++ ++ blocks = file_inode(file)->i_blocks; ++ pr_info("begin truncating xino(b%d-%d), ib%llu, %llu/%llu free blks\n", ++ bindex, idx, (u64)blocks, st->f_bfree, st->f_blocks); ++ ++ xinew.copy_src = file; ++ new_xino = au_xi_new(sb, &xinew); ++ if (IS_ERR(new_xino)) { ++ err = PTR_ERR(new_xino); ++ pr_err("xino(b%d-%d), err %d, ignored\n", bindex, idx, err); ++ goto out; ++ } ++ ++ err = vfs_statfs(&new_xino->f_path, st); ++ if (!err) ++ pr_info("end truncating xino(b%d-%d), ib%llu, %llu/%llu free blks\n", ++ bindex, idx, (u64)file_inode(new_xino)->i_blocks, ++ st->f_bfree, st->f_blocks); ++ else { ++ AuErr1("statfs err %d, ignored\n", err); ++ err = 0; ++ } ++ ++out: ++ return err; ++} ++ ++int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex, int idx_begin) ++{ ++ int err, i; ++ unsigned long jiffy; ++ aufs_bindex_t bbot; ++ struct kstatfs *st; ++ struct au_branch *br; ++ struct au_xino *xi; ++ ++ err = -ENOMEM; ++ st = kmalloc(sizeof(*st), GFP_NOFS); ++ if (unlikely(!st)) ++ goto out; ++ ++ err = -EINVAL; ++ bbot = au_sbbot(sb); ++ if (unlikely(bindex < 0 || bbot < bindex)) ++ goto out_st; ++ ++ err = 0; ++ jiffy = jiffies; ++ br = au_sbr(sb, bindex); ++ xi = br->br_xino; ++ for (i = idx_begin; !err && i < xi->xi_nfile; i++) ++ err = au_xino_do_trunc(sb, bindex, i, st); ++ if (!err) ++ au_sbi(sb)->si_xino_jiffy = jiffy; ++ ++out_st: ++ au_kfree_rcu(st); ++out: ++ return err; ++} ++ ++struct xino_do_trunc_args { ++ struct super_block *sb; ++ struct au_branch *br; ++ int idx; ++}; ++ ++static void xino_do_trunc(void *_args) ++{ ++ struct xino_do_trunc_args *args = _args; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct inode *dir; ++ int err, idx; ++ aufs_bindex_t bindex; ++ ++ err = 0; ++ sb = args->sb; ++ dir = d_inode(sb->s_root); ++ br = args->br; ++ idx = args->idx; ++ ++ si_noflush_write_lock(sb); ++ ii_read_lock_parent(dir); ++ bindex = au_br_index(sb, br->br_id); ++ err = au_xino_trunc(sb, bindex, idx); ++ ii_read_unlock(dir); ++ if (unlikely(err)) ++ pr_warn("err b%d, (%d)\n", bindex, err); ++ atomic_dec(&br->br_xino->xi_truncating); ++ au_lcnt_dec(&br->br_count); ++ si_write_unlock(sb); ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ au_kfree_rcu(args); ++} ++ ++/* ++ * returns the index in the xi_file array whose corresponding file is necessary ++ * to truncate, or -1 which means no need to truncate. ++ */ ++static int xino_trunc_test(struct super_block *sb, struct au_branch *br) ++{ ++ int err; ++ unsigned int u; ++ struct kstatfs st; ++ struct au_sbinfo *sbinfo; ++ struct au_xino *xi; ++ struct file *file; ++ ++ /* todo: si_xino_expire and the ratio should be customizable */ ++ sbinfo = au_sbi(sb); ++ if (time_before(jiffies, ++ sbinfo->si_xino_jiffy + sbinfo->si_xino_expire)) ++ return -1; ++ ++ /* truncation border */ ++ xi = br->br_xino; ++ for (u = 0; u < xi->xi_nfile; u++) { ++ file = au_xino_file(xi, u); ++ if (!file) ++ continue; ++ ++ err = vfs_statfs(&file->f_path, &st); ++ if (unlikely(err)) { ++ AuErr1("statfs err %d, ignored\n", err); ++ return -1; ++ } ++ if (div64_u64(st.f_bfree * 100, st.f_blocks) ++ >= AUFS_XINO_DEF_TRUNC) ++ return u; ++ } ++ ++ return -1; ++} ++ ++static void xino_try_trunc(struct super_block *sb, struct au_branch *br) ++{ ++ int idx; ++ struct xino_do_trunc_args *args; ++ int wkq_err; ++ ++ idx = xino_trunc_test(sb, br); ++ if (idx < 0) ++ return; ++ ++ if (atomic_inc_return(&br->br_xino->xi_truncating) > 1) ++ goto out; ++ ++ /* lock and kfree() will be called in trunc_xino() */ ++ args = kmalloc(sizeof(*args), GFP_NOFS); ++ if (unlikely(!args)) { ++ AuErr1("no memory\n"); ++ goto out; ++ } ++ ++ au_lcnt_inc(&br->br_count); ++ args->sb = sb; ++ args->br = br; ++ args->idx = idx; ++ wkq_err = au_wkq_nowait(xino_do_trunc, args, sb, /*flags*/0); ++ if (!wkq_err) ++ return; /* success */ ++ ++ pr_err("wkq %d\n", wkq_err); ++ au_lcnt_dec(&br->br_count); ++ au_kfree_rcu(args); ++ ++out: ++ atomic_dec(&br->br_xino->xi_truncating); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_xi_calc { ++ int idx; ++ loff_t pos; ++}; ++ ++static void au_xi_calc(struct super_block *sb, ino_t h_ino, ++ struct au_xi_calc *calc) ++{ ++ loff_t maxent; ++ ++ maxent = au_xi_maxent(sb); ++ calc->idx = div64_u64_rem(h_ino, maxent, &calc->pos); ++ calc->pos *= sizeof(ino_t); ++} ++ ++static int au_xino_do_new_async(struct super_block *sb, struct au_branch *br, ++ struct au_xi_calc *calc) ++{ ++ int err; ++ struct file *file; ++ struct au_xino *xi = br->br_xino; ++ struct au_xi_new xinew = { ++ .xi = xi ++ }; ++ ++ SiMustAnyLock(sb); ++ ++ err = 0; ++ if (!xi) ++ goto out; ++ ++ mutex_lock(&xi->xi_mtx); ++ file = au_xino_file(xi, calc->idx); ++ if (file) ++ goto out_mtx; ++ ++ file = au_xino_file(xi, /*idx*/-1); ++ AuDebugOn(!file); ++ xinew.idx = calc->idx; ++ xinew.base = &file->f_path; ++ /* xinew.copy_src = NULL; */ ++ file = au_xi_new(sb, &xinew); ++ if (IS_ERR(file)) ++ err = PTR_ERR(file); ++ ++out_mtx: ++ mutex_unlock(&xi->xi_mtx); ++out: ++ return err; ++} ++ ++struct au_xino_do_new_async_args { ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_xi_calc calc; ++ ino_t ino; ++}; ++ ++struct au_xi_writing { ++ struct hlist_bl_node node; ++ ino_t h_ino, ino; ++}; ++ ++static int au_xino_do_write(vfs_writef_t write, struct file *file, ++ struct au_xi_calc *calc, ino_t ino); ++ ++static void au_xino_call_do_new_async(void *args) ++{ ++ struct au_xino_do_new_async_args *a = args; ++ struct au_branch *br; ++ struct super_block *sb; ++ struct au_sbinfo *sbi; ++ struct inode *root; ++ struct file *file; ++ struct au_xi_writing *del, *p; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ int err; ++ ++ br = a->br; ++ sb = a->sb; ++ sbi = au_sbi(sb); ++ si_noflush_read_lock(sb); ++ root = d_inode(sb->s_root); ++ ii_read_lock_child(root); ++ err = au_xino_do_new_async(sb, br, &a->calc); ++ if (unlikely(err)) { ++ AuIOErr("err %d\n", err); ++ goto out; ++ } ++ ++ file = au_xino_file(br->br_xino, a->calc.idx); ++ AuDebugOn(!file); ++ err = au_xino_do_write(sbi->si_xwrite, file, &a->calc, a->ino); ++ if (unlikely(err)) { ++ AuIOErr("err %d\n", err); ++ goto out; ++ } ++ ++ del = NULL; ++ hbl = &br->br_xino->xi_writing; ++ hlist_bl_lock(hbl); ++ au_hbl_for_each(pos, hbl) { ++ p = container_of(pos, struct au_xi_writing, node); ++ if (p->ino == a->ino) { ++ del = p; ++ hlist_bl_del(&p->node); ++ break; ++ } ++ } ++ hlist_bl_unlock(hbl); ++ au_kfree_rcu(del); ++ ++out: ++ au_lcnt_dec(&br->br_count); ++ ii_read_unlock(root); ++ si_read_unlock(sb); ++ au_nwt_done(&sbi->si_nowait); ++ au_kfree_rcu(a); ++} ++ ++/* ++ * create a new xino file asynchronously ++ */ ++static int au_xino_new_async(struct super_block *sb, struct au_branch *br, ++ struct au_xi_calc *calc, ino_t ino) ++{ ++ int err; ++ struct au_xino_do_new_async_args *arg; ++ ++ err = -ENOMEM; ++ arg = kmalloc(sizeof(*arg), GFP_NOFS); ++ if (unlikely(!arg)) ++ goto out; ++ ++ arg->sb = sb; ++ arg->br = br; ++ arg->calc = *calc; ++ arg->ino = ino; ++ au_lcnt_inc(&br->br_count); ++ err = au_wkq_nowait(au_xino_call_do_new_async, arg, sb, AuWkq_NEST); ++ if (unlikely(err)) { ++ pr_err("wkq %d\n", err); ++ au_lcnt_dec(&br->br_count); ++ au_kfree_rcu(arg); ++ } ++ ++out: ++ return err; ++} ++ ++/* ++ * read @ino from xinofile for the specified branch{@sb, @bindex} ++ * at the position of @h_ino. ++ */ ++int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t *ino) ++{ ++ int err; ++ ssize_t sz; ++ struct au_xi_calc calc; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ struct au_xino *xi; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_xi_writing *p; ++ ++ *ino = 0; ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ return 0; /* no xino */ ++ ++ err = 0; ++ au_xi_calc(sb, h_ino, &calc); ++ xi = au_sbr(sb, bindex)->br_xino; ++ file = au_xino_file(xi, calc.idx); ++ if (!file) { ++ hbl = &xi->xi_writing; ++ hlist_bl_lock(hbl); ++ au_hbl_for_each(pos, hbl) { ++ p = container_of(pos, struct au_xi_writing, node); ++ if (p->h_ino == h_ino) { ++ AuDbg("hi%llu, i%llu, found\n", ++ (u64)p->h_ino, (u64)p->ino); ++ *ino = p->ino; ++ break; ++ } ++ } ++ hlist_bl_unlock(hbl); ++ return 0; ++ } else if (vfsub_f_size_read(file) < calc.pos + sizeof(*ino)) ++ return 0; /* no xino */ ++ ++ sbinfo = au_sbi(sb); ++ sz = xino_fread(sbinfo->si_xread, file, ino, sizeof(*ino), &calc.pos); ++ if (sz == sizeof(*ino)) ++ return 0; /* success */ ++ ++ err = sz; ++ if (unlikely(sz >= 0)) { ++ err = -EIO; ++ AuIOErr("xino read error (%zd)\n", sz); ++ } ++ return err; ++} ++ ++static int au_xino_do_write(vfs_writef_t write, struct file *file, ++ struct au_xi_calc *calc, ino_t ino) ++{ ++ ssize_t sz; ++ ++ sz = xino_fwrite(write, file, &ino, sizeof(ino), &calc->pos); ++ if (sz == sizeof(ino)) ++ return 0; /* success */ ++ ++ AuIOErr("write failed (%zd)\n", sz); ++ return -EIO; ++} ++ ++/* ++ * write @ino to the xinofile for the specified branch{@sb, @bindex} ++ * at the position of @h_ino. ++ * even if @ino is zero, it is written to the xinofile and means no entry. ++ * if the size of the xino file on a specific filesystem exceeds the watermark, ++ * try truncating it. ++ */ ++int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t ino) ++{ ++ int err; ++ unsigned int mnt_flags; ++ struct au_xi_calc calc; ++ struct file *file; ++ struct au_branch *br; ++ struct au_xino *xi; ++ struct au_xi_writing *p; ++ ++ SiMustAnyLock(sb); ++ ++ mnt_flags = au_mntflags(sb); ++ if (!au_opt_test(mnt_flags, XINO)) ++ return 0; ++ ++ au_xi_calc(sb, h_ino, &calc); ++ br = au_sbr(sb, bindex); ++ xi = br->br_xino; ++ file = au_xino_file(xi, calc.idx); ++ if (!file) { ++ /* store the inum pair into the list */ ++ p = kmalloc(sizeof(*p), GFP_NOFS | __GFP_NOFAIL); ++ p->h_ino = h_ino; ++ p->ino = ino; ++ au_hbl_add(&p->node, &xi->xi_writing); ++ ++ /* create and write a new xino file asynchronously */ ++ err = au_xino_new_async(sb, br, &calc, ino); ++ if (!err) ++ return 0; /* success */ ++ goto out; ++ } ++ ++ err = au_xino_do_write(au_sbi(sb)->si_xwrite, file, &calc, ino); ++ if (!err) { ++ br = au_sbr(sb, bindex); ++ if (au_opt_test(mnt_flags, TRUNC_XINO) ++ && au_test_fs_trunc_xino(au_br_sb(br))) ++ xino_try_trunc(sb, br); ++ return 0; /* success */ ++ } ++ ++out: ++ AuIOErr("write failed (%d)\n", err); ++ return -EIO; ++} ++ ++static ssize_t xino_fread_wkq(vfs_readf_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos); ++ ++/* todo: unnecessary to support mmap_sem since kernel-space? */ ++ssize_t xino_fread(vfs_readf_t func, struct file *file, void *kbuf, size_t size, ++ loff_t *pos) ++{ ++ ssize_t err; ++ mm_segment_t oldfs; ++ union { ++ void *k; ++ char __user *u; ++ } buf; ++ int i; ++ const int prevent_endless = 10; ++ ++ i = 0; ++ buf.k = kbuf; ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ do { ++ err = func(file, buf.u, size, pos); ++ if (err == -EINTR ++ && !au_wkq_test() ++ && fatal_signal_pending(current)) { ++ set_fs(oldfs); ++ err = xino_fread_wkq(func, file, kbuf, size, pos); ++ BUG_ON(err == -EINTR); ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ } ++ } while (i++ < prevent_endless ++ && (err == -EAGAIN || err == -EINTR)); ++ set_fs(oldfs); ++ ++#if 0 /* reserved for future use */ ++ if (err > 0) ++ fsnotify_access(file->f_path.dentry); ++#endif ++ ++ return err; ++} ++ ++struct xino_fread_args { ++ ssize_t *errp; ++ vfs_readf_t func; ++ struct file *file; ++ void *buf; ++ size_t size; ++ loff_t *pos; ++}; ++ ++static void call_xino_fread(void *args) ++{ ++ struct xino_fread_args *a = args; ++ *a->errp = xino_fread(a->func, a->file, a->buf, a->size, a->pos); ++} ++ ++static ssize_t xino_fread_wkq(vfs_readf_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ int wkq_err; ++ struct xino_fread_args args = { ++ .errp = &err, ++ .func = func, ++ .file = file, ++ .buf = buf, ++ .size = size, ++ .pos = pos ++ }; ++ ++ wkq_err = au_wkq_wait(call_xino_fread, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ ++ return err; ++} ++ ++static ssize_t xino_fwrite_wkq(vfs_writef_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos); ++ ++static ssize_t do_xino_fwrite(vfs_writef_t func, struct file *file, void *kbuf, ++ size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ mm_segment_t oldfs; ++ union { ++ void *k; ++ const char __user *u; ++ } buf; ++ int i; ++ const int prevent_endless = 10; ++ ++ i = 0; ++ buf.k = kbuf; ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ do { ++ err = func(file, buf.u, size, pos); ++ if (err == -EINTR ++ && !au_wkq_test() ++ && fatal_signal_pending(current)) { ++ set_fs(oldfs); ++ err = xino_fwrite_wkq(func, file, kbuf, size, pos); ++ BUG_ON(err == -EINTR); ++ oldfs = get_fs(); ++ set_fs(KERNEL_DS); ++ } ++ } while (i++ < prevent_endless ++ && (err == -EAGAIN || err == -EINTR)); ++ set_fs(oldfs); ++ ++#if 0 /* reserved for future use */ ++ if (err > 0) ++ fsnotify_modify(file->f_path.dentry); ++#endif ++ ++ return err; ++} ++ ++struct do_xino_fwrite_args { ++ ssize_t *errp; ++ vfs_writef_t func; ++ struct file *file; ++ void *buf; ++ size_t size; ++ loff_t *pos; ++}; ++ ++static void call_do_xino_fwrite(void *args) ++{ ++ struct do_xino_fwrite_args *a = args; ++ *a->errp = do_xino_fwrite(a->func, a->file, a->buf, a->size, a->pos); ++} ++ ++static ssize_t xino_fwrite_wkq(vfs_writef_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ int wkq_err; ++ struct do_xino_fwrite_args args = { ++ .errp = &err, ++ .func = func, ++ .file = file, ++ .buf = buf, ++ .size = size, ++ .pos = pos ++ }; ++ ++ /* ++ * it breaks RLIMIT_FSIZE and normal user's limit, ++ * users should care about quota and real 'filesystem full.' ++ */ ++ wkq_err = au_wkq_wait(call_do_xino_fwrite, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ ++ return err; ++} ++ ++ssize_t xino_fwrite(vfs_writef_t func, struct file *file, void *buf, ++ size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ ++ if (rlimit(RLIMIT_FSIZE) == RLIM_INFINITY) { ++ lockdep_off(); ++ err = do_xino_fwrite(func, file, buf, size, pos); ++ lockdep_on(); ++ } else { ++ lockdep_off(); ++ err = xino_fwrite_wkq(func, file, buf, size, pos); ++ lockdep_on(); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * inode number bitmap ++ */ ++static const int page_bits = (int)PAGE_SIZE * BITS_PER_BYTE; ++static ino_t xib_calc_ino(unsigned long pindex, int bit) ++{ ++ ino_t ino; ++ ++ AuDebugOn(bit < 0 || page_bits <= bit); ++ ino = AUFS_FIRST_INO + pindex * page_bits + bit; ++ return ino; ++} ++ ++static void xib_calc_bit(ino_t ino, unsigned long *pindex, int *bit) ++{ ++ AuDebugOn(ino < AUFS_FIRST_INO); ++ ino -= AUFS_FIRST_INO; ++ *pindex = ino / page_bits; ++ *bit = ino % page_bits; ++} ++ ++static int xib_pindex(struct super_block *sb, unsigned long pindex) ++{ ++ int err; ++ loff_t pos; ++ ssize_t sz; ++ struct au_sbinfo *sbinfo; ++ struct file *xib; ++ unsigned long *p; ++ ++ sbinfo = au_sbi(sb); ++ MtxMustLock(&sbinfo->si_xib_mtx); ++ AuDebugOn(pindex > ULONG_MAX / PAGE_SIZE ++ || !au_opt_test(sbinfo->si_mntflags, XINO)); ++ ++ if (pindex == sbinfo->si_xib_last_pindex) ++ return 0; ++ ++ xib = sbinfo->si_xib; ++ p = sbinfo->si_xib_buf; ++ pos = sbinfo->si_xib_last_pindex; ++ pos *= PAGE_SIZE; ++ sz = xino_fwrite(sbinfo->si_xwrite, xib, p, PAGE_SIZE, &pos); ++ if (unlikely(sz != PAGE_SIZE)) ++ goto out; ++ ++ pos = pindex; ++ pos *= PAGE_SIZE; ++ if (vfsub_f_size_read(xib) >= pos + PAGE_SIZE) ++ sz = xino_fread(sbinfo->si_xread, xib, p, PAGE_SIZE, &pos); ++ else { ++ memset(p, 0, PAGE_SIZE); ++ sz = xino_fwrite(sbinfo->si_xwrite, xib, p, PAGE_SIZE, &pos); ++ } ++ if (sz == PAGE_SIZE) { ++ sbinfo->si_xib_last_pindex = pindex; ++ return 0; /* success */ ++ } ++ ++out: ++ AuIOErr1("write failed (%zd)\n", sz); ++ err = sz; ++ if (sz >= 0) ++ err = -EIO; ++ return err; ++} ++ ++static void au_xib_clear_bit(struct inode *inode) ++{ ++ int err, bit; ++ unsigned long pindex; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++ AuDebugOn(inode->i_nlink); ++ ++ sb = inode->i_sb; ++ xib_calc_bit(inode->i_ino, &pindex, &bit); ++ AuDebugOn(page_bits <= bit); ++ sbinfo = au_sbi(sb); ++ mutex_lock(&sbinfo->si_xib_mtx); ++ err = xib_pindex(sb, pindex); ++ if (!err) { ++ clear_bit(bit, sbinfo->si_xib_buf); ++ sbinfo->si_xib_next_bit = bit; ++ } ++ mutex_unlock(&sbinfo->si_xib_mtx); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * truncate a xino bitmap file ++ */ ++ ++/* todo: slow */ ++static int do_xib_restore(struct super_block *sb, struct file *file, void *page) ++{ ++ int err, bit; ++ ssize_t sz; ++ unsigned long pindex; ++ loff_t pos, pend; ++ struct au_sbinfo *sbinfo; ++ vfs_readf_t func; ++ ino_t *ino; ++ unsigned long *p; ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ MtxMustLock(&sbinfo->si_xib_mtx); ++ p = sbinfo->si_xib_buf; ++ func = sbinfo->si_xread; ++ pend = vfsub_f_size_read(file); ++ pos = 0; ++ while (pos < pend) { ++ sz = xino_fread(func, file, page, PAGE_SIZE, &pos); ++ err = sz; ++ if (unlikely(sz <= 0)) ++ goto out; ++ ++ err = 0; ++ for (ino = page; sz > 0; ino++, sz -= sizeof(ino)) { ++ if (unlikely(*ino < AUFS_FIRST_INO)) ++ continue; ++ ++ xib_calc_bit(*ino, &pindex, &bit); ++ AuDebugOn(page_bits <= bit); ++ err = xib_pindex(sb, pindex); ++ if (!err) ++ set_bit(bit, p); ++ else ++ goto out; ++ } ++ } ++ ++out: ++ return err; ++} ++ ++static int xib_restore(struct super_block *sb) ++{ ++ int err, i; ++ unsigned int nfile; ++ aufs_bindex_t bindex, bbot; ++ void *page; ++ struct au_branch *br; ++ struct au_xino *xi; ++ struct file *file; ++ ++ err = -ENOMEM; ++ page = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!page)) ++ goto out; ++ ++ err = 0; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; !err && bindex <= bbot; bindex++) ++ if (!bindex || is_sb_shared(sb, bindex, bindex - 1) < 0) { ++ br = au_sbr(sb, bindex); ++ xi = br->br_xino; ++ nfile = xi->xi_nfile; ++ for (i = 0; i < nfile; i++) { ++ file = au_xino_file(xi, i); ++ if (file) ++ err = do_xib_restore(sb, file, page); ++ } ++ } else ++ AuDbg("skip shared b%d\n", bindex); ++ free_page((unsigned long)page); ++ ++out: ++ return err; ++} ++ ++int au_xib_trunc(struct super_block *sb) ++{ ++ int err; ++ ssize_t sz; ++ loff_t pos; ++ struct au_sbinfo *sbinfo; ++ unsigned long *p; ++ struct file *file; ++ ++ SiMustWriteLock(sb); ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ if (!au_opt_test(sbinfo->si_mntflags, XINO)) ++ goto out; ++ ++ file = sbinfo->si_xib; ++ if (vfsub_f_size_read(file) <= PAGE_SIZE) ++ goto out; ++ ++ file = au_xino_create2(sb, &sbinfo->si_xib->f_path, NULL); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ fput(sbinfo->si_xib); ++ sbinfo->si_xib = file; ++ ++ p = sbinfo->si_xib_buf; ++ memset(p, 0, PAGE_SIZE); ++ pos = 0; ++ sz = xino_fwrite(sbinfo->si_xwrite, sbinfo->si_xib, p, PAGE_SIZE, &pos); ++ if (unlikely(sz != PAGE_SIZE)) { ++ err = sz; ++ AuIOErr("err %d\n", err); ++ if (sz >= 0) ++ err = -EIO; ++ goto out; ++ } ++ ++ mutex_lock(&sbinfo->si_xib_mtx); ++ /* mnt_want_write() is unnecessary here */ ++ err = xib_restore(sb); ++ mutex_unlock(&sbinfo->si_xib_mtx); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_xino *au_xino_alloc(unsigned int nfile) ++{ ++ struct au_xino *xi; ++ ++ xi = kzalloc(sizeof(*xi), GFP_NOFS); ++ if (unlikely(!xi)) ++ goto out; ++ xi->xi_nfile = nfile; ++ xi->xi_file = kcalloc(nfile, sizeof(*xi->xi_file), GFP_NOFS); ++ if (unlikely(!xi->xi_file)) ++ goto out_free; ++ ++ xi->xi_nondir.total = 8; /* initial size */ ++ xi->xi_nondir.array = kcalloc(xi->xi_nondir.total, sizeof(ino_t), ++ GFP_NOFS); ++ if (unlikely(!xi->xi_nondir.array)) ++ goto out_file; ++ ++ spin_lock_init(&xi->xi_nondir.spin); ++ init_waitqueue_head(&xi->xi_nondir.wqh); ++ mutex_init(&xi->xi_mtx); ++ INIT_HLIST_BL_HEAD(&xi->xi_writing); ++ atomic_set(&xi->xi_truncating, 0); ++ kref_init(&xi->xi_kref); ++ goto out; /* success */ ++ ++out_file: ++ au_kfree_try_rcu(xi->xi_file); ++out_free: ++ au_kfree_rcu(xi); ++ xi = NULL; ++out: ++ return xi; ++} ++ ++static int au_xino_init(struct au_branch *br, int idx, struct file *file) ++{ ++ int err; ++ struct au_xino *xi; ++ ++ err = 0; ++ xi = au_xino_alloc(idx + 1); ++ if (unlikely(!xi)) { ++ err = -ENOMEM; ++ goto out; ++ } ++ ++ if (file) ++ get_file(file); ++ xi->xi_file[idx] = file; ++ AuDebugOn(br->br_xino); ++ br->br_xino = xi; ++ ++out: ++ return err; ++} ++ ++static void au_xino_release(struct kref *kref) ++{ ++ struct au_xino *xi; ++ int i; ++ unsigned long ul; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos, *n; ++ struct au_xi_writing *p; ++ ++ xi = container_of(kref, struct au_xino, xi_kref); ++ for (i = 0; i < xi->xi_nfile; i++) ++ if (xi->xi_file[i]) ++ fput(xi->xi_file[i]); ++ for (i = xi->xi_nondir.total - 1; i >= 0; i--) ++ AuDebugOn(xi->xi_nondir.array[i]); ++ mutex_destroy(&xi->xi_mtx); ++ hbl = &xi->xi_writing; ++ ul = au_hbl_count(hbl); ++ if (unlikely(ul)) { ++ pr_warn("xi_writing %lu\n", ul); ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry_safe (p, pos, n, hbl, node) { ++ hlist_bl_del(&p->node); ++ au_kfree_rcu(p); ++ } ++ hlist_bl_unlock(hbl); ++ } ++ au_kfree_try_rcu(xi->xi_file); ++ au_kfree_try_rcu(xi->xi_nondir.array); ++ au_kfree_rcu(xi); ++} ++ ++int au_xino_put(struct au_branch *br) ++{ ++ int ret; ++ struct au_xino *xi; ++ ++ ret = 0; ++ xi = br->br_xino; ++ if (xi) { ++ br->br_xino = NULL; ++ ret = kref_put(&xi->xi_kref, au_xino_release); ++ } ++ ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * xino mount option handlers ++ */ ++ ++/* xino bitmap */ ++static void xino_clear_xib(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ /* unnecessary to clear sbinfo->si_xread and ->si_xwrite */ ++ if (sbinfo->si_xib) ++ fput(sbinfo->si_xib); ++ sbinfo->si_xib = NULL; ++ if (sbinfo->si_xib_buf) ++ free_page((unsigned long)sbinfo->si_xib_buf); ++ sbinfo->si_xib_buf = NULL; ++} ++ ++static int au_xino_set_xib(struct super_block *sb, struct path *path) ++{ ++ int err; ++ loff_t pos; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ struct super_block *xi_sb; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ file = au_xino_create2(sb, path, sbinfo->si_xib); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ if (sbinfo->si_xib) ++ fput(sbinfo->si_xib); ++ sbinfo->si_xib = file; ++ sbinfo->si_xread = vfs_readf(file); ++ sbinfo->si_xwrite = vfs_writef(file); ++ xi_sb = file_inode(file)->i_sb; ++ sbinfo->si_ximaxent = xi_sb->s_maxbytes; ++ if (unlikely(sbinfo->si_ximaxent < PAGE_SIZE)) { ++ err = -EIO; ++ pr_err("s_maxbytes(%llu) on %s is too small\n", ++ (u64)sbinfo->si_ximaxent, au_sbtype(xi_sb)); ++ goto out_unset; ++ } ++ sbinfo->si_ximaxent /= sizeof(ino_t); ++ ++ err = -ENOMEM; ++ if (!sbinfo->si_xib_buf) ++ sbinfo->si_xib_buf = (void *)get_zeroed_page(GFP_NOFS); ++ if (unlikely(!sbinfo->si_xib_buf)) ++ goto out_unset; ++ ++ sbinfo->si_xib_last_pindex = 0; ++ sbinfo->si_xib_next_bit = 0; ++ if (vfsub_f_size_read(file) < PAGE_SIZE) { ++ pos = 0; ++ err = xino_fwrite(sbinfo->si_xwrite, file, sbinfo->si_xib_buf, ++ PAGE_SIZE, &pos); ++ if (unlikely(err != PAGE_SIZE)) ++ goto out_free; ++ } ++ err = 0; ++ goto out; /* success */ ++ ++out_free: ++ if (sbinfo->si_xib_buf) ++ free_page((unsigned long)sbinfo->si_xib_buf); ++ sbinfo->si_xib_buf = NULL; ++ if (err >= 0) ++ err = -EIO; ++out_unset: ++ fput(sbinfo->si_xib); ++ sbinfo->si_xib = NULL; ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* xino for each branch */ ++static void xino_clear_br(struct super_block *sb) ++{ ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ AuDebugOn(!br); ++ au_xino_put(br); ++ } ++} ++ ++static void au_xino_set_br_shared(struct super_block *sb, struct au_branch *br, ++ aufs_bindex_t bshared) ++{ ++ struct au_branch *brshared; ++ ++ brshared = au_sbr(sb, bshared); ++ AuDebugOn(!brshared->br_xino); ++ AuDebugOn(!brshared->br_xino->xi_file); ++ if (br->br_xino != brshared->br_xino) { ++ au_xino_get(brshared); ++ au_xino_put(br); ++ br->br_xino = brshared->br_xino; ++ } ++} ++ ++struct au_xino_do_set_br { ++ vfs_writef_t writef; ++ struct au_branch *br; ++ ino_t h_ino; ++ aufs_bindex_t bshared; ++}; ++ ++static int au_xino_do_set_br(struct super_block *sb, struct path *path, ++ struct au_xino_do_set_br *args) ++{ ++ int err; ++ struct au_xi_calc calc; ++ struct file *file; ++ struct au_branch *br; ++ struct au_xi_new xinew = { ++ .base = path ++ }; ++ ++ br = args->br; ++ xinew.xi = br->br_xino; ++ au_xi_calc(sb, args->h_ino, &calc); ++ xinew.copy_src = au_xino_file(xinew.xi, calc.idx); ++ if (args->bshared >= 0) ++ /* shared xino */ ++ au_xino_set_br_shared(sb, br, args->bshared); ++ else if (!xinew.xi) { ++ /* new xino */ ++ err = au_xino_init(br, calc.idx, xinew.copy_src); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ /* force re-creating */ ++ xinew.xi = br->br_xino; ++ xinew.idx = calc.idx; ++ mutex_lock(&xinew.xi->xi_mtx); ++ file = au_xi_new(sb, &xinew); ++ mutex_unlock(&xinew.xi->xi_mtx); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ AuDebugOn(!file); ++ ++ err = au_xino_do_write(args->writef, file, &calc, AUFS_ROOT_INO); ++ if (unlikely(err)) ++ au_xino_put(br); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_xino_set_br(struct super_block *sb, struct path *path) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct au_xino_do_set_br args; ++ struct inode *inode; ++ ++ SiMustWriteLock(sb); ++ ++ bbot = au_sbbot(sb); ++ inode = d_inode(sb->s_root); ++ args.writef = au_sbi(sb)->si_xwrite; ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ args.h_ino = au_h_iptr(inode, bindex)->i_ino; ++ args.br = au_sbr(sb, bindex); ++ args.bshared = is_sb_shared(sb, bindex, bindex - 1); ++ err = au_xino_do_set_br(sb, path, &args); ++ if (unlikely(err)) ++ break; ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_xino_clr(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ au_xigen_clr(sb); ++ xino_clear_xib(sb); ++ xino_clear_br(sb); ++ dbgaufs_brs_del(sb, 0); ++ sbinfo = au_sbi(sb); ++ /* lvalue, do not call au_mntflags() */ ++ au_opt_clr(sbinfo->si_mntflags, XINO); ++} ++ ++int au_xino_set(struct super_block *sb, struct au_opt_xino *xiopt, int remount) ++{ ++ int err, skip; ++ struct dentry *dentry, *parent, *cur_dentry, *cur_parent; ++ struct qstr *dname, *cur_name; ++ struct file *cur_xino; ++ struct au_sbinfo *sbinfo; ++ struct path *path, *cur_path; ++ ++ SiMustWriteLock(sb); ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ path = &xiopt->file->f_path; ++ dentry = path->dentry; ++ parent = dget_parent(dentry); ++ if (remount) { ++ skip = 0; ++ cur_xino = sbinfo->si_xib; ++ if (cur_xino) { ++ cur_path = &cur_xino->f_path; ++ cur_dentry = cur_path->dentry; ++ cur_parent = dget_parent(cur_dentry); ++ cur_name = &cur_dentry->d_name; ++ dname = &dentry->d_name; ++ skip = (cur_parent == parent ++ && au_qstreq(dname, cur_name)); ++ dput(cur_parent); ++ } ++ if (skip) ++ goto out; ++ } ++ ++ au_opt_set(sbinfo->si_mntflags, XINO); ++ err = au_xino_set_xib(sb, path); ++ /* si_x{read,write} are set */ ++ if (!err) ++ err = au_xigen_set(sb, path); ++ if (!err) ++ err = au_xino_set_br(sb, path); ++ if (!err) { ++ dbgaufs_brs_add(sb, 0, /*topdown*/1); ++ goto out; /* success */ ++ } ++ ++ /* reset all */ ++ AuIOErr("failed setting xino(%d).\n", err); ++ au_xino_clr(sb); ++ ++out: ++ dput(parent); ++ return err; ++} ++ ++/* ++ * create a xinofile at the default place/path. ++ */ ++struct file *au_xino_def(struct super_block *sb) ++{ ++ struct file *file; ++ char *page, *p; ++ struct au_branch *br; ++ struct super_block *h_sb; ++ struct path path; ++ aufs_bindex_t bbot, bindex, bwr; ++ ++ br = NULL; ++ bbot = au_sbbot(sb); ++ bwr = -1; ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_writable(br->br_perm) ++ && !au_test_fs_bad_xino(au_br_sb(br))) { ++ bwr = bindex; ++ break; ++ } ++ } ++ ++ if (bwr >= 0) { ++ file = ERR_PTR(-ENOMEM); ++ page = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!page)) ++ goto out; ++ path.mnt = au_br_mnt(br); ++ path.dentry = au_h_dptr(sb->s_root, bwr); ++ p = d_path(&path, page, PATH_MAX - sizeof(AUFS_XINO_FNAME)); ++ file = (void *)p; ++ if (!IS_ERR(p)) { ++ strcat(p, "/" AUFS_XINO_FNAME); ++ AuDbg("%s\n", p); ++ file = au_xino_create(sb, p, /*silent*/0, /*wbrtop*/1); ++ } ++ free_page((unsigned long)page); ++ } else { ++ file = au_xino_create(sb, AUFS_XINO_DEFPATH, /*silent*/0, ++ /*wbrtop*/0); ++ if (IS_ERR(file)) ++ goto out; ++ h_sb = file->f_path.dentry->d_sb; ++ if (unlikely(au_test_fs_bad_xino(h_sb))) { ++ pr_err("xino doesn't support %s(%s)\n", ++ AUFS_XINO_DEFPATH, au_sbtype(h_sb)); ++ fput(file); ++ file = ERR_PTR(-EINVAL); ++ } ++ } ++ ++out: ++ return file; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * initialize the xinofile for the specified branch @br ++ * at the place/path where @base_file indicates. ++ * test whether another branch is on the same filesystem or not, ++ * if found then share the xinofile with another branch. ++ */ ++int au_xino_init_br(struct super_block *sb, struct au_branch *br, ino_t h_ino, ++ struct path *base) ++{ ++ int err; ++ struct au_xino_do_set_br args = { ++ .h_ino = h_ino, ++ .br = br ++ }; ++ ++ args.writef = au_sbi(sb)->si_xwrite; ++ args.bshared = sbr_find_shared(sb, /*btop*/0, au_sbbot(sb), ++ au_br_sb(br)); ++ err = au_xino_do_set_br(sb, base, &args); ++ if (unlikely(err)) ++ au_xino_put(br); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * get an unused inode number from bitmap ++ */ ++ino_t au_xino_new_ino(struct super_block *sb) ++{ ++ ino_t ino; ++ unsigned long *p, pindex, ul, pend; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ int free_bit, err; ++ ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ return iunique(sb, AUFS_FIRST_INO); ++ ++ sbinfo = au_sbi(sb); ++ mutex_lock(&sbinfo->si_xib_mtx); ++ p = sbinfo->si_xib_buf; ++ free_bit = sbinfo->si_xib_next_bit; ++ if (free_bit < page_bits && !test_bit(free_bit, p)) ++ goto out; /* success */ ++ free_bit = find_first_zero_bit(p, page_bits); ++ if (free_bit < page_bits) ++ goto out; /* success */ ++ ++ pindex = sbinfo->si_xib_last_pindex; ++ for (ul = pindex - 1; ul < ULONG_MAX; ul--) { ++ err = xib_pindex(sb, ul); ++ if (unlikely(err)) ++ goto out_err; ++ free_bit = find_first_zero_bit(p, page_bits); ++ if (free_bit < page_bits) ++ goto out; /* success */ ++ } ++ ++ file = sbinfo->si_xib; ++ pend = vfsub_f_size_read(file) / PAGE_SIZE; ++ for (ul = pindex + 1; ul <= pend; ul++) { ++ err = xib_pindex(sb, ul); ++ if (unlikely(err)) ++ goto out_err; ++ free_bit = find_first_zero_bit(p, page_bits); ++ if (free_bit < page_bits) ++ goto out; /* success */ ++ } ++ BUG(); ++ ++out: ++ set_bit(free_bit, p); ++ sbinfo->si_xib_next_bit = free_bit + 1; ++ pindex = sbinfo->si_xib_last_pindex; ++ mutex_unlock(&sbinfo->si_xib_mtx); ++ ino = xib_calc_ino(pindex, free_bit); ++ AuDbg("i%lu\n", (unsigned long)ino); ++ return ino; ++out_err: ++ mutex_unlock(&sbinfo->si_xib_mtx); ++ AuDbg("i0\n"); ++ return 0; ++} ++ ++/* for s_op->delete_inode() */ ++void au_xino_delete_inode(struct inode *inode, const int unlinked) ++{ ++ int err; ++ unsigned int mnt_flags; ++ aufs_bindex_t bindex, bbot, bi; ++ unsigned char try_trunc; ++ struct au_iinfo *iinfo; ++ struct super_block *sb; ++ struct au_hinode *hi; ++ struct inode *h_inode; ++ struct au_branch *br; ++ vfs_writef_t xwrite; ++ struct au_xi_calc calc; ++ struct file *file; ++ ++ AuDebugOn(au_is_bad_inode(inode)); ++ ++ sb = inode->i_sb; ++ mnt_flags = au_mntflags(sb); ++ if (!au_opt_test(mnt_flags, XINO) ++ || inode->i_ino == AUFS_ROOT_INO) ++ return; ++ ++ if (unlinked) { ++ au_xigen_inc(inode); ++ au_xib_clear_bit(inode); ++ } ++ ++ iinfo = au_ii(inode); ++ bindex = iinfo->ii_btop; ++ if (bindex < 0) ++ return; ++ ++ xwrite = au_sbi(sb)->si_xwrite; ++ try_trunc = !!au_opt_test(mnt_flags, TRUNC_XINO); ++ hi = au_hinode(iinfo, bindex); ++ bbot = iinfo->ii_bbot; ++ for (; bindex <= bbot; bindex++, hi++) { ++ h_inode = hi->hi_inode; ++ if (!h_inode ++ || (!unlinked && h_inode->i_nlink)) ++ continue; ++ ++ /* inode may not be revalidated */ ++ bi = au_br_index(sb, hi->hi_id); ++ if (bi < 0) ++ continue; ++ ++ br = au_sbr(sb, bi); ++ au_xi_calc(sb, h_inode->i_ino, &calc); ++ file = au_xino_file(br->br_xino, calc.idx); ++ if (IS_ERR_OR_NULL(file)) ++ continue; ++ ++ err = au_xino_do_write(xwrite, file, &calc, /*ino*/0); ++ if (!err && try_trunc ++ && au_test_fs_trunc_xino(au_br_sb(br))) ++ xino_try_trunc(sb, br); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_xinondir_find(struct au_xino *xi, ino_t h_ino) ++{ ++ int found, total, i; ++ ++ found = -1; ++ total = xi->xi_nondir.total; ++ for (i = 0; i < total; i++) { ++ if (xi->xi_nondir.array[i] != h_ino) ++ continue; ++ found = i; ++ break; ++ } ++ ++ return found; ++} ++ ++static int au_xinondir_expand(struct au_xino *xi) ++{ ++ int err, sz; ++ ino_t *p; ++ ++ BUILD_BUG_ON(KMALLOC_MAX_SIZE > INT_MAX); ++ ++ err = -ENOMEM; ++ sz = xi->xi_nondir.total * sizeof(ino_t); ++ if (unlikely(sz > KMALLOC_MAX_SIZE / 2)) ++ goto out; ++ p = au_kzrealloc(xi->xi_nondir.array, sz, sz << 1, GFP_ATOMIC, ++ /*may_shrink*/0); ++ if (p) { ++ xi->xi_nondir.array = p; ++ xi->xi_nondir.total <<= 1; ++ AuDbg("xi_nondir.total %d\n", xi->xi_nondir.total); ++ err = 0; ++ } ++ ++out: ++ return err; ++} ++ ++void au_xinondir_leave(struct super_block *sb, aufs_bindex_t bindex, ++ ino_t h_ino, int idx) ++{ ++ struct au_xino *xi; ++ ++ AuDebugOn(!au_opt_test(au_mntflags(sb), XINO)); ++ xi = au_sbr(sb, bindex)->br_xino; ++ AuDebugOn(idx < 0 || xi->xi_nondir.total <= idx); ++ ++ spin_lock(&xi->xi_nondir.spin); ++ AuDebugOn(xi->xi_nondir.array[idx] != h_ino); ++ xi->xi_nondir.array[idx] = 0; ++ spin_unlock(&xi->xi_nondir.spin); ++ wake_up_all(&xi->xi_nondir.wqh); ++} ++ ++int au_xinondir_enter(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ int *idx) ++{ ++ int err, found, empty; ++ struct au_xino *xi; ++ ++ err = 0; ++ *idx = -1; ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ goto out; /* no xino */ ++ ++ xi = au_sbr(sb, bindex)->br_xino; ++ ++again: ++ spin_lock(&xi->xi_nondir.spin); ++ found = au_xinondir_find(xi, h_ino); ++ if (found == -1) { ++ empty = au_xinondir_find(xi, /*h_ino*/0); ++ if (empty == -1) { ++ empty = xi->xi_nondir.total; ++ err = au_xinondir_expand(xi); ++ if (unlikely(err)) ++ goto out_unlock; ++ } ++ xi->xi_nondir.array[empty] = h_ino; ++ *idx = empty; ++ } else { ++ spin_unlock(&xi->xi_nondir.spin); ++ wait_event(xi->xi_nondir.wqh, ++ xi->xi_nondir.array[found] != h_ino); ++ goto again; ++ } ++ ++out_unlock: ++ spin_unlock(&xi->xi_nondir.spin); ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_xino_path(struct seq_file *seq, struct file *file) ++{ ++ int err; ++ ++ err = au_seq_path(seq, &file->f_path); ++ if (unlikely(err)) ++ goto out; ++ ++#define Deleted "\\040(deleted)" ++ seq->count -= sizeof(Deleted) - 1; ++ AuDebugOn(memcmp(seq->buf + seq->count, Deleted, ++ sizeof(Deleted) - 1)); ++#undef Deleted ++ ++out: ++ return err; ++} +diff -Nurp linux-5.4/fs/dcache.c linux-5.4-aufs/fs/dcache.c +--- linux-5.4/fs/dcache.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/fs/dcache.c 2019-11-28 01:25:59.069925618 +0200 +@@ -1264,7 +1264,7 @@ enum d_walk_ret { + * + * The @enter() callbacks are called with d_lock held. + */ +-static void d_walk(struct dentry *parent, void *data, ++void d_walk(struct dentry *parent, void *data, + enum d_walk_ret (*enter)(void *, struct dentry *)) + { + struct dentry *this_parent; +diff -Nurp linux-5.4/fs/fcntl.c linux-5.4-aufs/fs/fcntl.c +--- linux-5.4/fs/fcntl.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/fs/fcntl.c 2019-11-28 01:25:59.069925618 +0200 +@@ -32,7 +32,7 @@ + + #define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME) + +-static int setfl(int fd, struct file * filp, unsigned long arg) ++int setfl(int fd, struct file * filp, unsigned long arg) + { + struct inode * inode = file_inode(filp); + int error = 0; +@@ -63,6 +63,8 @@ static int setfl(int fd, struct file * f + + if (filp->f_op->check_flags) + error = filp->f_op->check_flags(arg); ++ if (!error && filp->f_op->setfl) ++ error = filp->f_op->setfl(filp, arg); + if (error) + return error; + +diff -Nurp linux-5.4/fs/inode.c linux-5.4-aufs/fs/inode.c +--- linux-5.4/fs/inode.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/fs/inode.c 2019-11-28 01:25:59.070925617 +0200 +@@ -1673,7 +1673,7 @@ EXPORT_SYMBOL(generic_update_time); + * This does the actual work of updating an inodes time or version. Must have + * had called mnt_want_write() before calling this. + */ +-static int update_time(struct inode *inode, struct timespec64 *time, int flags) ++int update_time(struct inode *inode, struct timespec64 *time, int flags) + { + int (*update_time)(struct inode *, struct timespec64 *, int); + +diff -Nurp linux-5.4/fs/Kconfig linux-5.4-aufs/fs/Kconfig +--- linux-5.4/fs/Kconfig 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/fs/Kconfig 2019-11-28 01:33:04.893908639 +0200 +@@ -121,6 +121,7 @@ source "fs/quota/Kconfig" + source "fs/autofs/Kconfig" + source "fs/fuse/Kconfig" + source "fs/overlayfs/Kconfig" ++source "fs/aufs/Kconfig" + + menu "Caches" + +diff -Nurp linux-5.4/fs/Makefile linux-5.4-aufs/fs/Makefile +--- linux-5.4/fs/Makefile 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/fs/Makefile 2019-11-28 01:34:16.881905768 +0200 +@@ -110,6 +110,7 @@ obj-$(CONFIG_AUTOFS_FS) += autofs/ + obj-$(CONFIG_ADFS_FS) += adfs/ + obj-$(CONFIG_FUSE_FS) += fuse/ + obj-$(CONFIG_OVERLAY_FS) += overlayfs/ ++obj-$(CONFIG_AUFS_FS) += aufs/ + obj-$(CONFIG_ORANGEFS_FS) += orangefs/ + obj-$(CONFIG_UDF_FS) += udf/ + obj-$(CONFIG_SUN_OPENPROMFS) += openpromfs/ +diff -Nurp linux-5.4/fs/namespace.c linux-5.4-aufs/fs/namespace.c +--- linux-5.4/fs/namespace.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/fs/namespace.c 2019-11-28 01:25:59.070925617 +0200 +@@ -776,6 +776,12 @@ static inline int check_mnt(struct mount + return mnt->mnt_ns == current->nsproxy->mnt_ns; + } + ++/* for aufs, CONFIG_AUFS_BR_FUSE */ ++int is_current_mnt_ns(struct vfsmount *mnt) ++{ ++ return check_mnt(real_mount(mnt)); ++} ++ + /* + * vfsmount lock must be held for write + */ +diff -Nurp linux-5.4/fs/proc/base.c linux-5.4-aufs/fs/proc/base.c +--- linux-5.4/fs/proc/base.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/fs/proc/base.c 2019-11-28 01:25:59.070925617 +0200 +@@ -2037,7 +2037,7 @@ static int map_files_get_link(struct den + rc = -ENOENT; + vma = find_exact_vma(mm, vm_start, vm_end); + if (vma && vma->vm_file) { +- *path = vma->vm_file->f_path; ++ *path = vma_pr_or_file(vma)->f_path; + path_get(path); + rc = 0; + } +diff -Nurp linux-5.4/fs/proc/nommu.c linux-5.4-aufs/fs/proc/nommu.c +--- linux-5.4/fs/proc/nommu.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/fs/proc/nommu.c 2019-11-28 01:25:59.070925617 +0200 +@@ -41,7 +41,10 @@ static int nommu_region_show(struct seq_ + file = region->vm_file; + + if (file) { +- struct inode *inode = file_inode(region->vm_file); ++ struct inode *inode; ++ ++ file = vmr_pr_or_file(region); ++ inode = file_inode(file); + dev = inode->i_sb->s_dev; + ino = inode->i_ino; + } +diff -Nurp linux-5.4/fs/proc/task_mmu.c linux-5.4-aufs/fs/proc/task_mmu.c +--- linux-5.4/fs/proc/task_mmu.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/fs/proc/task_mmu.c 2019-11-28 01:25:59.070925617 +0200 +@@ -309,7 +309,10 @@ show_map_vma(struct seq_file *m, struct + const char *name = NULL; + + if (file) { +- struct inode *inode = file_inode(vma->vm_file); ++ struct inode *inode; ++ ++ file = vma_pr_or_file(vma); ++ inode = file_inode(file); + dev = inode->i_sb->s_dev; + ino = inode->i_ino; + pgoff = ((loff_t)vma->vm_pgoff) << PAGE_SHIFT; +@@ -1819,7 +1822,7 @@ static int show_numa_map(struct seq_file + struct proc_maps_private *proc_priv = &numa_priv->proc_maps; + struct vm_area_struct *vma = v; + struct numa_maps *md = &numa_priv->md; +- struct file *file = vma->vm_file; ++ struct file *file = vma_pr_or_file(vma); + struct mm_struct *mm = vma->vm_mm; + struct mempolicy *pol; + char buffer[64]; +diff -Nurp linux-5.4/fs/proc/task_nommu.c linux-5.4-aufs/fs/proc/task_nommu.c +--- linux-5.4/fs/proc/task_nommu.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/fs/proc/task_nommu.c 2019-11-28 01:25:59.070925617 +0200 +@@ -155,7 +155,10 @@ static int nommu_vma_show(struct seq_fil + file = vma->vm_file; + + if (file) { +- struct inode *inode = file_inode(vma->vm_file); ++ struct inode *inode; ++ ++ file = vma_pr_or_file(vma); ++ inode = file_inode(file); + dev = inode->i_sb->s_dev; + ino = inode->i_ino; + pgoff = (loff_t)vma->vm_pgoff << PAGE_SHIFT; +diff -Nurp linux-5.4/fs/read_write.c linux-5.4-aufs/fs/read_write.c +--- linux-5.4/fs/read_write.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/fs/read_write.c 2019-11-28 01:25:59.070925617 +0200 +@@ -498,6 +498,28 @@ static ssize_t __vfs_write(struct file * + return -EINVAL; + } + ++vfs_readf_t vfs_readf(struct file *file) ++{ ++ const struct file_operations *fop = file->f_op; ++ ++ if (fop->read) ++ return fop->read; ++ if (fop->read_iter) ++ return new_sync_read; ++ return ERR_PTR(-ENOSYS); ++} ++ ++vfs_writef_t vfs_writef(struct file *file) ++{ ++ const struct file_operations *fop = file->f_op; ++ ++ if (fop->write) ++ return fop->write; ++ if (fop->write_iter) ++ return new_sync_write; ++ return ERR_PTR(-ENOSYS); ++} ++ + ssize_t __kernel_write(struct file *file, const void *buf, size_t count, loff_t *pos) + { + mm_segment_t old_fs; +diff -Nurp linux-5.4/fs/splice.c linux-5.4-aufs/fs/splice.c +--- linux-5.4/fs/splice.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/fs/splice.c 2019-11-28 01:25:59.071925617 +0200 +@@ -834,8 +834,8 @@ EXPORT_SYMBOL(generic_splice_sendpage); + /* + * Attempt to initiate a splice from pipe to file. + */ +-static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, +- loff_t *ppos, size_t len, unsigned int flags) ++long do_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags) + { + ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, + loff_t *, size_t, unsigned int); +@@ -851,9 +851,9 @@ static long do_splice_from(struct pipe_i + /* + * Attempt to initiate a splice from a file to a pipe. + */ +-static long do_splice_to(struct file *in, loff_t *ppos, +- struct pipe_inode_info *pipe, size_t len, +- unsigned int flags) ++long do_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags) + { + ssize_t (*splice_read)(struct file *, loff_t *, + struct pipe_inode_info *, size_t, unsigned int); +diff -Nurp linux-5.4/fs/sync.c linux-5.4-aufs/fs/sync.c +--- linux-5.4/fs/sync.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/fs/sync.c 2019-11-28 01:25:59.071925617 +0200 +@@ -28,7 +28,7 @@ + * wait == 1 case since in that case write_inode() functions do + * sync_dirty_buffer() and thus effectively write one block at a time. + */ +-static int __sync_filesystem(struct super_block *sb, int wait) ++int __sync_filesystem(struct super_block *sb, int wait) + { + if (wait) + sync_inodes_sb(sb); +diff -Nurp linux-5.4/include/linux/fs.h linux-5.4-aufs/include/linux/fs.h +--- linux-5.4/include/linux/fs.h 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/include/linux/fs.h 2019-11-28 01:25:59.071925617 +0200 +@@ -1349,6 +1349,7 @@ extern void fasync_free(struct fasync_st + /* can be called from interrupts */ + extern void kill_fasync(struct fasync_struct **, int, int); + ++extern int setfl(int fd, struct file * filp, unsigned long arg); + extern void __f_setown(struct file *filp, struct pid *, enum pid_type, int force); + extern int f_setown(struct file *filp, unsigned long arg, int force); + extern void f_delown(struct file *filp); +@@ -1835,6 +1836,7 @@ struct file_operations { + ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); + unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); + int (*check_flags)(int); ++ int (*setfl)(struct file *, unsigned long); + int (*flock) (struct file *, int, struct file_lock *); + ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); + ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); +@@ -1905,6 +1907,12 @@ ssize_t rw_copy_check_uvector(int type, + struct iovec *fast_pointer, + struct iovec **ret_pointer); + ++typedef ssize_t (*vfs_readf_t)(struct file *, char __user *, size_t, loff_t *); ++typedef ssize_t (*vfs_writef_t)(struct file *, const char __user *, size_t, ++ loff_t *); ++vfs_readf_t vfs_readf(struct file *file); ++vfs_writef_t vfs_writef(struct file *file); ++ + extern ssize_t __vfs_read(struct file *, char __user *, size_t, loff_t *); + extern ssize_t vfs_read(struct file *, char __user *, size_t, loff_t *); + extern ssize_t vfs_write(struct file *, const char __user *, size_t, loff_t *); +@@ -2325,6 +2333,7 @@ extern int current_umask(void); + extern void ihold(struct inode * inode); + extern void iput(struct inode *); + extern int generic_update_time(struct inode *, struct timespec64 *, int); ++extern int update_time(struct inode *, struct timespec64 *, int); + + /* /sys/fs */ + extern struct kobject *fs_kobj; +@@ -2613,6 +2622,7 @@ static inline bool sb_is_blkdev_sb(struc + return false; + } + #endif ++extern int __sync_filesystem(struct super_block *, int); + extern int sync_filesystem(struct super_block *); + extern const struct file_operations def_blk_fops; + extern const struct file_operations def_chr_fops; +diff -Nurp linux-5.4/include/linux/lockdep.h linux-5.4-aufs/include/linux/lockdep.h +--- linux-5.4/include/linux/lockdep.h 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/include/linux/lockdep.h 2019-11-28 01:25:59.071925617 +0200 +@@ -331,6 +331,8 @@ static inline int lockdep_match_key(stru + return lock->key == key; + } + ++struct lock_class *lockdep_hlock_class(struct held_lock *hlock); ++ + /* + * Acquire a lock. + * +@@ -473,6 +475,7 @@ struct lockdep_map { }; + + #define lockdep_depth(tsk) (0) + ++#define lockdep_is_held(lock) (1) + #define lockdep_is_held_type(l, r) (1) + + #define lockdep_assert_held(l) do { (void)(l); } while (0) +diff -Nurp linux-5.4/include/linux/mm.h linux-5.4-aufs/include/linux/mm.h +--- linux-5.4/include/linux/mm.h 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/include/linux/mm.h 2019-11-28 01:25:59.071925617 +0200 +@@ -1510,6 +1510,28 @@ static inline void unmap_shared_mapping_ + unmap_mapping_range(mapping, holebegin, holelen, 0); + } + ++extern void vma_do_file_update_time(struct vm_area_struct *, const char[], int); ++extern struct file *vma_do_pr_or_file(struct vm_area_struct *, const char[], ++ int); ++extern void vma_do_get_file(struct vm_area_struct *, const char[], int); ++extern void vma_do_fput(struct vm_area_struct *, const char[], int); ++ ++#define vma_file_update_time(vma) vma_do_file_update_time(vma, __func__, \ ++ __LINE__) ++#define vma_pr_or_file(vma) vma_do_pr_or_file(vma, __func__, \ ++ __LINE__) ++#define vma_get_file(vma) vma_do_get_file(vma, __func__, __LINE__) ++#define vma_fput(vma) vma_do_fput(vma, __func__, __LINE__) ++ ++#ifndef CONFIG_MMU ++extern struct file *vmr_do_pr_or_file(struct vm_region *, const char[], int); ++extern void vmr_do_fput(struct vm_region *, const char[], int); ++ ++#define vmr_pr_or_file(region) vmr_do_pr_or_file(region, __func__, \ ++ __LINE__) ++#define vmr_fput(region) vmr_do_fput(region, __func__, __LINE__) ++#endif /* !CONFIG_MMU */ ++ + extern int access_process_vm(struct task_struct *tsk, unsigned long addr, + void *buf, int len, unsigned int gup_flags); + extern int access_remote_vm(struct mm_struct *mm, unsigned long addr, +diff -Nurp linux-5.4/include/linux/mm_types.h linux-5.4-aufs/include/linux/mm_types.h +--- linux-5.4/include/linux/mm_types.h 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/include/linux/mm_types.h 2019-11-28 01:25:59.071925617 +0200 +@@ -267,6 +267,7 @@ struct vm_region { + 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 */ ++ struct file *vm_prfile; /* the virtual 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 +@@ -341,6 +342,7 @@ struct vm_area_struct { + unsigned long vm_pgoff; /* Offset (within vm_file) in PAGE_SIZE + units */ + struct file * vm_file; /* File we map to (can be NULL). */ ++ struct file *vm_prfile; /* shadow of vm_file */ + void * vm_private_data; /* was vm_pte (shared mem) */ + + #ifdef CONFIG_SWAP +diff -Nurp linux-5.4/include/linux/mnt_namespace.h linux-5.4-aufs/include/linux/mnt_namespace.h +--- linux-5.4/include/linux/mnt_namespace.h 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/include/linux/mnt_namespace.h 2019-11-28 01:25:59.071925617 +0200 +@@ -6,11 +6,14 @@ + struct mnt_namespace; + struct fs_struct; + struct user_namespace; ++struct vfsmount; + + extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_namespace *, + struct user_namespace *, struct fs_struct *); + extern void put_mnt_ns(struct mnt_namespace *ns); + ++extern int is_current_mnt_ns(struct vfsmount *mnt); ++ + extern const struct file_operations proc_mounts_operations; + extern const struct file_operations proc_mountinfo_operations; + extern const struct file_operations proc_mountstats_operations; +diff -Nurp linux-5.4/include/linux/splice.h linux-5.4-aufs/include/linux/splice.h +--- linux-5.4/include/linux/splice.h 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/include/linux/splice.h 2019-11-28 01:25:59.071925617 +0200 +@@ -87,4 +87,10 @@ extern void splice_shrink_spd(struct spl + + extern const struct pipe_buf_operations page_cache_pipe_buf_ops; + extern const struct pipe_buf_operations default_pipe_buf_ops; ++ ++extern long do_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags); ++extern long do_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags); + #endif +diff -Nurp linux-5.4/include/uapi/linux/aufs_type.h linux-5.4-aufs/include/uapi/linux/aufs_type.h +--- linux-5.4/include/uapi/linux/aufs_type.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/include/uapi/linux/aufs_type.h 2019-11-28 01:25:59.071925617 +0200 +@@ -0,0 +1,439 @@ ++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ ++/* ++ * Copyright (C) 2005-2019 Junjiro R. Okajima ++ */ ++ ++#ifndef __AUFS_TYPE_H__ ++#define __AUFS_TYPE_H__ ++ ++#define AUFS_NAME "aufs" ++ ++#ifdef __KERNEL__ ++/* ++ * define it before including all other headers. ++ * sched.h may use pr_* macros before defining "current", so define the ++ * no-current version first, and re-define later. ++ */ ++#define pr_fmt(fmt) AUFS_NAME " %s:%d: " fmt, __func__, __LINE__ ++#include ++#undef pr_fmt ++#define pr_fmt(fmt) \ ++ AUFS_NAME " %s:%d:%.*s[%d]: " fmt, __func__, __LINE__, \ ++ (int)sizeof(current->comm), current->comm, current->pid ++#else ++#include ++#include ++#endif /* __KERNEL__ */ ++ ++#include ++ ++#define AUFS_VERSION "5.4" ++ ++/* todo? move this to linux-2.6.19/include/magic.h */ ++#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's') ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_BRANCH_MAX_127 ++typedef int8_t aufs_bindex_t; ++#define AUFS_BRANCH_MAX 127 ++#else ++typedef int16_t aufs_bindex_t; ++#ifdef CONFIG_AUFS_BRANCH_MAX_511 ++#define AUFS_BRANCH_MAX 511 ++#elif defined(CONFIG_AUFS_BRANCH_MAX_1023) ++#define AUFS_BRANCH_MAX 1023 ++#elif defined(CONFIG_AUFS_BRANCH_MAX_32767) ++#define AUFS_BRANCH_MAX 32767 ++#endif ++#endif ++ ++#ifdef __KERNEL__ ++#ifndef AUFS_BRANCH_MAX ++#error unknown CONFIG_AUFS_BRANCH_MAX value ++#endif ++#endif /* __KERNEL__ */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AUFS_FSTYPE AUFS_NAME ++ ++#define AUFS_ROOT_INO 2 ++#define AUFS_FIRST_INO 11 ++ ++#define AUFS_WH_PFX ".wh." ++#define AUFS_WH_PFX_LEN ((int)sizeof(AUFS_WH_PFX) - 1) ++#define AUFS_WH_TMP_LEN 4 ++/* a limit for rmdir/rename a dir and copyup */ ++#define AUFS_MAX_NAMELEN (NAME_MAX \ ++ - AUFS_WH_PFX_LEN * 2 /* doubly whiteouted */\ ++ - 1 /* dot */\ ++ - AUFS_WH_TMP_LEN) /* hex */ ++#define AUFS_XINO_FNAME "." AUFS_NAME ".xino" ++#define AUFS_XINO_DEFPATH "/tmp/" AUFS_XINO_FNAME ++#define AUFS_XINO_DEF_SEC 30 /* seconds */ ++#define AUFS_XINO_DEF_TRUNC 45 /* percentage */ ++#define AUFS_DIRWH_DEF 3 ++#define AUFS_RDCACHE_DEF 10 /* seconds */ ++#define AUFS_RDCACHE_MAX 3600 /* seconds */ ++#define AUFS_RDBLK_DEF 512 /* bytes */ ++#define AUFS_RDHASH_DEF 32 ++#define AUFS_WKQ_NAME AUFS_NAME "d" ++#define AUFS_MFS_DEF_SEC 30 /* seconds */ ++#define AUFS_MFS_MAX_SEC 3600 /* seconds */ ++#define AUFS_FHSM_CACHE_DEF_SEC 30 /* seconds */ ++#define AUFS_PLINK_WARN 50 /* number of plinks in a single bucket */ ++ ++/* pseudo-link maintenace under /proc */ ++#define AUFS_PLINK_MAINT_NAME "plink_maint" ++#define AUFS_PLINK_MAINT_DIR "fs/" AUFS_NAME ++#define AUFS_PLINK_MAINT_PATH AUFS_PLINK_MAINT_DIR "/" AUFS_PLINK_MAINT_NAME ++ ++/* dirren, renamed dir */ ++#define AUFS_DR_INFO_PFX AUFS_WH_PFX ".dr." ++#define AUFS_DR_BRHINO_NAME AUFS_WH_PFX "hino" ++/* whiteouted doubly */ ++#define AUFS_WH_DR_INFO_PFX AUFS_WH_PFX AUFS_DR_INFO_PFX ++#define AUFS_WH_DR_BRHINO AUFS_WH_PFX AUFS_DR_BRHINO_NAME ++ ++#define AUFS_DIROPQ_NAME AUFS_WH_PFX ".opq" /* whiteouted doubly */ ++#define AUFS_WH_DIROPQ AUFS_WH_PFX AUFS_DIROPQ_NAME ++ ++#define AUFS_BASE_NAME AUFS_WH_PFX AUFS_NAME ++#define AUFS_PLINKDIR_NAME AUFS_WH_PFX "plnk" ++#define AUFS_ORPHDIR_NAME AUFS_WH_PFX "orph" ++ ++/* doubly whiteouted */ ++#define AUFS_WH_BASE AUFS_WH_PFX AUFS_BASE_NAME ++#define AUFS_WH_PLINKDIR AUFS_WH_PFX AUFS_PLINKDIR_NAME ++#define AUFS_WH_ORPHDIR AUFS_WH_PFX AUFS_ORPHDIR_NAME ++ ++/* branch permissions and attributes */ ++#define AUFS_BRPERM_RW "rw" ++#define AUFS_BRPERM_RO "ro" ++#define AUFS_BRPERM_RR "rr" ++#define AUFS_BRATTR_COO_REG "coo_reg" ++#define AUFS_BRATTR_COO_ALL "coo_all" ++#define AUFS_BRATTR_FHSM "fhsm" ++#define AUFS_BRATTR_UNPIN "unpin" ++#define AUFS_BRATTR_ICEX "icex" ++#define AUFS_BRATTR_ICEX_SEC "icexsec" ++#define AUFS_BRATTR_ICEX_SYS "icexsys" ++#define AUFS_BRATTR_ICEX_TR "icextr" ++#define AUFS_BRATTR_ICEX_USR "icexusr" ++#define AUFS_BRATTR_ICEX_OTH "icexoth" ++#define AUFS_BRRATTR_WH "wh" ++#define AUFS_BRWATTR_NLWH "nolwh" ++#define AUFS_BRWATTR_MOO "moo" ++ ++#define AuBrPerm_RW 1 /* writable, hardlinkable wh */ ++#define AuBrPerm_RO (1 << 1) /* readonly */ ++#define AuBrPerm_RR (1 << 2) /* natively readonly */ ++#define AuBrPerm_Mask (AuBrPerm_RW | AuBrPerm_RO | AuBrPerm_RR) ++ ++#define AuBrAttr_COO_REG (1 << 3) /* copy-up on open */ ++#define AuBrAttr_COO_ALL (1 << 4) ++#define AuBrAttr_COO_Mask (AuBrAttr_COO_REG | AuBrAttr_COO_ALL) ++ ++#define AuBrAttr_FHSM (1 << 5) /* file-based hsm */ ++#define AuBrAttr_UNPIN (1 << 6) /* rename-able top dir of ++ branch. meaningless since ++ linux-3.18-rc1 */ ++ ++/* ignore error in copying XATTR */ ++#define AuBrAttr_ICEX_SEC (1 << 7) ++#define AuBrAttr_ICEX_SYS (1 << 8) ++#define AuBrAttr_ICEX_TR (1 << 9) ++#define AuBrAttr_ICEX_USR (1 << 10) ++#define AuBrAttr_ICEX_OTH (1 << 11) ++#define AuBrAttr_ICEX (AuBrAttr_ICEX_SEC \ ++ | AuBrAttr_ICEX_SYS \ ++ | AuBrAttr_ICEX_TR \ ++ | AuBrAttr_ICEX_USR \ ++ | AuBrAttr_ICEX_OTH) ++ ++#define AuBrRAttr_WH (1 << 12) /* whiteout-able */ ++#define AuBrRAttr_Mask AuBrRAttr_WH ++ ++#define AuBrWAttr_NoLinkWH (1 << 13) /* un-hardlinkable whiteouts */ ++#define AuBrWAttr_MOO (1 << 14) /* move-up on open */ ++#define AuBrWAttr_Mask (AuBrWAttr_NoLinkWH | AuBrWAttr_MOO) ++ ++#define AuBrAttr_CMOO_Mask (AuBrAttr_COO_Mask | AuBrWAttr_MOO) ++ ++/* #warning test userspace */ ++#ifdef __KERNEL__ ++#ifndef CONFIG_AUFS_FHSM ++#undef AuBrAttr_FHSM ++#define AuBrAttr_FHSM 0 ++#endif ++#ifndef CONFIG_AUFS_XATTR ++#undef AuBrAttr_ICEX ++#define AuBrAttr_ICEX 0 ++#undef AuBrAttr_ICEX_SEC ++#define AuBrAttr_ICEX_SEC 0 ++#undef AuBrAttr_ICEX_SYS ++#define AuBrAttr_ICEX_SYS 0 ++#undef AuBrAttr_ICEX_TR ++#define AuBrAttr_ICEX_TR 0 ++#undef AuBrAttr_ICEX_USR ++#define AuBrAttr_ICEX_USR 0 ++#undef AuBrAttr_ICEX_OTH ++#define AuBrAttr_ICEX_OTH 0 ++#endif ++#endif ++ ++/* the longest combination */ ++/* AUFS_BRATTR_ICEX and AUFS_BRATTR_ICEX_TR don't affect here */ ++#define AuBrPermStrSz sizeof(AUFS_BRPERM_RW \ ++ "+" AUFS_BRATTR_COO_REG \ ++ "+" AUFS_BRATTR_FHSM \ ++ "+" AUFS_BRATTR_UNPIN \ ++ "+" AUFS_BRATTR_ICEX_SEC \ ++ "+" AUFS_BRATTR_ICEX_SYS \ ++ "+" AUFS_BRATTR_ICEX_USR \ ++ "+" AUFS_BRATTR_ICEX_OTH \ ++ "+" AUFS_BRWATTR_NLWH) ++ ++typedef struct { ++ char a[AuBrPermStrSz]; ++} au_br_perm_str_t; ++ ++static inline int au_br_writable(int brperm) ++{ ++ return brperm & AuBrPerm_RW; ++} ++ ++static inline int au_br_whable(int brperm) ++{ ++ return brperm & (AuBrPerm_RW | AuBrRAttr_WH); ++} ++ ++static inline int au_br_wh_linkable(int brperm) ++{ ++ return !(brperm & AuBrWAttr_NoLinkWH); ++} ++ ++static inline int au_br_cmoo(int brperm) ++{ ++ return brperm & AuBrAttr_CMOO_Mask; ++} ++ ++static inline int au_br_fhsm(int brperm) ++{ ++ return brperm & AuBrAttr_FHSM; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ioctl */ ++enum { ++ /* readdir in userspace */ ++ AuCtl_RDU, ++ AuCtl_RDU_INO, ++ ++ AuCtl_WBR_FD, /* pathconf wrapper */ ++ AuCtl_IBUSY, /* busy inode */ ++ AuCtl_MVDOWN, /* move-down */ ++ AuCtl_BR, /* info about branches */ ++ AuCtl_FHSM_FD /* connection for fhsm */ ++}; ++ ++/* borrowed from linux/include/linux/kernel.h */ ++#ifndef ALIGN ++#ifdef _GNU_SOURCE ++#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1) ++#else ++#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) ++#endif ++#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask)) ++#endif ++ ++/* borrowed from linux/include/linux/compiler-gcc3.h */ ++#ifndef __aligned ++#define __aligned(x) __attribute__((aligned(x))) ++#endif ++ ++#ifdef __KERNEL__ ++#ifndef __packed ++#define __packed __attribute__((packed)) ++#endif ++#endif ++ ++struct au_rdu_cookie { ++ uint64_t h_pos; ++ int16_t bindex; ++ uint8_t flags; ++ uint8_t pad; ++ uint32_t generation; ++} __aligned(8); ++ ++struct au_rdu_ent { ++ uint64_t ino; ++ int16_t bindex; ++ uint8_t type; ++ uint8_t nlen; ++ uint8_t wh; ++ char name[0]; ++} __aligned(8); ++ ++static inline int au_rdu_len(int nlen) ++{ ++ /* include the terminating NULL */ ++ return ALIGN(sizeof(struct au_rdu_ent) + nlen + 1, ++ sizeof(uint64_t)); ++} ++ ++union au_rdu_ent_ul { ++ struct au_rdu_ent __user *e; ++ uint64_t ul; ++}; ++ ++enum { ++ AufsCtlRduV_SZ, ++ AufsCtlRduV_End ++}; ++ ++struct aufs_rdu { ++ /* input */ ++ union { ++ uint64_t sz; /* AuCtl_RDU */ ++ uint64_t nent; /* AuCtl_RDU_INO */ ++ }; ++ union au_rdu_ent_ul ent; ++ uint16_t verify[AufsCtlRduV_End]; ++ ++ /* input/output */ ++ uint32_t blk; ++ ++ /* output */ ++ union au_rdu_ent_ul tail; ++ /* number of entries which were added in a single call */ ++ uint64_t rent; ++ uint8_t full; ++ uint8_t shwh; ++ ++ struct au_rdu_cookie cookie; ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dirren. the branch is identified by the filename who contains this */ ++struct au_drinfo { ++ uint64_t ino; ++ union { ++ uint8_t oldnamelen; ++ uint64_t _padding; ++ }; ++ uint8_t oldname[0]; ++} __aligned(8); ++ ++struct au_drinfo_fdata { ++ uint32_t magic; ++ struct au_drinfo drinfo; ++} __aligned(8); ++ ++#define AUFS_DRINFO_MAGIC_V1 ('a' << 24 | 'd' << 16 | 'r' << 8 | 0x01) ++/* future */ ++#define AUFS_DRINFO_MAGIC_V2 ('a' << 24 | 'd' << 16 | 'r' << 8 | 0x02) ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct aufs_wbr_fd { ++ uint32_t oflags; ++ int16_t brid; ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct aufs_ibusy { ++ uint64_t ino, h_ino; ++ int16_t bindex; ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* error code for move-down */ ++/* the actual message strings are implemented in aufs-util.git */ ++enum { ++ EAU_MVDOWN_OPAQUE = 1, ++ EAU_MVDOWN_WHITEOUT, ++ EAU_MVDOWN_UPPER, ++ EAU_MVDOWN_BOTTOM, ++ EAU_MVDOWN_NOUPPER, ++ EAU_MVDOWN_NOLOWERBR, ++ EAU_Last ++}; ++ ++/* flags for move-down */ ++#define AUFS_MVDOWN_DMSG 1 ++#define AUFS_MVDOWN_OWLOWER (1 << 1) /* overwrite lower */ ++#define AUFS_MVDOWN_KUPPER (1 << 2) /* keep upper */ ++#define AUFS_MVDOWN_ROLOWER (1 << 3) /* do even if lower is RO */ ++#define AUFS_MVDOWN_ROLOWER_R (1 << 4) /* did on lower RO */ ++#define AUFS_MVDOWN_ROUPPER (1 << 5) /* do even if upper is RO */ ++#define AUFS_MVDOWN_ROUPPER_R (1 << 6) /* did on upper RO */ ++#define AUFS_MVDOWN_BRID_UPPER (1 << 7) /* upper brid */ ++#define AUFS_MVDOWN_BRID_LOWER (1 << 8) /* lower brid */ ++#define AUFS_MVDOWN_FHSM_LOWER (1 << 9) /* find fhsm attr for lower */ ++#define AUFS_MVDOWN_STFS (1 << 10) /* req. stfs */ ++#define AUFS_MVDOWN_STFS_FAILED (1 << 11) /* output: stfs is unusable */ ++#define AUFS_MVDOWN_BOTTOM (1 << 12) /* output: no more lowers */ ++ ++/* index for move-down */ ++enum { ++ AUFS_MVDOWN_UPPER, ++ AUFS_MVDOWN_LOWER, ++ AUFS_MVDOWN_NARRAY ++}; ++ ++/* ++ * additional info of move-down ++ * number of free blocks and inodes. ++ * subset of struct kstatfs, but smaller and always 64bit. ++ */ ++struct aufs_stfs { ++ uint64_t f_blocks; ++ uint64_t f_bavail; ++ uint64_t f_files; ++ uint64_t f_ffree; ++}; ++ ++struct aufs_stbr { ++ int16_t brid; /* optional input */ ++ int16_t bindex; /* output */ ++ struct aufs_stfs stfs; /* output when AUFS_MVDOWN_STFS set */ ++} __aligned(8); ++ ++struct aufs_mvdown { ++ uint32_t flags; /* input/output */ ++ struct aufs_stbr stbr[AUFS_MVDOWN_NARRAY]; /* input/output */ ++ int8_t au_errno; /* output */ ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++union aufs_brinfo { ++ /* PATH_MAX may differ between kernel-space and user-space */ ++ char _spacer[4096]; ++ struct { ++ int16_t id; ++ int perm; ++ char path[0]; ++ }; ++} __aligned(8); ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AuCtlType 'A' ++#define AUFS_CTL_RDU _IOWR(AuCtlType, AuCtl_RDU, struct aufs_rdu) ++#define AUFS_CTL_RDU_INO _IOWR(AuCtlType, AuCtl_RDU_INO, struct aufs_rdu) ++#define AUFS_CTL_WBR_FD _IOW(AuCtlType, AuCtl_WBR_FD, \ ++ struct aufs_wbr_fd) ++#define AUFS_CTL_IBUSY _IOWR(AuCtlType, AuCtl_IBUSY, struct aufs_ibusy) ++#define AUFS_CTL_MVDOWN _IOWR(AuCtlType, AuCtl_MVDOWN, \ ++ struct aufs_mvdown) ++#define AUFS_CTL_BRINFO _IOW(AuCtlType, AuCtl_BR, union aufs_brinfo) ++#define AUFS_CTL_FHSM_FD _IOW(AuCtlType, AuCtl_FHSM_FD, int) ++ ++#endif /* __AUFS_TYPE_H__ */ +diff -Nurp linux-5.4/kernel/fork.c linux-5.4-aufs/kernel/fork.c +--- linux-5.4/kernel/fork.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/kernel/fork.c 2019-11-28 01:25:59.072925617 +0200 +@@ -562,7 +562,7 @@ static __latent_entropy int dup_mmap(str + struct inode *inode = file_inode(file); + struct address_space *mapping = file->f_mapping; + +- get_file(file); ++ vma_get_file(tmp); + if (tmp->vm_flags & VM_DENYWRITE) + atomic_dec(&inode->i_writecount); + i_mmap_lock_write(mapping); +diff -Nurp linux-5.4/kernel/locking/lockdep.c linux-5.4-aufs/kernel/locking/lockdep.c +--- linux-5.4/kernel/locking/lockdep.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/kernel/locking/lockdep.c 2019-11-28 01:25:59.072925617 +0200 +@@ -153,7 +153,7 @@ static + struct lock_class lock_classes[MAX_LOCKDEP_KEYS]; + static DECLARE_BITMAP(lock_classes_in_use, MAX_LOCKDEP_KEYS); + +-static inline struct lock_class *hlock_class(struct held_lock *hlock) ++inline struct lock_class *lockdep_hlock_class(struct held_lock *hlock) + { + unsigned int class_idx = hlock->class_idx; + +@@ -174,6 +174,7 @@ static inline struct lock_class *hlock_c + */ + return lock_classes + class_idx; + } ++#define hlock_class(hlock) lockdep_hlock_class(hlock) + + #ifdef CONFIG_LOCK_STAT + static DEFINE_PER_CPU(struct lock_class_stats[MAX_LOCKDEP_KEYS], cpu_lock_stats); +diff -Nurp linux-5.4/MAINTAINERS linux-5.4-aufs/MAINTAINERS +--- linux-5.4/MAINTAINERS 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/MAINTAINERS 2019-11-28 01:25:59.062925618 +0200 +@@ -2832,6 +2832,19 @@ F: include/linux/audit.h + F: include/uapi/linux/audit.h + F: kernel/audit* + ++AUFS (advanced multi layered unification filesystem) FILESYSTEM ++M: "J. R. Okajima" ++L: aufs-users@lists.sourceforge.net (members only) ++L: linux-unionfs@vger.kernel.org ++W: http://aufs.sourceforge.net ++T: git://github.com/sfjro/aufs4-linux.git ++S: Supported ++F: Documentation/filesystems/aufs/ ++F: Documentation/ABI/testing/debugfs-aufs ++F: Documentation/ABI/testing/sysfs-aufs ++F: fs/aufs/ ++F: include/uapi/linux/aufs_type.h ++ + AUXILIARY DISPLAY DRIVERS + M: Miguel Ojeda Sandonis + S: Maintained +diff -Nurp linux-5.4/mm/filemap.c linux-5.4-aufs/mm/filemap.c +--- linux-5.4/mm/filemap.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/mm/filemap.c 2019-11-28 01:25:59.072925617 +0200 +@@ -2696,7 +2696,7 @@ vm_fault_t filemap_page_mkwrite(struct v + vm_fault_t ret = VM_FAULT_LOCKED; + + sb_start_pagefault(inode->i_sb); +- file_update_time(vmf->vma->vm_file); ++ vma_file_update_time(vmf->vma); + lock_page(page); + if (page->mapping != inode->i_mapping) { + unlock_page(page); +diff -Nurp linux-5.4/mm/Makefile linux-5.4-aufs/mm/Makefile +--- linux-5.4/mm/Makefile 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/mm/Makefile 2019-11-28 01:25:59.072925617 +0200 +@@ -42,7 +42,7 @@ obj-y := filemap.o mempool.o oom_kill. + mm_init.o mmu_context.o percpu.o slab_common.o \ + compaction.o vmacache.o \ + interval_tree.o list_lru.o workingset.o \ +- debug.o gup.o $(mmu-y) ++ prfile.o debug.o gup.o $(mmu-y) + + # Give 'page_alloc' its own module-parameter namespace + page-alloc-y := page_alloc.o +diff -Nurp linux-5.4/mm/mmap.c linux-5.4-aufs/mm/mmap.c +--- linux-5.4/mm/mmap.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/mm/mmap.c 2019-11-28 01:25:59.073925617 +0200 +@@ -182,7 +182,7 @@ static struct vm_area_struct *remove_vma + if (vma->vm_ops && vma->vm_ops->close) + vma->vm_ops->close(vma); + if (vma->vm_file) +- fput(vma->vm_file); ++ vma_fput(vma); + mpol_put(vma_policy(vma)); + vm_area_free(vma); + return next; +@@ -940,7 +940,7 @@ again: + if (remove_next) { + if (file) { + uprobe_munmap(next, next->vm_start, next->vm_end); +- fput(file); ++ vma_fput(vma); + } + if (next->anon_vma) + anon_vma_merge(vma, next); +@@ -1865,8 +1865,8 @@ out: + return addr; + + unmap_and_free_vma: ++ vma_fput(vma); + vma->vm_file = NULL; +- fput(file); + + /* Undo any partial mapping done by a device driver. */ + unmap_region(mm, vma, prev, vma->vm_start, vma->vm_end); +@@ -2695,7 +2695,7 @@ int __split_vma(struct mm_struct *mm, st + goto out_free_mpol; + + if (new->vm_file) +- get_file(new->vm_file); ++ vma_get_file(new); + + if (new->vm_ops && new->vm_ops->open) + new->vm_ops->open(new); +@@ -2714,7 +2714,7 @@ int __split_vma(struct mm_struct *mm, st + if (new->vm_ops && new->vm_ops->close) + new->vm_ops->close(new); + if (new->vm_file) +- fput(new->vm_file); ++ vma_fput(new); + unlink_anon_vmas(new); + out_free_mpol: + mpol_put(vma_policy(new)); +@@ -2906,7 +2906,7 @@ SYSCALL_DEFINE5(remap_file_pages, unsign + struct vm_area_struct *vma; + unsigned long populate = 0; + unsigned long ret = -EINVAL; +- struct file *file; ++ struct file *file, *prfile; + + pr_warn_once("%s (%d) uses deprecated remap_file_pages() syscall. See Documentation/vm/remap_file_pages.rst.\n", + current->comm, current->pid); +@@ -2981,10 +2981,27 @@ SYSCALL_DEFINE5(remap_file_pages, unsign + } + } + +- file = get_file(vma->vm_file); ++ vma_get_file(vma); ++ file = vma->vm_file; ++ prfile = vma->vm_prfile; + ret = do_mmap_pgoff(vma->vm_file, start, size, + prot, flags, pgoff, &populate, NULL); ++ if (!IS_ERR_VALUE(ret) && file && prfile) { ++ struct vm_area_struct *new_vma; ++ ++ new_vma = find_vma(mm, ret); ++ if (!new_vma->vm_prfile) ++ new_vma->vm_prfile = prfile; ++ if (new_vma != vma) ++ get_file(prfile); ++ } ++ /* ++ * two fput()s instead of vma_fput(vma), ++ * coz vma may not be available anymore. ++ */ + fput(file); ++ if (prfile) ++ fput(prfile); + out: + up_write(&mm->mmap_sem); + if (populate) +@@ -3274,7 +3291,7 @@ struct vm_area_struct *copy_vma(struct v + if (anon_vma_clone(new_vma, vma)) + goto out_free_mempol; + if (new_vma->vm_file) +- get_file(new_vma->vm_file); ++ vma_get_file(new_vma); + if (new_vma->vm_ops && new_vma->vm_ops->open) + new_vma->vm_ops->open(new_vma); + vma_link(mm, new_vma, prev, rb_link, rb_parent); +diff -Nurp linux-5.4/mm/nommu.c linux-5.4-aufs/mm/nommu.c +--- linux-5.4/mm/nommu.c 2019-11-25 02:32:01.000000000 +0200 ++++ linux-5.4-aufs/mm/nommu.c 2019-11-28 01:25:59.073925617 +0200 +@@ -552,7 +552,7 @@ static void __put_nommu_region(struct vm + up_write(&nommu_region_sem); + + if (region->vm_file) +- fput(region->vm_file); ++ vmr_fput(region); + + /* IO memory and memory shared directly out of the pagecache + * from ramfs/tmpfs mustn't be released here */ +@@ -690,7 +690,7 @@ static void delete_vma(struct mm_struct + if (vma->vm_ops && vma->vm_ops->close) + vma->vm_ops->close(vma); + if (vma->vm_file) +- fput(vma->vm_file); ++ vma_fput(vma); + put_nommu_region(vma->vm_region); + vm_area_free(vma); + } +@@ -1213,7 +1213,7 @@ unsigned long do_mmap(struct file *file, + goto error_just_free; + } + } +- fput(region->vm_file); ++ vmr_fput(region); + kmem_cache_free(vm_region_jar, region); + region = pregion; + result = start; +@@ -1290,10 +1290,10 @@ error_just_free: + up_write(&nommu_region_sem); + error: + if (region->vm_file) +- fput(region->vm_file); ++ vmr_fput(region); + kmem_cache_free(vm_region_jar, region); + if (vma->vm_file) +- fput(vma->vm_file); ++ vma_fput(vma); + vm_area_free(vma); + return ret; + +diff -Nurp linux-5.4/mm/prfile.c linux-5.4-aufs/mm/prfile.c +--- linux-5.4/mm/prfile.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-5.4-aufs/mm/prfile.c 2019-11-28 01:25:59.073925617 +0200 +@@ -0,0 +1,86 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Mainly for aufs which mmap(2) different file and wants to print different ++ * path in /proc/PID/maps. ++ * Call these functions via macros defined in linux/mm.h. ++ * ++ * See Documentation/filesystems/aufs/design/06mmap.txt ++ * ++ * Copyright (c) 2014-2019 Junjro R. Okajima ++ * Copyright (c) 2014 Ian Campbell ++ */ ++ ++#include ++#include ++#include ++ ++/* #define PRFILE_TRACE */ ++static inline void prfile_trace(struct file *f, struct file *pr, ++ const char func[], int line, const char func2[]) ++{ ++#ifdef PRFILE_TRACE ++ if (pr) ++ pr_info("%s:%d: %s, %pD2\n", func, line, func2, f); ++#endif ++} ++ ++void vma_do_file_update_time(struct vm_area_struct *vma, const char func[], ++ int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ file_update_time(f); ++ if (f && pr) ++ file_update_time(pr); ++} ++ ++struct file *vma_do_pr_or_file(struct vm_area_struct *vma, const char func[], ++ int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ return (f && pr) ? pr : f; ++} ++ ++void vma_do_get_file(struct vm_area_struct *vma, const char func[], int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ get_file(f); ++ if (f && pr) ++ get_file(pr); ++} ++ ++void vma_do_fput(struct vm_area_struct *vma, const char func[], int line) ++{ ++ struct file *f = vma->vm_file, *pr = vma->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ fput(f); ++ if (f && pr) ++ fput(pr); ++} ++ ++#ifndef CONFIG_MMU ++struct file *vmr_do_pr_or_file(struct vm_region *region, const char func[], ++ int line) ++{ ++ struct file *f = region->vm_file, *pr = region->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ return (f && pr) ? pr : f; ++} ++ ++void vmr_do_fput(struct vm_region *region, const char func[], int line) ++{ ++ struct file *f = region->vm_file, *pr = region->vm_prfile; ++ ++ prfile_trace(f, pr, func, line, __func__); ++ fput(f); ++ if (f && pr) ++ fput(pr); ++} ++#endif /* !CONFIG_MMU */ diff --git a/kernel/tools/perf/files/patches/mageia/fs-vboxsf.patch b/kernel/tools/perf/files/patches/mageia/fs-vboxsf.patch new file mode 100644 index 0000000000..434fdee6d6 --- /dev/null +++ b/kernel/tools/perf/files/patches/mageia/fs-vboxsf.patch @@ -0,0 +1,3410 @@ +From df4028658f9dd7f82fd190e9db5bd82c05f94625 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 28 Oct 2019 12:17:44 +0100 +Subject: staging: Add VirtualBox guest shared folder (vboxsf) support + +VirtualBox hosts can share folders with guests, this commit adds a +VFS driver implementing the Linux-guest side of this, allowing folders +exported by the host to be mounted under Linux. + +This driver depends on the guest <-> host IPC functions exported by +the vboxguest driver. + +Signed-off-by: Hans de Goede +Link: https://lore.kernel.org/r/20191028111744.143863-2-hdegoede@redhat.com +Signed-off-by: Greg Kroah-Hartman +--- + MAINTAINERS | 6 + + drivers/staging/Kconfig | 2 + + drivers/staging/Makefile | 1 + + drivers/staging/vboxsf/Kconfig | 10 + + drivers/staging/vboxsf/Makefile | 5 + + drivers/staging/vboxsf/TODO | 7 + + drivers/staging/vboxsf/dir.c | 418 ++++++++++++++ + drivers/staging/vboxsf/file.c | 370 +++++++++++++ + drivers/staging/vboxsf/shfl_hostintf.h | 901 +++++++++++++++++++++++++++++++ + drivers/staging/vboxsf/super.c | 499 +++++++++++++++++ + drivers/staging/vboxsf/utils.c | 550 +++++++++++++++++++ + drivers/staging/vboxsf/vboxsf_wrappers.c | 371 +++++++++++++ + drivers/staging/vboxsf/vfsmod.h | 138 +++++ + 13 files changed, 3278 insertions(+) + create mode 100644 drivers/staging/vboxsf/Kconfig + create mode 100644 drivers/staging/vboxsf/Makefile + create mode 100644 drivers/staging/vboxsf/TODO + create mode 100644 drivers/staging/vboxsf/dir.c + create mode 100644 drivers/staging/vboxsf/file.c + create mode 100644 drivers/staging/vboxsf/shfl_hostintf.h + create mode 100644 drivers/staging/vboxsf/super.c + create mode 100644 drivers/staging/vboxsf/utils.c + create mode 100644 drivers/staging/vboxsf/vboxsf_wrappers.c + create mode 100644 drivers/staging/vboxsf/vfsmod.h + +diff --git a/MAINTAINERS b/MAINTAINERS +index c6c34d04ce95..71789e42ed17 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -17335,6 +17335,12 @@ F: include/linux/vbox_utils.h + F: include/uapi/linux/vbox*.h + F: drivers/virt/vboxguest/ + ++VIRTUAL BOX SHARED FOLDER VFS DRIVER: ++M: Hans de Goede ++L: linux-fsdevel@vger.kernel.org ++S: Maintained ++F: drivers/staging/vboxsf/* ++ + VIRTUAL SERIO DEVICE DRIVER + M: Stephen Chandler Paul + S: Maintained +diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig +index 6f1fa4c849a1..927d29eb92c6 100644 +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -125,4 +125,6 @@ source "drivers/staging/exfat/Kconfig" + + source "drivers/staging/qlge/Kconfig" + ++source "drivers/staging/vboxsf/Kconfig" ++ + endif # STAGING +diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile +index a90f9b308c8d..f01f04199073 100644 +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -53,3 +53,4 @@ obj-$(CONFIG_UWB) += uwb/ + obj-$(CONFIG_USB_WUSB) += wusbcore/ + obj-$(CONFIG_EXFAT_FS) += exfat/ + obj-$(CONFIG_QLGE) += qlge/ ++obj-$(CONFIG_VBOXSF_FS) += vboxsf/ +diff --git a/drivers/staging/vboxsf/Kconfig b/drivers/staging/vboxsf/Kconfig +new file mode 100644 +index 000000000000..b84586ae08b3 +--- /dev/null ++++ b/drivers/staging/vboxsf/Kconfig +@@ -0,0 +1,10 @@ ++config VBOXSF_FS ++ tristate "VirtualBox guest shared folder (vboxsf) support" ++ depends on X86 && VBOXGUEST ++ select NLS ++ help ++ VirtualBox hosts can share folders with guests, this driver ++ implements the Linux-guest side of this allowing folders exported ++ by the host to be mounted under Linux. ++ ++ If you want to use shared folders in VirtualBox guests, answer Y or M. +diff --git a/drivers/staging/vboxsf/Makefile b/drivers/staging/vboxsf/Makefile +new file mode 100644 +index 000000000000..9e4328e79623 +--- /dev/null ++++ b/drivers/staging/vboxsf/Makefile +@@ -0,0 +1,5 @@ ++# SPDX-License-Identifier: MIT ++ ++obj-$(CONFIG_VBOXSF_FS) += vboxsf.o ++ ++vboxsf-y := dir.o file.o utils.o vboxsf_wrappers.o super.o +diff --git a/drivers/staging/vboxsf/TODO b/drivers/staging/vboxsf/TODO +new file mode 100644 +index 000000000000..8b9193d0d4f0 +--- /dev/null ++++ b/drivers/staging/vboxsf/TODO +@@ -0,0 +1,7 @@ ++TODO: ++- Find a file-system developer to review this and give their Reviewed-By ++- Address any items coming up during review ++- Move to fs/vboxfs ++ ++Please send any patches to Greg Kroah-Hartman ++and Hans de Goede +diff --git a/drivers/staging/vboxsf/dir.c b/drivers/staging/vboxsf/dir.c +new file mode 100644 +index 000000000000..f260b5cc1646 +--- /dev/null ++++ b/drivers/staging/vboxsf/dir.c +@@ -0,0 +1,418 @@ ++// SPDX-License-Identifier: MIT ++/* ++ * VirtualBox Guest Shared Folders support: Directory inode and file operations ++ * ++ * Copyright (C) 2006-2018 Oracle Corporation ++ */ ++ ++#include ++#include ++#include "vfsmod.h" ++ ++static int vboxsf_dir_open(struct inode *inode, struct file *file) ++{ ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(inode->i_sb); ++ struct shfl_createparms params = {}; ++ struct vboxsf_dir_info *sf_d; ++ int err; ++ ++ sf_d = vboxsf_dir_info_alloc(); ++ if (!sf_d) ++ return -ENOMEM; ++ ++ params.handle = SHFL_HANDLE_NIL; ++ params.create_flags = SHFL_CF_DIRECTORY | SHFL_CF_ACT_OPEN_IF_EXISTS | ++ SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACCESS_READ; ++ ++ err = vboxsf_create_at_dentry(file_dentry(file), ¶ms); ++ if (err) ++ goto err_free_dir_info; ++ ++ if (params.result != SHFL_FILE_EXISTS) { ++ err = -ENOENT; ++ goto err_close; ++ } ++ ++ err = vboxsf_dir_read_all(sbi, sf_d, params.handle); ++ if (err) ++ goto err_close; ++ ++ vboxsf_close(sbi->root, params.handle); ++ file->private_data = sf_d; ++ return 0; ++ ++err_close: ++ vboxsf_close(sbi->root, params.handle); ++err_free_dir_info: ++ vboxsf_dir_info_free(sf_d); ++ return err; ++} ++ ++static int vboxsf_dir_release(struct inode *inode, struct file *file) ++{ ++ if (file->private_data) ++ vboxsf_dir_info_free(file->private_data); ++ ++ return 0; ++} ++ ++static unsigned int vboxsf_get_d_type(u32 mode) ++{ ++ unsigned int d_type; ++ ++ switch (mode & SHFL_TYPE_MASK) { ++ case SHFL_TYPE_FIFO: ++ d_type = DT_FIFO; ++ break; ++ case SHFL_TYPE_DEV_CHAR: ++ d_type = DT_CHR; ++ break; ++ case SHFL_TYPE_DIRECTORY: ++ d_type = DT_DIR; ++ break; ++ case SHFL_TYPE_DEV_BLOCK: ++ d_type = DT_BLK; ++ break; ++ case SHFL_TYPE_FILE: ++ d_type = DT_REG; ++ break; ++ case SHFL_TYPE_SYMLINK: ++ d_type = DT_LNK; ++ break; ++ case SHFL_TYPE_SOCKET: ++ d_type = DT_SOCK; ++ break; ++ case SHFL_TYPE_WHITEOUT: ++ d_type = DT_WHT; ++ break; ++ default: ++ d_type = DT_UNKNOWN; ++ break; ++ } ++ return d_type; ++} ++ ++static bool vboxsf_dir_emit(struct file *dir, struct dir_context *ctx) ++{ ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(file_inode(dir)->i_sb); ++ struct vboxsf_dir_info *sf_d = dir->private_data; ++ struct shfl_dirinfo *info; ++ struct vboxsf_dir_buf *b; ++ unsigned int d_type; ++ loff_t i, cur = 0; ++ ino_t fake_ino; ++ size_t size; ++ int err; ++ ++ list_for_each_entry(b, &sf_d->info_list, head) { ++try_next_entry: ++ if (ctx->pos >= cur + b->entries) { ++ cur += b->entries; ++ continue; ++ } ++ ++ /* ++ * Note the vboxsf_dir_info objects we are iterating over here ++ * are variable sized, so the info pointer may end up being ++ * unaligned. This is how we get the data from the host. ++ * Since vboxsf is only supported on x86 machines this is not ++ * a problem. ++ */ ++ for (i = 0, info = b->buf; i < ctx->pos - cur; i++) { ++ size = offsetof(struct shfl_dirinfo, name.string) + ++ info->name.size; ++ info = (struct shfl_dirinfo *)((uintptr_t)info + size); ++ } ++ ++ /* Info now points to the right entry, emit it. */ ++ d_type = vboxsf_get_d_type(info->info.attr.mode); ++ ++ /* ++ * On 32 bit systems pos is 64 signed, while ino is 32 bit ++ * unsigned so fake_ino may overflow, check for this. ++ */ ++ if ((ino_t)(ctx->pos + 1) != (u64)(ctx->pos + 1)) { ++ vbg_err("vboxsf: fake ino overflow, truncating dir\n"); ++ return false; ++ } ++ fake_ino = ctx->pos + 1; ++ ++ if (sbi->nls) { ++ char d_name[NAME_MAX]; ++ ++ err = vboxsf_nlscpy(sbi, d_name, NAME_MAX, ++ info->name.string.utf8, ++ info->name.length); ++ if (err) { ++ /* skip erroneous entry and proceed */ ++ ctx->pos += 1; ++ goto try_next_entry; ++ } ++ ++ return dir_emit(ctx, d_name, strlen(d_name), ++ fake_ino, d_type); ++ } ++ ++ return dir_emit(ctx, info->name.string.utf8, info->name.length, ++ fake_ino, d_type); ++ } ++ ++ return false; ++} ++ ++static int vboxsf_dir_iterate(struct file *dir, struct dir_context *ctx) ++{ ++ bool keep_iterating; ++ ++ for (keep_iterating = true; keep_iterating; ctx->pos += 1) ++ keep_iterating = vboxsf_dir_emit(dir, ctx); ++ ++ return 0; ++} ++ ++const struct file_operations vboxsf_dir_fops = { ++ .open = vboxsf_dir_open, ++ .iterate = vboxsf_dir_iterate, ++ .release = vboxsf_dir_release, ++ .read = generic_read_dir, ++ .llseek = generic_file_llseek, ++}; ++ ++/* ++ * This is called during name resolution/lookup to check if the @dentry in ++ * the cache is still valid. the job is handled by vboxsf_inode_revalidate. ++ */ ++static int vboxsf_dentry_revalidate(struct dentry *dentry, unsigned int flags) ++{ ++ if (flags & LOOKUP_RCU) ++ return -ECHILD; ++ ++ if (d_really_is_positive(dentry)) ++ return vboxsf_inode_revalidate(dentry) == 0; ++ else ++ return vboxsf_stat_dentry(dentry, NULL) == -ENOENT; ++} ++ ++const struct dentry_operations vboxsf_dentry_ops = { ++ .d_revalidate = vboxsf_dentry_revalidate ++}; ++ ++/* iops */ ++ ++static struct dentry *vboxsf_dir_lookup(struct inode *parent, ++ struct dentry *dentry, ++ unsigned int flags) ++{ ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb); ++ struct shfl_fsobjinfo fsinfo; ++ struct inode *inode; ++ int err; ++ ++ dentry->d_time = jiffies; ++ ++ err = vboxsf_stat_dentry(dentry, &fsinfo); ++ if (err) { ++ inode = (err == -ENOENT) ? NULL : ERR_PTR(err); ++ } else { ++ inode = vboxsf_new_inode(parent->i_sb); ++ if (!IS_ERR(inode)) ++ vboxsf_init_inode(sbi, inode, &fsinfo); ++ } ++ ++ return d_splice_alias(inode, dentry); ++} ++ ++static int vboxsf_dir_instantiate(struct inode *parent, struct dentry *dentry, ++ struct shfl_fsobjinfo *info) ++{ ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb); ++ struct vboxsf_inode *sf_i; ++ struct inode *inode; ++ ++ inode = vboxsf_new_inode(parent->i_sb); ++ if (IS_ERR(inode)) ++ return PTR_ERR(inode); ++ ++ sf_i = VBOXSF_I(inode); ++ /* The host may have given us different attr then requested */ ++ sf_i->force_restat = 1; ++ vboxsf_init_inode(sbi, inode, info); ++ ++ d_instantiate(dentry, inode); ++ ++ return 0; ++} ++ ++static int vboxsf_dir_create(struct inode *parent, struct dentry *dentry, ++ umode_t mode, int is_dir) ++{ ++ struct vboxsf_inode *sf_parent_i = VBOXSF_I(parent); ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb); ++ struct shfl_createparms params = {}; ++ int err; ++ ++ params.handle = SHFL_HANDLE_NIL; ++ params.create_flags = SHFL_CF_ACT_CREATE_IF_NEW | ++ SHFL_CF_ACT_FAIL_IF_EXISTS | ++ SHFL_CF_ACCESS_READWRITE | ++ (is_dir ? SHFL_CF_DIRECTORY : 0); ++ params.info.attr.mode = (mode & 0777) | ++ (is_dir ? SHFL_TYPE_DIRECTORY : SHFL_TYPE_FILE); ++ params.info.attr.additional = SHFLFSOBJATTRADD_NOTHING; ++ ++ err = vboxsf_create_at_dentry(dentry, ¶ms); ++ if (err) ++ return err; ++ ++ if (params.result != SHFL_FILE_CREATED) ++ return -EPERM; ++ ++ vboxsf_close(sbi->root, params.handle); ++ ++ err = vboxsf_dir_instantiate(parent, dentry, ¶ms.info); ++ if (err) ++ return err; ++ ++ /* parent directory access/change time changed */ ++ sf_parent_i->force_restat = 1; ++ ++ return 0; ++} ++ ++static int vboxsf_dir_mkfile(struct inode *parent, struct dentry *dentry, ++ umode_t mode, bool excl) ++{ ++ return vboxsf_dir_create(parent, dentry, mode, 0); ++} ++ ++static int vboxsf_dir_mkdir(struct inode *parent, struct dentry *dentry, ++ umode_t mode) ++{ ++ return vboxsf_dir_create(parent, dentry, mode, 1); ++} ++ ++static int vboxsf_dir_unlink(struct inode *parent, struct dentry *dentry) ++{ ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb); ++ struct vboxsf_inode *sf_parent_i = VBOXSF_I(parent); ++ struct inode *inode = d_inode(dentry); ++ struct shfl_string *path; ++ u32 flags; ++ int err; ++ ++ if (S_ISDIR(inode->i_mode)) ++ flags = SHFL_REMOVE_DIR; ++ else ++ flags = SHFL_REMOVE_FILE; ++ ++ if (S_ISLNK(inode->i_mode)) ++ flags |= SHFL_REMOVE_SYMLINK; ++ ++ path = vboxsf_path_from_dentry(sbi, dentry); ++ if (IS_ERR(path)) ++ return PTR_ERR(path); ++ ++ err = vboxsf_remove(sbi->root, path, flags); ++ __putname(path); ++ if (err) ++ return err; ++ ++ /* parent directory access/change time changed */ ++ sf_parent_i->force_restat = 1; ++ ++ return 0; ++} ++ ++static int vboxsf_dir_rename(struct inode *old_parent, ++ struct dentry *old_dentry, ++ struct inode *new_parent, ++ struct dentry *new_dentry, ++ unsigned int flags) ++{ ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(old_parent->i_sb); ++ struct vboxsf_inode *sf_old_parent_i = VBOXSF_I(old_parent); ++ struct vboxsf_inode *sf_new_parent_i = VBOXSF_I(new_parent); ++ u32 shfl_flags = SHFL_RENAME_FILE | SHFL_RENAME_REPLACE_IF_EXISTS; ++ struct shfl_string *old_path, *new_path; ++ int err; ++ ++ if (flags) ++ return -EINVAL; ++ ++ old_path = vboxsf_path_from_dentry(sbi, old_dentry); ++ if (IS_ERR(old_path)) ++ return PTR_ERR(old_path); ++ ++ new_path = vboxsf_path_from_dentry(sbi, new_dentry); ++ if (IS_ERR(new_path)) { ++ err = PTR_ERR(new_path); ++ goto err_put_old_path; ++ } ++ ++ if (d_inode(old_dentry)->i_mode & S_IFDIR) ++ shfl_flags = 0; ++ ++ err = vboxsf_rename(sbi->root, old_path, new_path, shfl_flags); ++ if (err == 0) { ++ /* parent directories access/change time changed */ ++ sf_new_parent_i->force_restat = 1; ++ sf_old_parent_i->force_restat = 1; ++ } ++ ++ __putname(new_path); ++err_put_old_path: ++ __putname(old_path); ++ return err; ++} ++ ++static int vboxsf_dir_symlink(struct inode *parent, struct dentry *dentry, ++ const char *symname) ++{ ++ struct vboxsf_inode *sf_parent_i = VBOXSF_I(parent); ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(parent->i_sb); ++ int symname_size = strlen(symname) + 1; ++ struct shfl_string *path, *ssymname; ++ struct shfl_fsobjinfo info; ++ int err; ++ ++ path = vboxsf_path_from_dentry(sbi, dentry); ++ if (IS_ERR(path)) ++ return PTR_ERR(path); ++ ++ ssymname = kmalloc(SHFLSTRING_HEADER_SIZE + symname_size, GFP_KERNEL); ++ if (!ssymname) { ++ __putname(path); ++ return -ENOMEM; ++ } ++ ssymname->length = symname_size - 1; ++ ssymname->size = symname_size; ++ memcpy(ssymname->string.utf8, symname, symname_size); ++ ++ err = vboxsf_symlink(sbi->root, path, ssymname, &info); ++ kfree(ssymname); ++ __putname(path); ++ if (err) { ++ /* -EROFS means symlinks are note support -> -EPERM */ ++ return (err == -EROFS) ? -EPERM : err; ++ } ++ ++ err = vboxsf_dir_instantiate(parent, dentry, &info); ++ if (err) ++ return err; ++ ++ /* parent directory access/change time changed */ ++ sf_parent_i->force_restat = 1; ++ return 0; ++} ++ ++const struct inode_operations vboxsf_dir_iops = { ++ .lookup = vboxsf_dir_lookup, ++ .create = vboxsf_dir_mkfile, ++ .mkdir = vboxsf_dir_mkdir, ++ .rmdir = vboxsf_dir_unlink, ++ .unlink = vboxsf_dir_unlink, ++ .rename = vboxsf_dir_rename, ++ .symlink = vboxsf_dir_symlink, ++ .getattr = vboxsf_getattr, ++ .setattr = vboxsf_setattr, ++}; +diff --git a/drivers/staging/vboxsf/file.c b/drivers/staging/vboxsf/file.c +new file mode 100644 +index 000000000000..4b61ccf83fca +--- /dev/null ++++ b/drivers/staging/vboxsf/file.c +@@ -0,0 +1,370 @@ ++// SPDX-License-Identifier: MIT ++/* ++ * VirtualBox Guest Shared Folders support: Regular file inode and file ops. ++ * ++ * Copyright (C) 2006-2018 Oracle Corporation ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "vfsmod.h" ++ ++struct vboxsf_handle { ++ u64 handle; ++ u32 root; ++ u32 access_flags; ++ struct kref refcount; ++ struct list_head head; ++}; ++ ++static int vboxsf_file_open(struct inode *inode, struct file *file) ++{ ++ struct vboxsf_inode *sf_i = VBOXSF_I(inode); ++ struct shfl_createparms params = {}; ++ struct vboxsf_handle *sf_handle; ++ u32 access_flags = 0; ++ int err; ++ ++ sf_handle = kmalloc(sizeof(*sf_handle), GFP_KERNEL); ++ if (!sf_handle) ++ return -ENOMEM; ++ ++ /* ++ * We check the value of params.handle afterwards to find out if ++ * the call succeeded or failed, as the API does not seem to cleanly ++ * distinguish error and informational messages. ++ * ++ * Furthermore, we must set params.handle to SHFL_HANDLE_NIL to ++ * make the shared folders host service use our mode parameter. ++ */ ++ params.handle = SHFL_HANDLE_NIL; ++ if (file->f_flags & O_CREAT) { ++ params.create_flags |= SHFL_CF_ACT_CREATE_IF_NEW; ++ /* ++ * We ignore O_EXCL, as the Linux kernel seems to call create ++ * beforehand itself, so O_EXCL should always fail. ++ */ ++ if (file->f_flags & O_TRUNC) ++ params.create_flags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS; ++ else ++ params.create_flags |= SHFL_CF_ACT_OPEN_IF_EXISTS; ++ } else { ++ params.create_flags |= SHFL_CF_ACT_FAIL_IF_NEW; ++ if (file->f_flags & O_TRUNC) ++ params.create_flags |= SHFL_CF_ACT_OVERWRITE_IF_EXISTS; ++ } ++ ++ switch (file->f_flags & O_ACCMODE) { ++ case O_RDONLY: ++ access_flags |= SHFL_CF_ACCESS_READ; ++ break; ++ ++ case O_WRONLY: ++ access_flags |= SHFL_CF_ACCESS_WRITE; ++ break; ++ ++ case O_RDWR: ++ access_flags |= SHFL_CF_ACCESS_READWRITE; ++ break; ++ ++ default: ++ WARN_ON(1); ++ } ++ ++ if (file->f_flags & O_APPEND) ++ access_flags |= SHFL_CF_ACCESS_APPEND; ++ ++ params.create_flags |= access_flags; ++ params.info.attr.mode = inode->i_mode; ++ ++ err = vboxsf_create_at_dentry(file_dentry(file), ¶ms); ++ if (err == 0 && params.handle == SHFL_HANDLE_NIL) ++ err = (params.result == SHFL_FILE_EXISTS) ? -EEXIST : -ENOENT; ++ if (err) { ++ kfree(sf_handle); ++ return err; ++ } ++ ++ /* the host may have given us different attr then requested */ ++ sf_i->force_restat = 1; ++ ++ /* init our handle struct and add it to the inode's handles list */ ++ sf_handle->handle = params.handle; ++ sf_handle->root = VBOXSF_SBI(inode->i_sb)->root; ++ sf_handle->access_flags = access_flags; ++ kref_init(&sf_handle->refcount); ++ ++ mutex_lock(&sf_i->handle_list_mutex); ++ list_add(&sf_handle->head, &sf_i->handle_list); ++ mutex_unlock(&sf_i->handle_list_mutex); ++ ++ file->private_data = sf_handle; ++ return 0; ++} ++ ++static void vboxsf_handle_release(struct kref *refcount) ++{ ++ struct vboxsf_handle *sf_handle = ++ container_of(refcount, struct vboxsf_handle, refcount); ++ ++ vboxsf_close(sf_handle->root, sf_handle->handle); ++ kfree(sf_handle); ++} ++ ++static int vboxsf_file_release(struct inode *inode, struct file *file) ++{ ++ struct vboxsf_inode *sf_i = VBOXSF_I(inode); ++ struct vboxsf_handle *sf_handle = file->private_data; ++ ++ /* ++ * When a file is closed on our (the guest) side, we want any subsequent ++ * accesses done on the host side to see all changes done from our side. ++ */ ++ filemap_write_and_wait(inode->i_mapping); ++ ++ mutex_lock(&sf_i->handle_list_mutex); ++ list_del(&sf_handle->head); ++ mutex_unlock(&sf_i->handle_list_mutex); ++ ++ kref_put(&sf_handle->refcount, vboxsf_handle_release); ++ return 0; ++} ++ ++/* ++ * Write back dirty pages now, because there may not be any suitable ++ * open files later ++ */ ++static void vboxsf_vma_close(struct vm_area_struct *vma) ++{ ++ filemap_write_and_wait(vma->vm_file->f_mapping); ++} ++ ++static const struct vm_operations_struct vboxsf_file_vm_ops = { ++ .close = vboxsf_vma_close, ++ .fault = filemap_fault, ++ .map_pages = filemap_map_pages, ++}; ++ ++static int vboxsf_file_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ int err; ++ ++ err = generic_file_mmap(file, vma); ++ if (!err) ++ vma->vm_ops = &vboxsf_file_vm_ops; ++ ++ return err; ++} ++ ++/* ++ * Note that since we are accessing files on the host's filesystem, files ++ * may always be changed underneath us by the host! ++ * ++ * The vboxsf API between the guest and the host does not offer any functions ++ * to deal with this. There is no inode-generation to check for changes, no ++ * events / callback on changes and no way to lock files. ++ * ++ * To avoid returning stale data when a file gets *opened* on our (the guest) ++ * side, we do a "stat" on the host side, then compare the mtime with the ++ * last known mtime and invalidate the page-cache if they differ. ++ * This is done from vboxsf_inode_revalidate(). ++ * ++ * When reads are done through the read_iter fop, it is possible to do ++ * further cache revalidation then, there are 3 options to deal with this: ++ * ++ * 1) Rely solely on the revalidation done at open time ++ * 2) Do another "stat" and compare mtime again. Unfortunately the vboxsf ++ * host API does not allow stat on handles, so we would need to use ++ * file->f_path.dentry and the stat will then fail if the file was unlinked ++ * or renamed (and there is no thing like NFS' silly-rename). So we get: ++ * 2a) "stat" and compare mtime, on stat failure invalidate the cache ++ * 2b) "stat" and compare mtime, on stat failure do nothing ++ * 3) Simply always call invalidate_inode_pages2_range on the range of the read ++ * ++ * Currently we are keeping things KISS and using option 1. this allows ++ * directly using generic_file_read_iter without wrapping it. ++ * ++ * This means that only data written on the host side before open() on ++ * the guest side is guaranteed to be seen by the guest. If necessary ++ * we may provide other read-cache strategies in the future and make this ++ * configurable through a mount option. ++ */ ++const struct file_operations vboxsf_reg_fops = { ++ .llseek = generic_file_llseek, ++ .read_iter = generic_file_read_iter, ++ .write_iter = generic_file_write_iter, ++ .mmap = vboxsf_file_mmap, ++ .open = vboxsf_file_open, ++ .release = vboxsf_file_release, ++ .fsync = noop_fsync, ++ .splice_read = generic_file_splice_read, ++}; ++ ++const struct inode_operations vboxsf_reg_iops = { ++ .getattr = vboxsf_getattr, ++ .setattr = vboxsf_setattr ++}; ++ ++static int vboxsf_readpage(struct file *file, struct page *page) ++{ ++ struct vboxsf_handle *sf_handle = file->private_data; ++ loff_t off = page_offset(page); ++ u32 nread = PAGE_SIZE; ++ u8 *buf; ++ int err; ++ ++ buf = kmap(page); ++ ++ err = vboxsf_read(sf_handle->root, sf_handle->handle, off, &nread, buf); ++ if (err == 0) { ++ memset(&buf[nread], 0, PAGE_SIZE - nread); ++ flush_dcache_page(page); ++ SetPageUptodate(page); ++ } else { ++ SetPageError(page); ++ } ++ ++ kunmap(page); ++ unlock_page(page); ++ return err; ++} ++ ++static struct vboxsf_handle *vboxsf_get_write_handle(struct vboxsf_inode *sf_i) ++{ ++ struct vboxsf_handle *h, *sf_handle = NULL; ++ ++ mutex_lock(&sf_i->handle_list_mutex); ++ list_for_each_entry(h, &sf_i->handle_list, head) { ++ if (h->access_flags == SHFL_CF_ACCESS_WRITE || ++ h->access_flags == SHFL_CF_ACCESS_READWRITE) { ++ kref_get(&h->refcount); ++ sf_handle = h; ++ break; ++ } ++ } ++ mutex_unlock(&sf_i->handle_list_mutex); ++ ++ return sf_handle; ++} ++ ++static int vboxsf_writepage(struct page *page, struct writeback_control *wbc) ++{ ++ struct inode *inode = page->mapping->host; ++ struct vboxsf_inode *sf_i = VBOXSF_I(inode); ++ struct vboxsf_handle *sf_handle; ++ loff_t off = page_offset(page); ++ loff_t size = i_size_read(inode); ++ u32 nwrite = PAGE_SIZE; ++ u8 *buf; ++ int err; ++ ++ if (off + PAGE_SIZE > size) ++ nwrite = size & ~PAGE_MASK; ++ ++ sf_handle = vboxsf_get_write_handle(sf_i); ++ if (!sf_handle) ++ return -EBADF; ++ ++ buf = kmap(page); ++ err = vboxsf_write(sf_handle->root, sf_handle->handle, ++ off, &nwrite, buf); ++ kunmap(page); ++ ++ kref_put(&sf_handle->refcount, vboxsf_handle_release); ++ ++ if (err == 0) { ++ ClearPageError(page); ++ /* mtime changed */ ++ sf_i->force_restat = 1; ++ } else { ++ ClearPageUptodate(page); ++ } ++ ++ unlock_page(page); ++ return err; ++} ++ ++static int vboxsf_write_end(struct file *file, struct address_space *mapping, ++ loff_t pos, unsigned int len, unsigned int copied, ++ struct page *page, void *fsdata) ++{ ++ struct inode *inode = mapping->host; ++ struct vboxsf_handle *sf_handle = file->private_data; ++ unsigned int from = pos & ~PAGE_MASK; ++ u32 nwritten = len; ++ u8 *buf; ++ int err; ++ ++ buf = kmap(page); ++ err = vboxsf_write(sf_handle->root, sf_handle->handle, ++ pos, &nwritten, buf + from); ++ kunmap(page); ++ ++ if (err) { ++ nwritten = 0; ++ goto out; ++ } ++ ++ /* mtime changed */ ++ VBOXSF_I(inode)->force_restat = 1; ++ ++ if (!PageUptodate(page) && nwritten == PAGE_SIZE) ++ SetPageUptodate(page); ++ ++ pos += nwritten; ++ if (pos > inode->i_size) ++ i_size_write(inode, pos); ++ ++out: ++ unlock_page(page); ++ put_page(page); ++ ++ return nwritten; ++} ++ ++const struct address_space_operations vboxsf_reg_aops = { ++ .readpage = vboxsf_readpage, ++ .writepage = vboxsf_writepage, ++ .set_page_dirty = __set_page_dirty_nobuffers, ++ .write_begin = simple_write_begin, ++ .write_end = vboxsf_write_end, ++}; ++ ++static const char *vboxsf_get_link(struct dentry *dentry, struct inode *inode, ++ struct delayed_call *done) ++{ ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(inode->i_sb); ++ struct shfl_string *path; ++ char *link; ++ int err; ++ ++ if (!dentry) ++ return ERR_PTR(-ECHILD); ++ ++ path = vboxsf_path_from_dentry(sbi, dentry); ++ if (IS_ERR(path)) ++ return (char *)path; ++ ++ link = kzalloc(PATH_MAX, GFP_KERNEL); ++ if (!link) { ++ __putname(path); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ err = vboxsf_readlink(sbi->root, path, PATH_MAX, link); ++ __putname(path); ++ if (err) { ++ kfree(link); ++ return ERR_PTR(err); ++ } ++ ++ set_delayed_call(done, kfree_link, link); ++ return link; ++} ++ ++const struct inode_operations vboxsf_lnk_iops = { ++ .get_link = vboxsf_get_link ++}; +diff --git a/drivers/staging/vboxsf/shfl_hostintf.h b/drivers/staging/vboxsf/shfl_hostintf.h +new file mode 100644 +index 000000000000..aca829062c12 +--- /dev/null ++++ b/drivers/staging/vboxsf/shfl_hostintf.h +@@ -0,0 +1,901 @@ ++/* SPDX-License-Identifier: MIT */ ++/* ++ * VirtualBox Shared Folders: host interface definition. ++ * ++ * Copyright (C) 2006-2018 Oracle Corporation ++ */ ++ ++#ifndef SHFL_HOSTINTF_H ++#define SHFL_HOSTINTF_H ++ ++#include ++ ++/* The max in/out buffer size for a FN_READ or FN_WRITE call */ ++#define SHFL_MAX_RW_COUNT (16 * SZ_1M) ++ ++/* ++ * Structures shared between guest and the service ++ * can be relocated and use offsets to point to variable ++ * length parts. ++ * ++ * Shared folders protocol works with handles. ++ * Before doing any action on a file system object, ++ * one have to obtain the object handle via a SHFL_FN_CREATE ++ * request. A handle must be closed with SHFL_FN_CLOSE. ++ */ ++ ++enum { ++ SHFL_FN_QUERY_MAPPINGS = 1, /* Query mappings changes. */ ++ SHFL_FN_QUERY_MAP_NAME = 2, /* Query map name. */ ++ SHFL_FN_CREATE = 3, /* Open/create object. */ ++ SHFL_FN_CLOSE = 4, /* Close object handle. */ ++ SHFL_FN_READ = 5, /* Read object content. */ ++ SHFL_FN_WRITE = 6, /* Write new object content. */ ++ SHFL_FN_LOCK = 7, /* Lock/unlock a range in the object. */ ++ SHFL_FN_LIST = 8, /* List object content. */ ++ SHFL_FN_INFORMATION = 9, /* Query/set object information. */ ++ /* Note function number 10 is not used! */ ++ SHFL_FN_REMOVE = 11, /* Remove object */ ++ SHFL_FN_MAP_FOLDER_OLD = 12, /* Map folder (legacy) */ ++ SHFL_FN_UNMAP_FOLDER = 13, /* Unmap folder */ ++ SHFL_FN_RENAME = 14, /* Rename object */ ++ SHFL_FN_FLUSH = 15, /* Flush file */ ++ SHFL_FN_SET_UTF8 = 16, /* Select UTF8 filename encoding */ ++ SHFL_FN_MAP_FOLDER = 17, /* Map folder */ ++ SHFL_FN_READLINK = 18, /* Read symlink dest (as of VBox 4.0) */ ++ SHFL_FN_SYMLINK = 19, /* Create symlink (as of VBox 4.0) */ ++ SHFL_FN_SET_SYMLINKS = 20, /* Ask host to show symlinks (4.0+) */ ++}; ++ ++/* Root handles for a mapping are of type u32, Root handles are unique. */ ++#define SHFL_ROOT_NIL UINT_MAX ++ ++/* Shared folders handle for an opened object are of type u64. */ ++#define SHFL_HANDLE_NIL ULLONG_MAX ++ ++/* Hardcoded maximum length (in chars) of a shared folder name. */ ++#define SHFL_MAX_LEN (256) ++/* Hardcoded maximum number of shared folder mapping available to the guest. */ ++#define SHFL_MAX_MAPPINGS (64) ++ ++/** Shared folder string buffer structure. */ ++struct shfl_string { ++ /** Allocated size of the string member in bytes. */ ++ u16 size; ++ ++ /** Length of string without trailing nul in bytes. */ ++ u16 length; ++ ++ /** UTF-8 or UTF-16 string. Nul terminated. */ ++ union { ++ u8 utf8[2]; ++ u16 utf16[1]; ++ u16 ucs2[1]; /* misnomer, use utf16. */ ++ } string; ++}; ++VMMDEV_ASSERT_SIZE(shfl_string, 6); ++ ++/* The size of shfl_string w/o the string part. */ ++#define SHFLSTRING_HEADER_SIZE 4 ++ ++/* Calculate size of the string. */ ++static inline u32 shfl_string_buf_size(const struct shfl_string *string) ++{ ++ return string ? SHFLSTRING_HEADER_SIZE + string->size : 0; ++} ++ ++/* Set user id on execution (S_ISUID). */ ++#define SHFL_UNIX_ISUID 0004000U ++/* Set group id on execution (S_ISGID). */ ++#define SHFL_UNIX_ISGID 0002000U ++/* Sticky bit (S_ISVTX / S_ISTXT). */ ++#define SHFL_UNIX_ISTXT 0001000U ++ ++/* Owner readable (S_IRUSR). */ ++#define SHFL_UNIX_IRUSR 0000400U ++/* Owner writable (S_IWUSR). */ ++#define SHFL_UNIX_IWUSR 0000200U ++/* Owner executable (S_IXUSR). */ ++#define SHFL_UNIX_IXUSR 0000100U ++ ++/* Group readable (S_IRGRP). */ ++#define SHFL_UNIX_IRGRP 0000040U ++/* Group writable (S_IWGRP). */ ++#define SHFL_UNIX_IWGRP 0000020U ++/* Group executable (S_IXGRP). */ ++#define SHFL_UNIX_IXGRP 0000010U ++ ++/* Other readable (S_IROTH). */ ++#define SHFL_UNIX_IROTH 0000004U ++/* Other writable (S_IWOTH). */ ++#define SHFL_UNIX_IWOTH 0000002U ++/* Other executable (S_IXOTH). */ ++#define SHFL_UNIX_IXOTH 0000001U ++ ++/* Named pipe (fifo) (S_IFIFO). */ ++#define SHFL_TYPE_FIFO 0010000U ++/* Character device (S_IFCHR). */ ++#define SHFL_TYPE_DEV_CHAR 0020000U ++/* Directory (S_IFDIR). */ ++#define SHFL_TYPE_DIRECTORY 0040000U ++/* Block device (S_IFBLK). */ ++#define SHFL_TYPE_DEV_BLOCK 0060000U ++/* Regular file (S_IFREG). */ ++#define SHFL_TYPE_FILE 0100000U ++/* Symbolic link (S_IFLNK). */ ++#define SHFL_TYPE_SYMLINK 0120000U ++/* Socket (S_IFSOCK). */ ++#define SHFL_TYPE_SOCKET 0140000U ++/* Whiteout (S_IFWHT). */ ++#define SHFL_TYPE_WHITEOUT 0160000U ++/* Type mask (S_IFMT). */ ++#define SHFL_TYPE_MASK 0170000U ++ ++/* Checks the mode flags indicate a directory (S_ISDIR). */ ++#define SHFL_IS_DIRECTORY(m) (((m) & SHFL_TYPE_MASK) == SHFL_TYPE_DIRECTORY) ++/* Checks the mode flags indicate a symbolic link (S_ISLNK). */ ++#define SHFL_IS_SYMLINK(m) (((m) & SHFL_TYPE_MASK) == SHFL_TYPE_SYMLINK) ++ ++/** The available additional information in a shfl_fsobjattr object. */ ++enum shfl_fsobjattr_add { ++ /** No additional information is available / requested. */ ++ SHFLFSOBJATTRADD_NOTHING = 1, ++ /** ++ * The additional unix attributes (shfl_fsobjattr::u::unix_attr) are ++ * available / requested. ++ */ ++ SHFLFSOBJATTRADD_UNIX, ++ /** ++ * The additional extended attribute size (shfl_fsobjattr::u::size) is ++ * available / requested. ++ */ ++ SHFLFSOBJATTRADD_EASIZE, ++ /** ++ * The last valid item (inclusive). ++ * The valid range is SHFLFSOBJATTRADD_NOTHING thru ++ * SHFLFSOBJATTRADD_LAST. ++ */ ++ SHFLFSOBJATTRADD_LAST = SHFLFSOBJATTRADD_EASIZE, ++ ++ /** The usual 32-bit hack. */ ++ SHFLFSOBJATTRADD_32BIT_SIZE_HACK = 0x7fffffff ++}; ++ ++/** ++ * Additional unix Attributes, these are available when ++ * shfl_fsobjattr.additional == SHFLFSOBJATTRADD_UNIX. ++ */ ++struct shfl_fsobjattr_unix { ++ /** ++ * The user owning the filesystem object (st_uid). ++ * This field is ~0U if not supported. ++ */ ++ u32 uid; ++ ++ /** ++ * The group the filesystem object is assigned (st_gid). ++ * This field is ~0U if not supported. ++ */ ++ u32 gid; ++ ++ /** ++ * Number of hard links to this filesystem object (st_nlink). ++ * This field is 1 if the filesystem doesn't support hardlinking or ++ * the information isn't available. ++ */ ++ u32 hardlinks; ++ ++ /** ++ * The device number of the device which this filesystem object resides ++ * on (st_dev). This field is 0 if this information is not available. ++ */ ++ u32 inode_id_device; ++ ++ /** ++ * The unique identifier (within the filesystem) of this filesystem ++ * object (st_ino). Together with inode_id_device, this field can be ++ * used as a OS wide unique id, when both their values are not 0. ++ * This field is 0 if the information is not available. ++ */ ++ u64 inode_id; ++ ++ /** ++ * User flags (st_flags). ++ * This field is 0 if this information is not available. ++ */ ++ u32 flags; ++ ++ /** ++ * The current generation number (st_gen). ++ * This field is 0 if this information is not available. ++ */ ++ u32 generation_id; ++ ++ /** ++ * The device number of a char. or block device type object (st_rdev). ++ * This field is 0 if the file isn't a char. or block device or when ++ * the OS doesn't use the major+minor device idenfication scheme. ++ */ ++ u32 device; ++} __packed; ++ ++/** Extended attribute size. */ ++struct shfl_fsobjattr_easize { ++ /** Size of EAs. */ ++ s64 cb; ++} __packed; ++ ++/** Shared folder filesystem object attributes. */ ++struct shfl_fsobjattr { ++ /** Mode flags (st_mode). SHFL_UNIX_*, SHFL_TYPE_*, and SHFL_DOS_*. */ ++ u32 mode; ++ ++ /** The additional attributes available. */ ++ enum shfl_fsobjattr_add additional; ++ ++ /** ++ * Additional attributes. ++ * ++ * Unless explicitly specified to an API, the API can provide additional ++ * data as it is provided by the underlying OS. ++ */ ++ union { ++ struct shfl_fsobjattr_unix unix_attr; ++ struct shfl_fsobjattr_easize size; ++ } __packed u; ++} __packed; ++VMMDEV_ASSERT_SIZE(shfl_fsobjattr, 44); ++ ++struct shfl_timespec { ++ s64 ns_relative_to_unix_epoch; ++}; ++ ++/** Filesystem object information structure. */ ++struct shfl_fsobjinfo { ++ /** ++ * Logical size (st_size). ++ * For normal files this is the size of the file. ++ * For symbolic links, this is the length of the path name contained ++ * in the symbolic link. ++ * For other objects this fields needs to be specified. ++ */ ++ s64 size; ++ ++ /** Disk allocation size (st_blocks * DEV_BSIZE). */ ++ s64 allocated; ++ ++ /** Time of last access (st_atime). */ ++ struct shfl_timespec access_time; ++ ++ /** Time of last data modification (st_mtime). */ ++ struct shfl_timespec modification_time; ++ ++ /** ++ * Time of last status change (st_ctime). ++ * If not available this is set to modification_time. ++ */ ++ struct shfl_timespec change_time; ++ ++ /** ++ * Time of file birth (st_birthtime). ++ * If not available this is set to change_time. ++ */ ++ struct shfl_timespec birth_time; ++ ++ /** Attributes. */ ++ struct shfl_fsobjattr attr; ++ ++} __packed; ++VMMDEV_ASSERT_SIZE(shfl_fsobjinfo, 92); ++ ++/** ++ * result of an open/create request. ++ * Along with handle value the result code ++ * identifies what has happened while ++ * trying to open the object. ++ */ ++enum shfl_create_result { ++ SHFL_NO_RESULT, ++ /** Specified path does not exist. */ ++ SHFL_PATH_NOT_FOUND, ++ /** Path to file exists, but the last component does not. */ ++ SHFL_FILE_NOT_FOUND, ++ /** File already exists and either has been opened or not. */ ++ SHFL_FILE_EXISTS, ++ /** New file was created. */ ++ SHFL_FILE_CREATED, ++ /** Existing file was replaced or overwritten. */ ++ SHFL_FILE_REPLACED ++}; ++ ++/* No flags. Initialization value. */ ++#define SHFL_CF_NONE (0x00000000) ++ ++/* ++ * Only lookup the object, do not return a handle. When this is set all other ++ * flags are ignored. ++ */ ++#define SHFL_CF_LOOKUP (0x00000001) ++ ++/* ++ * Open parent directory of specified object. ++ * Useful for the corresponding Windows FSD flag ++ * and for opening paths like \\dir\\*.* to search the 'dir'. ++ */ ++#define SHFL_CF_OPEN_TARGET_DIRECTORY (0x00000002) ++ ++/* Create/open a directory. */ ++#define SHFL_CF_DIRECTORY (0x00000004) ++ ++/* ++ * Open/create action to do if object exists ++ * and if the object does not exists. ++ * REPLACE file means atomically DELETE and CREATE. ++ * OVERWRITE file means truncating the file to 0 and ++ * setting new size. ++ * When opening an existing directory REPLACE and OVERWRITE ++ * actions are considered invalid, and cause returning ++ * FILE_EXISTS with NIL handle. ++ */ ++#define SHFL_CF_ACT_MASK_IF_EXISTS (0x000000f0) ++#define SHFL_CF_ACT_MASK_IF_NEW (0x00000f00) ++ ++/* What to do if object exists. */ ++#define SHFL_CF_ACT_OPEN_IF_EXISTS (0x00000000) ++#define SHFL_CF_ACT_FAIL_IF_EXISTS (0x00000010) ++#define SHFL_CF_ACT_REPLACE_IF_EXISTS (0x00000020) ++#define SHFL_CF_ACT_OVERWRITE_IF_EXISTS (0x00000030) ++ ++/* What to do if object does not exist. */ ++#define SHFL_CF_ACT_CREATE_IF_NEW (0x00000000) ++#define SHFL_CF_ACT_FAIL_IF_NEW (0x00000100) ++ ++/* Read/write requested access for the object. */ ++#define SHFL_CF_ACCESS_MASK_RW (0x00003000) ++ ++/* No access requested. */ ++#define SHFL_CF_ACCESS_NONE (0x00000000) ++/* Read access requested. */ ++#define SHFL_CF_ACCESS_READ (0x00001000) ++/* Write access requested. */ ++#define SHFL_CF_ACCESS_WRITE (0x00002000) ++/* Read/Write access requested. */ ++#define SHFL_CF_ACCESS_READWRITE (0x00003000) ++ ++/* Requested share access for the object. */ ++#define SHFL_CF_ACCESS_MASK_DENY (0x0000c000) ++ ++/* Allow any access. */ ++#define SHFL_CF_ACCESS_DENYNONE (0x00000000) ++/* Do not allow read. */ ++#define SHFL_CF_ACCESS_DENYREAD (0x00004000) ++/* Do not allow write. */ ++#define SHFL_CF_ACCESS_DENYWRITE (0x00008000) ++/* Do not allow access. */ ++#define SHFL_CF_ACCESS_DENYALL (0x0000c000) ++ ++/* Requested access to attributes of the object. */ ++#define SHFL_CF_ACCESS_MASK_ATTR (0x00030000) ++ ++/* No access requested. */ ++#define SHFL_CF_ACCESS_ATTR_NONE (0x00000000) ++/* Read access requested. */ ++#define SHFL_CF_ACCESS_ATTR_READ (0x00010000) ++/* Write access requested. */ ++#define SHFL_CF_ACCESS_ATTR_WRITE (0x00020000) ++/* Read/Write access requested. */ ++#define SHFL_CF_ACCESS_ATTR_READWRITE (0x00030000) ++ ++/* ++ * The file is opened in append mode. ++ * Ignored if SHFL_CF_ACCESS_WRITE is not set. ++ */ ++#define SHFL_CF_ACCESS_APPEND (0x00040000) ++ ++/** Create parameters buffer struct for SHFL_FN_CREATE call */ ++struct shfl_createparms { ++ /** Returned handle of opened object. */ ++ u64 handle; ++ ++ /** Returned result of the operation */ ++ enum shfl_create_result result; ++ ++ /** SHFL_CF_* */ ++ u32 create_flags; ++ ++ /** ++ * Attributes of object to create and ++ * returned actual attributes of opened/created object. ++ */ ++ struct shfl_fsobjinfo info; ++} __packed; ++ ++/** Shared Folder directory information */ ++struct shfl_dirinfo { ++ /** Full information about the object. */ ++ struct shfl_fsobjinfo info; ++ /** ++ * The length of the short field (number of UTF16 chars). ++ * It is 16-bit for reasons of alignment. ++ */ ++ u16 short_name_len; ++ /** ++ * The short name for 8.3 compatibility. ++ * Empty string if not available. ++ */ ++ u16 short_name[14]; ++ struct shfl_string name; ++}; ++ ++/** Shared folder filesystem properties. */ ++struct shfl_fsproperties { ++ /** ++ * The maximum size of a filesystem object name. ++ * This does not include the '\\0'. ++ */ ++ u32 max_component_len; ++ ++ /** ++ * True if the filesystem is remote. ++ * False if the filesystem is local. ++ */ ++ bool remote; ++ ++ /** ++ * True if the filesystem is case sensitive. ++ * False if the filesystem is case insensitive. ++ */ ++ bool case_sensitive; ++ ++ /** ++ * True if the filesystem is mounted read only. ++ * False if the filesystem is mounted read write. ++ */ ++ bool read_only; ++ ++ /** ++ * True if the filesystem can encode unicode object names. ++ * False if it can't. ++ */ ++ bool supports_unicode; ++ ++ /** ++ * True if the filesystem is compresses. ++ * False if it isn't or we don't know. ++ */ ++ bool compressed; ++ ++ /** ++ * True if the filesystem compresses of individual files. ++ * False if it doesn't or we don't know. ++ */ ++ bool file_compression; ++}; ++VMMDEV_ASSERT_SIZE(shfl_fsproperties, 12); ++ ++struct shfl_volinfo { ++ s64 total_allocation_bytes; ++ s64 available_allocation_bytes; ++ u32 bytes_per_allocation_unit; ++ u32 bytes_per_sector; ++ u32 serial; ++ struct shfl_fsproperties properties; ++}; ++ ++ ++/** SHFL_FN_MAP_FOLDER Parameters structure. */ ++struct shfl_map_folder { ++ /** ++ * pointer, in: ++ * Points to struct shfl_string buffer. ++ */ ++ struct vmmdev_hgcm_function_parameter path; ++ ++ /** ++ * pointer, out: SHFLROOT (u32) ++ * Root handle of the mapping which name is queried. ++ */ ++ struct vmmdev_hgcm_function_parameter root; ++ ++ /** ++ * pointer, in: UTF16 ++ * Path delimiter ++ */ ++ struct vmmdev_hgcm_function_parameter delimiter; ++ ++ /** ++ * pointer, in: SHFLROOT (u32) ++ * Case senstive flag ++ */ ++ struct vmmdev_hgcm_function_parameter case_sensitive; ++ ++}; ++ ++/* Number of parameters */ ++#define SHFL_CPARMS_MAP_FOLDER (4) ++ ++ ++/** SHFL_FN_UNMAP_FOLDER Parameters structure. */ ++struct shfl_unmap_folder { ++ /** ++ * pointer, in: SHFLROOT (u32) ++ * Root handle of the mapping which name is queried. ++ */ ++ struct vmmdev_hgcm_function_parameter root; ++ ++}; ++ ++/* Number of parameters */ ++#define SHFL_CPARMS_UNMAP_FOLDER (1) ++ ++ ++/** SHFL_FN_CREATE Parameters structure. */ ++struct shfl_create { ++ /** ++ * pointer, in: SHFLROOT (u32) ++ * Root handle of the mapping which name is queried. ++ */ ++ struct vmmdev_hgcm_function_parameter root; ++ ++ /** ++ * pointer, in: ++ * Points to struct shfl_string buffer. ++ */ ++ struct vmmdev_hgcm_function_parameter path; ++ ++ /** ++ * pointer, in/out: ++ * Points to struct shfl_createparms buffer. ++ */ ++ struct vmmdev_hgcm_function_parameter parms; ++ ++}; ++ ++/* Number of parameters */ ++#define SHFL_CPARMS_CREATE (3) ++ ++ ++/** SHFL_FN_CLOSE Parameters structure. */ ++struct shfl_close { ++ /** ++ * pointer, in: SHFLROOT (u32) ++ * Root handle of the mapping which name is queried. ++ */ ++ struct vmmdev_hgcm_function_parameter root; ++ ++ /** ++ * value64, in: ++ * SHFLHANDLE (u64) of object to close. ++ */ ++ struct vmmdev_hgcm_function_parameter handle; ++ ++}; ++ ++/* Number of parameters */ ++#define SHFL_CPARMS_CLOSE (2) ++ ++ ++/** SHFL_FN_READ Parameters structure. */ ++struct shfl_read { ++ /** ++ * pointer, in: SHFLROOT (u32) ++ * Root handle of the mapping which name is queried. ++ */ ++ struct vmmdev_hgcm_function_parameter root; ++ ++ /** ++ * value64, in: ++ * SHFLHANDLE (u64) of object to read from. ++ */ ++ struct vmmdev_hgcm_function_parameter handle; ++ ++ /** ++ * value64, in: ++ * Offset to read from. ++ */ ++ struct vmmdev_hgcm_function_parameter offset; ++ ++ /** ++ * value64, in/out: ++ * Bytes to read/How many were read. ++ */ ++ struct vmmdev_hgcm_function_parameter cb; ++ ++ /** ++ * pointer, out: ++ * Buffer to place data to. ++ */ ++ struct vmmdev_hgcm_function_parameter buffer; ++ ++}; ++ ++/* Number of parameters */ ++#define SHFL_CPARMS_READ (5) ++ ++ ++/** SHFL_FN_WRITE Parameters structure. */ ++struct shfl_write { ++ /** ++ * pointer, in: SHFLROOT (u32) ++ * Root handle of the mapping which name is queried. ++ */ ++ struct vmmdev_hgcm_function_parameter root; ++ ++ /** ++ * value64, in: ++ * SHFLHANDLE (u64) of object to write to. ++ */ ++ struct vmmdev_hgcm_function_parameter handle; ++ ++ /** ++ * value64, in: ++ * Offset to write to. ++ */ ++ struct vmmdev_hgcm_function_parameter offset; ++ ++ /** ++ * value64, in/out: ++ * Bytes to write/How many were written. ++ */ ++ struct vmmdev_hgcm_function_parameter cb; ++ ++ /** ++ * pointer, in: ++ * Data to write. ++ */ ++ struct vmmdev_hgcm_function_parameter buffer; ++ ++}; ++ ++/* Number of parameters */ ++#define SHFL_CPARMS_WRITE (5) ++ ++ ++/* ++ * SHFL_FN_LIST ++ * Listing information includes variable length RTDIRENTRY[EX] structures. ++ */ ++ ++#define SHFL_LIST_NONE 0 ++#define SHFL_LIST_RETURN_ONE 1 ++ ++/** SHFL_FN_LIST Parameters structure. */ ++struct shfl_list { ++ /** ++ * pointer, in: SHFLROOT (u32) ++ * Root handle of the mapping which name is queried. ++ */ ++ struct vmmdev_hgcm_function_parameter root; ++ ++ /** ++ * value64, in: ++ * SHFLHANDLE (u64) of object to be listed. ++ */ ++ struct vmmdev_hgcm_function_parameter handle; ++ ++ /** ++ * value32, in: ++ * List flags SHFL_LIST_*. ++ */ ++ struct vmmdev_hgcm_function_parameter flags; ++ ++ /** ++ * value32, in/out: ++ * Bytes to be used for listing information/How many bytes were used. ++ */ ++ struct vmmdev_hgcm_function_parameter cb; ++ ++ /** ++ * pointer, in/optional ++ * Points to struct shfl_string buffer that specifies a search path. ++ */ ++ struct vmmdev_hgcm_function_parameter path; ++ ++ /** ++ * pointer, out: ++ * Buffer to place listing information to. (struct shfl_dirinfo) ++ */ ++ struct vmmdev_hgcm_function_parameter buffer; ++ ++ /** ++ * value32, in/out: ++ * Indicates a key where the listing must be resumed. ++ * in: 0 means start from begin of object. ++ * out: 0 means listing completed. ++ */ ++ struct vmmdev_hgcm_function_parameter resume_point; ++ ++ /** ++ * pointer, out: ++ * Number of files returned ++ */ ++ struct vmmdev_hgcm_function_parameter file_count; ++}; ++ ++/* Number of parameters */ ++#define SHFL_CPARMS_LIST (8) ++ ++ ++/** SHFL_FN_READLINK Parameters structure. */ ++struct shfl_readLink { ++ /** ++ * pointer, in: SHFLROOT (u32) ++ * Root handle of the mapping which name is queried. ++ */ ++ struct vmmdev_hgcm_function_parameter root; ++ ++ /** ++ * pointer, in: ++ * Points to struct shfl_string buffer. ++ */ ++ struct vmmdev_hgcm_function_parameter path; ++ ++ /** ++ * pointer, out: ++ * Buffer to place data to. ++ */ ++ struct vmmdev_hgcm_function_parameter buffer; ++ ++}; ++ ++/* Number of parameters */ ++#define SHFL_CPARMS_READLINK (3) ++ ++ ++/* SHFL_FN_INFORMATION */ ++ ++/* Mask of Set/Get bit. */ ++#define SHFL_INFO_MODE_MASK (0x1) ++/* Get information */ ++#define SHFL_INFO_GET (0x0) ++/* Set information */ ++#define SHFL_INFO_SET (0x1) ++ ++/* Get name of the object. */ ++#define SHFL_INFO_NAME (0x2) ++/* Set size of object (extend/trucate); only applies to file objects */ ++#define SHFL_INFO_SIZE (0x4) ++/* Get/Set file object info. */ ++#define SHFL_INFO_FILE (0x8) ++/* Get volume information. */ ++#define SHFL_INFO_VOLUME (0x10) ++ ++/** SHFL_FN_INFORMATION Parameters structure. */ ++struct shfl_information { ++ /** ++ * pointer, in: SHFLROOT (u32) ++ * Root handle of the mapping which name is queried. ++ */ ++ struct vmmdev_hgcm_function_parameter root; ++ ++ /** ++ * value64, in: ++ * SHFLHANDLE (u64) of object to be listed. ++ */ ++ struct vmmdev_hgcm_function_parameter handle; ++ ++ /** ++ * value32, in: ++ * SHFL_INFO_* ++ */ ++ struct vmmdev_hgcm_function_parameter flags; ++ ++ /** ++ * value32, in/out: ++ * Bytes to be used for information/How many bytes were used. ++ */ ++ struct vmmdev_hgcm_function_parameter cb; ++ ++ /** ++ * pointer, in/out: ++ * Information to be set/get (shfl_fsobjinfo or shfl_string). Do not ++ * forget to set the shfl_fsobjinfo::attr::additional for a get ++ * operation as well. ++ */ ++ struct vmmdev_hgcm_function_parameter info; ++ ++}; ++ ++/* Number of parameters */ ++#define SHFL_CPARMS_INFORMATION (5) ++ ++ ++/* SHFL_FN_REMOVE */ ++ ++#define SHFL_REMOVE_FILE (0x1) ++#define SHFL_REMOVE_DIR (0x2) ++#define SHFL_REMOVE_SYMLINK (0x4) ++ ++/** SHFL_FN_REMOVE Parameters structure. */ ++struct shfl_remove { ++ /** ++ * pointer, in: SHFLROOT (u32) ++ * Root handle of the mapping which name is queried. ++ */ ++ struct vmmdev_hgcm_function_parameter root; ++ ++ /** ++ * pointer, in: ++ * Points to struct shfl_string buffer. ++ */ ++ struct vmmdev_hgcm_function_parameter path; ++ ++ /** ++ * value32, in: ++ * remove flags (file/directory) ++ */ ++ struct vmmdev_hgcm_function_parameter flags; ++ ++}; ++ ++#define SHFL_CPARMS_REMOVE (3) ++ ++ ++/* SHFL_FN_RENAME */ ++ ++#define SHFL_RENAME_FILE (0x1) ++#define SHFL_RENAME_DIR (0x2) ++#define SHFL_RENAME_REPLACE_IF_EXISTS (0x4) ++ ++/** SHFL_FN_RENAME Parameters structure. */ ++struct shfl_rename { ++ /** ++ * pointer, in: SHFLROOT (u32) ++ * Root handle of the mapping which name is queried. ++ */ ++ struct vmmdev_hgcm_function_parameter root; ++ ++ /** ++ * pointer, in: ++ * Points to struct shfl_string src. ++ */ ++ struct vmmdev_hgcm_function_parameter src; ++ ++ /** ++ * pointer, in: ++ * Points to struct shfl_string dest. ++ */ ++ struct vmmdev_hgcm_function_parameter dest; ++ ++ /** ++ * value32, in: ++ * rename flags (file/directory) ++ */ ++ struct vmmdev_hgcm_function_parameter flags; ++ ++}; ++ ++#define SHFL_CPARMS_RENAME (4) ++ ++ ++/** SHFL_FN_SYMLINK Parameters structure. */ ++struct shfl_symlink { ++ /** ++ * pointer, in: SHFLROOT (u32) ++ * Root handle of the mapping which name is queried. ++ */ ++ struct vmmdev_hgcm_function_parameter root; ++ ++ /** ++ * pointer, in: ++ * Points to struct shfl_string of path for the new symlink. ++ */ ++ struct vmmdev_hgcm_function_parameter new_path; ++ ++ /** ++ * pointer, in: ++ * Points to struct shfl_string of destination for symlink. ++ */ ++ struct vmmdev_hgcm_function_parameter old_path; ++ ++ /** ++ * pointer, out: ++ * Information about created symlink. ++ */ ++ struct vmmdev_hgcm_function_parameter info; ++ ++}; ++ ++#define SHFL_CPARMS_SYMLINK (4) ++ ++#endif +diff --git a/drivers/staging/vboxsf/super.c b/drivers/staging/vboxsf/super.c +new file mode 100644 +index 000000000000..3913ffafa83b +--- /dev/null ++++ b/drivers/staging/vboxsf/super.c +@@ -0,0 +1,499 @@ ++// SPDX-License-Identifier: MIT ++/* ++ * VirtualBox Guest Shared Folders support: Virtual File System. ++ * ++ * Module initialization/finalization ++ * File system registration/deregistration ++ * Superblock reading ++ * Few utility functions ++ * ++ * Copyright (C) 2006-2018 Oracle Corporation ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "vfsmod.h" ++ ++#define VBOXSF_SUPER_MAGIC 0x786f4256 /* 'VBox' little endian */ ++ ++#define VBSF_MOUNT_SIGNATURE_BYTE_0 ('\000') ++#define VBSF_MOUNT_SIGNATURE_BYTE_1 ('\377') ++#define VBSF_MOUNT_SIGNATURE_BYTE_2 ('\376') ++#define VBSF_MOUNT_SIGNATURE_BYTE_3 ('\375') ++ ++static int follow_symlinks; ++module_param(follow_symlinks, int, 0444); ++MODULE_PARM_DESC(follow_symlinks, ++ "Let host resolve symlinks rather than showing them"); ++ ++static DEFINE_IDA(vboxsf_bdi_ida); ++static DEFINE_MUTEX(vboxsf_setup_mutex); ++static bool vboxsf_setup_done; ++static struct super_operations vboxsf_super_ops; /* forward declaration */ ++static struct kmem_cache *vboxsf_inode_cachep; ++ ++static char * const vboxsf_default_nls = CONFIG_NLS_DEFAULT; ++ ++enum { opt_nls, opt_uid, opt_gid, opt_ttl, opt_dmode, opt_fmode, ++ opt_dmask, opt_fmask }; ++ ++static const struct fs_parameter_spec vboxsf_param_specs[] = { ++ fsparam_string ("nls", opt_nls), ++ fsparam_u32 ("uid", opt_uid), ++ fsparam_u32 ("gid", opt_gid), ++ fsparam_u32 ("ttl", opt_ttl), ++ fsparam_u32oct ("dmode", opt_dmode), ++ fsparam_u32oct ("fmode", opt_fmode), ++ fsparam_u32oct ("dmask", opt_dmask), ++ fsparam_u32oct ("fmask", opt_fmask), ++ {} ++}; ++ ++static const struct fs_parameter_description vboxsf_fs_parameters = { ++ .name = "vboxsf", ++ .specs = vboxsf_param_specs, ++}; ++ ++static int vboxsf_parse_param(struct fs_context *fc, struct fs_parameter *param) ++{ ++ struct vboxsf_fs_context *ctx = fc->fs_private; ++ struct fs_parse_result result; ++ kuid_t uid; ++ kgid_t gid; ++ int opt; ++ ++ opt = fs_parse(fc, &vboxsf_fs_parameters, param, &result); ++ if (opt < 0) ++ return opt; ++ ++ switch (opt) { ++ case opt_nls: ++ if (fc->purpose != FS_CONTEXT_FOR_MOUNT) { ++ vbg_err("vboxsf: Cannot reconfigure nls option\n"); ++ return -EINVAL; ++ } ++ ctx->nls_name = param->string; ++ param->string = NULL; ++ break; ++ case opt_uid: ++ uid = make_kuid(current_user_ns(), result.uint_32); ++ if (!uid_valid(uid)) ++ return -EINVAL; ++ ctx->o.uid = uid; ++ break; ++ case opt_gid: ++ gid = make_kgid(current_user_ns(), result.uint_32); ++ if (!gid_valid(gid)) ++ return -EINVAL; ++ ctx->o.gid = gid; ++ break; ++ case opt_ttl: ++ ctx->o.ttl = msecs_to_jiffies(result.uint_32); ++ break; ++ case opt_dmode: ++ if (result.uint_32 & ~0777) ++ return -EINVAL; ++ ctx->o.dmode = result.uint_32; ++ ctx->o.dmode_set = true; ++ break; ++ case opt_fmode: ++ if (result.uint_32 & ~0777) ++ return -EINVAL; ++ ctx->o.fmode = result.uint_32; ++ ctx->o.fmode_set = true; ++ break; ++ case opt_dmask: ++ if (result.uint_32 & ~07777) ++ return -EINVAL; ++ ctx->o.dmask = result.uint_32; ++ break; ++ case opt_fmask: ++ if (result.uint_32 & ~07777) ++ return -EINVAL; ++ ctx->o.fmask = result.uint_32; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int vboxsf_fill_super(struct super_block *sb, struct fs_context *fc) ++{ ++ struct vboxsf_fs_context *ctx = fc->fs_private; ++ struct shfl_string *folder_name, root_path; ++ struct vboxsf_sbi *sbi; ++ struct dentry *droot; ++ struct inode *iroot; ++ char *nls_name; ++ size_t size; ++ int err; ++ ++ if (!fc->source) ++ return -EINVAL; ++ ++ sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); ++ if (!sbi) ++ return -ENOMEM; ++ ++ sbi->o = ctx->o; ++ idr_init(&sbi->ino_idr); ++ spin_lock_init(&sbi->ino_idr_lock); ++ sbi->next_generation = 1; ++ sbi->bdi_id = -1; ++ ++ /* Load nls if not utf8 */ ++ nls_name = ctx->nls_name ? ctx->nls_name : vboxsf_default_nls; ++ if (strcmp(nls_name, "utf8") != 0) { ++ if (nls_name == vboxsf_default_nls) ++ sbi->nls = load_nls_default(); ++ else ++ sbi->nls = load_nls(nls_name); ++ ++ if (!sbi->nls) { ++ vbg_err("vboxsf: Count not load '%s' nls\n", nls_name); ++ err = -EINVAL; ++ goto fail_free; ++ } ++ } ++ ++ sbi->bdi_id = ida_simple_get(&vboxsf_bdi_ida, 0, 0, GFP_KERNEL); ++ if (sbi->bdi_id < 0) { ++ err = sbi->bdi_id; ++ goto fail_free; ++ } ++ ++ err = super_setup_bdi_name(sb, "vboxsf-%s.%d", fc->source, sbi->bdi_id); ++ if (err) ++ goto fail_free; ++ ++ /* Turn source into a shfl_string and map the folder */ ++ size = strlen(fc->source) + 1; ++ folder_name = kmalloc(SHFLSTRING_HEADER_SIZE + size, GFP_KERNEL); ++ if (!folder_name) ++ goto fail_free; ++ folder_name->size = size; ++ folder_name->length = size - 1; ++ strlcpy(folder_name->string.utf8, fc->source, size); ++ err = vboxsf_map_folder(folder_name, &sbi->root); ++ kfree(folder_name); ++ if (err) { ++ vbg_err("vboxsf: Host rejected mount of '%s' with error %d\n", ++ fc->source, err); ++ goto fail_free; ++ } ++ ++ root_path.length = 1; ++ root_path.size = 2; ++ root_path.string.utf8[0] = '/'; ++ root_path.string.utf8[1] = 0; ++ err = vboxsf_stat(sbi, &root_path, &sbi->root_info); ++ if (err) ++ goto fail_unmap; ++ ++ sb->s_magic = VBOXSF_SUPER_MAGIC; ++ sb->s_blocksize = 1024; ++ sb->s_maxbytes = MAX_LFS_FILESIZE; ++ sb->s_op = &vboxsf_super_ops; ++ sb->s_d_op = &vboxsf_dentry_ops; ++ ++ iroot = iget_locked(sb, 0); ++ if (!iroot) { ++ err = -ENOMEM; ++ goto fail_unmap; ++ } ++ vboxsf_init_inode(sbi, iroot, &sbi->root_info); ++ unlock_new_inode(iroot); ++ ++ droot = d_make_root(iroot); ++ if (!droot) { ++ err = -ENOMEM; ++ goto fail_unmap; ++ } ++ ++ sb->s_root = droot; ++ sb->s_fs_info = sbi; ++ return 0; ++ ++fail_unmap: ++ vboxsf_unmap_folder(sbi->root); ++fail_free: ++ if (sbi->bdi_id >= 0) ++ ida_simple_remove(&vboxsf_bdi_ida, sbi->bdi_id); ++ if (sbi->nls) ++ unload_nls(sbi->nls); ++ idr_destroy(&sbi->ino_idr); ++ kfree(sbi); ++ return err; ++} ++ ++static void vboxsf_inode_init_once(void *data) ++{ ++ struct vboxsf_inode *sf_i = data; ++ ++ mutex_init(&sf_i->handle_list_mutex); ++ inode_init_once(&sf_i->vfs_inode); ++} ++ ++static struct inode *vboxsf_alloc_inode(struct super_block *sb) ++{ ++ struct vboxsf_inode *sf_i; ++ ++ sf_i = kmem_cache_alloc(vboxsf_inode_cachep, GFP_NOFS); ++ if (!sf_i) ++ return NULL; ++ ++ sf_i->force_restat = 0; ++ INIT_LIST_HEAD(&sf_i->handle_list); ++ ++ return &sf_i->vfs_inode; ++} ++ ++static void vboxsf_free_inode(struct inode *inode) ++{ ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(inode->i_sb); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&sbi->ino_idr_lock, flags); ++ idr_remove(&sbi->ino_idr, inode->i_ino); ++ spin_unlock_irqrestore(&sbi->ino_idr_lock, flags); ++ kmem_cache_free(vboxsf_inode_cachep, VBOXSF_I(inode)); ++} ++ ++static void vboxsf_put_super(struct super_block *sb) ++{ ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(sb); ++ ++ vboxsf_unmap_folder(sbi->root); ++ if (sbi->bdi_id >= 0) ++ ida_simple_remove(&vboxsf_bdi_ida, sbi->bdi_id); ++ if (sbi->nls) ++ unload_nls(sbi->nls); ++ ++ /* ++ * vboxsf_free_inode uses the idr, make sure all delayed rcu free ++ * inodes are flushed. ++ */ ++ rcu_barrier(); ++ idr_destroy(&sbi->ino_idr); ++ kfree(sbi); ++} ++ ++static int vboxsf_statfs(struct dentry *dentry, struct kstatfs *stat) ++{ ++ struct super_block *sb = dentry->d_sb; ++ struct shfl_volinfo shfl_volinfo; ++ struct vboxsf_sbi *sbi; ++ u32 buf_len; ++ int err; ++ ++ sbi = VBOXSF_SBI(sb); ++ buf_len = sizeof(shfl_volinfo); ++ err = vboxsf_fsinfo(sbi->root, 0, SHFL_INFO_GET | SHFL_INFO_VOLUME, ++ &buf_len, &shfl_volinfo); ++ if (err) ++ return err; ++ ++ stat->f_type = VBOXSF_SUPER_MAGIC; ++ stat->f_bsize = shfl_volinfo.bytes_per_allocation_unit; ++ ++ do_div(shfl_volinfo.total_allocation_bytes, ++ shfl_volinfo.bytes_per_allocation_unit); ++ stat->f_blocks = shfl_volinfo.total_allocation_bytes; ++ ++ do_div(shfl_volinfo.available_allocation_bytes, ++ shfl_volinfo.bytes_per_allocation_unit); ++ stat->f_bfree = shfl_volinfo.available_allocation_bytes; ++ stat->f_bavail = shfl_volinfo.available_allocation_bytes; ++ ++ stat->f_files = 1000; ++ /* ++ * Don't return 0 here since the guest may then think that it is not ++ * possible to create any more files. ++ */ ++ stat->f_ffree = 1000000; ++ stat->f_fsid.val[0] = 0; ++ stat->f_fsid.val[1] = 0; ++ stat->f_namelen = 255; ++ return 0; ++} ++ ++static struct super_operations vboxsf_super_ops = { ++ .alloc_inode = vboxsf_alloc_inode, ++ .free_inode = vboxsf_free_inode, ++ .put_super = vboxsf_put_super, ++ .statfs = vboxsf_statfs, ++}; ++ ++static int vboxsf_setup(void) ++{ ++ int err; ++ ++ mutex_lock(&vboxsf_setup_mutex); ++ ++ if (vboxsf_setup_done) ++ goto success; ++ ++ vboxsf_inode_cachep = ++ kmem_cache_create("vboxsf_inode_cache", ++ sizeof(struct vboxsf_inode), 0, ++ (SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD | ++ SLAB_ACCOUNT), ++ vboxsf_inode_init_once); ++ if (!vboxsf_inode_cachep) { ++ err = -ENOMEM; ++ goto fail_nomem; ++ } ++ ++ err = vboxsf_connect(); ++ if (err) { ++ vbg_err("vboxsf: err %d connecting to guest PCI-device\n", err); ++ vbg_err("vboxsf: make sure you are inside a VirtualBox VM\n"); ++ vbg_err("vboxsf: and check dmesg for vboxguest errors\n"); ++ goto fail_free_cache; ++ } ++ ++ err = vboxsf_set_utf8(); ++ if (err) { ++ vbg_err("vboxsf_setutf8 error %d\n", err); ++ goto fail_disconnect; ++ } ++ ++ if (!follow_symlinks) { ++ err = vboxsf_set_symlinks(); ++ if (err) ++ vbg_warn("vboxsf: Unable to show symlinks: %d\n", err); ++ } ++ ++ vboxsf_setup_done = true; ++success: ++ mutex_unlock(&vboxsf_setup_mutex); ++ return 0; ++ ++fail_disconnect: ++ vboxsf_disconnect(); ++fail_free_cache: ++ kmem_cache_destroy(vboxsf_inode_cachep); ++fail_nomem: ++ mutex_unlock(&vboxsf_setup_mutex); ++ return err; ++} ++ ++static int vboxsf_parse_monolithic(struct fs_context *fc, void *data) ++{ ++ char *options = data; ++ ++ if (options && options[0] == VBSF_MOUNT_SIGNATURE_BYTE_0 && ++ options[1] == VBSF_MOUNT_SIGNATURE_BYTE_1 && ++ options[2] == VBSF_MOUNT_SIGNATURE_BYTE_2 && ++ options[3] == VBSF_MOUNT_SIGNATURE_BYTE_3) { ++ vbg_err("vboxsf: Old binary mount data not supported, remove obsolete mount.vboxsf and/or update your VBoxService.\n"); ++ return -EINVAL; ++ } ++ ++ return generic_parse_monolithic(fc, data); ++} ++ ++static int vboxsf_get_tree(struct fs_context *fc) ++{ ++ int err; ++ ++ err = vboxsf_setup(); ++ if (err) ++ return err; ++ ++ return vfs_get_super(fc, vfs_get_independent_super, vboxsf_fill_super); ++} ++ ++static int vboxsf_reconfigure(struct fs_context *fc) ++{ ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(fc->root->d_sb); ++ struct vboxsf_fs_context *ctx = fc->fs_private; ++ struct inode *iroot; ++ ++ iroot = ilookup(fc->root->d_sb, 0); ++ if (!iroot) ++ return -ENOENT; ++ ++ /* Apply changed options to the root inode */ ++ sbi->o = ctx->o; ++ vboxsf_init_inode(sbi, iroot, &sbi->root_info); ++ ++ return 0; ++} ++ ++static void vboxsf_free_fc(struct fs_context *fc) ++{ ++ struct vboxsf_fs_context *ctx = fc->fs_private; ++ ++ kfree(ctx->nls_name); ++ kfree(ctx); ++} ++ ++static const struct fs_context_operations vboxsf_context_ops = { ++ .free = vboxsf_free_fc, ++ .parse_param = vboxsf_parse_param, ++ .parse_monolithic = vboxsf_parse_monolithic, ++ .get_tree = vboxsf_get_tree, ++ .reconfigure = vboxsf_reconfigure, ++}; ++ ++static int vboxsf_init_fs_context(struct fs_context *fc) ++{ ++ struct vboxsf_fs_context *ctx; ++ ++ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); ++ if (!ctx) ++ return -ENOMEM; ++ ++ current_uid_gid(&ctx->o.uid, &ctx->o.gid); ++ ++ fc->fs_private = ctx; ++ fc->ops = &vboxsf_context_ops; ++ return 0; ++} ++ ++static struct file_system_type vboxsf_fs_type = { ++ .owner = THIS_MODULE, ++ .name = "vboxsf", ++ .init_fs_context = vboxsf_init_fs_context, ++ .parameters = &vboxsf_fs_parameters, ++ .kill_sb = kill_anon_super ++}; ++ ++/* Module initialization/finalization handlers */ ++static int __init vboxsf_init(void) ++{ ++ return register_filesystem(&vboxsf_fs_type); ++} ++ ++static void __exit vboxsf_fini(void) ++{ ++ unregister_filesystem(&vboxsf_fs_type); ++ ++ mutex_lock(&vboxsf_setup_mutex); ++ if (vboxsf_setup_done) { ++ vboxsf_disconnect(); ++ /* ++ * Make sure all delayed rcu free inodes are flushed ++ * before we destroy the cache. ++ */ ++ rcu_barrier(); ++ kmem_cache_destroy(vboxsf_inode_cachep); ++ } ++ mutex_unlock(&vboxsf_setup_mutex); ++} ++ ++module_init(vboxsf_init); ++module_exit(vboxsf_fini); ++ ++MODULE_DESCRIPTION("Oracle VM VirtualBox Module for Host File System Access"); ++MODULE_AUTHOR("Oracle Corporation"); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS_FS("vboxsf"); +diff --git a/drivers/staging/vboxsf/utils.c b/drivers/staging/vboxsf/utils.c +new file mode 100644 +index 000000000000..1870b69c824e +--- /dev/null ++++ b/drivers/staging/vboxsf/utils.c +@@ -0,0 +1,550 @@ ++// SPDX-License-Identifier: MIT ++/* ++ * VirtualBox Guest Shared Folders support: Utility functions. ++ * Mainly conversion from/to VirtualBox/Linux data structures. ++ * ++ * Copyright (C) 2006-2018 Oracle Corporation ++ */ ++ ++#include ++#include ++#include ++#include ++#include "vfsmod.h" ++ ++struct inode *vboxsf_new_inode(struct super_block *sb) ++{ ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(sb); ++ struct inode *inode; ++ unsigned long flags; ++ int cursor, ret; ++ u32 gen; ++ ++ inode = new_inode(sb); ++ if (!inode) ++ return ERR_PTR(-ENOMEM); ++ ++ idr_preload(GFP_KERNEL); ++ spin_lock_irqsave(&sbi->ino_idr_lock, flags); ++ cursor = idr_get_cursor(&sbi->ino_idr); ++ ret = idr_alloc_cyclic(&sbi->ino_idr, inode, 1, 0, GFP_ATOMIC); ++ if (ret >= 0 && ret < cursor) ++ sbi->next_generation++; ++ gen = sbi->next_generation; ++ spin_unlock_irqrestore(&sbi->ino_idr_lock, flags); ++ idr_preload_end(); ++ ++ if (ret < 0) { ++ iput(inode); ++ return ERR_PTR(ret); ++ } ++ ++ inode->i_ino = ret; ++ inode->i_generation = gen; ++ return inode; ++} ++ ++/* set [inode] attributes based on [info], uid/gid based on [sbi] */ ++void vboxsf_init_inode(struct vboxsf_sbi *sbi, struct inode *inode, ++ const struct shfl_fsobjinfo *info) ++{ ++ const struct shfl_fsobjattr *attr; ++ s64 allocated; ++ int mode; ++ ++ attr = &info->attr; ++ ++#define mode_set(r) ((attr->mode & (SHFL_UNIX_##r)) ? (S_##r) : 0) ++ ++ mode = mode_set(IRUSR); ++ mode |= mode_set(IWUSR); ++ mode |= mode_set(IXUSR); ++ ++ mode |= mode_set(IRGRP); ++ mode |= mode_set(IWGRP); ++ mode |= mode_set(IXGRP); ++ ++ mode |= mode_set(IROTH); ++ mode |= mode_set(IWOTH); ++ mode |= mode_set(IXOTH); ++ ++#undef mode_set ++ ++ /* We use the host-side values for these */ ++ inode->i_flags |= S_NOATIME | S_NOCMTIME; ++ inode->i_mapping->a_ops = &vboxsf_reg_aops; ++ ++ if (SHFL_IS_DIRECTORY(attr->mode)) { ++ inode->i_mode = sbi->o.dmode_set ? sbi->o.dmode : mode; ++ inode->i_mode &= ~sbi->o.dmask; ++ inode->i_mode |= S_IFDIR; ++ inode->i_op = &vboxsf_dir_iops; ++ inode->i_fop = &vboxsf_dir_fops; ++ /* ++ * XXX: this probably should be set to the number of entries ++ * in the directory plus two (. ..) ++ */ ++ set_nlink(inode, 1); ++ } else if (SHFL_IS_SYMLINK(attr->mode)) { ++ inode->i_mode = sbi->o.fmode_set ? sbi->o.fmode : mode; ++ inode->i_mode &= ~sbi->o.fmask; ++ inode->i_mode |= S_IFLNK; ++ inode->i_op = &vboxsf_lnk_iops; ++ set_nlink(inode, 1); ++ } else { ++ inode->i_mode = sbi->o.fmode_set ? sbi->o.fmode : mode; ++ inode->i_mode &= ~sbi->o.fmask; ++ inode->i_mode |= S_IFREG; ++ inode->i_op = &vboxsf_reg_iops; ++ inode->i_fop = &vboxsf_reg_fops; ++ set_nlink(inode, 1); ++ } ++ ++ inode->i_uid = sbi->o.uid; ++ inode->i_gid = sbi->o.gid; ++ ++ inode->i_size = info->size; ++ inode->i_blkbits = 12; ++ /* i_blocks always in units of 512 bytes! */ ++ allocated = info->allocated + 511; ++ do_div(allocated, 512); ++ inode->i_blocks = allocated; ++ ++ inode->i_atime = ns_to_timespec64( ++ info->access_time.ns_relative_to_unix_epoch); ++ inode->i_ctime = ns_to_timespec64( ++ info->change_time.ns_relative_to_unix_epoch); ++ inode->i_mtime = ns_to_timespec64( ++ info->modification_time.ns_relative_to_unix_epoch); ++} ++ ++int vboxsf_create_at_dentry(struct dentry *dentry, ++ struct shfl_createparms *params) ++{ ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(dentry->d_sb); ++ struct shfl_string *path; ++ int err; ++ ++ path = vboxsf_path_from_dentry(sbi, dentry); ++ if (IS_ERR(path)) ++ return PTR_ERR(path); ++ ++ err = vboxsf_create(sbi->root, path, params); ++ __putname(path); ++ ++ return err; ++} ++ ++int vboxsf_stat(struct vboxsf_sbi *sbi, struct shfl_string *path, ++ struct shfl_fsobjinfo *info) ++{ ++ struct shfl_createparms params = {}; ++ int err; ++ ++ params.handle = SHFL_HANDLE_NIL; ++ params.create_flags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW; ++ ++ err = vboxsf_create(sbi->root, path, ¶ms); ++ if (err) ++ return err; ++ ++ if (params.result != SHFL_FILE_EXISTS) ++ return -ENOENT; ++ ++ if (info) ++ *info = params.info; ++ ++ return 0; ++} ++ ++int vboxsf_stat_dentry(struct dentry *dentry, struct shfl_fsobjinfo *info) ++{ ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(dentry->d_sb); ++ struct shfl_string *path; ++ int err; ++ ++ path = vboxsf_path_from_dentry(sbi, dentry); ++ if (IS_ERR(path)) ++ return PTR_ERR(path); ++ ++ err = vboxsf_stat(sbi, path, info); ++ __putname(path); ++ return err; ++} ++ ++int vboxsf_inode_revalidate(struct dentry *dentry) ++{ ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(dentry->d_sb); ++ struct vboxsf_inode *sf_i; ++ struct shfl_fsobjinfo info; ++ struct timespec64 prev_mtime; ++ struct inode *inode; ++ int err; ++ ++ if (!dentry || !d_really_is_positive(dentry)) ++ return -EINVAL; ++ ++ inode = d_inode(dentry); ++ prev_mtime = inode->i_mtime; ++ sf_i = VBOXSF_I(inode); ++ if (!sf_i->force_restat) { ++ if (time_before(jiffies, dentry->d_time + sbi->o.ttl)) ++ return 0; ++ } ++ ++ err = vboxsf_stat_dentry(dentry, &info); ++ if (err) ++ return err; ++ ++ dentry->d_time = jiffies; ++ sf_i->force_restat = 0; ++ vboxsf_init_inode(sbi, inode, &info); ++ ++ /* ++ * If the file was changed on the host side we need to invalidate the ++ * page-cache for it. Note this also gets triggered by our own writes, ++ * this is unavoidable. ++ */ ++ if (timespec64_compare(&inode->i_mtime, &prev_mtime) > 0) ++ invalidate_inode_pages2(inode->i_mapping); ++ ++ return 0; ++} ++ ++int vboxsf_getattr(const struct path *path, struct kstat *kstat, ++ u32 request_mask, unsigned int flags) ++{ ++ int err; ++ struct dentry *dentry = path->dentry; ++ struct inode *inode = d_inode(dentry); ++ struct vboxsf_inode *sf_i = VBOXSF_I(inode); ++ ++ switch (flags & AT_STATX_SYNC_TYPE) { ++ case AT_STATX_DONT_SYNC: ++ err = 0; ++ break; ++ case AT_STATX_FORCE_SYNC: ++ sf_i->force_restat = 1; ++ /* fall-through */ ++ default: ++ err = vboxsf_inode_revalidate(dentry); ++ } ++ if (err) ++ return err; ++ ++ generic_fillattr(d_inode(dentry), kstat); ++ return 0; ++} ++ ++int vboxsf_setattr(struct dentry *dentry, struct iattr *iattr) ++{ ++ struct vboxsf_inode *sf_i = VBOXSF_I(d_inode(dentry)); ++ struct vboxsf_sbi *sbi = VBOXSF_SBI(dentry->d_sb); ++ struct shfl_createparms params = {}; ++ struct shfl_fsobjinfo info = {}; ++ u32 buf_len; ++ int err; ++ ++ params.handle = SHFL_HANDLE_NIL; ++ params.create_flags = SHFL_CF_ACT_OPEN_IF_EXISTS | ++ SHFL_CF_ACT_FAIL_IF_NEW | ++ SHFL_CF_ACCESS_ATTR_WRITE; ++ ++ /* this is at least required for Posix hosts */ ++ if (iattr->ia_valid & ATTR_SIZE) ++ params.create_flags |= SHFL_CF_ACCESS_WRITE; ++ ++ err = vboxsf_create_at_dentry(dentry, ¶ms); ++ if (err || params.result != SHFL_FILE_EXISTS) ++ return err ? err : -ENOENT; ++ ++#define mode_set(r) ((iattr->ia_mode & (S_##r)) ? SHFL_UNIX_##r : 0) ++ ++ /* ++ * Setting the file size and setting the other attributes has to ++ * be handled separately. ++ */ ++ if (iattr->ia_valid & (ATTR_MODE | ATTR_ATIME | ATTR_MTIME)) { ++ if (iattr->ia_valid & ATTR_MODE) { ++ info.attr.mode = mode_set(IRUSR); ++ info.attr.mode |= mode_set(IWUSR); ++ info.attr.mode |= mode_set(IXUSR); ++ info.attr.mode |= mode_set(IRGRP); ++ info.attr.mode |= mode_set(IWGRP); ++ info.attr.mode |= mode_set(IXGRP); ++ info.attr.mode |= mode_set(IROTH); ++ info.attr.mode |= mode_set(IWOTH); ++ info.attr.mode |= mode_set(IXOTH); ++ ++ if (iattr->ia_mode & S_IFDIR) ++ info.attr.mode |= SHFL_TYPE_DIRECTORY; ++ else ++ info.attr.mode |= SHFL_TYPE_FILE; ++ } ++ ++ if (iattr->ia_valid & ATTR_ATIME) ++ info.access_time.ns_relative_to_unix_epoch = ++ timespec64_to_ns(&iattr->ia_atime); ++ ++ if (iattr->ia_valid & ATTR_MTIME) ++ info.modification_time.ns_relative_to_unix_epoch = ++ timespec64_to_ns(&iattr->ia_mtime); ++ ++ /* ++ * Ignore ctime (inode change time) as it can't be set ++ * from userland anyway. ++ */ ++ ++ buf_len = sizeof(info); ++ err = vboxsf_fsinfo(sbi->root, params.handle, ++ SHFL_INFO_SET | SHFL_INFO_FILE, &buf_len, ++ &info); ++ if (err) { ++ vboxsf_close(sbi->root, params.handle); ++ return err; ++ } ++ ++ /* the host may have given us different attr then requested */ ++ sf_i->force_restat = 1; ++ } ++ ++#undef mode_set ++ ++ if (iattr->ia_valid & ATTR_SIZE) { ++ memset(&info, 0, sizeof(info)); ++ info.size = iattr->ia_size; ++ buf_len = sizeof(info); ++ err = vboxsf_fsinfo(sbi->root, params.handle, ++ SHFL_INFO_SET | SHFL_INFO_SIZE, &buf_len, ++ &info); ++ if (err) { ++ vboxsf_close(sbi->root, params.handle); ++ return err; ++ } ++ ++ /* the host may have given us different attr then requested */ ++ sf_i->force_restat = 1; ++ } ++ ++ vboxsf_close(sbi->root, params.handle); ++ ++ /* Update the inode with what the host has actually given us. */ ++ if (sf_i->force_restat) ++ vboxsf_inode_revalidate(dentry); ++ ++ return 0; ++} ++ ++/* ++ * [dentry] contains string encoded in coding system that corresponds ++ * to [sbi]->nls, we must convert it to UTF8 here. ++ * Returns a shfl_string allocated through __getname (must be freed using ++ * __putname), or an ERR_PTR on error. ++ */ ++struct shfl_string *vboxsf_path_from_dentry(struct vboxsf_sbi *sbi, ++ struct dentry *dentry) ++{ ++ struct shfl_string *shfl_path; ++ int path_len, out_len, nb; ++ char *buf, *path; ++ wchar_t uni; ++ u8 *out; ++ ++ buf = __getname(); ++ if (!buf) ++ return ERR_PTR(-ENOMEM); ++ ++ path = dentry_path_raw(dentry, buf, PATH_MAX); ++ if (IS_ERR(path)) { ++ __putname(buf); ++ return (struct shfl_string *)path; ++ } ++ path_len = strlen(path); ++ ++ if (sbi->nls) { ++ shfl_path = __getname(); ++ if (!shfl_path) { ++ __putname(buf); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ out = shfl_path->string.utf8; ++ out_len = PATH_MAX - SHFLSTRING_HEADER_SIZE - 1; ++ ++ while (path_len) { ++ nb = sbi->nls->char2uni(path, path_len, &uni); ++ if (nb < 0) { ++ __putname(shfl_path); ++ __putname(buf); ++ return ERR_PTR(-EINVAL); ++ } ++ path += nb; ++ path_len -= nb; ++ ++ nb = utf32_to_utf8(uni, out, out_len); ++ if (nb < 0) { ++ __putname(shfl_path); ++ __putname(buf); ++ return ERR_PTR(-ENAMETOOLONG); ++ } ++ out += nb; ++ out_len -= nb; ++ } ++ *out = 0; ++ shfl_path->length = out - shfl_path->string.utf8; ++ shfl_path->size = shfl_path->length + 1; ++ __putname(buf); ++ } else { ++ if ((SHFLSTRING_HEADER_SIZE + path_len + 1) > PATH_MAX) { ++ __putname(buf); ++ return ERR_PTR(-ENAMETOOLONG); ++ } ++ /* ++ * dentry_path stores the name at the end of buf, but the ++ * shfl_string string we return must be properly aligned. ++ */ ++ shfl_path = (struct shfl_string *)buf; ++ memmove(shfl_path->string.utf8, path, path_len); ++ shfl_path->string.utf8[path_len] = 0; ++ shfl_path->length = path_len; ++ shfl_path->size = path_len + 1; ++ } ++ ++ return shfl_path; ++} ++ ++int vboxsf_nlscpy(struct vboxsf_sbi *sbi, char *name, size_t name_bound_len, ++ const unsigned char *utf8_name, size_t utf8_len) ++{ ++ const char *in; ++ char *out; ++ size_t out_len; ++ size_t out_bound_len; ++ size_t in_bound_len; ++ ++ in = utf8_name; ++ in_bound_len = utf8_len; ++ ++ out = name; ++ out_len = 0; ++ /* Reserve space for terminating 0 */ ++ out_bound_len = name_bound_len - 1; ++ ++ while (in_bound_len) { ++ int nb; ++ unicode_t uni; ++ ++ nb = utf8_to_utf32(in, in_bound_len, &uni); ++ if (nb < 0) ++ return -EINVAL; ++ ++ in += nb; ++ in_bound_len -= nb; ++ ++ nb = sbi->nls->uni2char(uni, out, out_bound_len); ++ if (nb < 0) ++ return nb; ++ ++ out += nb; ++ out_bound_len -= nb; ++ out_len += nb; ++ } ++ ++ *out = 0; ++ ++ return 0; ++} ++ ++static struct vboxsf_dir_buf *vboxsf_dir_buf_alloc(struct list_head *list) ++{ ++ struct vboxsf_dir_buf *b; ++ ++ b = kmalloc(sizeof(*b), GFP_KERNEL); ++ if (!b) ++ return NULL; ++ ++ b->buf = kmalloc(DIR_BUFFER_SIZE, GFP_KERNEL); ++ if (!b->buf) { ++ kfree(b); ++ return NULL; ++ } ++ ++ b->entries = 0; ++ b->used = 0; ++ b->free = DIR_BUFFER_SIZE; ++ list_add(&b->head, list); ++ ++ return b; ++} ++ ++static void vboxsf_dir_buf_free(struct vboxsf_dir_buf *b) ++{ ++ list_del(&b->head); ++ kfree(b->buf); ++ kfree(b); ++} ++ ++struct vboxsf_dir_info *vboxsf_dir_info_alloc(void) ++{ ++ struct vboxsf_dir_info *p; ++ ++ p = kmalloc(sizeof(*p), GFP_KERNEL); ++ if (!p) ++ return NULL; ++ ++ INIT_LIST_HEAD(&p->info_list); ++ return p; ++} ++ ++void vboxsf_dir_info_free(struct vboxsf_dir_info *p) ++{ ++ struct list_head *list, *pos, *tmp; ++ ++ list = &p->info_list; ++ list_for_each_safe(pos, tmp, list) { ++ struct vboxsf_dir_buf *b; ++ ++ b = list_entry(pos, struct vboxsf_dir_buf, head); ++ vboxsf_dir_buf_free(b); ++ } ++ kfree(p); ++} ++ ++int vboxsf_dir_read_all(struct vboxsf_sbi *sbi, struct vboxsf_dir_info *sf_d, ++ u64 handle) ++{ ++ struct vboxsf_dir_buf *b; ++ u32 entries, size; ++ int err = 0; ++ void *buf; ++ ++ /* vboxsf_dirinfo returns 1 on end of dir */ ++ while (err == 0) { ++ b = vboxsf_dir_buf_alloc(&sf_d->info_list); ++ if (!b) { ++ err = -ENOMEM; ++ break; ++ } ++ ++ buf = b->buf; ++ size = b->free; ++ ++ err = vboxsf_dirinfo(sbi->root, handle, NULL, 0, 0, ++ &size, buf, &entries); ++ if (err < 0) ++ break; ++ ++ b->entries += entries; ++ b->free -= size; ++ b->used += size; ++ } ++ ++ if (b && b->used == 0) ++ vboxsf_dir_buf_free(b); ++ ++ /* -EILSEQ means the host could not translate a filename, ignore */ ++ if (err > 0 || err == -EILSEQ) ++ err = 0; ++ ++ return err; ++} +diff --git a/drivers/staging/vboxsf/vboxsf_wrappers.c b/drivers/staging/vboxsf/vboxsf_wrappers.c +new file mode 100644 +index 000000000000..bfc78a097dae +--- /dev/null ++++ b/drivers/staging/vboxsf/vboxsf_wrappers.c +@@ -0,0 +1,371 @@ ++// SPDX-License-Identifier: MIT ++/* ++ * Wrapper functions for the shfl host calls. ++ * ++ * Copyright (C) 2006-2018 Oracle Corporation ++ */ ++ ++#include ++#include ++#include ++#include ++#include "vfsmod.h" ++ ++#define SHFL_REQUEST \ ++ (VMMDEV_REQUESTOR_KERNEL | VMMDEV_REQUESTOR_USR_DRV_OTHER | \ ++ VMMDEV_REQUESTOR_CON_DONT_KNOW | VMMDEV_REQUESTOR_TRUST_NOT_GIVEN) ++ ++static u32 vboxsf_client_id; ++ ++int vboxsf_connect(void) ++{ ++ struct vbg_dev *gdev; ++ struct vmmdev_hgcm_service_location loc; ++ int err, vbox_status; ++ ++ loc.type = VMMDEV_HGCM_LOC_LOCALHOST_EXISTING; ++ strcpy(loc.u.localhost.service_name, "VBoxSharedFolders"); ++ ++ gdev = vbg_get_gdev(); ++ if (IS_ERR(gdev)) ++ return -ENODEV; /* No guest-device */ ++ ++ err = vbg_hgcm_connect(gdev, SHFL_REQUEST, &loc, ++ &vboxsf_client_id, &vbox_status); ++ vbg_put_gdev(gdev); ++ ++ return err ? err : vbg_status_code_to_errno(vbox_status); ++} ++ ++void vboxsf_disconnect(void) ++{ ++ struct vbg_dev *gdev; ++ int vbox_status; ++ ++ gdev = vbg_get_gdev(); ++ if (IS_ERR(gdev)) ++ return; /* guest-device is gone, already disconnected */ ++ ++ vbg_hgcm_disconnect(gdev, SHFL_REQUEST, vboxsf_client_id, &vbox_status); ++ vbg_put_gdev(gdev); ++} ++ ++static int vboxsf_call(u32 function, void *parms, u32 parm_count, int *status) ++{ ++ struct vbg_dev *gdev; ++ int err, vbox_status; ++ ++ gdev = vbg_get_gdev(); ++ if (IS_ERR(gdev)) ++ return -ESHUTDOWN; /* guest-dev removed underneath us */ ++ ++ err = vbg_hgcm_call(gdev, SHFL_REQUEST, vboxsf_client_id, function, ++ U32_MAX, parms, parm_count, &vbox_status); ++ vbg_put_gdev(gdev); ++ ++ if (err < 0) ++ return err; ++ ++ if (status) ++ *status = vbox_status; ++ ++ return vbg_status_code_to_errno(vbox_status); ++} ++ ++int vboxsf_map_folder(struct shfl_string *folder_name, u32 *root) ++{ ++ struct shfl_map_folder parms; ++ int err, status; ++ ++ parms.path.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL; ++ parms.path.u.pointer.size = shfl_string_buf_size(folder_name); ++ parms.path.u.pointer.u.linear_addr = (uintptr_t)folder_name; ++ ++ parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.root.u.value32 = 0; ++ ++ parms.delimiter.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.delimiter.u.value32 = '/'; ++ ++ parms.case_sensitive.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.case_sensitive.u.value32 = 1; ++ ++ err = vboxsf_call(SHFL_FN_MAP_FOLDER, &parms, SHFL_CPARMS_MAP_FOLDER, ++ &status); ++ if (err == -ENOSYS && status == VERR_NOT_IMPLEMENTED) ++ vbg_err("%s: Error host is too old\n", __func__); ++ ++ *root = parms.root.u.value32; ++ return err; ++} ++ ++int vboxsf_unmap_folder(u32 root) ++{ ++ struct shfl_unmap_folder parms; ++ ++ parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.root.u.value32 = root; ++ ++ return vboxsf_call(SHFL_FN_UNMAP_FOLDER, &parms, ++ SHFL_CPARMS_UNMAP_FOLDER, NULL); ++} ++ ++/** ++ * vboxsf_create - Create a new file or folder ++ * @root: Root of the shared folder in which to create the file ++ * @parsed_path: The path of the file or folder relative to the shared folder ++ * @param: create_parms Parameters for file/folder creation. ++ * ++ * Create a new file or folder or open an existing one in a shared folder. ++ * Note this function always returns 0 / success unless an exceptional condition ++ * occurs - out of memory, invalid arguments, etc. If the file or folder could ++ * not be opened or created, create_parms->handle will be set to ++ * SHFL_HANDLE_NIL on return. In this case the value in create_parms->result ++ * provides information as to why (e.g. SHFL_FILE_EXISTS), create_parms->result ++ * is also set on success as additional information. ++ * ++ * Returns: ++ * 0 or negative errno value. ++ */ ++int vboxsf_create(u32 root, struct shfl_string *parsed_path, ++ struct shfl_createparms *create_parms) ++{ ++ struct shfl_create parms; ++ ++ parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.root.u.value32 = root; ++ ++ parms.path.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL; ++ parms.path.u.pointer.size = shfl_string_buf_size(parsed_path); ++ parms.path.u.pointer.u.linear_addr = (uintptr_t)parsed_path; ++ ++ parms.parms.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL; ++ parms.parms.u.pointer.size = sizeof(struct shfl_createparms); ++ parms.parms.u.pointer.u.linear_addr = (uintptr_t)create_parms; ++ ++ return vboxsf_call(SHFL_FN_CREATE, &parms, SHFL_CPARMS_CREATE, NULL); ++} ++ ++int vboxsf_close(u32 root, u64 handle) ++{ ++ struct shfl_close parms; ++ ++ parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.root.u.value32 = root; ++ ++ parms.handle.type = VMMDEV_HGCM_PARM_TYPE_64BIT; ++ parms.handle.u.value64 = handle; ++ ++ return vboxsf_call(SHFL_FN_CLOSE, &parms, SHFL_CPARMS_CLOSE, NULL); ++} ++ ++int vboxsf_remove(u32 root, struct shfl_string *parsed_path, u32 flags) ++{ ++ struct shfl_remove parms; ++ ++ parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.root.u.value32 = root; ++ ++ parms.path.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN; ++ parms.path.u.pointer.size = shfl_string_buf_size(parsed_path); ++ parms.path.u.pointer.u.linear_addr = (uintptr_t)parsed_path; ++ ++ parms.flags.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.flags.u.value32 = flags; ++ ++ return vboxsf_call(SHFL_FN_REMOVE, &parms, SHFL_CPARMS_REMOVE, NULL); ++} ++ ++int vboxsf_rename(u32 root, struct shfl_string *src_path, ++ struct shfl_string *dest_path, u32 flags) ++{ ++ struct shfl_rename parms; ++ ++ parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.root.u.value32 = root; ++ ++ parms.src.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN; ++ parms.src.u.pointer.size = shfl_string_buf_size(src_path); ++ parms.src.u.pointer.u.linear_addr = (uintptr_t)src_path; ++ ++ parms.dest.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN; ++ parms.dest.u.pointer.size = shfl_string_buf_size(dest_path); ++ parms.dest.u.pointer.u.linear_addr = (uintptr_t)dest_path; ++ ++ parms.flags.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.flags.u.value32 = flags; ++ ++ return vboxsf_call(SHFL_FN_RENAME, &parms, SHFL_CPARMS_RENAME, NULL); ++} ++ ++int vboxsf_read(u32 root, u64 handle, u64 offset, u32 *buf_len, u8 *buf) ++{ ++ struct shfl_read parms; ++ int err; ++ ++ parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.root.u.value32 = root; ++ ++ parms.handle.type = VMMDEV_HGCM_PARM_TYPE_64BIT; ++ parms.handle.u.value64 = handle; ++ parms.offset.type = VMMDEV_HGCM_PARM_TYPE_64BIT; ++ parms.offset.u.value64 = offset; ++ parms.cb.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.cb.u.value32 = *buf_len; ++ parms.buffer.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_OUT; ++ parms.buffer.u.pointer.size = *buf_len; ++ parms.buffer.u.pointer.u.linear_addr = (uintptr_t)buf; ++ ++ err = vboxsf_call(SHFL_FN_READ, &parms, SHFL_CPARMS_READ, NULL); ++ ++ *buf_len = parms.cb.u.value32; ++ return err; ++} ++ ++int vboxsf_write(u32 root, u64 handle, u64 offset, u32 *buf_len, u8 *buf) ++{ ++ struct shfl_write parms; ++ int err; ++ ++ parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.root.u.value32 = root; ++ ++ parms.handle.type = VMMDEV_HGCM_PARM_TYPE_64BIT; ++ parms.handle.u.value64 = handle; ++ parms.offset.type = VMMDEV_HGCM_PARM_TYPE_64BIT; ++ parms.offset.u.value64 = offset; ++ parms.cb.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.cb.u.value32 = *buf_len; ++ parms.buffer.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN; ++ parms.buffer.u.pointer.size = *buf_len; ++ parms.buffer.u.pointer.u.linear_addr = (uintptr_t)buf; ++ ++ err = vboxsf_call(SHFL_FN_WRITE, &parms, SHFL_CPARMS_WRITE, NULL); ++ ++ *buf_len = parms.cb.u.value32; ++ return err; ++} ++ ++/* Returns 0 on success, 1 on end-of-dir, negative errno otherwise */ ++int vboxsf_dirinfo(u32 root, u64 handle, ++ struct shfl_string *parsed_path, u32 flags, u32 index, ++ u32 *buf_len, struct shfl_dirinfo *buf, u32 *file_count) ++{ ++ struct shfl_list parms; ++ int err, status; ++ ++ parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.root.u.value32 = root; ++ ++ parms.handle.type = VMMDEV_HGCM_PARM_TYPE_64BIT; ++ parms.handle.u.value64 = handle; ++ parms.flags.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.flags.u.value32 = flags; ++ parms.cb.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.cb.u.value32 = *buf_len; ++ if (parsed_path) { ++ parms.path.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN; ++ parms.path.u.pointer.size = shfl_string_buf_size(parsed_path); ++ parms.path.u.pointer.u.linear_addr = (uintptr_t)parsed_path; ++ } else { ++ parms.path.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_IN; ++ parms.path.u.pointer.size = 0; ++ parms.path.u.pointer.u.linear_addr = 0; ++ } ++ ++ parms.buffer.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_OUT; ++ parms.buffer.u.pointer.size = *buf_len; ++ parms.buffer.u.pointer.u.linear_addr = (uintptr_t)buf; ++ ++ parms.resume_point.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.resume_point.u.value32 = index; ++ parms.file_count.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.file_count.u.value32 = 0; /* out parameter only */ ++ ++ err = vboxsf_call(SHFL_FN_LIST, &parms, SHFL_CPARMS_LIST, &status); ++ if (err == -ENODATA && status == VERR_NO_MORE_FILES) ++ err = 1; ++ ++ *buf_len = parms.cb.u.value32; ++ *file_count = parms.file_count.u.value32; ++ return err; ++} ++ ++int vboxsf_fsinfo(u32 root, u64 handle, u32 flags, ++ u32 *buf_len, void *buf) ++{ ++ struct shfl_information parms; ++ int err; ++ ++ parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.root.u.value32 = root; ++ ++ parms.handle.type = VMMDEV_HGCM_PARM_TYPE_64BIT; ++ parms.handle.u.value64 = handle; ++ parms.flags.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.flags.u.value32 = flags; ++ parms.cb.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.cb.u.value32 = *buf_len; ++ parms.info.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL; ++ parms.info.u.pointer.size = *buf_len; ++ parms.info.u.pointer.u.linear_addr = (uintptr_t)buf; ++ ++ err = vboxsf_call(SHFL_FN_INFORMATION, &parms, SHFL_CPARMS_INFORMATION, ++ NULL); ++ ++ *buf_len = parms.cb.u.value32; ++ return err; ++} ++ ++int vboxsf_readlink(u32 root, struct shfl_string *parsed_path, ++ u32 buf_len, u8 *buf) ++{ ++ struct shfl_readLink parms; ++ ++ parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.root.u.value32 = root; ++ ++ parms.path.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN; ++ parms.path.u.pointer.size = shfl_string_buf_size(parsed_path); ++ parms.path.u.pointer.u.linear_addr = (uintptr_t)parsed_path; ++ ++ parms.buffer.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_OUT; ++ parms.buffer.u.pointer.size = buf_len; ++ parms.buffer.u.pointer.u.linear_addr = (uintptr_t)buf; ++ ++ return vboxsf_call(SHFL_FN_READLINK, &parms, SHFL_CPARMS_READLINK, ++ NULL); ++} ++ ++int vboxsf_symlink(u32 root, struct shfl_string *new_path, ++ struct shfl_string *old_path, struct shfl_fsobjinfo *buf) ++{ ++ struct shfl_symlink parms; ++ ++ parms.root.type = VMMDEV_HGCM_PARM_TYPE_32BIT; ++ parms.root.u.value32 = root; ++ ++ parms.new_path.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN; ++ parms.new_path.u.pointer.size = shfl_string_buf_size(new_path); ++ parms.new_path.u.pointer.u.linear_addr = (uintptr_t)new_path; ++ ++ parms.old_path.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_IN; ++ parms.old_path.u.pointer.size = shfl_string_buf_size(old_path); ++ parms.old_path.u.pointer.u.linear_addr = (uintptr_t)old_path; ++ ++ parms.info.type = VMMDEV_HGCM_PARM_TYPE_LINADDR_KERNEL_OUT; ++ parms.info.u.pointer.size = sizeof(struct shfl_fsobjinfo); ++ parms.info.u.pointer.u.linear_addr = (uintptr_t)buf; ++ ++ return vboxsf_call(SHFL_FN_SYMLINK, &parms, SHFL_CPARMS_SYMLINK, NULL); ++} ++ ++int vboxsf_set_utf8(void) ++{ ++ return vboxsf_call(SHFL_FN_SET_UTF8, NULL, 0, NULL); ++} ++ ++int vboxsf_set_symlinks(void) ++{ ++ return vboxsf_call(SHFL_FN_SET_SYMLINKS, NULL, 0, NULL); ++} +diff --git a/drivers/staging/vboxsf/vfsmod.h b/drivers/staging/vboxsf/vfsmod.h +new file mode 100644 +index 000000000000..de650d65fbe4 +--- /dev/null ++++ b/drivers/staging/vboxsf/vfsmod.h +@@ -0,0 +1,138 @@ ++/* SPDX-License-Identifier: MIT */ ++/* ++ * VirtualBox Guest Shared Folders support: module header. ++ * ++ * Copyright (C) 2006-2018 Oracle Corporation ++ */ ++ ++#ifndef VFSMOD_H ++#define VFSMOD_H ++ ++#include ++#include ++#include ++#include "shfl_hostintf.h" ++ ++#define DIR_BUFFER_SIZE SZ_16K ++ ++/* The cast is to prevent assignment of void * to pointers of arbitrary type */ ++#define VBOXSF_SBI(sb) ((struct vboxsf_sbi *)(sb)->s_fs_info) ++#define VBOXSF_I(i) container_of(i, struct vboxsf_inode, vfs_inode) ++ ++struct vboxsf_options { ++ unsigned long ttl; ++ kuid_t uid; ++ kgid_t gid; ++ bool dmode_set; ++ bool fmode_set; ++ umode_t dmode; ++ umode_t fmode; ++ umode_t dmask; ++ umode_t fmask; ++}; ++ ++struct vboxsf_fs_context { ++ struct vboxsf_options o; ++ char *nls_name; ++}; ++ ++/* per-shared folder information */ ++struct vboxsf_sbi { ++ struct vboxsf_options o; ++ struct shfl_fsobjinfo root_info; ++ struct idr ino_idr; ++ spinlock_t ino_idr_lock; /* This protects ino_idr */ ++ struct nls_table *nls; ++ u32 next_generation; ++ u32 root; ++ int bdi_id; ++}; ++ ++/* per-inode information */ ++struct vboxsf_inode { ++ /* some information was changed, update data on next revalidate */ ++ int force_restat; ++ /* list of open handles for this inode + lock protecting it */ ++ struct list_head handle_list; ++ /* This mutex protects handle_list accesses */ ++ struct mutex handle_list_mutex; ++ /* The VFS inode struct */ ++ struct inode vfs_inode; ++}; ++ ++struct vboxsf_dir_info { ++ struct list_head info_list; ++}; ++ ++struct vboxsf_dir_buf { ++ size_t entries; ++ size_t free; ++ size_t used; ++ void *buf; ++ struct list_head head; ++}; ++ ++/* globals */ ++extern const struct inode_operations vboxsf_dir_iops; ++extern const struct inode_operations vboxsf_lnk_iops; ++extern const struct inode_operations vboxsf_reg_iops; ++extern const struct file_operations vboxsf_dir_fops; ++extern const struct file_operations vboxsf_reg_fops; ++extern const struct address_space_operations vboxsf_reg_aops; ++extern const struct dentry_operations vboxsf_dentry_ops; ++ ++/* from utils.c */ ++struct inode *vboxsf_new_inode(struct super_block *sb); ++void vboxsf_init_inode(struct vboxsf_sbi *sbi, struct inode *inode, ++ const struct shfl_fsobjinfo *info); ++int vboxsf_create_at_dentry(struct dentry *dentry, ++ struct shfl_createparms *params); ++int vboxsf_stat(struct vboxsf_sbi *sbi, struct shfl_string *path, ++ struct shfl_fsobjinfo *info); ++int vboxsf_stat_dentry(struct dentry *dentry, struct shfl_fsobjinfo *info); ++int vboxsf_inode_revalidate(struct dentry *dentry); ++int vboxsf_getattr(const struct path *path, struct kstat *kstat, ++ u32 request_mask, unsigned int query_flags); ++int vboxsf_setattr(struct dentry *dentry, struct iattr *iattr); ++struct shfl_string *vboxsf_path_from_dentry(struct vboxsf_sbi *sbi, ++ struct dentry *dentry); ++int vboxsf_nlscpy(struct vboxsf_sbi *sbi, char *name, size_t name_bound_len, ++ const unsigned char *utf8_name, size_t utf8_len); ++struct vboxsf_dir_info *vboxsf_dir_info_alloc(void); ++void vboxsf_dir_info_free(struct vboxsf_dir_info *p); ++int vboxsf_dir_read_all(struct vboxsf_sbi *sbi, struct vboxsf_dir_info *sf_d, ++ u64 handle); ++ ++/* from vboxsf_wrappers.c */ ++int vboxsf_connect(void); ++void vboxsf_disconnect(void); ++ ++int vboxsf_create(u32 root, struct shfl_string *parsed_path, ++ struct shfl_createparms *create_parms); ++ ++int vboxsf_close(u32 root, u64 handle); ++int vboxsf_remove(u32 root, struct shfl_string *parsed_path, u32 flags); ++int vboxsf_rename(u32 root, struct shfl_string *src_path, ++ struct shfl_string *dest_path, u32 flags); ++ ++int vboxsf_read(u32 root, u64 handle, u64 offset, u32 *buf_len, u8 *buf); ++int vboxsf_write(u32 root, u64 handle, u64 offset, u32 *buf_len, u8 *buf); ++ ++int vboxsf_dirinfo(u32 root, u64 handle, ++ struct shfl_string *parsed_path, u32 flags, u32 index, ++ u32 *buf_len, struct shfl_dirinfo *buf, u32 *file_count); ++int vboxsf_fsinfo(u32 root, u64 handle, u32 flags, ++ u32 *buf_len, void *buf); ++ ++int vboxsf_map_folder(struct shfl_string *folder_name, u32 *root); ++int vboxsf_unmap_folder(u32 root); ++ ++int vboxsf_readlink(u32 root, struct shfl_string *parsed_path, ++ u32 buf_len, u8 *buf); ++int vboxsf_symlink(u32 root, struct shfl_string *new_path, ++ struct shfl_string *old_path, struct shfl_fsobjinfo *buf); ++ ++int vboxsf_set_utf8(void); ++int vboxsf_set_symlinks(void); ++ ++#endif +-- +cgit 1.2-0.3.lf.el7 + diff --git a/kernel/tools/perf/pspec.xml b/kernel/tools/perf/pspec.xml index 3cdede3024..55c48c0305 100644 --- a/kernel/tools/perf/pspec.xml +++ b/kernel/tools/perf/pspec.xml @@ -38,14 +38,14 @@ - patches/linux/patch-5.4.6.xz + patches/linux/patch-5.4.16.xz - patches/mageia/fs-aufs-5.4.patch - patches/mageia/fs-aufs-5.4-modular.patch - patches/mageia/fs-vboxsf.patch - - - patches/pisilinux/kernel-5.4-build-fix.patch + patches/mageia/fs-aufs-5.4.patch + patches/mageia/fs-aufs-5.4-modular.patch + patches/mageia/fs-vboxsf.patch + patches/mageia/CVE-2019-12379.patch + + @@ -78,8 +78,8 @@ - 2019-12-28 - 5.4.6 + 2020-01-30 + 5.4.16 Version bump. Idris Kalp idriskalp@gmail.com