From 36f3fe26a12b74b894bd3858039b73179435a529 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ertu=C4=9Frul=20Erata?= Date: Sun, 20 Jan 2019 08:48:02 +0300 Subject: [PATCH] cpupowertools --- kernel/kernel/pspec.xml | 2 +- .../files/patches/linux/patch-4.19.16.xz | Bin 0 -> 508744 bytes .../mageia_4_19/fs-aufs-4.19-modular.patch | 404 + .../patches/mageia_4_19/fs-aufs-4.19.patch | 37882 ++++++++++++++++ kernel/tools/cpupowertools/pspec.xml | 20 +- 5 files changed, 38300 insertions(+), 8 deletions(-) create mode 100644 kernel/tools/cpupowertools/files/patches/linux/patch-4.19.16.xz create mode 100644 kernel/tools/cpupowertools/files/patches/mageia_4_19/fs-aufs-4.19-modular.patch create mode 100644 kernel/tools/cpupowertools/files/patches/mageia_4_19/fs-aufs-4.19.patch diff --git a/kernel/kernel/pspec.xml b/kernel/kernel/pspec.xml index 6486b53d..5705e0ba 100644 --- a/kernel/kernel/pspec.xml +++ b/kernel/kernel/pspec.xml @@ -3,7 +3,7 @@ kernel - http://www.kernel.org + https://www.kernel.org Ertuğrul Erata ertugrulerata@gmail.com diff --git a/kernel/tools/cpupowertools/files/patches/linux/patch-4.19.16.xz b/kernel/tools/cpupowertools/files/patches/linux/patch-4.19.16.xz new file mode 100644 index 0000000000000000000000000000000000000000..dd79a316fb8c6f16de4a82b526b53a6344e42566 GIT binary patch literal 508744 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

gVUM$eC59_9LX;Q> z9cu6^bb)__XFN)~ZGD;50-;#_tvTGO#}s)G(#0pB53aWi`fQ6?L0GB(7}eLqEcW38 zm&jJ>%b@KVq8eM&X&)hYLg!jsM)x@M zKIc!N;hDCni{4+snvcHaS&mC^g3I75p58*ARBU_vA504gL3J<06Ds>|c!+*Bu?H?T z-Z1N!H)vP+C4;dST;F%(@reN{A1-*u(555SjlU!`Vy^&D%d!KgU%9(kZWd+Q{c@xp zON(IHLSHl@yBCa%BndmLC1B~)R-I*7>A*i&d9MbdCMk~Tv4pJj5fFIaFs~7`&M4UH zb+30k?xmm?9B~(EPcW{%&>4197EX8X=x|@gu(t8(lw6?-)L)@>@mfw1;Jeh!F3xB7 z>!LfKS({(Ah8x*D`OF;rKhu;yR7L#T7OJFgupKZpYpJcrr6JHciZA zz+{8k?YcE5t7CJ6wtlx?jkGNScVW}2I$|6TspgIiA0wuZW_qT_7TB|2^p8KcG98hT z%qsl<&nontu^_aebkl)ouSVH{Vi{o2SKUmyKpoJ%uMD87bJvvZdQ(-_G^@t^6~GZ> zH|RwI$OB~2#1E z0uIkMRlWQywE2n(^GV9>2a-y?O#}+bi}F z*zfwW5wrPR0<0ySM5u)5Zg%8YXK0OteO=&8L*TEL#HX)Q`!2 zg(@>YkDQ;s+#c>c_V5t>sXyBK`~?Vgi;EiNe8mP6Nd5+Ht44WdOxSClOefN4ppA%0 z&I5u_?x+jPVGjLR=A8X;x{{QAsMjo^M3KqGbxA~0=;I92?tQ&Wzy=9E`f4k9wRygk z_S|I7^0Cj`z2X+LYUPyVD~yN?6)e8(BTy$K%>RIgxxI~x?wMj{06Qq_sp%%mY8UD4 z2Oa9!LrtVL;d(CF?EZi(K8tMmapCcq2l=2BNt@j$Rg*Y%?phGij|Zf_mF6{8NnVDA zOb5eE$soOB?Vh7@}utHenJC(1?-J_aOVe@-{{#`nla8rYdZQ9V5U80 zi$>uu`1geprdDaU-#T(m%IGXDXV&u%MdGMT8M-fTqL~Q}fhVq~JT<%nalPfd$+q;~ z`kUPM#8K{A#%#fO!NIG&ldOy!2~w_e1LI14Fl`!zpY~X4Mj@+`CGfeI#?0yAHPpe@ zqv%fq1}XwiUzI10mec{@zsEU@?`T<-AF{U7?GxZ?U6wH9$gkoxfRM%DRswN#MWEF= z75s_jQ@9;cCl_&TfxXYbMy!kRcX-Pax!)I(><|wN_3Vq_oM^`U_UkeE^{JS(uIutQ zYl&TdMK&$*FhF_kJ=g7CBGJj(oPx|4&{Z#E6zB zf{IU5szjq4#L|~pS@HjL@V(1}Vw9+;m3b##ridvd1bOCy9-Mmh8vpFpoPL-iH@f`_>U))?l`Y5y}koNhT!a zZrZv|Uh;Sn@8x1Hac%ButT2+M8Xand)1r^j>TpjD=4%SpRUSVlFf8CTs&sB=7?4){bQtD@x)iTLG5)r#(1U^4{gm8z$nocaW*Dk)w zPNxkvGaG279IH&c@3`I!w;q z%~lK4JAWK7A|g$=l1P3gxFeBEo>d@UFD9tRI81;%KZ8&nQ2gRyka4Gau|CZEYLuj#B?TVv|A*!(IH7H_i-tv}nNUD_mdy}@C5w#D!8m&DhT&^4Yc?$_({^vR6E?20a-dB(f>aVa`XJvNG!oTd6VFXg~?(Ee7n zt-SvyrB4P^i73`t6PJhpsHckzFOs^DVh|BE=o;^-05h2oRJv z*jZ5~B5-5EjTWwum$nmnqV3f9e!nO)Mv&@fm~i?u?$}uD>6H+5u<+fmBd>q>N@dpzRoF@# z7U-?3{SW)`wvFl_U0a+0#%D{S8gq|zl&B7fgq%Dee zZrQWOSQY(0%_UKPuOPgxAPek03ahRL&*%_QeE~d!{XlkJWtH2}0MY&<|7L(1?=?e~ z9Wm!dV5c;jUHHaT?HND#_91jUPabC-j#H>Xd_*}l>x*kXG@}B5?)DK@a+xTtoXHHX z)Y`@$D{R!w13BU`%FQB?pdS3-CCjmf0Hn^f-iS^IXe@qxR{#J(>^LdLky?TXDq2mi z=JdEUD4j)Q7<6<8AEtT<=whEGLA+)ZRhosnnGV&J?i40A>DuAyT@bJ>?*PC>zZP?O zDUnKTlMAG@fUEUEC*zv@wDqEq=>Y34NnhER(0z23mkwvA1IgHNze<=ITbJDyw_vqF z@F`K>rZMlzXEcPv>4Me|Y^P{T+@k(x@3rO;tKnkBq+8I)P?t&f`F(0LyvKx?PB|AJ zWu5r{79)0ti){#2Uh{Ewpxpop2{gK^KVmf%ffhg)Mt)JL#-7GCxj9xxCJ37nCa-fl zc4`N0EjT3v7}ijy1l_>YS*ND1`Zw+89eZ{4R3ZXsJe^?aVapL8Riu)xbx zyJzC<<>!I^^Gi*aVk&8dT*-Y}=I`}=nq4${iag7&{$AC zzo!ma-W1wb;Mgce9uGpIq^0*wLPu(UNRGxXG|_qx1w={M2(Jg+yAeu*sPy4D)=8&Z!RnAbI< zbG~b}4YmLW#wqQB+^E8FG<*+7`?J$Vo~p5fkuq+gZYBh4esoW-TKBp90O|RaI#y+* z|6}D}8Z{HeJDD_(B~-MCTB17|z!j~q7*}_quZh~e+0XODHj8NAO>-5Xwzq>L<0w{@ zW4K34=~f$NiOUy*LcnlkD6m9W{6``x81n01^eSCWfF>qaJog+sY%KL9!=}H+CZ%>O zJK^i7tgzA9|8Xdn`g}rXthzdA>$QQ zFaajP5cx8HB>$H1zL2%4C>^F?Rot3~q{3KaD%(2GN3Y3ADlM1}S;M(LwFI6c^(}JM9D&TF;+W|2fT}}6MHQ2IloC{^Emx@mg z^WF~~0Sx=8M)%ZtXI`1P3)E~q#Rl)3h5n#3-P*?TL)YFOS3nG^SL-Q|R8m@qE&39$!3yGby1Zwx+vz`Vd0O6dBLEy3F3p9-ir;vNOHcTQJhgN> za+&wPu)Dvc?1_A2v!GtVO$K(JYj%1mDfxd)mTX8b(};m)3w_Cad5$#@^IvVz=ge`* zDhIYZ2gn^Q$S+U*nfOsygjD;JBZmtISl>k*K9%aSl_6>K-dcjH?0S?w=EHDl{)glg zd!%=w9Z@)<_yCldl^HqW63@-E+Nqf39(<>#cTW-4cyeeSJDptlu+Jhk#d^0s_quDq zyl`|TFOY5$$ezv$5$W7aYUhy`g9aU85;nfe4GF;N@HhxQf5g>^Ir02yF;p8L6d=Gp zw^`QqUrM7F2=YIgig0kGgE8Jq41&#$yzb-(#EDxFhzSoH)gHABA<&v2W^L}VBTsKn z{U|WEbqE>N9h^uTc1D^{lzO630IhQ3*OWKpis!7#IwtPY*vdgpb`y6@&lnfutle5* zvyku1kN1>gR`sw$(Hb8zjV(cnSCZL&%3iONQpz@?LBgnaCG9UWeWT@zGPXPY2JF9x|L~NZoKMH#se7W6k zSO!J=VCM7)XH78pYpnJF#z9hvaU)lY9*#O_jCi>e1)_Xh3r#q$@T93$(KWePCFTI> zO*@4Ieubt~2Dh;-?4rhmZ!J_aO>sJ0HAVQ=Q`SQhIMSa4n-*4{z0WPYIe&8#V{`Zh z8V#;Q$gVccN!bOcizIX6t98_S1D#8=>IT0N5%h^WoA4vWJpVGw5H*DK355c!U#t4` zIxxO4)4X0it}UI-Rj{mIE9OD{`qo^hWIS1TXfE9J2n_?=8J9zW3Cc~cHw7V&MvUJo z87O+qgM@1sBy`Zz? z?#Ua(VPITy21WjY^^o||ly&o$jY?*Ko66XmRFNGxEnF>wSTn_Ao`wY+FQ!JNH=+Z> z^L58R?3liom1Cj?d1I6pydgO%L6+fs9V?lnKG$QXzo4%C(!=Yr6suX&o)pqUCB#zOrSNF|p*!v#o>1%=;}KgFgru2r-9Er(!6j z4wFShtPI*f^#7SA>_w88v?Gfn*HFI^Ha1K8Ew6Ru^V1M6Di!*&X$Y;rl0y0t;5~Oq zQ{6syXn0y^fH$%0SY}8@I~q(hW{y)7Kk*iq%MX-Sh&deW>@@d)z=evuV>M2#;|`fi z6eQedX#O>xF{}jXm%#Tj?-pIBxk5sJ?s3!9Juq)WC-7a?F1i#WU-};}mbMZr%8SHs zjjdG#e{O^$)kel8Plt${cWpuF_&1+OXCHQ~FOcLoTUt0$3$DJ7Afv4djBdM;<6E8W z^0?)zNZjFD`NWsM5k%nsdYO{ez-|aK096$PrLt{hmHWs7*GY;@Et@SPtto=8PcGVZ z(J}F3ZO+yS=4oyqnLX~1XxHXpu29PTvg-RV@5hy;!m2iYzG56iI{U%#UM+U5slrJ0h8Wxh}LkLX)RJ1vCckMZMw>v;9#Qo?+!GlOoL%0LL(QN#S&$E#Q zsvlU6M`Ie%C9R&G{^l7AlNlT)f}x*scuiRNy)`K1(=W;Ma+XQ+ z{{o^JXo*Q?QiCb|-B?5mv%rZ{8!iZ-E(_Rxp7dCme$n)$0Xvd&>o=+>FuEU9GOWUH zwBdkr!jr=U$!ewg1gg7c+E#zMtH7HS;3yA1F>jPwx7wVkhI`O(ixfgJd;hYub^gmJ z=lXdOsrH5+Kx1PEN(`j6`}mEG*VWfCkP{V@cs0ooEkec6MNh}Ud`MN_XZGyyT4c)L zGCHsk85_C-@!d!L+d+MUD(;HCsI$P`)$8%1;W&X^y)dRm=J^MZ6C!ZO5r0Ja1R7E^ zAJkk5!)586yo~x%(QTVc7p>(X^)RsQd^3Y~baGGIIwL#TL|c})IEf;eQF6ZK1a$S7 zx3Z=8eCvqnBQ~zlk(CR=N>%ORkUcuf4uFUSx5mU|QJ_Sl9virk$GzDjUu`!mEu4?5 zU9D8l-Wbdk1nL&rO)9iy4hGP)yqBgf+`fU-2(UX>t+kYkI0uuR7IEWFZ*CXz-BCtc zZg#pDq;gO14n)VAk+o*I;v2=U=3o8TrERf))!E6o_|aoy*yjqBQ97%Gi;m{phStxW zh@ne*e~bs0gHx!XVRSs*N$SS6Iia|x)4;H9i7S1B?_ij=*W!9twr}rmI>qGGfPLPi zCDl#>mol)2F>W(ItP$KoOdua)jxFt*pZJlaVc8M*IKu`mX~#kzY@E;kjT=^Pks-25 z&37R**MdI_jYrPx_pkl&Sj+Z-7b&LjQyitoAYp;MF^(Qr;-679ow973rplXhK33*#@gg)F$ zrJOUy#h?)qf^lCWe-VC0Q-(T&vZl9=3`hN!*+4YCP*o7nSI9-(6Fl zt7m$9ohHVPsQIX`GmUFj0RV$9sxrxo5EIHmpAEb8`_Z=~Ayp@$B(RXF^eg?v`UlSKBQ_cA2cJ_!M4xvGz z8IBHY2g*!*LWACkoK6USoJ?r;PFl$D(E;3umoV%|_=hF?Plkl3ia#hfw~UPjTs_M+ zcV|@iZ=kJSWDt3rLtpL)cC+6ZaPY>#^o_!R4q8Aex>aL=S@v81?Uv>Cwh@z$j` zodFy3r1MAWwoZXUHD`@@O+q7|g6-|fHEy!c?wSK-)My?a)sLTn{+bIw68a6iYi{JH zxW$5OGjfJ+n!zX?!UaM}5OOC{g4|NqXT_$NfQP$# z8=Qy6&wX0pAKGw<+3^w6rc@yVw1iwx=aWUxNF|Kauh=@B7W?zhaO0yOvwQ#$bT7+Q zIGGpVQ?T$iW*rKPTQ-PnsCk!Bn7!>8ms>NX zt*|s+-8GNG-M^TT+-L+u&!3qQk!sN;?1!mIBU7I~j71a~&Gg3=F^}e7glFfQJHbh6 z?bDZAK1*;|#kdfGY=lpM$xK)4S@kiv@I9-SFic&l2E1;d7n?KI%BlfQlQlj4Ts}5;S=W)XHQCU_s*%k@{z*c4h!ykZlx$=Owf^3NQ4S zGkl0${(F2Eq*)6AQY8pU-c+#1-G-@yIb`*)>8l2m^L$PF&m%hdjN^3ikbT%)qwBUiOmJVfj(;hh@k(Kh^Lg9!p_g z#R0au%Mxf#%bR`XYWC0^?vKNKG!j0R0Mpd+#}E9jT(h1&ALaQcz&}}nT##bHr}VF) zM(&InlZUv^1GFOvdkLovZS0z(`>UlCbzer0l~(h8*75WbBA(kIv4j`AF%VkK*MoX2 zkKK`Kb@D^p1Dk5WGb^w7Cd#;Ep7>zkl3EZ;C5%!cuKlQ^#k5KhnYQmsD|Its&Fer# z?eUK}Ei?V>)t6Aquz24KlK#a6(4#b*ow#4qsOlm+>B9!{Mk>_hNlA$357MCaa@zf2 z7AvcD=c;__8*dpi6s}R)%m1MvO((qMz1dq%v)FROR=vl~80AuCV&7i;jayN0)K>9q$vza}WpUWBymnnr><63|3tg2B+>we3nSN;#9nm zc1CyO^{;=K0L5)Bdm$zG~Ob4HObj3+5>rMx#|838ni& zb*XeI*Z@&Po0Y)qulU%$%U)52cw|-2OdD2!(!U`~lF+*J|p{~Mvy-*Ba;kHB}~fn_VG3r@l(ip9DhCen`HuUpKIpah8B#TVx) z)91C0QpX;UOx(tBmj{vS1^Udh?6b)c)+yvRAwB3-EiWI?#%n0+u4Y`x8D) zDu(QW1bQAuUfux7&)%ITtWWqXJC<8mVHK#j3K0(?OCvmnPQRe^*eMpAsrouifNzgr zL|(AfAd0%jCw3&`PX9~_)xpn&z3t`FP`^?17`BBOb=EP7F4f@BxAqXJxxFuUDHnL# zYHp`E z5J5xkY^{koD!I6SNu0)RB$ZFUtZFE+nwE;8;`uRY3plICBBD^?ua~5n*|%Q&K>1<> z$rlLL3xB0K+mouBh${oeRpXTV8^^jOX|^kS)VC2P?yXH#oQrck!lZg5eu0zw5B0tw zovMm(G82scp2t8l_-InLbykxJAx}&j)m6n#`T^OXb$Jz| zsWqA`!P1H^>0KR@L^B#`;1Em2SWr1xW`*5G8WLiiY2=KtB75Pg-=K*?-6N}t5dQ5E zGHwqMr^PNZiTZ7F^489-%uG?5t?2@_oj);An|u>0J*P+KxB&G%?E%;%K*1zTMjb=e z2;E}ZD2iY)kjIXRQGn-j?_MI&*_7)Rn(Jc%KH{qYB|%^M!C;&SJ>|k~NM5su$(sZ0 z5)Ev&pd;s!J^q1M^eG~4t$`m#d}sM@7j{IHdWp&Uv9w(3Ewx}%8Vy<`Ms2H5F~UU@ z%zAGbaX8BgUg-Zzbc54KoF2ViP+*7SCND1wvb*+5f03?K?rMuevg_`0Wr4DkwxE+c zkEQCS2Z4PcP3?$U{|gT#ZrQh4w-l8uRh2z|F9eb3cSE?A zq0$}EDzx8+t?1sqk-sC^BPZLO&@F>nH`5r9VUx zeREaJG+~!a_oWom`d*s2GN~f@eJE7S1+EBGu(xE7WO|Gu1!%4BhCLSDdD=xk;*)|- zMP003P^54UDP)PHwRwIU)Q^Ic+<+#PD>NREFRrgAD}w0vRD2{7t-(NvGhf@vqmz{= z!h$G)O6)Eqkqk)ET25=wF^PV9)t7O|=832L-eA&XT#RECk0d#)e2ZotKW;^HMek?u zLFJl^cX8BsZ}*v~pLr+9;t7}4gYowbKeV?9v}WNl227;?XoPG1+tnI`C7`DxVhw$A zz%bsn*ciE`Khg*5s0Twk$`Hl+dI&A~KfQn!^7qEfwzoDxbeoVd6JVA}#nt+R`Sh?@TybZb zwz^CR(4|fre0Ng^tapIvG5LJ1;(JD8g19K2Yl!`z#hj*-PkWc8*?{7*ZQlQhfgqL6 zWln-;xIdp2ninpp;!9Sn44wCsf(HQ=#MeZ<4&SR*@*=Mk;_ z?6i61!z{XPYV7+;(l}B>1>YetpeNNTEU(>o1}6ZHY_0zDs}1szop`u&dA{#*r0~lq zRl|AMI<1OFf*)L!iHgUG&uOHLhvdOsD3iPQ=z%CHZfZnv|BEm$IgEm003$%$zw0vu z=?N)2R=f8i%hjwg0;e0K4(6Fc+({7Z1jb)Wu`ons$=sX{?qL0W0ZH{65Zs5$$a@o4 z{YF17R?)A4S){lm(0+Z?i$UhD#Q)s|fU1zZyqHJ;qB{0PxbdL<+0m`CQK1WR8@|Z8 zWg*(W!vrf?>k7I}8|mSYd*Q&ATCD!OvZd7(LKNwEIN*fWf5T8ad^U8C;pf!OP%O3c zNI6uY>s+9wmAHUphi8N<-3V?!AYl07nS8e+t5KeLM_CgYANxhGzL@Io-jGb^4+YG7 ztR2EI82()m)`Z%w-k2p_svt4NdwVceDzSsbfFF6+Jb5+2Cli++zTS}j^E?J+)5Ejy zQPTbO7{C{0e9X3`%LyVO#FT)*Z)3`je(nz8C2+3aU0syMO{^ok8v2*Wv%fb39(l8` zs1(WDQE;0j8c#0Y1DWh;WQSns1ndlb=?<(cn^K%@>f;qx-d8RInZAuc2hE4Sys7w{ zS+Rlo2SP6C+mbW*br$B`9&nMU%0v+dhm7SSFrFGonK&k4lL8P&=|{JO>0jX_pC9g< zNP$S+>r|5wAsLs!4GtV4Yc>cGtPB*w#8vv+Ih76Ot)FVmwu+;+8~2}DNnia#V(`r+ zJS=(qLoG?X)4esZeUIQyYb0(kakzFO@O-IdpQ#riekanE8|eJ@rEV{Bfa0K9=8?>p zW?wQ;Fmz8UGf~!gda9x1djMVqM5?jYLRRsNlW?m0Frzs5BMB0L#!ESU+sLfqS^3p4 zC?g4w6i0Frph{Vp;@pEpf)WXc{M?o-py(`g`%Whb|9^bVm)}p&939saO>z4X7PrEwp+?W71RlR9<`krM84i|?vLc%5TeNW_h^WrX9hqD3&{xy8lu*% zTTn5{O6F~-+PW`wCBnm@qvR6Du4D9=81N!{u;frlD(r?@x)VUg$YA|nIi4)Z_W zSPHr{W4|gSuvKao5)jfQk@QFgdd01aMKkjQ@#)_TqvSAPgow}}lQO{!DfR74 z-FL#HK0KffMEWhJ>_fL0pbBlDpW(P{PGqQ629MeM`iF9eN;?Ia;77$3ZwKL-e3urv zK$7@f>a2k8xorZy{Zm4XQ#l}`af$Y@pyziJ@vUsgA)u)N@6HyWH|{{hFB?W~_R!+pzn8Y-+*!*>|I=UJOS$=)IK|HW1j3ye&K`j|#VIF{=y1 z-g-*6P+S#;KWrQpCiyMu+UARL_ZTPziEf!&@F5xUC$>!7(K*=vb1(eCJzycf-N_`>KQYQh?@2qBh*Po8^amk zM$CKL7;)}DM8nwZJm*OUDJ11+&8~{7rHkELBVYb>jd{a0MRo2Yr>MjW>&@lp9jOD6k9tfoN*(U)s|+{FrV(#jVU`4$vb5I-4xO6CiUi2cf=7F3{V$l{!+_n;SX5I;Z@i>KHU$iFWTf zxFr3@vr$W0RNw z68J)-JOaE=-JWi*V8RWKi-{_aC?U%J7k2!(7x%^3Lzuw+4XB8(RMTdmXI-yeZ-Y3x$v+1%FpK+$+*{A=RY zG|UpUp!Q~I72BRhr7eA3Gud(Sb6RFs5QW-#r7T_*AsU&0bkl zI&^1YkCMT;n80u@pwa6ThjyBkW{LxRdK2opqU&xiS7=Iv31lt_R+Kmf7|N{p5xfzt%9f;Ts9Q^v~Bb2swIkFRaeH&+R*c)3M>A{T&K-_}p@9 zC>{l}%H=*I;aXuGbS7d=HLB!pJDDr-x%QWrNa(d6UezA%qcS~Wxj_jM797^}I- z0u$c5x}RdBguu>*FVMPk#@a75zgFt8RlBte;o$?4fM%mBXrD^w%lj$sqIJ&1o zOq@AIsUGH*2>CdK`0im4PgA<|C~GS@i5Syk?ZQs-eeBGXC-P2s#>R*1 zUl~e0@TQQE_0+o`yN^I#H#x7>qH1I(O+oPKXG9+2eL0FkV!AT6F2U>rW2p+OV-347V?}6<;PQq_W3hVaue4g=5SNxHAN^_F_i7DQg-L z2$VaaWm{%tes(G=f^I!x+sMwc6hf)bf>uJ4xZ9^?{CnwRHiR@b(ULe^yIy&!I0jB# z>>l)gypBfOxhlG2N0eJ@Du11lyav|YG`g5Dy&=7bJ3A1lCdt&9px;X?b9yOIc8S1L z6v;mi6G_~|MCWrDD`+KH3`lq2i&A(75#N)PG%6YjdBq~i0L_uVFAED}Jii)S(d7_- zhdpFGYKqJCRtFe;3;qHONUfSjU~BPf&h|4B2L9zRe=&5PsO(BB4>sq#)8_n#Sc9+9 zq=`$>-LMes{An*P&B^qSA}ho7c2&0sGV(td1HyXZ$?~tw>RHs(@Q*#+Z8w(rL{55; zYvjFG`XpLz&7}B%^Egi`V;DV;DbqD|w5H(9j$<#Myf z-P+g41l?2?BIGHDZ{nzev45Z0!%Hm0Zcm(uI?sz~jU~aXCxPXRS+=bXbYR+a>^Jun zU%(nE-O8KcI2j5tV~xZ<>Ve=O(B4DgiJ2va(4}v#w_`K`sDsGp4Cq?g8Hp0VbaG4Q zFq=P9n&Q)1OSm6IvRLYbLsr&1%)s)It+Dgw7=(vy@BaX8I>*n%r7;LyAQQ6z9Kb2D zN^N#G?H6Q@@dlan#f~}ge|+~iNUA@Pq9I>ncl=a?9^2j5rT~=)v8C`=BM7!pzlj{{Q!yxwY~b(fUvE05>BK0F`VQ z)zlxDHC(F&WE^0ehPo;TB;qWbD&Wgu4|_p)$eUBnwuDi9%>RM@X zsLfnU_@X!isy17ZlDQ#^U`&f)hvlzpc>eKoIxqZ!l}7VvvL=6~_J{6AG_YO=m6^q7 z!hi8g)E{YPuGi3$QZS|Wb?cJKjrQ&u>urvtd%ifP`^oTdlHd&GMn&dbPjLI4?*1DfrL2X-A;c+YYCA)=^z6n3rxorC2G!f* zxD=Ko9arSSNBmB>KEUGZ7ZJz|q1{3eQ$N3g!#y!0AC;vp5pHoE!RJXBAB|8i@L6!pW4c0VM~t%0dKgX ztIBXOB@O?}^J0P>_d4uUyWB)eaSJU%TZTO9L9z*_0P^6Np94*C-1T16STs>y6829k z8q(~;8Cpel1W{Cwey2dI79V5GXf01v`z9-_&i^*TcVn2fRNTCV!H<7)}yT~DFb z$230Db5lJDwuN@?7ujS515Z`$?BUAqQaxw3dC;Uh=A(RT?9R<)_es0;f%T4U*$i)# zNMZ{K3%P0USaM={tZ;jy((qe^4^}Y_LsMf+0*QK*XY&FM0a)H0N^OsU2mTs}ENB-o zddIWg;->FIIiAQH5mFOM4Fudu*w-)?7``-KjE`vpSze;Cs08JA>911;1M2d?So(va z_o;3U+(k6-1tFHqa5|ZHK1KcjML=*VRv#i~rLUld1;SelELUH(_NuzF+yBLG(CnG1 zXk$wu+lRFrWK|6D5g>)}0wJz~T=)Qhsf9h7=!-$LL>zti7`97C8iKD0*{~(6w|f1H zshuI-1yFV=IDk?)#$sJqc4jrXXGR6@^o6}@5n*$mzxct%Gp~7>kMC2MYfXmWOlPkF z)_p}z0A$y#k-8+Jo^AYgef`2)t=Ves5jS+;E+#;va5kderHrf6;PQ05(h}P>`j1Yu z-yV(N>vS??L~D09);=z{vQ(E)CF+mz5C9Y`H?G6FMl(&i46$d@Jb7xG!n zhVXB^d$Q-*6aw_Fw`R&V!uNXXZYXfbOP?q;S0kM z$rk>8*S9wfChJOOtI4K!Q92K4aN&O4Q3>bQ`;ZIGzJIe5u6b9kHO z5x!=J);Iz^x04x?06e6~Bk03Un#o!+_XUgYt*9 zB^G;DcxWON1}_OgS97fQZ{zd~AO##&X(QI9?SnE381b4Gt9n~cmsg2CwjfEX10DT? zi`#%FFnhgu5$X$HV-}*i*RgR9BdUC07XwZoGV+~-QF z-|z2F7j^<5OO{@83ixk`xGqoFIl%l)u%`to9h^>DJw-e+(%L>%6PB!EP>6scwI!%& z3^#JV=DIT=wr4p|ZNT~ICtwx9b8;0B(4~?cV0g`(bQp_3Px^RyHUigM`^)zFkfh}g zoPx4p@3n$oQ|(vLsQx8t7)2z=c%k+L1D7BAN$eYgY~NwD4!bWDV-ey5qQq9Tm&Zdq zj}9QNEGn^TsCT;Kg(98$Q8$xI2UA1Ne$AzPGR>ksN61Q^C*1}gdX9G%{hYd!v}u5o zxa~)CDW2wlo67G+D-hZ?n3vQWrY^n1Z*g+p!)tWWSQrLkm0YQ&r!#;0Dq!`FRI1VI z%{vFhk43L?WeuNcZUCF(-hT{q-DbckAhKq!7xlj-^ff&lp8erY3N6oeIQlUJx zGoBo#W*Hc#+Y4VPk%edy6F3>Rgq3|kAqduSTk_e_y;bK}ciaJFrG0xRxJ`A_^xF}3 zuMLCO0W@@2buG* z9n0{mjvCG=XFz`MZ7xI768<+G=#2kqFd}!Z9l)WmOSV^5CCtrScH8`S|H~4BBrv0g z5zDzUrVeQZc%w6!gC)nJ4ltSrEYZHOa4yuEOE>tRNohZE(yACIHVG?GpSx3wL-;_R ztXYA#>`9|m>O>6n0lmRvY+knuw}IuU4~#%B_}`&bSB`ZQ66<}bR=H7l`42lyQlT6Z z3)&>lpq=&^oubAMaSKa|3puQ}iY!L6`y>7pF(|Kj^)iSe$7p;L-O!=yge)&H5NcdV zB_FJF0qS^CEpXkAe{I=G^*c*-A1~8{aG&IOCZixInP3AP|5nCJiNgv#xOlG=^`B_0 z&O@Xde8209YqmmKI=6M+g)B~y@q_18!#DlYq88!^ke#fUqvNzTC@;<*(y>AIKm)C2 zYrxo~6utq*x5ODAfGvB}C%h*tU>Uc(q}%;@0~|x!PM8Nn9!bB%WaE%g=c;wMH2Qz|IM znyCYjA9!E15_D{sh)ody`ntw~mg-|3GygmZH#{%X{a;m2#%m~_4N2THXS@44XH?hF z&k~|=qTYamlM9@q*x2KwScs-{WiYamd-dMa(%v;4yugkCILO=VU+%w(XgiFM`EKvUllbUCT-(io3Rj_qa=__W|>=$!Jrn!CeXsG$-+eS2w7=>y8D*OEeKE& zey94rXY|oNuLf&SanvoQA0~>W(V8?))M~3j@atRY0___PIVJA+mKfxR7x$!c3z|@f zGxMalh*kl)`jTqMaki*+&-Tn_82}f2T#Ydi|K8lQ@UG#=@-N@_M#kVo81yCyxK=F2 zYz2&jXYgOv#j`YBGp<3O13_wTbCQ0Bq|o4##YmUEI($~RmjR#QB*phy#rS>5d!*H5 z_?20oK5wVkrQ#mfHo-Ng-2eAR0ZFXp?Qwh4420<_lm-b8W+8bmAPQ(B=20baw;j!& z7mo_P)Ym{77oTwF$~7rC#GyGAU}f~Edi2(kEjj#_Om2DnroQ|>e4?=wC?+whnZh|ulzg%`%Wgowo4i|0?T0G zx@uBY8-a2&ta^Zy?f;0|p6$c3To%FF^q#pc1(^|^>XF;Q!~|mfb90hJ`?lfr<7NuB zJtOKYu$L8w!P=FJCIW(v)b)#9k7nsffGn-X+6L9}SXIhC%o|72G^zRE2oq*adEFXR zS8l=koQTP~!L_$;UYbtQP|CLJ;N+RxBn!Lm*NSHmZK>DKFTP^Sg7{;mRfaVMI}&S1 z2?gxA-MFyglRV$noWHwF{;2W;SSbJ49|1osej!mWRa*8hf+bo$bn|^;YbXvH{OQlJzU$49Z6Q-ah1O(bDL0vjyYau+*sY1@_wNh(}A9tRYj`alH&aOm=J9`KMfT?De5zQ2X=EAdhr4g zK@EcDMM2-U?glSJQ)7-y^UfEux*kU%>OGzM$P191YoI(^))smwle3?H?nY!)hw{#n zLLG`FkI?}n*x2TgdG^~w`Vf7Zan9@!!aocrt# zN_j=0RS01PCPm|&0zfdsW+I>o zQE|lF>fv)PaKFt}h}psKc|IW28Q)T>{W-&@qJb2Cr9mQZP(Qwv&qlHAFvTd%0&ix` zaercMP(ju34PD5qszL3^%9JT3U{BtU;<^-Uh)ix)W$Q`8JC#TbRshmu;kr)&kySuy z;Ru_=AW@S4IQt}eibk?mLQYEsAz=xc90kDkr zA__4zznbD198l9mq?Muc#RzZ`-wL^n^pLETh&5MO#>t4)mCGCCgGXAYst>|&-rcI4 zBG-YDT+lZ1i54@PXTbHp7rbwS5@87b(W!hRHV5*!FNs5)_}0b}gM@=Ma+&2x{Hh1&c zRZ4&VpRIRiF9MPkSs)ST)2pqNKrvK1(9U4`w_ba{jWqd$1B)!hd%0QWY==&P%obi*u2})xVJi5xIV5DCNn83^ za$b^KE3v4hq)ZVfHE>crxNEQ%I)a|?1r70~S~ly-X1=aheB{2OBU5<3z0NV1+4`gJ zHUAP_lP5M*sDJ;-DZ?Jl>BWr6v;{N27b1y+n9c1q!*zA>@XJ=S0~rjn)5r;zXCkGQ zC?D8JUrxy|kOJci>DKKjLv(yR8V_t_b;%DI#0KRqDw!)Sm$Xjie;e0~3vZN4-rMSca^OPqkeuz8I9!y8+Lux*K6c8#w=KF%{yHMjl~HY2z-+l%np)A%^sfD)kWF%^O69s zLUj(oTa1M3KwsJ8VYHqLE1^3$@*;&_%%ou1xkg@Nbhkt~)Y`uz4G!PanzTM^Wn<=W zweUC^#^dIJ)tIVX7OHaWDd}By_~cMGBmci;(kX3SUicAyt<9YbaHw1+Ud;NZ$oFQh ztxb6De0&!J@?3C?QOcg11ZLQJHx|i@%ZpFr$E$VZBJjYneAXzPE^m0|06#to9(Pm3 z3qmnArvMef^(Ei`&V4JkFfHMV#OZxQxQYbbR;rG4Ma>U#Hr7AwvfIs_!iT>tBdJ5? z`5$!{(MqkS=0p$MF7PDblOV@?N6q^q60Ok*+lJ6&%QF*(?hFH#y-^DWtiSjO5t~3V zuhqCnv&ZFJ74oDQCeOrvo)#uu%1vgZ=($*5p`ef1!ez|8F&PlNqOkEDsbw~E?`5__ zSvUDepG(iiOr?Uz%mh=$^!i00a#OKphcr+|U}}Qhk{va}(q!=ELEi{>$p4_9{VdV0 zP^uar?ifa*J}p*|>T-faox8W!=l><=11 zKf-?ZIz~BF!6{5qa*AjOtQF=WuM*52!T?~?oJ}>3mgwVrsiwYI z{4%M%Xf^XC=eDYM?8f7U+F&9%E>0&UXv+>7c-%DW8$tUbia9t+^$4%wnmcax&ThWC zQdBWF89ewg`nI6aGHIvmmIZQm8m*`d1jA^n60aQet?S(q z%%K|jk%Gwr2JSa6{*tE)8HaG%ksZL})3Lkz{vJvpc9uZX*S7K5L3@YftsBLGKw z#e;p(OFzr9Q$xcn%hCEam%g>|i_IU4QPC@lfoFfikjHVn15S6g!u$X)l`07AQj?K)vd#$;f@cE< zjydO$*lG;$)TIh^E^@Sf&UDSVc>?a_<65zZ#kE$#`?AFxUKLJTo3;khtX*=Gs@RChSDi?K2+HTS`v|pC5P4e5? zVgt;mAg&H%GyT_`#6Pa_3StHURBMLp5kn00L{K;(3=Zf5{m_A_n@JA#fHps8^?28j zB0|tvj4O-anQOL+y_*x)L@QTr`^q%6*EE^?9B-me-4vKy1m1@5uUr}Qlp0{VhUf}A ziX5m?57M=8x}$Wq=Q&yK9l#RXedo_-@cE$yw{DK(X;7?+r_SgCFAhiLpX-e5fVClS zVGp6uf6!T46J@a=%sAsZ-etS0NeRO-I2W^cj$<-XY~VMQxuIvR1!st#Fs{caO1gw3 zDX(WS3&3L(U@wkGtozuM$)p%&G6?Xy*7o}-8Kx-Ct{_5}*!sg)=3D{QbZr7v#TuMs zz);tx7o||y^x`^E?cOTGL8+A1k=oi#h@%rM59nMU{`7RYP(r0C22{@ulwM%K(>!>P zB@pP+{Ku`J89i@&T0h#6^yQVmVK*uRt}b8?f&z!Vs7i*vBtZcm!Wcjoc^wXYF;eZ| zbB#O5j!?o9l3#yeOb4#1$d$Or6p8hVXFGuqC5=LW@0~CdDKB{Ks67*V1%^*j8AP3D zV`z?hDN%d+`7MkN4E4h&dHb2_wmUoTRf4X;4VyB89FftQX&`R?9#9YYB z*Aqm8`6+ug!IQ6JX$$+0k|)(UGkN`R@`RvmU(6~4s-wGpvD!r!!VMvLl{RTc1SWct z#3QH#bGxuWO-%%wb|V0Jbjzgg-a)l#+X@ISnhP^3pXl=pw%W9g7*3-lc2inq4daEE z+K-bPWQ6HX*!-}%t!HR{nq;r6kA_zGBBfS892c_ATglh2QBP$_4<8*3vYh5Ohig~) z3oMW5HRYza2ds>yv8xpowkFWFkmbNgnAfubLUvK;MlwsLF`atm7P`_(1!MZ-jEH-J%7q^F+| zTC=z%d9nK?pdOvb9e^)1c}a ze2z$r;g4DOzIrg3Q^(vgA@yYmts~j4nJT2JVv-ov8Lxcls6K}wFdinqb#fbEjusZ#ojaQJPBWOfgghiWYCp7lb0rOXdQ#SV$cg{GjMP z<>&b;Lsf1HE0E4mh9(6SH)*>N**wj(P$r7o{KLv|7$t*x-v3^^@raGO62{VE!NuC0 znYwXMxzOMvl8nv!5Taxg%cz4*Dq+i1~Sk zJ69~dD{+}s$69JH`7hhfHTYyO$|%dso+aEebO`9ZQzmg;72jo*oOf4>1_p|bn+2kZ zc%F-CVuH9ZH4DBctX4S=s{au{sN}U++xm8PN>Zl0jN(1&1UPX*tSVp`{%w3-=TxV| zNNzdIef_C92K{dE7;WQZ*^(Ii+h#y-egU-k-&`pU5&JyVn8keV{d)C2w~jw zPmCy|#|D2YY*6Le24Yi*w3ZZ$%8(kllgs{s1<|Cf86hHzMKvtG0!iNYB^{iwqe%8p zyv@rj={zQ*;+DS?NSDfq&fELC1J%uLo6CC=P1h$8x-J7IK88nBm5UDewys-Fp__?4 zhsky6n#I>Pp7#7-r(@*F1*}h=18n-PBpOQu!Y}n2aJSQ}(;B?qt2zV-)>sG=h!#;ntBushDk)yN>=_7F}RjSYUG##DzWAz;HUjC!~z0RrD@%~>sC0U znt?z5C4UC39#ZlWxFF<2+EzV~G(tdzeHr}Gqv;Rg8no!@WIlP8V z^Y_26jM^!HWc_z7IN8*70i8Ocxmz_ktw5_SgUApzc}4m)l%*ubfz9RCSTA{$XrmmP&>_PP@ZXLh=3C=br+ zx2OG%8O>Khsco2C6G|iDjr#V%?M+O% z`k=4cTLo8s!H4Ifj> zDV2zprd%;Vc(G0bs?7v?|(l|jYE$B?TaHluck);3U4eeP{ z6(|DnK+ZlKO~`CibfW|65tjKGYx6q!NltPpPKiRTwl?79be0!)S0G+szpei^E65D$qYZZl0XGcExDw zVxC`tlCM=yC~cOrw!fN|FvGFH%E;OMa+n{O1>rXAxk=|iPbz!ZSX>p}TLvMy2fnV=8XWVDi z1;n#^el(EH=3$rF82o{myG`4Zf(9j**>nW_3|LTktM=umY7gu@aJ3lcP}Gfd!EpIv z_0p6nm5cd@seP@QT0rdYC8qwQ&=agPt%y<(-XySaNbBxC0v&iDsFLuSg17^l|CnR* z=K~<&^_S(~T3V&UO?jMjFNo$h%RlJ$I&>d#@lae;4UKrO;e(aaI>jI3&G$BJ>T>m% zJ5+5fPdJ~>*t8@Z)HJ&^?v5(7bhaRA_j}n;@G8AYQ+!^Fk~7WUuX-m!!eim0YkGtn zWjKe8I%~iX@c&pjPyZ8|ZYr2q+ttZobe%YpgkG(RX&KWG-UHcgkVU2%Y@Obe$e6l7 zRnrBI%N4iY1IEb0(L3A90(-)*s|3twBU)RO<0zZ-E&Sth3sz)+IrUY0{?>3p=@vLk zv+i%gvIK*J^;;AeBthvHd~6Q*Ftq(Wrld$!S2+ISMiIX`^3Nl3GHsXDK6WiAs?}Bj z<;Kaq(zM`+qWuq%L$z5H0xM>Ku_Kx)}138<=!bDs}AL=_-DS5Q2n(Hh~a1tfT3toOiVcOUX z&}oRD>wId$?fu(YdN+s=P{;qG1QBPO+mxYtW>*spsA?JI^{K)>JpTAbja~Pt>REQk z%egGt0z43Vy>Ec-9~MVZXces3Og!dx+(usw6VDEQ<%|&ukTWC(z#FyP+C-5Oq%E;! zqAN$#0_#f2X(Qn2splP$MvK^={Yu4`5^)b>%pJaCDy+uRYZh9VG6i}wH{q432wtMH z4=19{m}tz!Ecyj8DNZMcEFv(-#`mh%krZ0_>N~Znby()-wlBIr8I;$vPi*j@MY#1j z;TQ&dSJAvIIsD_3hjJm8q?GhqQo zS7|Fv!})yAw2bi9x#G^#QVNOajJB~HbKan}9x)GjU&@>B)OQb16$ZUdVB;FJAjb*t z*?bjkgW>iu;Xm8RQ3V*s#{`D;tuDP1^c2&%?LT&QNgLiVfTt&0C-4v0fDkkon^N3L zK8cfULVv?QcP1JKo7I-IaS@-2i#$k%8AGo8*DRJOt|c*bO3>&Fa+sn`+prZFNP8#6 zQ`8o);Qd&NGT{Y|s)A>kHU2|sMdKC5>p5fsf^xwBGTFK^rF6$t7sgGF3OD1-h39}1 zQlqj-fyqDslzhtL#%X?P#j74N`BFV?8(uxf_FeChjd1(lj(;3cDy3eLkQn4@?Irgf zk=(hM`Gasoty8edX^uJVRfQb}Mp2W(036L7JQhhFdNy7!=o-S~75FI@#6a z5&yM!G4ErVd2k74^1vB=QKC2E?(7H|kiF>KF1M#1K3XW0hyfg$jR zNnCJn+9G8792w_eONNX4S!_w5`dmRRk0HeLpNS?WF3jXv{4tZg%rQ!k|46Is+-9mU z2mk}cTmW!hvZKsmM>n zKW?dEh|LsTb|!$x$rLIZMfL(pC6A)WU54dsi@f4|&5ixVuAe5XW%Bj=UZxc`p2cgk zKqqsY)84HQ{UW-xQ4?t?ESYPkX4c|>J4K-YQ*4{o3SRXOWy#Schc59w+HiL7UKT^! z42Av^);Hepzn4Y*>LizwF_WegY6fg>oaI;pBQ-9{)6MlC8JTUYJ@SAoKcM+q7w#W< zDF}8UNlLR0OVyJ5gY%o_h1`p~op9zn4K4E&d=W=AA|p_3&EF=CKO@U<&=b_kHNKVJ zJyy%?(l|@+;n(6BPAS_<6xZmPmX4-aV(s{{Q%uuly#;tYsrR_T5=0|*pT~x+M?n3f zjme@5@%YW5_j$6|=>eTN=4H^T?zjhpw;Qm2F`uZ3)Gq?7M|msv#HvyP`_+@Qfw`Uj zwH?zp^sMMEF2pJLx$<~1bU}Hw5G1WF$7`gsl&_{x9vhpY!#zt#99R9` zoZM==ZDBo4m4-09#_VwOM}9&H5l8TM1}!}7k(2~qo~g!7 z+xW;~*O8!O!A2V*zGqLRp-9od0(5*puyTh|8k#*F#;+h(i`_|5C(fUNsZcNd;77QW z11z*c)mpqZR=N^*kt9^5i;7l%weXv!mie1VY^`(=0XU3Ch_J;cLU*{d+R}xV$=O;H zZ$E&9D*)E(p26b)`6_38gTR*|z8TS;S#Ktyexfs&4IKSn)?9dTL5abTT?Q*yEz;TU z`b$G%aT&rz@FY>z34hSw-^_$O_rI?9pd6sxUVT{R6e1Cz+C1!?nNw#L%d+}dO%JAV zanb}3qY#tMcyMC;^kd}A#7(~}$38s_gdwZ@hT!xq4_V@}&O~S%#trjG+$`xZq}CPu zE9QI?1^>xvWtsHAC_;BB_&zWAA$B_Co|nqhjG_Y|&tmZf^@Y8IJ46Lx)QNa4ntw84 z`l_4R(W+UJjy%#roe$T;tMCDpH0>7RPPcG48_B1;b*OBC9MAxg$PENbl#N42ZHfwH zr8V#^N<30VQLo-jb4*lc%EQI3@)2wuFQsoLFxac)v15Qk6Gxz!cVzEF1&hpL-^7cb zexkXqwUkf$YmENG^Q#Dg>Pmir4ijF7vDtwl^K&S#wC$$ARxFHf zbHeCIx{vV;p;PU5r6B5DY6IZE>aC{0J@jCn#d49Nfn%M^DLS~cPbR_Np=A@!V!^3y z5rL#4xS|AH4#qzqnuHoWNWA-vk$ObW6g|!ULVx@F()LGnS>P8lz;UR3Ee!@=Ky^6_ z(P`w0i41a`j71_B(R+t!M~=v8qFFnnfphPPnt-RPBKsn^;J%;AHd8}GfyL6}CiwN^?l%_VKggM%+7!~9$BkPrfX`j-qPvK@k5@un zJ#=i+>oKKRLfwRsZxb4$KWwGN?zvW@9V1ILWZU|}8PRC!BOBR7z(PVQLq}dL+8S+Z zeRBN$i3>FD2Y$sXbZ*G!OIrjRbM-0+dAqnNyOc0(S#E6KS!sGpZPEZZm;P0cGQ)I_ z8d`oyV%4}#sL4l)|SHX;cr2Mo)0j44_k$L<#6_qtxQ}?0`$GS+=RPrf3 zv(ysBWmL=I3EA;}gb%tIXH=5Y;kJ(zSgQoz!gteRbn4$vBXBz~kS>DB=~;U@71?vS zGp5hkE98u#hA$rpcc`2T)(6+KJvKX3&9jBsm()caIk$a%6coOtLe(%oMT*LN;FX8h z1~O3cyI)a|ht2cS_)CZSX|{Akl1emxivkjmFfZ9Id7qH9W8!Ue6r}vJ&$nG?>f1DGUKOB`i zR=B4>yv{i1d|$Uz7wi%;SOWhd#bkt4n=bcF?d}n&3X*`dF~s3!HPj}Em&L=_y?49( zFO1M`5H7FqROH&bY5>lY-Qg&bt&_~fG$M{&dRh2!w2HYS?CJ8(zghZyK&{;QHLtpG z+FB+9q8~xPSbqOT%OAqnv1XMTU*$fMLy%JU5P)0p*;)8UUcfxLCz#fA+-Veg?J;kV z{U|dclo#Z@xez%TeeA1}TY{cYP^C@1)4kSU{#(wj2%|+wlFq-+ndD93O3`#o7xexA z>lffRr579W8kf~R4I%RJ`+5JM>Nrvwe3kd}i(qZa%pSO)ox=y!8J%HuO*nDjUtRN}rip^ivWCc+ zjR~$T0{o-36`HZZcI`6-x8XmOI%uKz+g8WB%U2M|n?QE05k$r0$3t7IWw_-00S_UU7f#3jc*T}|r1Qdti4$hzlu=XSsxaBL=Q zVf6*k1=~FeZ>u|&$2lzrPgB-^0w?$3^^xEL>`QFzV~s<`7g8hj*a06X!6e61oYHmH zo;;em)`Yd=pe|QZ3yfg@t2!M!y&I<*0>+zD|0qDl_k{)VJ#Q3Av9_iS@jU9=rC>r? z)43AoX3A!h#>|KEa@e>|*YWkbC-YTvBKt^&wNp5rc|ht-X9P||@u?57y@l>7lbvL9 z8`evaDu+0!JwmpiE_(Kxc@9QoeMoxAmL+jpGb2oC41NKy;)5NLt3Unhpm#ZmdAE4u zp9+OYHo?k6in!iTKx3I=sV$tt%gPmCj`H_z!)QUI1L{KJdz-$x2Lm4*J0b1NR?}*; z(XQU5?LP+E0v&sYGx4Kxj$6GL({g+cdh@#=dVk`e2Ja=NgwIb1tzD(=UJ+#UekJ!JbYD*r{fqlHdqTe}u|~OQY@-^{kgA z9wTLz=rkbOVH#VUn1d7Z<%HXtswj-`skcJFv7R0K266|9qlq=A_4a?5DWsB;J=`nX z0Lf51HZ$=a_JNDiy6B_>s5E^|xR?SIRS39h6}tf;`38a@`w4u};v1u?z0`8_I}jiG z;kf#Uc2d&L*Pd-Q=4i`0DPC^s1M`!fzE4E9!<{hCkDea)>GVUDr+U-+f3XTuv$@w@ z>8|p%>u6eSK33dYsIS0>k7zr?X=6#cYNE19I%UKgc(&*1-c5B&b+)Q|ExSr_JKK?b zNciOKduk4xc=U;`^5`pIVLMfc7lC8peBXh)aK9VxkG!9^#=M78_YL?xBS3c_L<)jU z%&yK$6-O)O=30|zs6P*CmxVozcz%n?LY9>qXCU@VM(&%qLORiJ(OEfB=`Zn{>MCza z_cijHd=QvYRVfVmi?&#?8G@(@he5oxz!Zo9tI_;9bkh@goS62{)`jST^aFlVE0aX-hE36|hc z!zeBpf`2$%d~YQC1FNTuZes$=6`EBy-B}e6h85M5s`n|s?m7pDTUa6H<^nI{)r}-D zzbmw-kQkcVF62?q!1DKk!(&jPW3}qn*J_4enC?1R%2h=|QHYW(pE=Ttx+Xpk5RHt! zIMk_6y_`P-jd3B2@rQzQ7ybrDiFK4X4RLB)f!Az&bDkyh9MFH2R&Jso<5F$ab83(Z zq=A!YU#4S8X_toBYp)o+nJM>&@v9eV>}>5|ilAl-{ze#M07gK$zv&InBxRdOErJ)d z{dPWMvp>EPBN1!`0YbB}z^Yg> zO|{F+BH%FT?qPgG@Dj0-I1E(0xE9oxazoz8=5GOeOxnx5%u^q!=w`m@sX|}j*5Z=4 znxELb<%FC~N~{cmeuSSB(1=OlzJl`O*Uzxy2%}x;yfxC5z{#80^+#L*0wQM(S@KTa zdd*3xEVB%9Yj$)*FQm>om=!ZyW{aN+naG>szsB3Q&nX*$S4P!GP-9%uK%W=#L!LZ6 zNI>4}l@y3xOx>y^=c7paMKhQr26Z`jT+9@F;)~9|%UivmzEI=V~tPSN1;U; zhhEL-76rq_x1LV;yURSG5x&s+7p7GVakWd5K~`s42&As~WMu*yBuIC;K^eNCeF&VK z-t6hQ^+v=mXtB13ed#wWHGW$`n(e)(eQNQYLLDVQ_*Iu+{{7B-IeGuxL!+QFV%V{> zB1dH}(5Pv%){Jz++$1G<1Lx{2ndbBCpoUkt4!#Q)z2dj#ABAAFrJ9}gAv@|PE`mV$ zk*g{pVa)}aDQ5Ikvodp*arr-u2f=F~{uRDnE2cY!8^D;<`1^6CqTr1c%6nN@NBtZD?i8{KTOtdW8xdcP$ z=QR#0M^l@rj2k5(f4e6#;(VkIYo12w+FVYQ0GyYc=YpRQzIbO1`xA&iLp9rWV2wiM zb8jtF%jUbAvFc#Sf$sh7p~V*=x8miZc9a9cLPvmx*sz1nJHx}x@g@xzJiY~hgljtk zPg7aFX(=PI`VqKwO4MyJgWo%xw>>MsAZ^{Vd|#P8fzJ)aq}u%)Zc#BC0n`~!XjXJ9 zUAqkO1HtEhYEZLEE=}B#Zy;)*9$a7BxMO<0l6W!z`;&TNR6uL1Jyj|9=+At8x9rLKQmpH$jb+JVTE8 z)rN&)0DC?0uI)-`od$HFdXi&*{O;FTdun`9j_vkCjzC3~f7xtJowG?BH9zg^r@-Jc z_78(|P3^BEbjEZql=%Gc-Af*P_wmdAUmW;n93E zx2JXy_syZGfsM7xWzdVP^r9q3mK0Nw-GPbR4#{FK%JL@mE{G{Zqbqq06BP5!vBGbC z^Q=a`sD4$8<@YQGfQ`l8bkQbX^dd9l-MJ-&+5u-H_%!(j^`A$Ih8^rnSsD@E{%wB7 zJb)b(Kvq;uUu&#a#wrE_q#tG!2X?>%+}C8Zk&uyl{GizsSjj7Jf)(^z5o6ql=&;}O z6;ml^fpVL)aW)5-JL-*kyBHB|>9n1yz zpm%79+^8bq4%4q#lLC175~2bx`vwB|m0YL26W~c3BSl<`*eqK~p;K~=3X#n^aTB+JU==uGZL7Ck2J~hRdgx%_q z;~p?uE~0M7#_(rxgwZ{*Djf@!&la%Plr$&1=c>PQZ8554M?Saf%VJNYlrfGRWB;|w zlsg>j))E_Oj=>m4s))S|4q?Lbxn_Mxib(ut^e29sdN##SO8gjxYdwh;3#kJ*+y9yZ-=QHQ1qm(wl z5IAo1X7HGUS<)BUgmF;44&$6)66;8Q*xK>J3s+@#It}TugZ#K=jmz9ytZ6~!)(5-r zDtcDJJxU4x(ZX-3Rr`^n1A>k%RRTo}Bxdm>Vw_JWeOVD~S)RPa_d$_?Ua?L1RdoLO zg5CJ9v}Q1Fe!53+5Fa6-o1jVGd2x#4f9J*BX_uO@O}Ys;{pjsr#@gqZuHt<>FP*D> zmxt7=zN_0jBJ9+A(VjqcDzH96?oZ&7=dWR=E+JR_J&{w#>R5@ zdcF_z_$j1cqGAp^0FXzL1*_mA!Ni^Lvc1xc1&& z(y`U>o3}4jgI;K}?v-9`mfmWODtc3Hx!C%y$Eb8YQo_cSauohr^YN#qm^h<3Mm?gp zMpkCyg@;T-+V4!jeVnoH!W^=BCXIqrFAo@E`LRk-fvdNeN{iLM^uM@JWncj92Z07p zDZyOL5Uuko%EdjZwcbtR1$ZI{#M^l7HdcAm6LUC>Qh>iMFH1g~tq=J901vaH$E>jor|jvYCLu4Wma1h6r8>!OK40pq-*QZ`4qQ2U#p6B6jR=B`y4 zl#(;74qtCcTR3Met9#SI+bTrF6=3YtDA2l4Ix5m|v!xIdP!^s~l3>n&J_QK(_~Wz%V| z&qA7qqOW}Nm->5+1$<7YM>x3gcv3uF$H5wGU=Sdzpjs@8HhR5qN4_@t1ulBScWSVY zF&Y`JT6vbEDvG^Nh<+i4+dYIlN%Of^W=Y@HeqVIoN*Ky>x3g?8O^dxERUE+(b6LeV zzLF#59!*>IZV%0U-2o3%`cW3SD<(LA)<;O~3gZy&vc{W3n0xyb!tAnT3zsOcZQEJd zEE^vbn|c+ZJ&SR!l)UUf9xL`gR=Z={7N5kL0bUg6s$toO^+lM0;CKFlt$1#kYOf8i zXQB^XOUTD*wJ3Ez9_mX05TI&P@L3RBp{9IOj=bbs*1LrX)9HJbb9 zGN}!-Zb3nN+cG%czo`Z6M(&C?4RlOP8`T@7i@wV#z*(r05jQfLz zN&I5`epSIVd|&jXv85P?QcUTvOyGuSk`yPS#AjDW z2g(6s_2{E1;>W%fI|9AV3D^|Pn^ON}m{A*)yF$GcwO;`0|rkVcR7 z)U70z-8~bpM8Qy3D$!1fD9uB(@E9oz&}kR=vR+IpOj>tAA)6QOMtws8UmLW^a4=a= zNeE#QO34)^2W zw4E3!P!6m~@Oa+~UM}{O-|6o)r|R}3D~aTQw14un6m;3SyFV1V3eq)Y+;|D^EHTW# zB4xeNK1Q3_8e&@*j%KiO^Ss(Qr-|XOQWc3A=HU&4m+?Ac`A46UBI)nSL$5|-;8tas zm+mo`*1~zzB&5e+Hv0opLdcd|7xk~-$1V~NASZNUoY<1yUo{CttMyd6KcL(7Ml49b|zSVJ+22TQN; z`zUfi=7|p{woDdJK$>d?Jvpzp4fW*L8K`T-zk`_`u$q@gT?y^xDMY_G>Ik8W%LtyC zahCG+E}GmKL*FEb6TG)A%_qilXh(H_=Qvwm_$kVvP!*{f2I>Vy^5cH`j^Qq;7S37| zdIvKPJ_`{b=|f5B_en(UvcXHB3P6j9oscIFP`r^FNIbk``X%2tP5(5hUQn54j!vsP+7raC&xHHLtit*M{&BZQ;dEr$;7WcuA`BQK z>Rv-L^Ms%q7*wU)>TX&9XQb2epV7{rIz?39a;x4Ne*j!A>4*>hp5O!TB75+#-}J#R z9*s2HO)wdcMn<)YBOssNQIRb*_h^;)p<&Qlu6!}USp`*Km9R{UFX zP^B6q1?i75Zn?92DOmEhu+UJ-ZQ>RPfLV?;Tq#ZRpESg3$-(j0Zmuj+Ue@9!kMuLY zAnY$xxWo(TreVvn?s0rTAh&Mo2YhGPXOI3YfnoEhLgMNcV%5x7=kGGxth&}lRE?WB z8g_u^PE$r_Y2Kszt82*QWLb+)b23=|s#MBK2@7qr zat?>0PL~zmq$2Xa_?p&o$v2m9-o=Bj6de8uE^-!{QS6$^Zq&IY01*YFL!r;CT&YKW zdsSPs&wAUkzJii=aL}?_Ap|suvKv_544_TGQ{vp#H3bmMF>;iC>P8dX^O47 zUWxu9dAU0gV1*zsR^XJG8Z2w&TO_8sQobC4l{v67NV!31J$azy`q6#-D;|$=-f(gh zGE+@$z&_6Qb5pNmn@w|gqS&cSd#Wmp&1YMF+QbhatepcM+>WhWBNP`RBVVX=eZ~-D z-oxZU-zRMo+;{7U#JFlYjE1~yB_*B_EyK8|E-Y(EA|>Y2hXA^J%dvR80w?KErb^QN zV)-YOdV>i9ZaSWR=UIkXPeSQ|4^d$R#j_h7AGukT616x97v8LKH@6`e4xV&$CQ?_o z@8Yky(B$#d`27{=b+s=zL5Qn{dkeeK$MWe+ z#+iW13)#jiM}Ux<1j#5~6M8F4imQ>@e^94!q-Xf#*Asp0SbS}m)WGIY@v4X&`VJry zv?PE{yCuKIexAxa&Sdb2i~MmMdzv2TqD!p*!(T~?Q(pQ?CCIA`+FSk)ze??q6mkW zix*#WUMH!<<-@rlwIhdlY5{Wo261?V&YwTrsq>EqbTG|Y#x@ihi0WLP~M05d#$|IgW48cxUeEO~paAV|}#j%L3g)%+-p zL3>{V$?1k0S@NhDZQzO9BzgkPdQh~`4beJaka>?k^>jabxJM~(#K)2NK=O@wHSey zv|J})ntl(c+ho6084Ppol6 z8apN@o|2dr&lN}|n7i9c?BDUcVO{o`gXdP@%t6E(H>`~u!%fe?9N|vvH zk=iM4*ph4W7VEXmq@5><^pdWce{l8J7UM!j8BI8A&y~Y=XVm~J*ur#U<|{;glBsFZ zZQSMrvBfaiz`M6k_XfqBW6W|b6lqdt%Mu@>1H4XqU#i$@zO8f4p}6T@2IR*&S|T3G z8aMZ9Y>981ru(kIc&{?|x#lTq1F}}&Ubd{=9ac}V*iQ;(=XFfB&nb+RK?jc_(Z(S>;OW5GOb372oT51MpxL*lnPg7o3RIz+u~Tb#SiF(iGQY#+%&7#$Le?@JOjv*+J7o2v zrLqFiB(qhEsKwH*?l6%?iG`Qm^Yop%k0-Mo!EB2qESNY%e#Z1J_}U6rO>?pfsZ)`k znw}8#9Mfe6aRy0Y7f)MbU8EJmGDXAn#XLZ(y?e8N3II>0`*b!Up*PjDRg(-&2ZxC8 z-j}n?noC4FNF7PLS1K0B5FFU0ux(xZsM;_=xe4&(K34IvA)UFrFm*Tj#~eWf01q(n zzogn8w#r;@Ujq70Am;xjkG@p>>-rC45&ecGg?b283}tv)94!73R4WJGg`;VS;Z7FM zOf+)wRog@F0z0KP-z^480lRizxQ4nH^?(^UJatM43EpS#+dssbQH{AkY+ybL5gIlQmRnRrGrBhPF!YPd-wIl%Ed zt`}(|@4bc7Hhn~g>YkMcRT5F*F7rq6)$ytdk;db(K?%n#x-GuovWbo+Dl+EJ!kK5* zawWE}2ZQXqs1vxoXhAhj^Y(94#E7ffz62RC%m%?8P(&${P*Eegm?H=o)A)&F+vO7`4F`i<(@k_i`IAku{UKpe9pfungZTq2vM#WM(yzZ@X`e#$7|kD)4(HzD4Rk!d=7yk(t>XTL%%0ei%~qlfhM95Q%D&)>5Ue>|qW*m1%jau~zJuRJpi}X1<_ybKEh|l` zQ40JFJmwC3e1ACt{UW3+F{yLmL?(5F;5rD=jW0cOl=z>MafmLI>fJ$4*hr0OR$!z%4(V9?5uViDY2zatyXaPt7*B^%!&UTt_fYlc5?rh}xb}c@|1_w7XJ? z`V6C9E!=x$R4Md+r(q3XN=2jvPKx+O%*KXkvUc8^Us{mWN?e~KV}6oEb}h#k2c*IT zwNgKd>%&ke)}Igf8IN1LgO|x)RGGx~NQtN<3)Ze`@)chnicfBG01?)* zEhs~jFp@hAbGW2_&PD2!$AlTOdA))kRrnWjbT$3uLmw^ST0-btm1%Ux$fWt~!@n3z zly%fya>3fvx5mX1m&L-sMy{4nrJ#0eG9zq|jxmX&Pl`%ruFYMOrJ?P;!ME{v1}$`J>D68yHDFi=CXe6H$lRnKEwH zYp{`|GPY6O71UDd2Jsuo-&MC==r;Uncx>SEYeXKD5a#Z9%(2Fxa}Rd?wsmsBYn>=# zt{wRc#>y8li`mKTEsBhhz(rc5Um^5qH0HLz?k33#HtxD{<`cs;ApaGlJ#+L%O*Q&#$x}ecPXLrdfrDZwAUDV02;b;FB(8 zdK|u`uea`#iIuAV?^{Z|>@$<`<3B1@UsSs**Qh^x3$efL%4f~XNB*vSqq^k4+2u8I zTlaHedi!KC=hD8&InwG9`U9WlO zvyZJn^E!&2H)3I&^XwDp8?tbx2Y5}K;tp$2PZo#P= zkducdig-?PPhUorUQEZW%{}ODoYPrgZQvTD)I>(!Qs7u z&95YT#Am~1y+<>+KX5bxtkyUkWwIWROwesyPnLX=M|p8rET@^Z=uSOE+mP;)VA(Tt zm`o05=x8u&4kq0J!ZysjvGcx*J{PKH9})bF@|Q-bHN7ZN4oBS-MEM>V5JI&G=MW=N zA3XL^xnx11oa3NmdEmPpqC5)G*@g0VudUHHVP&4inbfc5GS+~jJCOTZah4#Fm2R9s zZCxBVFSf8RB;DZ5U-6tC=&-l43vO-fQnc6oAHcVEld4Xc_W+4!jWgag%EL_QGFJW3 z9hF8Hf(Jwl!iy1`>#}f2SX?ES7>G8f5H986a?bGl2{f~EmsNl4S7h0rKBo(0#|BuD zDM3p>W}@YsA2|YKAQ5t;EKKqM2+Ee%rF|Gy*ECuQG5v!iFTp51ZmcQ=kU!m@_-D{k zg?J6{FSO;!2Y74XDugB$-AL-4SkNeZlENpw&;bz_uuun&<`q@`fM*fKr(!mD`=EVA0B4 zdj$1;yLCV_K6?|1^VgH4rob}zpx=g_(9umM**Yf;N>H(lSbdNw@xrt6R&OseaEUZz z#7zF)dO;sh>By?42-KbG{A(+3!}><#epPK1s87BA%=&sbmeJV}mF`w66az@RX5crF zn*=vG-zwT8Lf6}u71?yzz^GScTib#Iy(XZCqsk-F@%cRb#~en)SW7v{8$Yi4b* zCP!6!A#5*oUi|@I_HvD=T1}3Esf1~wu9LPYjsyf1&Q>_*XSb09aC}RJm4p6f_6PMi zBsKn4{{{-7?m6_0P+rYw6=8NgKVqE{kth)V31r*#(q!S({oz;C$4r?6kaA>-QsXyZ z)EDx&b-c2-!`-hwT);^n9;@g}JUSSSVX)FKsmS8AO=Dx?rWRdRSF|MBIlJsc7W{ARu4hp{6%4O(Fob7-SDh8CcX+Lpl#5Ik|%GIlg6FE7tQys3ZhI}h2!-us--p=?v7Otyy^jVN7)Jdv zkiw%qaL|o*pmWBAzoLR!ERIOFlE&TLo`=@LhGGNYKfe;u+I5Uh(0SD7>O30vj!)-w zZ$kOAhBx0;Oyi}k1*A?kQ*+r97p9#MG&-kt-v?}Fr8U$TQ;VVfgLlk+gocX$AP}_r z72?unhUNTO%kn@fy`a<;iq_NxyaJVKEW#Z8u82WU+22$RA#sJHykVH6LGCT|k;pc@ z(-GJfvJ$M9iA(q7XwOkkxE&8*1T%jKIq<$OKmJKadesc=iT z9(pUTpTy>lOM-0+v67*N?q6qucL5v7&K(rbiBomLcAmC{QCwmwxLEFX1*7h!)9GR0 z52nHV3f0XWNa7hKLQDOPa?maq} zT3F$d+`00H(;Z}%hsuYQQ^hNTUkC^Kmc?V25Fvf?*$?D1_oLI^zrbWm9e}aFlh?lA z)$Y4zbwB-%uP&l5Tz7@>9}MnXh!Ufv5v5%h2)#Nsl$C{3WrHY&b&lP@Gsn*5z-%YF zwC<7bmrQaZn3?)S1{@^9IP5vp(usjghY7@Sq7kgkvEu3v8pYQM!vtlTEF5^Dp* z7$3SX0RLaMcg^%~389mPQN%4hc1&#kx>80I)+A+!oZFgZy_$Gu_AUpb?QuDl zp`tqLz$i2#EP{W^LHfpg3-6S@fKVIUjDQ`1dAF`GrBf4!HW%{ws3NkvG9LsmwI2f5 z=?|jL7*ZV{BWA{=773kV{XNww3L18q!g~+@4X>uD?{7 z{hp6|u0?L%ic7jtFGutTqj1bCodfwX%C4m8B?7ya^wpgOD-} zYrzq<^-{Y5E3((z&Cho0=Ai-bfzp2Uynb82obIP#`KzKFQ!gUPi!ZX%mMiB~T6V*u+@+8lK zWQ3NfpPJT~K<~n$=UFcn1s9f?_r&2ZxJnIoQfaH584F$}R_tKsz;3iX8M;)m>dnEt zfcb2GJ{{A*@t{qR+KT209%9S6B|d(gV#t7Gn*2GqgmXNfEH~)cLNvi%j!_D!sHyU< zZ0`DJov@(W4Qg&$`mUxP4=a0e*Mg~MA!e*-@8hKwGDb9fEyYa`_I^``AGa;&$%(&$ zx4`zfM^!~O(F0h!$c!13;*yR7EZbN}#0}(#-ABlry?@9ehKo{huQLL+FgW>Zdqc4+0N!Cv0tEsyi zM6wJ*`{4e>PmEBuZBdbqVyVkw%OQ~jS1f_zzcj<{G5@=$aZvjBqARbcSs@;OfXMR# z;Q;MPHdgJg0Wd>@-Ep0SU7uYiADq!)-H9mt4;0Xm7b|t#94w+i!2a>3hXcwsr{KDF zN+=oHJ;?yS4|Ko>hzaS!+bfIEf#}&N4D$|Vn4oi7Kx!|Sed0U^y2qwjmechWd_Krf zb`Tq%5Dfd1G#)|uqdDe53N3C(e-d9Q*k5koWnNA zMy}GEs*Ep=_W1%56z&3Lvf}s=%Y?Sqy8Fl> zVS)w3qn_&5nHT;@STUYq1qr%SyBAilTWLAaKGh8BUl+mRV-HUIpW=o&-tUlLA^0{V z4z2lGWr~R_sFjJ+i1<@qNB93%fjrFxXMcd z@nL?Q8&yjtgApW5?8|dP9c0_K?$BAzspjTNe11ZMVnE|*FSPfT9^=PH{{ATe-PmgZ zHE3WWO7p>bpKNkZD9E+u>0URg@gto&J%S>Be&~iGR6RrR6vvo~HXgULCw^<(@NWeg zow2v`l1XdPHuZcoW>f%7X}rM2OA7$cCxD~IIC$&ml18f8RlnL#gyKk8;0Sa;;Ilea z;Bky}MoxQzI`bMaQuhOBz=Dem2u2}F(z3!@&!a<9y7wn_)j>p?Ees}8rwqXaSssCu z!5-|BO#JmS4xKp)5S`!aVW5-|czp#fut_)Y1tsVk0XSGoi*I`!SJdkb&N!8{(~VFa zDGY&_gzPyj)j~8yirF7%n19o;3y-f9EGQ3&p>Xh7 z{a1#hrf{pN$Wc8;Ri_{aLB82EA&`QAccXi@LUzWU6Vx0YH9abl6 z@-gGyz9^^y@pIJ@BGfP)*{4Q%n-{s=iigu@D=sTS`Kye14C!{dBbqQBm5T;~zY=K# zT!q5HtKn+n2f^mCY+(i;Y$|Wm>p5=j{%GU`QLfiDPvd^ZL-tq<(%t7CO^y#$^QX?- z*sXjK&b?^EpO4>*InZez3L~a1mq;p;zcP5E;+HlO6RlOO+A$w83VsjHk+0AQ?fe^s zu8b%~eqYoH^?mUJg^YADW$y8!s?lSad}kwOM>k|p)58PyV&1!Mx2hKxetpSIQBBx`bV6nnxPZfr>O6^$603F)y)$;%hz zd=#JoE2NV%Z*eD~I8*WTFsxQplSCQ~tZqltg;lX_%6@(&9)B->;Sd_9x*sg8oK7#p z-$tgc4D}8zm2z&u5Bi{PWh9&>ic@g~v$QR>Z7{>lSN#wE_e1*e@In4`$JBg2#5*fGrzU zjZ@g62Zhe_ML!&2My-NKW0)X+`-;sQdVJqzd9I3`q_oZB58w1B`61q3LXK1BDFmwB z+smgWokP?bWT)aLGFmEjXEI$F-TSqVqy)3jL@_7V6l5Z!3VhPoCV*OiwAmkAjZdZ{dw# z`8r~(c7*XwtvM?BOg8L+d z4pHRQE-F4f_udiGzCQNG+~Z={g0pUIEojfu=67rr$A0;`8bN)2F6w7R#poBdbA8cIj05 z3eOgb{XBgSP3G>%zd5f=br&RjEx4A9QC2K-e|(gw*x#CL2i+I&UmZn%&Kf7Y3u`q- zh5B#}+QO$KPqOC7sO9PSsmov(^(NAMnbRknP#S*sh5schF6qm3q=Q1!tJZyptWbSG z3f%LgLyTc8KneEQ)u?d#B&sPw7b_9!74=kfj4q$VCsC21o6m+y+m`Pr4FvD+;FU5s z7oq@Hv#7-+^nwfQzbR|JcO3u4zsZ=U-m|X6}>v)@oJ$&GbRXnwP1(++45oE^Lxm9hg-Z zu9lm)IFAYpXwb8W^1%P?j*15sk1Xes)V08`o@!7o?o6T~M#g_V1h*~qo4$L6f+GF$ zINu^7rZI(U!oR!LGh0J0X@zbs)DCE!{lVwxk3iBQBRP8zRLo$ztph^yt)I;vi((xe3L@(c}C!kQUd^@^_A zHlvGYYBl2U4(Pf+ZC1a|^)p8Ocp zUh8VFqkzj}7vBCaygboLZPP?OG0w%U9W`+_G9F6*oQajOAolBqR4La=(NlHO@V>*H zN@LjFyzMm}Q;zVfEErA+$ia*yJ(vpPLQ&&2^Evd2T}6#)Fgw1=9GgHjD~6Os!a_Y? zf`8TZ0Ui$Nh#P`{r+tK}nPx`!X|Spb!Ir{+WFvH+M802NnF}s82zbF52sK>CuxZMi z6){IaZi6r{Taq%@Qq43jvnEIv%+sVAxQoV(YXm{Zd3ixWV=fbc?{}1VM!|R=%W$NK znuSu2JAS}g9wUhu1#hi$XPIHjq;7ziUl{FvOiS+3uGyWmzKiam`p*J!Z)HUVo)C&e={VglFpZ5S9b> zwh(5V)tYaG7U|rcjDzY_LD23avDH;DRCyaB30yq@Cf0T4Ei^1uCQpt;6PBlpDR#KE za_=_H7I_?)eqypt^j4i%nR>A~#KFJx9iQ3TVnM%*Lo4TSN{GZ?76GGH?f?y_{2_l05FkxuC0TAue=>epqKkR`-1J z!uUi2flBWNuSZ}KdTndokvJN)YB&84-mrue3S#`}a(NEd_k>XehotI9SIEZD<1V+W z7U4dNx))<@6^u9E@cg1bfh{Y(dAmo%MS8%z3`SIGTWXi-{e1UdDYlbPQC{DWHpp>S((fk;6OJb>@=2a5DYAT$+MEA+$zm zI<>uCc-@B+6^bt&CoYg#IR$Jk%JRoU#;zEztX zWdF;undd(Yp=C3Vw1 zZ)f5dV=JIOz3n2Qjmi{VDGg$;d1KhRJbb#O&l03rt4=iM)s9u$WLPhC5dM(D2~K07 zqlk>gak;7;j<6u670#==`YsHK=}aC7rGf%+Sl^|-GVm^o%r~lDW!&DwrMT#;`>*d( zh8pSHDxJr>y8`n>dsxEI4iLuC-FSWHC{48iR?3qCu!-)Z-itWhB9W3(D>x@a@dwND z)JM2*BkFIY!Ex0M+GrP0EjeaA(u13K-_cPg7=Pc(+lRb6HC_5&9N(Tq4*GRudQtSu zuTRQioi~MH@tpri;S%1**;91SzOV`$*7xBR)+bpPNto3OCqA009dM7V7llbr>%BTHNK5Cb@nY zlM4Tu&_=;hCcr>)uH4%boNP7@q6s0QHFfIYO2q0)=Sg>!o;hpKu;R>%3TE^}v?biD zmFq?5`42< zRK!fsl!@U6l>8meu{LZq29FucIN793s`q7vIPLPgyQEPPm5rY?RR+Ac1@gyLME93y%YY zr&+z;4k~Fn;~Yf>qeL++ns3HwE##FU&35x)F64_9DSE*GXmPK`W#9SX16P6`?yDkA zgLnI=E%zhzyeOI7+{$KOHA|M#2Y~rZwgVR@X@U;N6J#QTo27Mliggm{ATL*Bhd1(K z#-y$R?}~R>8zYeqd8{z14gjaVF9k@RHK!+bRhpMu+H0#cT8e7jQzIg z#6%AiBnzPlVUP0>7JTco%mxhIJw@|Y$tIab1SAd#$4RZS7j|3t+GLD9^?5!h$kV`l zI*8Zzz|D{9;*g=<$1B0edi_j_k5REzwjcjOkz#%qMPF~dv|}C%C)f8Lw42wa2FpwA zs`(rtLf58K>9zrKZpZ`u zg?hx9Hp&1o_RIo?%roa0>slcEAAWyg@e`Vucrs8Ei%-dKiRU?v16nWAVgwJQSeqo= zMw-pDV%PRX7vdiP^*zu8!X*SxDzCR}lU^stQ!A_7VRw-WhfRu1j_~k3?LSB@JjGz| zWb8Mgc3gOZ_M+&(MCVR`xp?tpUFcU3%f$9BuC!J4w>_AZ>c}r9h~V#YbNg{i*y^9$ zz#gr)O+H<(W6A60N^3N^8r;)p`<7Ws0n8t&{`j)N=DfvZN*0vI-VwJj0@`_zBv5HtYvy44@YumP)b@N|0(CHx*8GtFHzz`>x? z-_0p=Fv-y4&Z5@L3C!8owtk^~nUw8>e<))<7OlT<-bb4v#*hI6{%?id1gJGCIPw}T zS8iE+()y$`lw1@Uxwp%{&L!%A>jj#cX8|Mn%>)ud^g+K+!5Y-W4v|_Ykg1T01hE(YeKsyI-SmdcgSs`3xVByc4=-8F+d;$tMoTvB!bb02X+eRj8G z<}$v{RW=Dtpc4*e?=68D7L8LVtj>SzfSJf}MFyqoIF)LsTOh)oO_*A-98*2MXk^g4 zv`mHYy;bUGk9zhM0seV^N$ZTV+xR_o>ij*Y|*$V@21q!>e)T=z{<4aBc3 zlr8*I0dSFC?v8|~Z8+aRnmtREHA>?%wkF{oT#rG&0Q)tXhoW3i-!1T;&^LRQuj(J8 z;ZJYOhvMaLINvvqg2%ouAJClVF29PtEL5|O$02J1c_8S!j<~o<;@WbWD|et7iPymZHthH%HL(e#TIGRsdvGaMlq9>-LF)&YA)mPxO&} zWTIkyga;s1esCpOE`b}isZU0@Cze1v78fr_BX{DK6fU}612=fXS_6Zg@ObCJ{~ldT zD6&;%e6;O315q6+!JP@hud$>>V^ljc;9#U}`rK=jp*Q3SK8_K7u|>{Bur^%0talW7 z5dQw)u!>8dfW;dg8icUd7n>>QOJ!b%VC+Jv^e#BL}j}9;vt~u08qA`cdi$&xoP>v=QYCUQVl|dmC3-r! z!dB#R0iwjOqBWPJ04`*#vd3FaM?kcIJ6Gu~LFv#I(=vvCOsxVnPEOG1{~Fy}9131b znw2zO1jUaa#A(_Pw@(4=QJIF=$K#zUQhx&e>P!6Zn=$=|buQ+}4tY~C2&dIxD zR_zP|)PXcNqz=L_(3+!ymnqv)lCNs`J8LS+0> zL4bsNftF>j0XU)nG(gM0ks{hTn?bbMRr52zGcU-X$e)mHdJCVT2+gZ}0W8k;qw(dM zSm(fiV#U38lVl7g0gKixoy~3=5FwU02;*m2#TFHJEd<$S{SVxItO<)VeQ^ED-wTi= z+Ds1=GTp|A1d;kFk7%mq-RoQqPjLI*bB1%tfI>pNy8c4?7bvRZF?7BCMjR~P#Y$TP zJO5w(v<*|Gpj7R?aX2a#c4}slrO!0&l4hG9k2z{I<3d#8SJ%YR6{5#dfFB|MgW*XA)i%D#6Y8!Ab!zO@{1aV#)PIVuG6xZrBws?laJo2N5kUWE=^FTLo^J}C=wDWhxS8F4Qv7?pTdyn zCcHO2A9^0Sh%?W>ewt8#PjHd=3yl<_E>9syi$dumU99Yi_OS8|{&oC*dODi3Lg6&{w68Mx!8+9cn4&2BJ zrmkqK_Sji_Q@R4*ZCdF+-5!ATR)#XYjvx-#0C{g>tztdBsvQWmJXsSvg4!mgqZ4e* zaZ8VBJ&d(ACo5ZCRXDh)km8{KB5ZeDd(<-$W21#C1)_X<5Lw#p?cZ?p7_WR}ew*Af z0Ux=2m|sg5&OO0GNp+|n1C#Y(y23y3+a((*4!n#+$e!L#7qsyNex8dZ=)(PK{KxFl zh}j3A`)m+$fVLb(9qN4;K>{$WVgLIyX%JCOmQ@SI44LQO{V);Y~|nz#lh2`)2a`DIc7A@x|ob~3|B!# zUFowuU0F6ID9SUBcT>1lLLqg>DsxAMD=S$7QbHxI?GqvN+8pB$xr?Z94){{ggr8=`Gs9_2M$5(@6-jpz9B~nsn5$ zY!n9xOkg*?C7pw%KoJB~Y>?ZjYq&B5Wo*r1Q*f{2?sY3skiSF2UBNj}?I~j_hE8Vq zSPr%=eFrlP{4om20)GaHb!H^6`($G>^YRA*tOmdoZ0F7u$94U(k`C9FD zkzwf_x_^n)o6ym{mTNrz9GQcpwBIt28%{4GTV6i&MGAq+b4ru4Zi-&L(?4#v`|sGU zDn5`K&*Vfhn!N&P;bjuhl7Uz3kvt!98n@KeQt5)K$PCm6$Wl2VPn;*^;-8IkQLQ2U zF)S~THVq=j9=OJez&c2f1_yn}054RoT`G8!)1H7MqJeRfs>XAY7r3^*96tl;<}>Z= zvbL89R@K@T?I*m8yP^JXCq_3-g{yYSH`S4r{U&}?X5dJKN)qv4qDsb9$|MKhVbrlG zgMQ)A=>m~@k(%c3xii;~(-oTl^6>QBN_IY_f+oXD(lCGtVPNUu5`=Gtd!pa*9Au^4 zNehzO2Qk7L)fjj?*8aC_@W*fKT-d_@zAy8~{Ga?TDm(dDOATb_3|{k=TuLmLyvb?D z@2t048LgrL96X-j*&|$`hgCOI(FLiAq`;3^5+wqB^RA4k(g0T<>;cvX{3Vt4Ah=#d^9I3zA$gpv>%;$b0fI}7 zI7#{2k^xLsEqG!mC4Ve_V5X4*!F(+?c%wdxr82d^hnmK=?pV5wmc9}NHqtZ65!5>d z)$mgLlE;egvNDlE{ztbDYy*9XUfgACWwPTyTFs z#S1?|1jweL$Tcq7B9`;KtXBmNYxtC~$w(*6^8c^k4m~N7-v}Yk-LvF;fJv%F9j+%S zR0ml_;hS;1E2K>HwIP_^g091a{!(>YR$0QA)-bQ`iRz^_ABhG+eSjcVoN$kpB$7^dji4ca=r{FSJj>9IyZKN1iA%9J)b+tKc^BYK|rW6n9W>-n zqknE)BIQb&*kU?E47joz=PJ;F)Bhi6z?@euYw%U{&yQOz{Dqn&Jn&?pnMTYjFt9zX zqUCktoH(Z4)^0Q;r_I`u94d^igbAe&iV68V+zD++94<9=rjTQoF zvzUPk1lkPWkUJq8(-!UbF`DgJ*^RDWp4l>5%+?XgGllx!cx*eX>3;`-@BH-v&ulc% zQp>I`b<$YDrEnD=R(1aDz(nKa#t>8Lw;XvJc6n-3_$55rS9bPk?RygsEQ$8*7Dtf< z&yPudWociFFpOeM$iy00%q@M@h#I|^lxvjQ=vfa-twCQqq~|PDRK_1o^ABi^YOh#| zL#oCaqh2y3o)(Dx#^Wi=j6&!FU&w9HB6KU^bcPGeAAi0bQiO)Sf<(|S;&&uc48O$* zDirfMG{Mib9*2{v+}lA9f$iNyDorGH*mVU5E)b})l5*jXWP7vLZlxNi76UM~Wcr1c0 zCe5>?X%wIS_J4dr%TS}lJPBZpD|wM0g#unO>q6RP5Ui6^;`cutA;IeW8Vbuuqf*e~ z=3fEe);XqU@HJQmO$#>z)~m)Koq)oPlx$xf>jO;RziYQai@tb^h27>Dw}Dn2I4ZWi z^xf^#G zd#WZ&bmw2!M@>CdZsc$XGB2~Wp=q?ldzA|r7e}2QgU-ZMACC8V)S%MKnA3i`4K`bA z5t!1IPNhpkh1y7EOjLbB3fHPNKHFhLe zEy+kcBq_dfF4{l_&e^1^CGB{8-9_>q$7`LOR#@M#fPiHND(he$ai`vGKe8#&14(lA zk=Et)Gc1>HxV>67MnXyE4~^`~k3l97%agCaehvf(j#+Ac59 zIwiQB1pZGS4OGgw5bn$}CJe$@S@ctm);81~b=}iiX%`;Szb{)?*=X!SY(ry91G)NL zvdzlU$~fO&UHrQY?@uP{eBHXuCkWPJEot6t|78PjG9iQTo0*WbPz=u={pb0?VS5H_DFQkwasjb0i$=&-B3h*U>w#MTkhT98sR2R) zTFOD!6IZJ6B#`*yNkqcXRV@PbFzsi#Xvr9H03EC?TVYBO`!3hrealo!HhU=*&BX@F6b+x3R0DagIfGf>)*#-yaviD9Eo>~4l2f(5^8-$a5`3GsPWZXL$g+S-vQ|NqCf-GhRQhA z2ozs#rjUZ(@|T&E?#eTqqVJVX?^xD~m&XFh@saWGt!R-&g<8*Qnqyb1(e|H;xv=G! zwN{3({>wKt=adpx-*J1IdI%lXlFe7~w#g*B1DEYlwl3!Aw3 z-j?)RbI%ni8Gx~8(1o3tq~wvr86sMxp|mPX@w~(LdK9G$41nhal-;IR@*IncMuiIW$}w z%7>{gI-mR4qv{WsSqb&M3wscpCX#7lW^$)2W9QeH8Jp6&Re!l>o5@A{4g35U)C?)r zX{?=}SE0Lh59{d!;8xv-qaXXc*&(~YKGOgkBJ-`F4>~t&N09Z^LQ_Xdx`Wnd? zWbzA5Uk(LLQ$B5ia5S=Ev`AMyQB-1jaNx(lP39K8Qs}& zr+Ks3dC32H5oj9FP$vBd2z$DDpM%R{4$E?olFZ5#Om5SAsk+on*n7M&D>om>q$Enl zub+9_sI!VhUN<&I!{G=p@MAR32D@@SEJ{;o{dn79<(3rYy^qRZjgCFn zLl5FPW~ygc*?HD$&nSd(im_n+6vYt9v}HpTVlP24-##NNbdW8?ZH|^z@>Og%Y8m)k zrJKl;k!UN=sf$Xs{oWu?ia%G>q4IH-9oFyb$8-0C#a$+;i}=)-4d8A$fC(9>Ek__W zMDvPhhVy42uK*c^6MbKEVDscs=b+GGg97AmAw7Bns84{(tSvkFMKoZFLheMlrp~mv zf5x$qwe=D%l1jhQNThZ6x;vZX6^6jnQYa4xT^KHMsERc&O-nL3gk!F<$G_H96rSeo&-jX%eU>9{2qXpTI|fZx7V zy|!kKOaS3R0>p);OTMb8HbeFv<*6rU%(9MiaANCi#ecFCS8>7 z)~>S$_zw58wchHzHJKZZb142QdC7ti)$L7`a3w`Tgx0HkC?Zu9AcizN&H(&m>JGYOEF&3%urfbNyOWi&6o85b!#>w*siDPT}r-;d1}tLE48 zr?*z>$t5@xn%4U%E@f*3v|>D{nboRKDBw?YqvU-sZQ$e-hlJze z)3?Ps-oUr!sUe?;;Pa=f=t$e#mcx(?R6*XJ#u7uK_qkGi1+O(d?NFX=-E%nfrw)Wr zu?2FonB9>JGghl+zW87vC9MOpBNZFUE|_K4DX)3lqd;}xa)1v)N<5|j_t~-4Etdob zlGY2Sm~w&_nwXuJ6mfy*+L4=j!4Z@@HpJ>9XAd8TZGEx~1v_>YFWe{(KtF#L$JaUC z3-UwN{>yf+Ya-~1;99vk4Vep^w5Rw?S;`HP%kK4k#lYFTr(X?=Zp(4&JGVx-ZyPpG zm-lo37@%jmb78g1m_s@*sXYfFliKga1cpA>1J`726V&n-?F1 ze$>Nw6cukJ#>80_XezP0#sL7zovT^l+jYF=FDP9}b_G&)s8C`NbfN;b2n-i0Fuk4u z0%16@Uc^1lBL+&B#NU%Y548~++g9Dm@P=n%87`0bR+`Vu`8M69dnXdmF*PU*pwS`E zE;2yr)(K0DjEe&gwOy1xYG8_N<)+7LrUv5vaBvPnX6F8FF(pdix^(lj zC=7jSfw_p9+T$pBsX5yz4aq&ot7#&h}dVX6+Dmdwp1kE;j;0#ZcM~pI;0`=pD$G zo)}=tm`8-3u+up0nP417v8#JC4FeCIdFGfM>Lcs>yY#UqiKT;hbJ3frT`G7bG8X3I zL#$>@WjD0XfIIcNRMo_Q6WG^Co;@D{Jn;TT8|_(fz&`DPUO4{~mHp8gO5r5^@#b0| zBm=7pa~ej{_0;PJxx}qE-tg82b~-($mC5S5TRcVIwCTx^D8=EmCKgs9_+OB-%xMC^ zg3u)l&n^;wPCMW_ykZ^O+C2}VMs{2P&pi{lpEuAIetlrnyKmFIG${rFzS(v*MJ_S+ zG9A*=1P&mrp1=JZf50FoePJfR_^n}5SJDa#;B`r2UxSu)CO!b1&*TFV>YCXxX2?t) ztdCry(!q55;ix?c>s81|Xr>!GeJeI~SiNtCE{&7)ueH3`5% zDg~FKNCSGv7osBRi!t4flv!~>5iuz>9K(&u?g?>&ro&ZcUWowVqzzN+XibianUH5^ zDcD(OgEJT=!D+v=0H+bnq*Fmj3^+$#p1#<$EjOWKmwatwD{o&U53xmjkIw`U4q#6IoM0Wb-bBgg|Qn^==u{3GLUi zlW>?X-Hj$@zyc;a#htARQ-AkEK%rZPrBIG6JBu!y*uPp{sD3eHZ0b9`nzuA4dZB(5 zpjsd=@{5CyGY;^FNH%7^&#T>cE4`ua<-!XO^tD@C#nbBfev$EKZPlU5u(PVn9L4-L z!WPla6$Ic}#5%t4ehzTs4gQ^?iH6t6BJ0X|TKnaNT0Q`8KuLFs+h46*zK3 z$+G6;1Ta_PSM7SN7B2_fQgYZz3udl zzlt(w=jQ!9{{Yc~rX#mJm<1ay-ZTm*up~ABD5Q78BRB48A~u|^(-Ni)zItw?VMT*@ z#kulQEM3o5CKcF!HBj4(Jp>C_!$}pu_xHIN7V-a6L0*E!|1^xzx10!Qp$`@plDQ_d z5>^SQNU|KTtb~mN>bcd)Y;cR3BfaRn@eZEo)aIBLUWj3Xjs7qtz_8=5}K=MGi4sy{*~upA=RC(}Q@bzJ%2ZheQG0 z+zhJA_N4+5oTz3A;d#CY^ZNq$`R14stmLxOfabpI#)8n%*}*-G=!i1A0IOb{P7Aw2 zX`r`H(sz=8x5-asRmgn`*gKb71rq1c7UxP4=J_3tq|sLURJktBR5aftVvrh8=6;zp zwr{b$uNFWo@JWD2Q^7)x8u}M6+F@v-+-8t2^fMQ9R{#Fi>hqF@s1ksvKKJ2{Z9$<# ztodq(3dkWpgUx7IQ{W+=YkKQQ9-jKDl||mP+wRhm&Vr<>$&WQKLBmT4?bw0SCsDQ) z!F8*VxFfv#EJSk)&N;qDrNBTWJROO)6Xj5w+I_Ml0bzZTdYc^XY4iTny0_3W)3w&^jc}{C-FAZR>ZCLx}5~yOrcB;GE6d@xpmWX~P5tc57(n zF%6QhAdq2D?lFtn*1jPw?r0n@N7#OJ`0{MWy<|*`L>7Ahi?lR=o93WyJ>c3L{Hu4z z2flgBbA%0gICG2ntG_DzMJ<~*1%Q6PT-vEy;-E4HlvCm*br!x^eX(k(r-*JR1xwFU00pYR(BYb7tV1WN7?ZP7#qwxce=xh%=2d`;5ej46{8Exp5DKWJyVq5%^_il zS;nQ-%`0dlO|b(-EfMAQBOV6N@ow#Ev`z6_pHNcHpvpC44W_e7J_ zMc;Gx!1g_3op;}Rv`2-iWw?BIb!eRXM@~c(hM)7utW#YrV-q%O?&DQEC#yxt3dNd# z4~rFNNW{pspBpy7IjNEvx-0k`uPq`U%x$ow+(`>k&>8h*(2nU1rvBV06thpm80zxs zXzhm)Gp=86S4#zebC6BGx3e;x;oUTV9Skh@Yv|B}(bnqxN5{XiViy9{Sdxq-#()iZOVT8+gzkv?|d&6L`?_(dkKM^UI$Uxvn}q zTBu~jy6KA?YZy%ZhUNEIQ(+KXXEx#@cM46jl)9-t->No<;1m`*Txq`A3;F_=9z0Nz zevmo`tM|hdy;tWRZ-n`FE^lr5<{FTFqGd<~J((NmDbX^|GWf9;IY3oEXr9*PC6x&m+l2q?Jn^g6GE0|AqbeEPVQH16U>- zU&P;0v&E(VKIoC)T`XIKz=HRsNrHpwNjlE;A?`!=0fdNXWF&aSX{26UbD95U`Rl35 z+BEXlejgf+qGwN)6Ap9`{D9=$EKEJ0{V(}ttF6QOq$NA>@1>e*z`Nh~(4e#LYqwAl;uW@9$D(@p}1OmzMr~$TO)8>(r zCd!$y1jtPshSW?4?TMda_E-5vin>p*??ZS@*nQq<8WYN$UjFuBnrZ5)rWH3HEgw3)D@<7y9K-$8&g@Z%*)L`myTjptrm*sX3#$Ebhpet zfU~8l_<^R6eR4~Co=^3TByj{56rV&dp)A>zfp?Oi73ZE5p+gGyJBX=&hR466P6Vmm@Pctr1tDL9r1}ZfI`)IgcA8 z4Ui6##T^nD{7Zr@UKGsZU91fUeq+ASLo)mCoqssJML4aTfxfJ5eEOP)*DL-D$=yLI zZ4C~%;xPav;%*H@`U?p%qx$7I;>#v>cnr=jQ1baQdmb3wi;e@(QV}$RD&45GR+bkc z0k#okuK9sM{zL1CjVhx~XU-Vrbgo;1a0wD1!^O_6@ zAf$`7z~qUa$i*2PY2mRiKY+X?{ddQV)$iKw6yEiF`P!h4|OK~&&(;vGGu3W(0QH>G0S?g`p>KLx19<(O<^ew12Kjt6v`6B+ z`_kZVlqxju7V{sCbSFD`Dyajy)C?~3@Bnd?;?4JcDMY|pX7uWz!|`M(dk1Ma@f0}2ca|)z2{mxK*Day~ zx}2%(K~IN4$R^vltgcbpa9$shAsm{bEpoc~C{8wUrXMJTet?a0@U6tf-swDSKz$1n zyeJ*NT4~OKC{Z_Hj)zZ2faTqPAINrJSr!8f6Z4Rd?; z@aZLb_L*Ux7pEFntF_*)@uQiS(4-VD09;#8QZ9Ie=btW;Quln!CY4K4!4*jc$CwH& zO8EGsloHau8P39Yp#u=Zz+#2kwn4>>b@-oHMyfJM!u~JE<64|rhXE3}7&ZD8?Q0l| zYjPn!v~&{lT!C=tL6y7eP)X{PNS#bZcg`Hg5=1Z~1W)3(_ZY6shh98Q9Oc_WX|R0o zzInG~UL}s4gdo3kve5ltQ&17-esf@5P9`$JaBx#4dh(de=1>;oRC~R2b(ohng(CXA zul-O6O)K0OHxzbL9;l<<@;%FH)R)O5k3ip(<;$pyn%~GvQNHEPo($vu{n-NQJFMnE zO&kr9^f`KAm*rpY3`oQh0t?`sLiF!zoK_H9PyTViC+b-1?Cu;3c-d~NhHAHZY|58Wmabq3v+yi0U8xR9PobMkoJX!kT^P|@vou=EYz}BW zn${KBbytXTK|};s?ge9{Kse@Z%wQ>WMc|?XXi?31Xn`#5pWenbv3-q*6yF3(4+p## zwSQ|@?j%sBoPJ0p;eFIDc5!$8rbyG#5*@Kdl>o*XM3JkuU@mz}z4)fMBBIYeACuVf z3KWah${73xU(g^U22s`7Bl=Tp`yt-05u}U8&a^iJM58UpjP^Y87#h1&vbya+0;c=i zu)N}zFeom+L6Y8+#(iy@k)Nm5^iNZKjZJArC5Dc2ggnIC%w{%KQEfGB{-r(Y-4N|O z4UyF-E-#PL6qdN-^!R79LBM60$^B=rS&HZbbrFM#xbE84rp${6iPk&Dv)bnM+Fnn* z83-Nt2Ai3?zrND6v76k%1v`^6!M>-9?6_$`N8 zMQ~=k84X%Y6Os*TeeCD2ng~r#T@~M}KaJT%v|_vDPY&f}!xER6a(&iXM{?@baf9#* zqRKpLEwIA3$6{CL_e` zV*B#i=O!0k)E~v5$clVCeXUk z8o2!d68~vb4!p-1QGUX3I77VN(%sgV!$7HyAukOvhJ`+B4i>6EbHH>tI^V_)5WH

0*a*zCgz{fd$eDrN9#Xvd-EJ`w?~l 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

ecok7DB{B|T)~=^g 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%0Dqnr+HS%@gu_BZF`8%BcW> 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%0AtOV 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ⅈzmPQ8em_pbhRiKE*b$HRqD6M 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 literal 0 HcmV?d00001 diff --git a/kernel/tools/cpupowertools/files/patches/mageia_4_19/fs-aufs-4.19-modular.patch b/kernel/tools/cpupowertools/files/patches/mageia_4_19/fs-aufs-4.19-modular.patch new file mode 100644 index 00000000..05bd0189 --- /dev/null +++ b/kernel/tools/cpupowertools/files/patches/mageia_4_19/fs-aufs-4.19-modular.patch @@ -0,0 +1,404 @@ + + fs/aufs/Kconfig | 2 +- + fs/dcache.c | 2 ++ + fs/exec.c | 1 + + fs/fcntl.c | 1 + + fs/file_table.c | 3 +++ + fs/inode.c | 1 + + fs/namespace.c | 2 ++ + fs/notify/group.c | 4 ++++ + fs/notify/mark.c | 3 +++ + fs/open.c | 1 + + fs/read_write.c | 4 ++++ + fs/splice.c | 2 ++ + fs/sync.c | 1 + + fs/xattr.c | 1 + + kernel/task_work.c | 1 + + security/commoncap.c | 2 ++ + security/device_cgroup.c | 2 ++ + security/security.c | 10 ++++++++++ + 18 files changed, 42 insertions(+), 1 deletion(-) + +diff -Nurp linux-4.19.1-aufs/fs/aufs/Kconfig linux-4.19.1-aufs-mod/fs/aufs/Kconfig +--- linux-4.19.1-aufs/fs/aufs/Kconfig 2018-11-05 20:06:43.402301839 +0200 ++++ linux-4.19.1-aufs-mod/fs/aufs/Kconfig 2018-11-05 20:08:19.014106701 +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-4.19.1-aufs/fs/dcache.c linux-4.19.1-aufs-mod/fs/dcache.c +--- linux-4.19.1-aufs/fs/dcache.c 2018-11-05 20:06:43.409301971 +0200 ++++ linux-4.19.1-aufs-mod/fs/dcache.c 2018-11-05 20:08:19.014106701 +0200 +@@ -1343,6 +1343,7 @@ rename_retry: + seq = 1; + goto again; + } ++EXPORT_SYMBOL_GPL(d_walk); + + struct check_mount { + struct vfsmount *mnt; +@@ -2837,6 +2838,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-4.19.1-aufs/fs/exec.c linux-4.19.1-aufs-mod/fs/exec.c +--- linux-4.19.1-aufs/fs/exec.c 2018-10-22 09:37:37.000000000 +0300 ++++ linux-4.19.1-aufs-mod/fs/exec.c 2018-11-05 20:08:19.014106701 +0200 +@@ -109,6 +109,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-4.19.1-aufs/fs/fcntl.c linux-4.19.1-aufs-mod/fs/fcntl.c +--- linux-4.19.1-aufs/fs/fcntl.c 2018-11-05 20:06:43.409301971 +0200 ++++ linux-4.19.1-aufs-mod/fs/fcntl.c 2018-11-05 20:08:19.015106720 +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-4.19.1-aufs/fs/file_table.c linux-4.19.1-aufs-mod/fs/file_table.c +--- linux-4.19.1-aufs/fs/file_table.c 2018-10-22 09:37:37.000000000 +0300 ++++ linux-4.19.1-aufs-mod/fs/file_table.c 2018-11-05 21:04:47.298905524 +0200 +@@ -161,6 +161,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. +@@ -323,6 +324,7 @@ void flush_delayed_fput(void) + { + delayed_fput(NULL); + } ++EXPORT_SYMBOL_GPL(flush_delayed_fput); + + static DECLARE_DELAYED_WORK(delayed_fput_work, delayed_fput); + +@@ -365,6 +367,7 @@ void __fput_sync(struct file *file) + } + + EXPORT_SYMBOL(fput); ++EXPORT_SYMBOL_GPL(__fput_sync); + + void __init files_init(void) + { +diff -Nurp linux-4.19.1-aufs/fs/inode.c linux-4.19.1-aufs-mod/fs/inode.c +--- linux-4.19.1-aufs/fs/inode.c 2018-11-05 20:06:43.409301971 +0200 ++++ linux-4.19.1-aufs-mod/fs/inode.c 2018-11-05 20:08:19.015106720 +0200 +@@ -1666,6 +1666,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-4.19.1-aufs/fs/namespace.c linux-4.19.1-aufs-mod/fs/namespace.c +--- linux-4.19.1-aufs/fs/namespace.c 2018-11-05 20:06:43.410301989 +0200 ++++ linux-4.19.1-aufs-mod/fs/namespace.c 2018-11-05 20:08:19.015106720 +0200 +@@ -437,6 +437,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 +@@ -1832,6 +1833,7 @@ int iterate_mounts(int (*f)(struct vfsmo + } + return 0; + } ++EXPORT_SYMBOL_GPL(iterate_mounts); + + static void cleanup_group_ids(struct mount *mnt, struct mount *end) + { +diff -Nurp linux-4.19.1-aufs/fs/notify/group.c linux-4.19.1-aufs-mod/fs/notify/group.c +--- linux-4.19.1-aufs/fs/notify/group.c 2018-10-22 09:37:37.000000000 +0300 ++++ linux-4.19.1-aufs-mod/fs/notify/group.c 2018-11-05 20:09:24.538349333 +0200 +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + #include + #include "fsnotify.h" +@@ -112,6 +113,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. +@@ -121,6 +123,7 @@ void fsnotify_put_group(struct fsnotify_ + if (refcount_dec_and_test(&group->refcnt)) + fsnotify_final_destroy_group(group); + } ++EXPORT_SYMBOL_GPL(fsnotify_put_group); + + /* + * Create a new fsnotify_group and hold a reference for the group returned. +@@ -150,6 +153,7 @@ struct fsnotify_group *fsnotify_alloc_gr + + return group; + } ++EXPORT_SYMBOL_GPL(fsnotify_alloc_group); + + int fsnotify_fasync(int fd, struct file *file, int on) + { +diff -Nurp linux-4.19.1-aufs/fs/notify/mark.c linux-4.19.1-aufs-mod/fs/notify/mark.c +--- linux-4.19.1-aufs/fs/notify/mark.c 2018-10-22 09:37:37.000000000 +0300 ++++ linux-4.19.1-aufs-mod/fs/notify/mark.c 2018-11-05 20:53:39.635340341 +0200 +@@ -125,6 +125,7 @@ __u32 fsnotify_conn_mask(struct fsnotify + + return *fsnotify_conn_mask_p(conn); + } ++EXPORT_SYMBOL_GPL(fsnotify_put_mark); + + static void __fsnotify_recalc_mask(struct fsnotify_mark_connector *conn) + { +@@ -289,6 +290,7 @@ static bool fsnotify_get_mark_safe(struc + } + return false; + } ++EXPORT_SYMBOL_GPL(fsnotify_destroy_mark); + + /* + * Puts marks and wakes up group destruction if necessary. +@@ -572,6 +574,7 @@ out_err: + spin_unlock(&mark->lock); + return err; + } ++EXPORT_SYMBOL_GPL(fsnotify_init_mark); + + /* + * Attach an initialized mark to a given group and fs object. +diff -Nurp linux-4.19.1-aufs/fs/open.c linux-4.19.1-aufs-mod/fs/open.c +--- linux-4.19.1-aufs/fs/open.c 2018-10-22 09:37:37.000000000 +0300 ++++ linux-4.19.1-aufs-mod/fs/open.c 2018-11-05 20:55:37.785556160 +0200 +@@ -64,6 +64,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-4.19.1-aufs/fs/read_write.c linux-4.19.1-aufs-mod/fs/read_write.c +--- linux-4.19.1-aufs/fs/read_write.c 2018-11-05 20:06:43.410301989 +0200 ++++ linux-4.19.1-aufs-mod/fs/read_write.c 2018-11-05 20:08:19.016106739 +0200 +@@ -459,6 +459,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) + { +@@ -499,6 +500,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) + { +@@ -510,6 +512,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) + { +@@ -579,6 +582,7 @@ ssize_t vfs_write(struct file *file, con + + return ret; + } ++EXPORT_SYMBOL_GPL(vfs_write); + + static inline loff_t file_pos_read(struct file *file) + { +diff -Nurp linux-4.19.1-aufs/fs/splice.c linux-4.19.1-aufs-mod/fs/splice.c +--- linux-4.19.1-aufs/fs/splice.c 2018-11-05 20:06:43.410301989 +0200 ++++ linux-4.19.1-aufs-mod/fs/splice.c 2018-11-05 20:08:19.016106739 +0200 +@@ -851,6 +851,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. +@@ -880,6 +881,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-4.19.1-aufs/fs/sync.c linux-4.19.1-aufs-mod/fs/sync.c +--- linux-4.19.1-aufs/fs/sync.c 2018-11-05 20:06:43.410301989 +0200 ++++ linux-4.19.1-aufs-mod/fs/sync.c 2018-11-05 20:08:19.016106739 +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-4.19.1-aufs/fs/xattr.c linux-4.19.1-aufs-mod/fs/xattr.c +--- linux-4.19.1-aufs/fs/xattr.c 2018-10-22 09:37:37.000000000 +0300 ++++ linux-4.19.1-aufs-mod/fs/xattr.c 2018-11-05 20:08:19.016106739 +0200 +@@ -295,6 +295,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-4.19.1-aufs/kernel/task_work.c linux-4.19.1-aufs-mod/kernel/task_work.c +--- linux-4.19.1-aufs/kernel/task_work.c 2018-10-22 09:37:37.000000000 +0300 ++++ linux-4.19.1-aufs-mod/kernel/task_work.c 2018-11-05 20:08:19.017106758 +0200 +@@ -116,3 +116,4 @@ void task_work_run(void) + } while (work); + } + } ++EXPORT_SYMBOL_GPL(task_work_run); +diff -Nurp linux-4.19.1-aufs/security/commoncap.c linux-4.19.1-aufs-mod/security/commoncap.c +--- linux-4.19.1-aufs/security/commoncap.c 2018-10-22 09:37:37.000000000 +0300 ++++ linux-4.19.1-aufs-mod/security/commoncap.c 2018-11-05 20:08:19.017106758 +0200 +@@ -1336,12 +1336,14 @@ int cap_mmap_addr(unsigned long addr) + } + return ret; + } ++EXPORT_SYMBOL_GPL(cap_mmap_addr); + + int cap_mmap_file(struct file *file, unsigned long reqprot, + unsigned long prot, unsigned long flags) + { + return 0; + } ++EXPORT_SYMBOL_GPL(cap_mmap_file); + + #ifdef CONFIG_SECURITY + +diff -Nurp linux-4.19.1-aufs/security/device_cgroup.c linux-4.19.1-aufs-mod/security/device_cgroup.c +--- linux-4.19.1-aufs/security/device_cgroup.c 2018-10-22 09:37:37.000000000 +0300 ++++ linux-4.19.1-aufs-mod/security/device_cgroup.c 2018-11-05 20:08:19.017106758 +0200 +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -824,3 +825,4 @@ int __devcgroup_check_permission(short t + + return 0; + } ++EXPORT_SYMBOL_GPL(__devcgroup_check_permission); +diff -Nurp linux-4.19.1-aufs/security/security.c linux-4.19.1-aufs-mod/security/security.c +--- linux-4.19.1-aufs/security/security.c 2018-10-22 09:37:37.000000000 +0300 ++++ linux-4.19.1-aufs-mod/security/security.c 2018-11-05 20:08:19.017106758 +0200 +@@ -542,6 +542,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) + { +@@ -558,6 +559,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) +@@ -566,6 +568,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, +@@ -593,6 +596,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) + { +@@ -600,6 +604,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) + { +@@ -607,6 +612,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) + { +@@ -692,6 +698,7 @@ int security_inode_readlink(struct dentr + return 0; + return call_int_hook(inode_readlink, 0, dentry); + } ++EXPORT_SYMBOL_GPL(security_inode_readlink); + + int security_inode_follow_link(struct dentry *dentry, struct inode *inode, + bool rcu) +@@ -707,6 +714,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) + { +@@ -878,6 +886,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) + { +@@ -937,6 +946,7 @@ int security_mmap_file(struct file *file + return ret; + return ima_file_mmap(file, prot); + } ++EXPORT_SYMBOL_GPL(security_mmap_file); + + int security_mmap_addr(unsigned long addr) + { diff --git a/kernel/tools/cpupowertools/files/patches/mageia_4_19/fs-aufs-4.19.patch b/kernel/tools/cpupowertools/files/patches/mageia_4_19/fs-aufs-4.19.patch new file mode 100644 index 00000000..5f947e71 --- /dev/null +++ b/kernel/tools/cpupowertools/files/patches/mageia_4_19/fs-aufs-4.19.patch @@ -0,0 +1,37882 @@ + Documentation/ABI/testing/debugfs-aufs | 55 + + Documentation/ABI/testing/sysfs-aufs | 31 + + Documentation/filesystems/aufs/README | 394 ++++ + Documentation/filesystems/aufs/design/01intro.txt | 158 ++ + Documentation/filesystems/aufs/design/02struct.txt | 245 +++ + .../filesystems/aufs/design/03atomic_open.txt | 72 + + Documentation/filesystems/aufs/design/03lookup.txt | 100 ++ + Documentation/filesystems/aufs/design/04branch.txt | 61 + + .../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 | 38 + + fs/aufs/aufs.h | 49 + + fs/aufs/branch.c | 1409 +++++++++++++++ + fs/aufs/branch.h | 354 ++++ + fs/aufs/cpup.c | 1431 +++++++++++++++ + fs/aufs/cpup.h | 87 + + fs/aufs/dbgaufs.c | 506 ++++++ + fs/aufs/dbgaufs.h | 40 + + fs/aufs/dcsub.c | 212 +++ + fs/aufs/dcsub.h | 124 ++ + fs/aufs/debug.c | 427 +++++ + fs/aufs/debug.h | 213 +++ + fs/aufs/dentry.c | 1140 ++++++++++++ + fs/aufs/dentry.h | 254 +++ + fs/aufs/dinfo.c | 541 ++++++ + fs/aufs/dir.c | 749 ++++++++ + fs/aufs/dir.h | 119 ++ + fs/aufs/dirren.c | 1303 ++++++++++++++ + fs/aufs/dirren.h | 127 ++ + fs/aufs/dynop.c | 357 ++++ + fs/aufs/dynop.h | 62 + + 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 | 328 ++++ + fs/aufs/finfo.c | 136 ++ + fs/aufs/fstype.h | 388 ++++ + fs/aufs/hbl.h | 52 + + fs/aufs/hfsnotify.c | 276 +++ + fs/aufs/hfsplus.c | 47 + + fs/aufs/hnotify.c | 707 ++++++++ + fs/aufs/i_op.c | 1493 ++++++++++++++++ + fs/aufs/i_op_add.c | 922 ++++++++++ + fs/aufs/i_op_del.c | 499 ++++++ + fs/aufs/i_op_ren.c | 1236 +++++++++++++ + fs/aufs/iinfo.c | 273 +++ + fs/aufs/inode.c | 515 ++++++ + fs/aufs/inode.h | 683 +++++++ + fs/aufs/ioctl.c | 207 +++ + fs/aufs/lcnt.h | 173 ++ + fs/aufs/loop.c | 135 ++ + fs/aufs/loop.h | 40 + + fs/aufs/magic.mk | 31 + + fs/aufs/module.c | 259 +++ + fs/aufs/module.h | 89 + + fs/aufs/mvdown.c | 692 ++++++++ + fs/aufs/opts.c | 1864 +++++++++++++++++++ + fs/aufs/opts.h | 212 +++ + fs/aufs/plink.c | 503 ++++++ + fs/aufs/poll.c | 38 + + fs/aufs/posix_acl.c | 90 + + fs/aufs/procfs.c | 158 ++ + fs/aufs/rdu.c | 369 ++++ + fs/aufs/rwsem.h | 60 + + fs/aufs/sbinfo.c | 300 ++++ + fs/aufs/super.c | 1035 +++++++++++ + fs/aufs/super.h | 576 ++++++ + fs/aufs/sysaufs.c | 80 + + fs/aufs/sysaufs.h | 89 + + fs/aufs/sysfs.c | 337 ++++ + fs/aufs/sysrq.c | 147 ++ + fs/aufs/vdir.c | 882 +++++++++ + fs/aufs/vfsub.c | 889 +++++++++ + fs/aufs/vfsub.h | 342 ++++ + 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 | 1877 ++++++++++++++++++++ + 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 | 435 +++++ + kernel/fork.c | 2 +- + kernel/locking/lockdep.c | 3 +- + mm/Makefile | 2 +- + mm/filemap.c | 2 +- + mm/mmap.c | 33 +- + mm/nommu.c | 8 +- + mm/prfile.c | 86 + + 119 files changed, 36738 insertions(+), 30 deletions(-) + +diff --git a/Documentation/ABI/testing/debugfs-aufs b/Documentation/ABI/testing/debugfs-aufs +new file mode 100644 +index 000000000000..4a6694194ba6 +--- /dev/null ++++ b/Documentation/ABI/testing/debugfs-aufs +@@ -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 --git a/Documentation/ABI/testing/sysfs-aufs b/Documentation/ABI/testing/sysfs-aufs +new file mode 100644 +index 000000000000..82f9518495ea +--- /dev/null ++++ b/Documentation/ABI/testing/sysfs-aufs +@@ -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 --git a/Documentation/filesystems/aufs/README b/Documentation/filesystems/aufs/README +new file mode 100644 +index 000000000000..79eb50ae06bd +--- /dev/null ++++ b/Documentation/filesystems/aufs/README +@@ -0,0 +1,394 @@ ++ ++Aufs4 -- advanced multi layered unification filesystem version 4.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 becomes totally different from ++Unionfs while keeping the basic features. ++Recently, Unionfs Version 2.x series begin taking some of the same ++approaches to aufs1's. ++Unionfs is being developed by Professor Erez Zadok at Stony Brook ++University and his team. ++ ++Aufs4 supports linux-4.0 and later, and for linux-3.x series try aufs3. ++If you want older kernel version support, try aufs2-2.6.git or ++aufs2-standalone.git repository, 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 aufs4. ++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 aufs4, aufs4-linux.git, ++aufs4-standalone.git, and aufs-util.git. Note that there is no "4" in ++"aufs-util.git." ++While the aufs-util is always necessary, you need either of aufs4-linux ++or aufs4-standalone. ++ ++The aufs4-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 aufs4 as an external kernel module. ++Several extra patches are not included in this tree. Only ++aufs4-standalone tree contains them. They are described in the later ++section "Configuration and Compilation." ++ ++On the other hand, the aufs4-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 "aufs4.x" where "x" ++represents the linux kernel version, "linux-4.x". For instance, ++"aufs4.0" is for linux-4.0. For latest "linux-4.x-rcN", use ++"aufs4.x-rcN" branch. ++ ++o aufs4-linux tree ++$ git clone --reference /your/linux/git/tree \ ++ git://github.com/sfjro/aufs4-linux.git aufs4-linux.git ++- if you don't have linux GIT tree, then remove "--reference ..." ++$ cd aufs4-linux.git ++$ git checkout origin/aufs4.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 aufs4 git://github.com/sfjro/aufs4-linux.git ++$ git fetch aufs4 ++$ git checkout -b my4.0 v4.0 ++$ (add your local change...) ++$ git pull aufs4 aufs4.0 ++- now you have v4.0 + your_changes + aufs4.0 in you my4.0 branch. ++- you may need to solve some conflicts between your_changes and ++ aufs4.0. in this case, git-rerere is recommended so that you can ++ solve the similar conflicts automatically when you upgrade to 4.1 or ++ later in the future. ++ ++o aufs4-standalone tree ++$ git clone git://github.com/sfjro/aufs4-standalone.git aufs4-standalone.git ++$ cd aufs4-standalone.git ++$ git checkout origin/aufs4.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/aufs4.0 ++ ++Note: The 4.x-rcN branch is to be used with `rc' kernel versions ONLY. ++The minor version number, 'x' in '4.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-4.10" and the "aufs4.10" branch ++does not exist in aufs-util repository, then "aufs4.9", "aufs4.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 aufs4-linux tree, ++- enable CONFIG_AUFS_FS. ++- set other aufs configurations if necessary. ++ ++For aufs4-standalone tree, ++There are several ways to build. ++ ++1. ++- apply ./aufs4-kbuild.patch to your kernel source files. ++- apply ./aufs4-base.patch too. ++- apply ./aufs4-mmap.patch too. ++- apply ./aufs4-standalone.patch too, if you have a plan to set ++ CONFIG_AUFS_FS=m. otherwise you don't need ./aufs4-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. ++ Note: Since linux-3.9, every filesystem module requires an alias ++ "fs-". You should make sure that "fs-aufs" is listed in your ++ modules.aliases file if you set CONFIG_AUFS_FS=m. ++- 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 ./aufs4-base.patch to your kernel source files. ++- apply ./aufs4-mmap.patch too. ++- apply ./aufs4-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". ++ Note: Since linux-3.9, every filesystem module requires an alias ++ "fs-". You should make sure that "fs-aufs" is listed in your ++ modules.aliases file. ++- 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 aufs4-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 aufs4-standalone.git. They are all ++optional. When you meet some problems, they will help you. ++- aufs4-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". ++- 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, 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). ++ ++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 --git a/Documentation/filesystems/aufs/design/01intro.txt b/Documentation/filesystems/aufs/design/01intro.txt +new file mode 100644 +index 000000000000..0e06d99eac9c +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/01intro.txt +@@ -0,0 +1,158 @@ ++ ++# Copyright (C) 2005-2018 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 --git a/Documentation/filesystems/aufs/design/02struct.txt b/Documentation/filesystems/aufs/design/02struct.txt +new file mode 100644 +index 000000000000..080c3777b37f +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/02struct.txt +@@ -0,0 +1,245 @@ ++ ++# Copyright (C) 2005-2018 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 --git a/Documentation/filesystems/aufs/design/03atomic_open.txt b/Documentation/filesystems/aufs/design/03atomic_open.txt +new file mode 100644 +index 000000000000..2d69d1d293ac +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/03atomic_open.txt +@@ -0,0 +1,72 @@ ++ ++# Copyright (C) 2015-2018 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 --git a/Documentation/filesystems/aufs/design/03lookup.txt b/Documentation/filesystems/aufs/design/03lookup.txt +new file mode 100644 +index 000000000000..d6d4432a6a36 +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/03lookup.txt +@@ -0,0 +1,100 @@ ++ ++# Copyright (C) 2005-2018 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 --git a/Documentation/filesystems/aufs/design/04branch.txt b/Documentation/filesystems/aufs/design/04branch.txt +new file mode 100644 +index 000000000000..49400cb27dd0 +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/04branch.txt +@@ -0,0 +1,61 @@ ++ ++# Copyright (C) 2005-2018 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 --git a/Documentation/filesystems/aufs/design/05wbr_policy.txt b/Documentation/filesystems/aufs/design/05wbr_policy.txt +new file mode 100644 +index 000000000000..f0eda9704407 +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/05wbr_policy.txt +@@ -0,0 +1,51 @@ ++ ++# Copyright (C) 2005-2018 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 --git a/Documentation/filesystems/aufs/design/06dirren.dot b/Documentation/filesystems/aufs/design/06dirren.dot +new file mode 100644 +index 000000000000..2d62bb6dd55f +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/06dirren.dot +@@ -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 --git a/Documentation/filesystems/aufs/design/06dirren.txt b/Documentation/filesystems/aufs/design/06dirren.txt +new file mode 100644 +index 000000000000..70e8c57b7221 +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/06dirren.txt +@@ -0,0 +1,89 @@ ++ ++# Copyright (C) 2017-2018 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 --git a/Documentation/filesystems/aufs/design/06fhsm.txt b/Documentation/filesystems/aufs/design/06fhsm.txt +new file mode 100644 +index 000000000000..c92c80225fa8 +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/06fhsm.txt +@@ -0,0 +1,105 @@ ++ ++# Copyright (C) 2011-2018 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 --git a/Documentation/filesystems/aufs/design/06mmap.txt b/Documentation/filesystems/aufs/design/06mmap.txt +new file mode 100644 +index 000000000000..75447670f919 +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/06mmap.txt +@@ -0,0 +1,59 @@ ++ ++# Copyright (C) 2005-2018 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 --git a/Documentation/filesystems/aufs/design/06xattr.txt b/Documentation/filesystems/aufs/design/06xattr.txt +new file mode 100644 +index 000000000000..1d9ae60e3979 +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/06xattr.txt +@@ -0,0 +1,81 @@ ++ ++# Copyright (C) 2014-2018 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 --git a/Documentation/filesystems/aufs/design/07export.txt b/Documentation/filesystems/aufs/design/07export.txt +new file mode 100644 +index 000000000000..f949089f7dd1 +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/07export.txt +@@ -0,0 +1,45 @@ ++ ++# Copyright (C) 2005-2018 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 --git a/Documentation/filesystems/aufs/design/08shwh.txt b/Documentation/filesystems/aufs/design/08shwh.txt +new file mode 100644 +index 000000000000..770cb009238a +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/08shwh.txt +@@ -0,0 +1,39 @@ ++ ++# Copyright (C) 2005-2018 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 --git a/Documentation/filesystems/aufs/design/10dynop.txt b/Documentation/filesystems/aufs/design/10dynop.txt +new file mode 100644 +index 000000000000..0da5f58da0a6 +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/10dynop.txt +@@ -0,0 +1,34 @@ ++ ++# Copyright (C) 2010-2018 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 --git a/MAINTAINERS b/MAINTAINERS +index b2f710eee67a..d21161917b56 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -2605,6 +2605,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: linux-unionfs@vger.kernel.org ++L: aufs-users@lists.sourceforge.net (members only) ++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 --git a/drivers/block/loop.c b/drivers/block/loop.c +index ea9debf59b22..9e534a36c594 100644 +--- a/drivers/block/loop.c ++++ b/drivers/block/loop.c +@@ -739,6 +739,24 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev, + 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 --git a/fs/Kconfig b/fs/Kconfig +index ac474a61be37..284cee954591 100644 +--- a/fs/Kconfig ++++ b/fs/Kconfig +@@ -255,6 +255,7 @@ source "fs/pstore/Kconfig" + source "fs/sysv/Kconfig" + source "fs/ufs/Kconfig" + source "fs/exofs/Kconfig" ++source "fs/aufs/Kconfig" + + endif # MISC_FILESYSTEMS + +diff --git a/fs/Makefile b/fs/Makefile +index 293733f61594..12d19d0de07a 100644 +--- a/fs/Makefile ++++ b/fs/Makefile +@@ -128,3 +128,4 @@ obj-y += exofs/ # Multiple modules + obj-$(CONFIG_CEPH_FS) += ceph/ + obj-$(CONFIG_PSTORE) += pstore/ + obj-$(CONFIG_EFIVAR_FS) += efivarfs/ ++obj-$(CONFIG_AUFS_FS) += aufs/ +diff --git a/fs/aufs/Kconfig b/fs/aufs/Kconfig +new file mode 100644 +index 000000000000..0b442aeb7b45 +--- /dev/null ++++ b/fs/aufs/Kconfig +@@ -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 --git a/fs/aufs/Makefile b/fs/aufs/Makefile +new file mode 100644 +index 000000000000..aa43f916b5ef +--- /dev/null ++++ b/fs/aufs/Makefile +@@ -0,0 +1,38 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++include ${srctree}/${src}/magic.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 --git a/fs/aufs/aufs.h b/fs/aufs/aufs.h +new file mode 100644 +index 000000000000..dea04e2ba37c +--- /dev/null ++++ b/fs/aufs/aufs.h +@@ -0,0 +1,49 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2018 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 --git a/fs/aufs/branch.c b/fs/aufs/branch.c +new file mode 100644 +index 000000000000..1451b4418950 +--- /dev/null ++++ b/fs/aufs/branch.c +@@ -0,0 +1,1409 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 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); ++ kfree(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(); ++ kfree(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(); */ ++ kfree(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: ++ kfree(add_branch->br_wbr); ++out_hnotify: ++ au_hnotify_fin_br(add_branch); ++out_xino: ++ au_xino_put(add_branch); ++out_br: ++ kfree(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)) { ++ kfree(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) ++ err = !access_ok(VERIFY_WRITE, &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; ++ ++ 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) { ++ put_write_access(file_inode(hf)); ++ __mnt_drop_write(hf->f_path.mnt); ++ } ++ } ++ ++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)) { ++ kfree(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); ++ kfree(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: ++ kfree(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 --git a/fs/aufs/branch.h b/fs/aufs/branch.h +new file mode 100644 +index 000000000000..3ef09d71b44f +--- /dev/null ++++ b/fs/aufs/branch.h +@@ -0,0 +1,354 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2018 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 */ ++ /* reserved for future use */ ++ /* wait_queue_head_t xi_wq; */ ++ /* atomic_t xi_pending; */ ++ ++ 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); ++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 --git a/fs/aufs/cpup.c b/fs/aufs/cpup.c +new file mode 100644 +index 000000000000..9309866b1a15 +--- /dev/null ++++ b/fs/aufs/cpup.c +@@ -0,0 +1,1431 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 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; ++ ++ err = -ENOMEM; ++ blksize = dst->f_path.dentry->d_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) ++ kfree(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; ++ 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->clone_file_range) { ++ err = au_do_copy(dst, src, len); ++ goto out; ++ } ++ ++ if (!au_test_nfs(h_src_sb)) { ++ inode_unlock_shared(h_src_inode); ++ err = vfsub_clone_file_range(src, dst, len); ++ inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); ++ } else ++ err = vfsub_clone_file_range(src, dst, len); ++ /* older XFS has a condition in cloning */ ++ if (unlikely(err != -EOPNOTSUPP)) ++ 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; ++ void *label; ++ } *f, file[] = { ++ { ++ .bindex = cpg->bsrc, ++ .flags = O_RDONLY | O_NOATIME | O_LARGEFILE, ++ .label = &&out ++ }, ++ { ++ .bindex = cpg->bdst, ++ .flags = O_WRONLY | O_NOATIME | O_LARGEFILE, ++ .force_wr = !!au_ftest_cpup(cpg->flags, RWDST), ++ .label = &&out_src ++ } ++ }; ++ 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); ++ err = PTR_ERR(f->file); ++ if (IS_ERR(f->file)) ++ goto *f->label; ++ } ++ ++ /* 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); ++ kfree(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 --git a/fs/aufs/cpup.h b/fs/aufs/cpup.h +new file mode 100644 +index 000000000000..34a0907dddda +--- /dev/null ++++ b/fs/aufs/cpup.h +@@ -0,0 +1,87 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2018 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 --git a/fs/aufs/dbgaufs.c b/fs/aufs/dbgaufs.c +new file mode 100644 +index 000000000000..6bb8843b7430 +--- /dev/null ++++ b/fs/aufs/dbgaufs.c +@@ -0,0 +1,506 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 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) ++{ ++ kfree(file->private_data); ++ 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 --git a/fs/aufs/dbgaufs.h b/fs/aufs/dbgaufs.h +new file mode 100644 +index 000000000000..e7ebe5125b30 +--- /dev/null ++++ b/fs/aufs/dbgaufs.h +@@ -0,0 +1,40 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2018 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 --git a/fs/aufs/dcsub.c b/fs/aufs/dcsub.c +new file mode 100644 +index 000000000000..5b060df99f33 +--- /dev/null ++++ b/fs/aufs/dcsub.c +@@ -0,0 +1,212 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 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: ++ kfree(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++); ++ kfree(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 --git a/fs/aufs/dcsub.h b/fs/aufs/dcsub.h +new file mode 100644 +index 000000000000..f00f4a1ed89d +--- /dev/null ++++ b/fs/aufs/dcsub.h +@@ -0,0 +1,124 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2018 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 --git a/fs/aufs/debug.c b/fs/aufs/debug.c +new file mode 100644 +index 000000000000..3a3b9ef48da3 +--- /dev/null ++++ b/fs/aufs/debug.c +@@ -0,0 +1,427 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 Junjiro R. Okajima ++ */ ++ ++/* ++ * debug print functions ++ */ ++ ++#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); ++ kfree(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 --git a/fs/aufs/debug.h b/fs/aufs/debug.h +new file mode 100644 +index 000000000000..11b486d4a3e8 +--- /dev/null ++++ b/fs/aufs/debug.h +@@ -0,0 +1,213 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2018 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 --git a/fs/aufs/dentry.c b/fs/aufs/dentry.c +new file mode 100644 +index 000000000000..e502a90670ff +--- /dev/null ++++ b/fs/aufs/dentry.c +@@ -0,0 +1,1140 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 Junjiro R. Okajima ++ */ ++ ++/* ++ * lookup and dentry operations ++ */ ++ ++#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); ++ kfree(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 --git a/fs/aufs/dentry.h b/fs/aufs/dentry.h +new file mode 100644 +index 000000000000..950ad2419856 +--- /dev/null ++++ b/fs/aufs/dentry.h +@@ -0,0 +1,254 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2018 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; ++} ____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 --git a/fs/aufs/dinfo.c b/fs/aufs/dinfo.c +new file mode 100644 +index 000000000000..f10b8f0b0b10 +--- /dev/null ++++ b/fs/aufs/dinfo.c +@@ -0,0 +1,541 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 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++); ++ } ++ kfree(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 --git a/fs/aufs/dir.c b/fs/aufs/dir.c +new file mode 100644 +index 000000000000..1d2879e08a54 +--- /dev/null ++++ b/fs/aufs/dir.c +@@ -0,0 +1,749 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 Junjiro R. Okajima ++ */ ++ ++/* ++ * directory operations ++ */ ++ ++#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); ++ kfree(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); ++ kfree(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)) ++ kfree(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); ++ } ++ kfree(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 --git a/fs/aufs/dir.h b/fs/aufs/dir.h +new file mode 100644 +index 000000000000..96e235b48f2b +--- /dev/null ++++ b/fs/aufs/dir.h +@@ -0,0 +1,119 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2018 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; ++} ____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; ++} ____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 --git a/fs/aufs/dirren.c b/fs/aufs/dirren.c +new file mode 100644 +index 000000000000..e2273c61fd05 +--- /dev/null ++++ b/fs/aufs/dirren.c +@@ -0,0 +1,1303 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2017-2018 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) ++ kfree(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)) { ++ kfree(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) ++{ ++ kfree(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); ++ kfree(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); ++ kfree(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); ++ kfree(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); ++ kfree(elm->info_last); ++ } ++ kfree(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); ++ kfree(ent); ++ ++out: ++ kfree(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 */ ++ kfree(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); ++ } ++ kfree(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) ++ kfree(*drinfo++); ++ kfree(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); ++ kfree(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; ++ ++ kfree(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 --git a/fs/aufs/dirren.h b/fs/aufs/dirren.h +new file mode 100644 +index 000000000000..65360459f32b +--- /dev/null ++++ b/fs/aufs/dirren.h +@@ -0,0 +1,127 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2017-2018 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 --git a/fs/aufs/dynop.c b/fs/aufs/dynop.c +new file mode 100644 +index 000000000000..d80f45763031 +--- /dev/null ++++ b/fs/aufs/dynop.c +@@ -0,0 +1,357 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2010-2018 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) { ++ key = tmp; ++ kref_get(&key->dk_kref); ++ 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) { ++ kref_get(&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) { ++ kfree(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; ++ ++ /* make sure that 'struct au_dykey *' can be any type */ ++ BUILD_BUG_ON(offsetof(struct au_dyaop, da_key)); ++ ++ 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 --git a/fs/aufs/dynop.h b/fs/aufs/dynop.h +new file mode 100644 +index 000000000000..4fdbe07983cf +--- /dev/null ++++ b/fs/aufs/dynop.h +@@ -0,0 +1,62 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2010-2018 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 */ ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* 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 --git a/fs/aufs/export.c b/fs/aufs/export.c +new file mode 100644 +index 000000000000..d5fb61a7a61f +--- /dev/null ++++ b/fs/aufs/export.c +@@ -0,0 +1,825 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 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 --git a/fs/aufs/f_op.c b/fs/aufs/f_op.c +new file mode 100644 +index 000000000000..5fda8c253d28 +--- /dev/null ++++ b/fs/aufs/f_op.c +@@ -0,0 +1,806 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 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 --git a/fs/aufs/fhsm.c b/fs/aufs/fhsm.c +new file mode 100644 +index 000000000000..fe8c97490122 +--- /dev/null ++++ b/fs/aufs/fhsm.c +@@ -0,0 +1,413 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2011-2018 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 --git a/fs/aufs/file.c b/fs/aufs/file.c +new file mode 100644 +index 000000000000..fa33fc2c91cb +--- /dev/null ++++ b/fs/aufs/file.c +@@ -0,0 +1,850 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 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 --git a/fs/aufs/file.h b/fs/aufs/file.h +new file mode 100644 +index 000000000000..4c73ac8da97c +--- /dev/null ++++ b/fs/aufs/file.h +@@ -0,0 +1,328 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2018 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 */ ++} ____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 --git a/fs/aufs/finfo.c b/fs/aufs/finfo.c +new file mode 100644 +index 000000000000..e46da749ef33 +--- /dev/null ++++ b/fs/aufs/finfo.c +@@ -0,0 +1,136 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 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 --git a/fs/aufs/fstype.h b/fs/aufs/fstype.h +new file mode 100644 +index 000000000000..0a6b40f9612c +--- /dev/null ++++ b/fs/aufs/fstype.h +@@ -0,0 +1,388 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2018 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 --git a/fs/aufs/hbl.h b/fs/aufs/hbl.h +new file mode 100644 +index 000000000000..feff55d18aa6 +--- /dev/null ++++ b/fs/aufs/hbl.h +@@ -0,0 +1,52 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2017-2018 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 --git a/fs/aufs/hfsnotify.c b/fs/aufs/hfsnotify.c +new file mode 100644 +index 000000000000..414527996ace +--- /dev/null ++++ b/fs/aufs/hfsnotify.c +@@ -0,0 +1,276 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 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"); */ ++ kfree(hfsn); ++} ++ ++static int au_hfsn_handle_event(struct fsnotify_group *group, ++ struct inode *inode, ++ u32 mask, const void *data, int data_type, ++ const unsigned char *file_name, u32 cookie, ++ struct fsnotify_iter_info *iter_info) ++{ ++ int err; ++ struct au_hnotify *hnotify; ++ struct inode *h_dir, *h_inode; ++ struct qstr h_child_qstr = QSTR_INIT(file_name, strlen(file_name)); ++ 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, &h_child_qstr, 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: ++ kfree(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 --git a/fs/aufs/hfsplus.c b/fs/aufs/hfsplus.c +new file mode 100644 +index 000000000000..7f60a264e00d +--- /dev/null ++++ b/fs/aufs/hfsplus.c +@@ -0,0 +1,47 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2010-2018 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 --git a/fs/aufs/hnotify.c b/fs/aufs/hnotify.c +new file mode 100644 +index 000000000000..7fdeb27cfa42 +--- /dev/null ++++ b/fs/aufs/hnotify.c +@@ -0,0 +1,707 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 Junjiro R. Okajima ++ */ ++ ++/* ++ * abstraction to notify the direct changes on lower directories ++ */ ++ ++#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); ++ kfree(a); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask, ++ 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 & FS_EVENTS_POSS_ON_CHILD) { ++ 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); ++ kfree(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 --git a/fs/aufs/i_op.c b/fs/aufs/i_op.c +new file mode 100644 +index 000000000000..232d29fa25ec +--- /dev/null ++++ b/fs/aufs/i_op.c +@@ -0,0 +1,1493 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode operations (except add/del/rename) ++ */ ++ ++#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) ++{ ++#if !defined(CONFIG_RWSEM_GENERIC_SPINLOCK) && defined(CONFIG_RWSEM_SPIN_ON_OWNER) ++ p->hdir->hi_inode->i_rwsem.owner = task; ++#endif ++} ++ ++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: ++ kfree(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: ++ kfree(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 --git a/fs/aufs/i_op_add.c b/fs/aufs/i_op_add.c +new file mode 100644 +index 000000000000..06c121e746cf +--- /dev/null ++++ b/fs/aufs/i_op_add.c +@@ -0,0 +1,922 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode operations (add entry) ++ */ ++ ++#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: ++ kfree(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: ++ kfree(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: ++ kfree(a); ++out: ++ return err; ++} +diff --git a/fs/aufs/i_op_del.c b/fs/aufs/i_op_del.c +new file mode 100644 +index 000000000000..35f6328c49e1 +--- /dev/null ++++ b/fs/aufs/i_op_del.c +@@ -0,0 +1,499 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode operations (del entry) ++ */ ++ ++#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: ++ kfree(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: ++ kfree(a); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff --git a/fs/aufs/i_op_ren.c b/fs/aufs/i_op_ren.c +new file mode 100644 +index 000000000000..5849f3c83f29 +--- /dev/null ++++ b/fs/aufs/i_op_ren.c +@@ -0,0 +1,1236 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode operation (rename entry) ++ * todo: this is crazy monster ++ */ ++ ++#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); ++ kfree(a); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff --git a/fs/aufs/iinfo.c b/fs/aufs/iinfo.c +new file mode 100644 +index 000000000000..f5c2bd14176e +--- /dev/null ++++ b/fs/aufs/iinfo.c +@@ -0,0 +1,273 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 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++; ++ } ++ } ++ kfree(iinfo->ii_hinode); ++ AuRwDestroy(&iinfo->ii_rwsem); ++} +diff --git a/fs/aufs/inode.c b/fs/aufs/inode.c +new file mode 100644 +index 000000000000..a798a6a07fda +--- /dev/null ++++ b/fs/aufs/inode.c +@@ -0,0 +1,515 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode functions ++ */ ++ ++#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 --git a/fs/aufs/inode.h b/fs/aufs/inode.h +new file mode 100644 +index 000000000000..b6dca8988666 +--- /dev/null ++++ b/fs/aufs/inode.h +@@ -0,0 +1,683 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2018 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 */ ++#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; ++} ____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, ++ 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 --git a/fs/aufs/ioctl.c b/fs/aufs/ioctl.c +new file mode 100644 +index 000000000000..194db41dc9d9 +--- /dev/null ++++ b/fs/aufs/ioctl.c +@@ -0,0 +1,207 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 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 --git a/fs/aufs/lcnt.h b/fs/aufs/lcnt.h +new file mode 100644 +index 000000000000..7fb1697b2f54 +--- /dev/null ++++ b/fs/aufs/lcnt.h +@@ -0,0 +1,173 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2018 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 --git a/fs/aufs/loop.c b/fs/aufs/loop.c +new file mode 100644 +index 000000000000..3d8434975ca4 +--- /dev/null ++++ b/fs/aufs/loop.c +@@ -0,0 +1,135 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 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(unsigned long)); ++ ++ 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); ++ kfree(au_warn_loopback_array); ++} +diff --git a/fs/aufs/loop.h b/fs/aufs/loop.h +new file mode 100644 +index 000000000000..05d703ddf190 +--- /dev/null ++++ b/fs/aufs/loop.h +@@ -0,0 +1,40 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2018 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 ++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 --git a/fs/aufs/magic.mk b/fs/aufs/magic.mk +new file mode 100644 +index 000000000000..7bc9eef3ffec +--- /dev/null ++++ b/fs/aufs/magic.mk +@@ -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 --git a/fs/aufs/module.c b/fs/aufs/module.c +new file mode 100644 +index 000000000000..59a119d834c7 +--- /dev/null ++++ b/fs/aufs/module.c +@@ -0,0 +1,259 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 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) { ++ kfree(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); ++ kfree(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 --git a/fs/aufs/module.h b/fs/aufs/module.h +new file mode 100644 +index 000000000000..f5cb96b8d5e2 +--- /dev/null ++++ b/fs/aufs/module.h +@@ -0,0 +1,89 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2018 Junjiro R. Okajima ++ */ ++ ++/* ++ * module initialization and module-global ++ */ ++ ++#ifndef __AUFS_MODULE_H__ ++#define __AUFS_MODULE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++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); ++ ++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(struct au_##name *p) \ ++{ kmem_cache_free(au_cache[AuCache_##index], 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 --git a/fs/aufs/mvdown.c b/fs/aufs/mvdown.c +new file mode 100644 +index 000000000000..583681ead8ce +--- /dev/null ++++ b/fs/aufs/mvdown.c +@@ -0,0 +1,692 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2011-2018 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) ++ err = !access_ok(VERIFY_WRITE, 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; ++ kfree(args); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff --git a/fs/aufs/opts.c b/fs/aufs/opts.c +new file mode 100644 +index 000000000000..7c42dde5ab8a +--- /dev/null ++++ b/fs/aufs/opts.c +@@ -0,0 +1,1864 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 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); ++ 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; ++ } ++ } ++ ++ kfree(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); ++ 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; ++ case Opt_prepend: ++ opt->add.bindex = 0; ++ 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) { ++ kfree(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 --git a/fs/aufs/opts.h b/fs/aufs/opts.h +new file mode 100644 +index 000000000000..8e21acc3f18b +--- /dev/null ++++ b/fs/aufs/opts.h +@@ -0,0 +1,212 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2018 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) /* busy inode when del-branch */ ++#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 --git a/fs/aufs/plink.c b/fs/aufs/plink.c +new file mode 100644 +index 000000000000..3dfd0296d42e +--- /dev/null ++++ b/fs/aufs/plink.c +@@ -0,0 +1,503 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 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 --git a/fs/aufs/poll.c b/fs/aufs/poll.c +new file mode 100644 +index 000000000000..cbf3c070cd8d +--- /dev/null ++++ b/fs/aufs/poll.c +@@ -0,0 +1,38 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 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 --git a/fs/aufs/posix_acl.c b/fs/aufs/posix_acl.c +new file mode 100644 +index 000000000000..ac918fee79e1 +--- /dev/null ++++ b/fs/aufs/posix_acl.c +@@ -0,0 +1,90 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2014-2018 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_OR_NULL(acl)) ++ 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); ++ dput(dentry); ++ err = ssz; ++ if (ssz >= 0) { ++ err = 0; ++ set_cached_acl(inode, type, acl); ++ } ++ ++out: ++ return err; ++} +diff --git a/fs/aufs/procfs.c b/fs/aufs/procfs.c +new file mode 100644 +index 000000000000..566a932fa72d +--- /dev/null ++++ b/fs/aufs/procfs.c +@@ -0,0 +1,158 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2010-2018 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)) { ++ kobject_get(&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 --git a/fs/aufs/rdu.c b/fs/aufs/rdu.c +new file mode 100644 +index 000000000000..8a7eb103a96e +--- /dev/null ++++ b/fs/aufs/rdu.c +@@ -0,0 +1,369 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 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; ++ ++ err = !access_ok(VERIFY_WRITE, 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) ++ err = !access_ok(VERIFY_WRITE, &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 --git a/fs/aufs/rwsem.h b/fs/aufs/rwsem.h +new file mode 100644 +index 000000000000..1e636d0039e6 +--- /dev/null ++++ b/fs/aufs/rwsem.h +@@ -0,0 +1,60 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2018 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 --git a/fs/aufs/sbinfo.c b/fs/aufs/sbinfo.c +new file mode 100644 +index 000000000000..6b04f5d18ddc +--- /dev/null ++++ b/fs/aufs/sbinfo.c +@@ -0,0 +1,300 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 Junjiro R. Okajima ++ */ ++ ++/* ++ * superblock private data ++ */ ++ ++#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); ++ ++ kfree(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 */ ++ kfree(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: ++ kfree(sbinfo->si_branch); ++out_sbinfo: ++ kfree(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 --git a/fs/aufs/super.c b/fs/aufs/super.c +new file mode 100644 +index 000000000000..777503e6c00e +--- /dev/null ++++ b/fs/aufs/super.c +@@ -0,0 +1,1035 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 Junjiro R. Okajima ++ */ ++ ++/* ++ * mount and super_block operations ++ */ ++ ++#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_cb(struct rcu_head *head) ++{ ++ struct inode *inode = container_of(head, struct inode, i_rcu); ++ ++ au_cache_free_icntnr(container_of(inode, struct au_icntnr, vfs_inode)); ++} ++ ++static void aufs_destroy_inode(struct inode *inode) ++{ ++ if (!au_is_bad_inode(inode)) ++ au_iinfo_fin(inode); ++ call_rcu(&inode->i_rcu, aufs_destroy_inode_cb); ++} ++ ++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, ++ /* 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 --git a/fs/aufs/super.h b/fs/aufs/super.h +new file mode 100644 +index 000000000000..fe9533038314 +--- /dev/null ++++ b/fs/aufs/super.h +@@ -0,0 +1,576 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2018 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 7 ++ ++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 --git a/fs/aufs/sysaufs.c b/fs/aufs/sysaufs.c +new file mode 100644 +index 000000000000..0e9bcb0232bc +--- /dev/null ++++ b/fs/aufs/sysaufs.c +@@ -0,0 +1,80 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 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 --git a/fs/aufs/sysaufs.h b/fs/aufs/sysaufs.h +new file mode 100644 +index 000000000000..bf82fa4730d3 +--- /dev/null ++++ b/fs/aufs/sysaufs.h +@@ -0,0 +1,89 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2018 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 --git a/fs/aufs/sysfs.c b/fs/aufs/sysfs.c +new file mode 100644 +index 000000000000..bb90eb1021cb +--- /dev/null ++++ b/fs/aufs/sysfs.c +@@ -0,0 +1,337 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 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; ++ } ++ kfree(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++) { ++ err = !access_ok(VERIFY_WRITE, 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: ++ kfree(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 --git a/fs/aufs/sysrq.c b/fs/aufs/sysrq.c +new file mode 100644 +index 000000000000..e6b842a65117 +--- /dev/null ++++ b/fs/aufs/sysrq.c +@@ -0,0 +1,147 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 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 --git a/fs/aufs/vdir.c b/fs/aufs/vdir.c +new file mode 100644 +index 000000000000..1e7075386a51 +--- /dev/null ++++ b/fs/aufs/vdir.c +@@ -0,0 +1,882 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 Junjiro R. Okajima ++ */ ++ ++/* ++ * virtual or vertical directory ++ */ ++ ++#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) ++ kfree(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++); ++ } ++ kfree(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--) ++ kfree(*deblk++); ++ kfree(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 */ ++ ++ kfree(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) { ++ kfree(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 --git a/fs/aufs/vfsub.c b/fs/aufs/vfsub.c +new file mode 100644 +index 000000000000..1978e190da9e +--- /dev/null ++++ b/fs/aufs/vfsub.c +@@ -0,0 +1,889 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 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 --git a/fs/aufs/vfsub.h b/fs/aufs/vfsub.h +new file mode 100644 +index 000000000000..11a3d4f90da7 +--- /dev/null ++++ b/fs/aufs/vfsub.h +@@ -0,0 +1,342 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2018 Junjiro R. Okajima ++ */ ++ ++/* ++ * sub-routines for VFS ++ */ ++ ++#ifndef __AUFS_VFSUB_H__ ++#define __AUFS_VFSUB_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#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 int vfsub_clone_file_range(struct file *src, struct file *dst, ++ u64 len) ++{ ++ int err; ++ ++ lockdep_off(); ++ err = vfs_clone_file_range(src, 0, dst, 0, len); ++ 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 --git a/fs/aufs/wbr_policy.c b/fs/aufs/wbr_policy.c +new file mode 100644 +index 000000000000..f15ed349e1de +--- /dev/null ++++ b/fs/aufs/wbr_policy.c +@@ -0,0 +1,817 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 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); ++ kfree(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 --git a/fs/aufs/whout.c b/fs/aufs/whout.c +new file mode 100644 +index 000000000000..a3c64efb2784 +--- /dev/null ++++ b/fs/aufs/whout.c +@@ -0,0 +1,1049 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 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) ++ kfree(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); ++ kfree(arg); ++ 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); ++ kfree(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); ++ kfree(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)) { ++ kfree(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); ++ kfree(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 --git a/fs/aufs/whout.h b/fs/aufs/whout.h +new file mode 100644 +index 000000000000..c790bfa66ea8 +--- /dev/null ++++ b/fs/aufs/whout.h +@@ -0,0 +1,73 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2018 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 --git a/fs/aufs/wkq.c b/fs/aufs/wkq.c +new file mode 100644 +index 000000000000..597099ef2137 +--- /dev/null ++++ b/fs/aufs/wkq.c +@@ -0,0 +1,379 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 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) ++{ ++ kfree(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: ?? */ ++ kfree(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) ++{ ++ kfree(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 --git a/fs/aufs/wkq.h b/fs/aufs/wkq.h +new file mode 100644 +index 000000000000..ec7bb8bd219c +--- /dev/null ++++ b/fs/aufs/wkq.h +@@ -0,0 +1,76 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2018 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 --git a/fs/aufs/xattr.c b/fs/aufs/xattr.c +new file mode 100644 +index 000000000000..6c877651fff7 +--- /dev/null ++++ b/fs/aufs/xattr.c +@@ -0,0 +1,343 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2014-2018 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); ++ } ++ ++ kfree(value); ++ ++out_free: ++ kfree(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 --git a/fs/aufs/xino.c b/fs/aufs/xino.c +new file mode 100644 +index 000000000000..6b097908ede9 +--- /dev/null ++++ b/fs/aufs/xino.c +@@ -0,0 +1,1877 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2018 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) ++{ ++ struct file *file; ++ struct dentry *h_parent, *d; ++ struct inode *h_dir, *inode; ++ int err; ++ ++ /* ++ * 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. ++ */ ++ file = vfsub_filp_open(fpath, O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE ++ /* | __FMODE_NONOTIFY */, ++ 0666); ++ if (IS_ERR(file)) { ++ 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); ++ /* 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: ++ kfree(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); ++ kfree(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); ++ kfree(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; ++}; ++ ++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; ++ 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 (!err) { ++ file = au_xino_file(br->br_xino, a->calc.idx); ++ if (file) ++ err = au_xino_do_write(sbi->si_xwrite, file, &a->calc, ++ a->ino); ++ if (unlikely(err)) ++ AuIOErr("err %d\n", err); ++ } else ++ AuIOErr("err %d\n", err); ++ au_lcnt_dec(&br->br_count); ++ ii_read_unlock(root); ++ si_read_unlock(sb); ++ au_nwt_done(&sbi->si_nowait); ++ kfree(args); ++} ++ ++/* ++ * 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); ++ kfree(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; ++ ++ *ino = 0; ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ return 0; /* no xino */ ++ ++ err = 0; ++ au_xi_calc(sb, h_ino, &calc); ++ file = au_xino_file(au_sbr(sb, bindex)->br_xino, calc.idx); ++ if (!file ++ || vfsub_f_size_read(file) < calc.pos + sizeof(*ino)) ++ return 0; /* no ino */ ++ ++ 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; ++ ++ 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) { ++ /* 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_waitqueue_head(&xi->xi_wq); */ ++ /* atomic_set(&xi->xi_pending, 0); */ ++ atomic_set(&xi->xi_truncating, 0); ++ kref_init(&xi->xi_kref); ++ goto out; /* success */ ++ ++out_file: ++ kfree(xi->xi_file); ++out_free: ++ kfree(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; ++ ++ 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); ++ kfree(xi->xi_file); ++ kfree(xi->xi_nondir.array); ++ kfree(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); ++ } ++ free_page((unsigned long)page); ++ } else { ++ file = au_xino_create(sb, AUFS_XINO_DEFPATH, /*silent*/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 --git a/fs/dcache.c b/fs/dcache.c +index 2e7e8d85e9b4..9f57bd87bce5 100644 +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -1238,7 +1238,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 --git a/fs/fcntl.c b/fs/fcntl.c +index 4137d96534a6..c91b3e3c4580 100644 +--- a/fs/fcntl.c ++++ b/fs/fcntl.c +@@ -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 * filp, unsigned long arg) + + 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 --git a/fs/inode.c b/fs/inode.c +index 42f6d25f32a5..fa6ae6a217fb 100644 +--- a/fs/inode.c ++++ b/fs/inode.c +@@ -1657,7 +1657,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 --git a/fs/namespace.c b/fs/namespace.c +index 99186556f8d3..72c93f3e8647 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -770,6 +770,12 @@ static inline int check_mnt(struct mount *mnt) + 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 --git a/fs/proc/base.c b/fs/proc/base.c +index 7e9f07bf260d..3ab59011067e 100644 +--- a/fs/proc/base.c ++++ b/fs/proc/base.c +@@ -2016,7 +2016,7 @@ static int map_files_get_link(struct dentry *dentry, struct path *path) + down_read(&mm->mmap_sem); + 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 --git a/fs/proc/nommu.c b/fs/proc/nommu.c +index 3b63be64e436..fb9913bf3d10 100644 +--- a/fs/proc/nommu.c ++++ b/fs/proc/nommu.c +@@ -45,7 +45,10 @@ static int nommu_region_show(struct seq_file *m, struct vm_region *region) + 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 --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c +index 5ea1d64cb0b4..7865a4707d23 100644 +--- a/fs/proc/task_mmu.c ++++ b/fs/proc/task_mmu.c +@@ -305,7 +305,10 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma) + 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; +@@ -1727,7 +1730,7 @@ static int show_numa_map(struct seq_file *m, void *v) + 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 mm_walk walk = { + .hugetlb_entry = gather_hugetlb_stats, +diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c +index 0b63d68dedb2..400d1c594ceb 100644 +--- a/fs/proc/task_nommu.c ++++ b/fs/proc/task_nommu.c +@@ -155,7 +155,10 @@ static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma) + 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 --git a/fs/read_write.c b/fs/read_write.c +index 8a2737f0d61d..42f64cc2eae9 100644 +--- a/fs/read_write.c ++++ b/fs/read_write.c +@@ -489,6 +489,28 @@ ssize_t __vfs_write(struct file *file, const char __user *p, size_t count, + 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 --git a/fs/splice.c b/fs/splice.c +index b3daa971f597..1dd7f96b22dc 100644 +--- a/fs/splice.c ++++ b/fs/splice.c +@@ -838,8 +838,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); +@@ -855,9 +855,9 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, + /* + * 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 --git a/fs/sync.c b/fs/sync.c +index b54e0541ad89..28607828e96f 100644 +--- a/fs/sync.c ++++ b/fs/sync.c +@@ -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 --git a/include/linux/fs.h b/include/linux/fs.h +index 897eae8faee1..7fb92a99efe8 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -1286,6 +1286,7 @@ extern void fasync_free(struct fasync_struct *); + /* 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); +@@ -1747,6 +1748,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); +@@ -1818,6 +1820,12 @@ ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, + 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 *); +@@ -2243,6 +2251,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; +@@ -2530,6 +2539,7 @@ static inline bool sb_is_blkdev_sb(struct super_block *sb) + 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 --git a/include/linux/lockdep.h b/include/linux/lockdep.h +index b0d0b51c4d85..f73ffaa0199e 100644 +--- a/include/linux/lockdep.h ++++ b/include/linux/lockdep.h +@@ -313,6 +313,8 @@ static inline int lockdep_match_key(struct lockdep_map *lock, + return lock->key == key; + } + ++struct lock_class *lockdep_hlock_class(struct held_lock *hlock); ++ + /* + * Acquire a lock. + * +@@ -439,6 +441,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 --git a/include/linux/mm.h b/include/linux/mm.h +index 0416a7204be3..4a298a92681b 100644 +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -1440,6 +1440,28 @@ static inline void unmap_shared_mapping_range(struct address_space *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 --git a/include/linux/mm_types.h b/include/linux/mm_types.h +index 5ed8f6292a53..01229754077f 100644 +--- a/include/linux/mm_types.h ++++ b/include/linux/mm_types.h +@@ -239,6 +239,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 +@@ -313,6 +314,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) */ + + atomic_long_t swap_readahead_info; +diff --git a/include/linux/mnt_namespace.h b/include/linux/mnt_namespace.h +index 35942084cd40..24f5fd1a789d 100644 +--- a/include/linux/mnt_namespace.h ++++ b/include/linux/mnt_namespace.h +@@ -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 --git a/include/linux/splice.h b/include/linux/splice.h +index 74b4911ac16d..19789fbea567 100644 +--- a/include/linux/splice.h ++++ b/include/linux/splice.h +@@ -87,4 +87,10 @@ extern void splice_shrink_spd(struct splice_pipe_desc *); + + 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 --git a/include/uapi/linux/aufs_type.h b/include/uapi/linux/aufs_type.h +new file mode 100644 +index 000000000000..5b21dd4f5738 +--- /dev/null ++++ b/include/uapi/linux/aufs_type.h +@@ -0,0 +1,435 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2018 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 "4.19" ++ ++/* 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 ++#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1) ++#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 --git a/kernel/fork.c b/kernel/fork.c +index f0b58479534f..fa562c364d02 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -505,7 +505,7 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm, + 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 --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c +index dd13f865ad40..fa6f5599a2a5 100644 +--- a/kernel/locking/lockdep.c ++++ b/kernel/locking/lockdep.c +@@ -140,7 +140,7 @@ static struct lock_list list_entries[MAX_LOCKDEP_ENTRIES]; + unsigned long nr_lock_classes; + static struct lock_class lock_classes[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) + { + if (!hlock->class_idx) { + /* +@@ -151,6 +151,7 @@ static inline struct lock_class *hlock_class(struct held_lock *hlock) + } + return lock_classes + hlock->class_idx - 1; + } ++#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 --git a/mm/Makefile b/mm/Makefile +index 26ef77a3883b..b2869af1ef08 100644 +--- a/mm/Makefile ++++ b/mm/Makefile +@@ -39,7 +39,7 @@ obj-y := filemap.o mempool.o oom_kill.o fadvise.o \ + 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 $(mmu-y) ++ prfile.o debug.o $(mmu-y) + + obj-y += init-mm.o + +diff --git a/mm/filemap.c b/mm/filemap.c +index 52517f28e6f4..250f675dcfb2 100644 +--- a/mm/filemap.c ++++ b/mm/filemap.c +@@ -2700,7 +2700,7 @@ vm_fault_t filemap_page_mkwrite(struct vm_fault *vmf) + 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 --git a/mm/mmap.c b/mm/mmap.c +index f7cd9cb966c0..515e88a194bd 100644 +--- a/mm/mmap.c ++++ b/mm/mmap.c +@@ -180,7 +180,7 @@ static struct vm_area_struct *remove_vma(struct vm_area_struct *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; +@@ -905,7 +905,7 @@ int __vma_adjust(struct vm_area_struct *vma, unsigned long start, + 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); +@@ -1821,8 +1821,8 @@ unsigned long mmap_region(struct file *file, unsigned long addr, + 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); +@@ -2641,7 +2641,7 @@ int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma, + 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); +@@ -2660,7 +2660,7 @@ int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma, + 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)); +@@ -2822,7 +2822,7 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size, + 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); +@@ -2897,10 +2897,27 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size, + } + } + +- 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) +@@ -3206,7 +3223,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, + 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 --git a/mm/nommu.c b/mm/nommu.c +index e4aac33216ae..b27b200f1c4f 100644 +--- a/mm/nommu.c ++++ b/mm/nommu.c +@@ -625,7 +625,7 @@ static void __put_nommu_region(struct vm_region *region) + 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 */ +@@ -763,7 +763,7 @@ static void delete_vma(struct mm_struct *mm, struct vm_area_struct *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); + put_nommu_region(vma->vm_region); + vm_area_free(vma); + } +@@ -1286,7 +1286,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; +@@ -1361,7 +1361,7 @@ unsigned long do_mmap(struct file *file, + 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); +diff --git a/mm/prfile.c b/mm/prfile.c +new file mode 100644 +index 000000000000..a27ac3688a35 +--- /dev/null ++++ b/mm/prfile.c +@@ -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-2018 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/cpupowertools/pspec.xml b/kernel/tools/cpupowertools/pspec.xml index c1469e3d..a08fd934 100644 --- a/kernel/tools/cpupowertools/pspec.xml +++ b/kernel/tools/cpupowertools/pspec.xml @@ -3,7 +3,7 @@ cpupowertools - http://www.kernel.org + https://www.kernel.org Ertuğrul Erata ertugrulerata@gmail.com @@ -12,20 +12,19 @@ app:console

CPU power management tools cpupowertools contains utilities to manage power management and frequency scaling policies of modern CPUs. - https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.14.tar.gz + https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.19.tar.gz pciutils-devel - + - patches/linux/patch-4.14.90.xz + patches/linux/patch-4.19.16.xz - patches/mageia_4_14/fs-aufs-4.14.patch - patches/mageia_4_14/fs-aufs-4.14-modular.patch - patches/mageia_4_14/fs-aufs-include-vmalloc.patch + patches/mageia_4_19/fs-aufs-4.19.patch + patches/mageia_4_19/fs-aufs-4.19-modular.patch @@ -52,6 +51,13 @@ + + 2019-01-19 + 4.19.16 + Rebuild + Ertuğrul Erata + ertugrulerata@gmail.com + 2018-12-22 4.14.90