From 518cb4a73ebbf782d279bbe9082d2466613b4f7b Mon Sep 17 00:00:00 2001 From: Rmys Date: Sat, 27 Nov 2021 15:54:05 +0300 Subject: [PATCH] kernel-5.15.5 --- .../files/patches/linux/patch-5.15.5.xz | Bin 0 -> 383556 bytes .../mageia/3rd-rtl8812au-kernel-5.10.patch | 281 + .../mageia/fs-aufs5.10-symbol-exports.patch | 284 + .../patches/mageia/fs-aufs5.10-tristate.patch | 24 + .../files/patches/mageia/fs-aufs5.10.patch | 37866 ++++++++++++++++ .../mageia/fs-aufs5.15-symbol-exports.patch | 14 +- .../files/patches/mageia/fs-aufs5.15.patch | 23 +- kernel/tools/cpupowertools/pspec.xml | 9 +- 8 files changed, 38465 insertions(+), 36 deletions(-) create mode 100644 kernel/tools/cpupowertools/files/patches/linux/patch-5.15.5.xz create mode 100644 kernel/tools/cpupowertools/files/patches/mageia/3rd-rtl8812au-kernel-5.10.patch create mode 100644 kernel/tools/cpupowertools/files/patches/mageia/fs-aufs5.10-symbol-exports.patch create mode 100644 kernel/tools/cpupowertools/files/patches/mageia/fs-aufs5.10-tristate.patch create mode 100644 kernel/tools/cpupowertools/files/patches/mageia/fs-aufs5.10.patch diff --git a/kernel/tools/cpupowertools/files/patches/linux/patch-5.15.5.xz b/kernel/tools/cpupowertools/files/patches/linux/patch-5.15.5.xz new file mode 100644 index 0000000000000000000000000000000000000000..2dab4c63d5f445076348527026ebdaf8740cfda8 GIT binary patch literal 383556 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%0D(Q&qcX;{t2(%tVq>CHBP`)D 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%0AxO2)b&UIw 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

S%ILucBaiBqkMYkZ*DNWbdO1 ze~NUadfD)q*MT1?gX#v7p7k3I_xm#kn3=~?sv?K#(6b#XT$Fy_dOlazuay)drzdda z8vuBQ9R3llVL6<&xA5!rOEbIr?>XK<_}vqPz?{=*0wkHPUQt(1+FoPjsAqKj826;M zL^y!}aKG*+n$UY!u~AH2Z<_utW)N>tI|nu;7EMK1S;tM#v4so>C=4(0VTs$KAX32j zvRDpNrz6O<7ui#1MjHeGx{206IQjc&@nZn+z4>-J5UMfDGV|hIqb;xS9XJesD@p1q zzCI`O8O(nJ3`FYGVua@kt5b3s0V^8&@hZ}Ao~ z;-Se4KqWBh&C;8Uy}ssTUC>uLlVok4m?}&#gU`6#aQ**;?zoG)x8kP>wC8*zf?yR* z(CPPw7}+Itq!W~IptW!i$U_QCS6 zNTOVGfKC;S^o=qaZ$k+pdRkG`7j-f#AmI*`?n-(MZe~n?D+I^{bGy^@8S}L9y*>liaWGt>@fx}79v+sXh$?)wZ zKABu1$h-qJF}TJXLH;LAtidJpBs{Fb)x5-M>|6pV@5(xdi2Ul!t5PbD#y6{$1ZQK} zkF%)+CHVgZ21dGPJe*G%6^g2d-&5*D3o+mmnb4y)b9S;wx+hS<`$SC=3mOkZ*ks&Z z2b}lamJ8A%Pd;(rzFcqu7)V%ZJHV?zsISWC>+7do!Mxohh_kfm-= z@Uj0o{m|AgC@}P0K@1Z&^gSg6bd$9XkJ7z9VnJ2O5H?Z#BN2p~v{_R#GtVi`9R{ z`}wZ)7LoZ(3kG_>OibEu1d%clgp7l2m-4*3or0=;Xuom#sA|J}9YdQT@#vhi&bb#Y z$K*=CX!_`VzgxlU;1e8vM@kEm6puRmyoI0)fAKd^(-+WEaqyHf0iG8F)#+#%1)>q_C3f(M$L^(2tx;!VJ7nxPqG{}&}CJbzBovq zowC_cDV5lwIDG`hco!vQiem1zJ~D$J^ppv$@_T zu{qC7BlyB}78zx>=#~$-izX!R*Z?D>;_kQ>C*0GIVpfi&>`S050lP5@>WhsAKR(q? zfLBgefx0urK3-nYxx%u278A#3_sa{iO;5Mj{1ste-k&v^J{1#Xp`4)uY;iO6uB6AO z!c&z{>0}eEhE349T?==Mi#DR0kTCTLCns0+k+#&1vlA5vUR=af4uzN5YmRveaFjXc zlvA~QU#KzDozv1$g>UHuaQKr~&UN4bcvPG|n=YiVM%9Htz?!&#TO4k8*AAnS-)N#J zl~;*}7dzIrQr*bjN-Zle!G^zy7@{nrlFZwokKQ1Kl|CH@r!F!_Y>;TT=9%4k1L+6F zACB6W)he`6@I2TU@9eGxvNnW1JX3l zZtfvMIks0+LqtI$58m$^NwjcbdM3xWvP9IRb&U_EbMZ&8ZdH&j68s!0K|F#^5{De`04N<(9ou&R zEIfB@d+Ne<#G&knO`S>FxhV{=NJEa!Vjr&-=Kzo!BH!3K1534pNj5sn zI}5z!&u4awox;xOgO7Jedt`q|aubP05L4dm7XNq;BotZI7qnNhdV@L0h>iwCam-fo zmA`r?(Os*Jnr$g!o41B%?PPXbzE`#-$ZE?7J ztKL2y&)Ug08E@uzI1!+7rri%CC}HcufZtb}83<%9ep9q7hiw%@O1SX^FSDlAPGenM zrxuMUuheK8Y-PsPZnyf`dh8mI;G-b=wWu(YUr8RF``Qwt&Wv+FiSe12$~owhi9MZg zuTGzf_zp~^jk2BYDq;0d>&NB#>`sP617h|A6+e#9T4S4pzYlv+l)=`8^pB{O>~2cW ztX`;ym@zeHC|O~D_dr8?Z8-IbSLb!NapWWRcIZaV{4{yPO-EB~_?K+Hc2S|&Nj@Fp zPIuBvdcMkk_*6)8-P-Tml2LiLVAxTnF{KzN6ZnM02z!g{Ith|4-z-|gw1HlqeNxVl z%IW$PuWD^a|3fos+E(E@#DwIDvKT{f=~lZ9_I6a?T87lbdxd9(eG}mfHRb=Q?qasL zK&1hTfnY`gs>v3&#FiHBwNQ86^~)&UV^&Xg-e;%8=n2Grxw2>k#1pkExR&{Z@@_;S zi;@U%qn_wuvWWu5G8HKH6rP`-9+k$h?;OInpgiG5m7ZnUU;;)7MCyj=*K*%k3(yo^ z=qBRqpb(0*H<0y5CLY9Ev*sASXT^nGzsTMX%)vi*dAW`j(DFF>PGXt?si<=(S$6;6 z6jFLFIb{=yf=I`770R!H*TZ5Z=Pmy%_p(IzNkQM7B?Eo;$fE`4$y`BT7RVoY5Ggnt z&Dq%=DZy0P0JD%L(`$D7UVPh$HobI5u(e`YufiV67rDM@0KO-!dJrU!=GiSY$i542 zQVe(iuFMn{fmA>1Wv=&v6N!_S9s-Fn37<**nd%rtvWU}ocivia)$UK0V4U31H3A`ncB~}wKy|(Kn;UGL|S$Dy~PW3fg{s5>uI+wlhRqhF>3JM!M1cC zRRcHwFXfIUrf$L*<=!5!eDdHqh+0EmO45OGno!Ho{}nx6TANYc`E|iUc4|!_(sD@RvCq<{{Ofqv{OP# z*mE%I0PUC=iz!*sYdhVubbnJkR2SQ=6%$9(i`&^RpstDgWrTNtNhXYrPF_|ciJego zZ2aN9REOD`73lY0-z%9~w1;vSi7bt`l|m_9CZm)P3-0k9m_m+rTWq@{U?)!jCicQD z2Lw`HbT3(jFXF4t)#Xdsd^m5kArM*u<$37h%o^i#Hfe+oceAc}GcaphZk<;0c8oN^ z5wF$gVig?{1D&;7S-2MAmmhuahLR|pP5G5xvgB)iPYKfov0Nt$Qg<(S8zZI0WE*xB z8Svf!^h#2c1BB+iQDyLktC?|<3W;siPJq_nO9W^e?1pWX`DXHv&&}3}E+l%RN~-Mk zW7B>6TA*2n5S#v;{MNgER?9T*RjLUA%SXC4)y2c04(#EqYiyqv~%33=NP z?z5kX=HtNO0?#?y1Ht?89R-P{ehlo~=W?>)vR|%l4nlsA;^-y)C?fc%`CsL8kye>o zSMc$(G7H7m(gUnCn`iyRWe?ZFvnqRk6?fd!^+P!{$3ZZ6Vg>Vz1=jeND^lwNY$u^R zE!g6bNRpw|-+qig{zJiie&vMvM?WM#5lL1Q*6`dNzy3;PeyD`Z@b5k4r8jmQ1%BMW z@RZN^?K;!_oKHnu(H3OLk8*;2GEvn()n=%W)lsdVlRypf#~|>Y+>9f9@mW6%OS?>- zW9TBgJ!gRVAj7Tu5VG?~{H8b={2C9U`!n*7)TSlRM)6w--o`hW0jY9JFO=Jv&;gk^ z4~~KZBw1_uv74nk36RHXq1zqbz`lIw=1%~~RRmZB3r3H_)&zZZpWcoP9khJ;dq|Rq zDrB+hLP_-^AG;%=Lk=oJg|F--ZX0E}ARyRoL2RT9MuFF#$Z@2m$`J&ru;=V4Rb?+H zcyBdvtCbR_lED%hMZNV~GoNGsvjYQ@vD;`90HFy*?URfeYzL?g3Mmooxqu+$A&@DLAkyJkq$@g@tq}7f{>9tOyee9%oxg58RqCwvI1206Rd$zbBTvbFIab zwPiZPclC?iM2di_l$>SjhvSC}`U&Mti@>?h+UhSSeIrI@_`jR}1kL(Ucj7uEQdj+p zA{6G{JQ4&Z6DimQtW1}sh5NYnhC;v6WWGz=2rGYTy5Lr){TXI6dyjjr;m(FOtLF)a zg4I2LsrWh_NNs9tO5C%J??4&$Dh0|EKEaXvFWs(cO?6HG>X!Vk*vyD#3&0Djn!Cx+ z_)WewnyRRmWu=l563M3h1~3!Hgr{sIKH_A{Yl8*Bm-l#Bx`2-CD^@)J=UjtGgPwiQ zLSE*~D3U&pv9nL0S8>}T#6T2P3McZL)n++vf+)D}L5NPXu=ps6fIuQL?b3kUn#wm# zv_{zVzp)eIfa+w@qcYC`C_@KBvv4x#O@lGw;=`**L(?sa@ghBHW^(55r%>%bM-0q? zMZDrgLl>Vo{H@T~WI#nBqpxU$E;00=fkyEPS%`3xr1)$=8#(|_Zoj=uA;pZ}ln=m# zsEKv#Yq=~&tp&Q-FxuGA<$Eg@WCV{y1eq?;iO}Uz!lWcm8>NrvRABsthnA&2pgCLl0EF z+%Fcx&s(qpgo6D_I3$a**z>3Znl=O=wni8@o_c-dO19!=hUO<1)p;0b`OwJR1(}!* zz~wkKHvSgBglAMvv=V~l3a=yE7%;<6vR4LK&x$-h1@?IL=ZsWw2M&r!AK^)|BZoCV zlRIaD()^kmv2x_=P8}Y*F2zuM)v2&3N>#hkSsDvCk;?FJR}si%_?y~(cISe!ReN{E z!<;+ZTLr8h#Bj^Tg!&DM5kqM#*f|}B%47L?xUl`erd^LdwDGHv+S6}GEdqNrrio0J zSY=08EfEH$J|O1+ikceFNZX8QfK>qEJ|x7_7a%hA8%f>(&43-~_la^9>sPl`SOTHr zXITLNnyp&mFpT^y?t%c7&3UOF?M=OzGs}rl$UB}Af)QCq3A%C!ToygT=2>^tCE{S% zXSTU1Fs~S*c*NG9DE)jgazIZ{IjV6YeD_=f+Wb8$!2FmGb!U3eD|u;Ic5}GHvn?k= zAgDurDkx<=XHxWPngX(YP!m_VqHkFz2Yy8jqn74PsWI*CmP~>^9`St%{cV6_(Je;t z&z*$anUTji2eLjyBJ!Xd`f&C;QMgNPbT7&ERW=n!V#KgRG46$K z7W6m9>+=&I@ki7C*S;1aZsBZ@9;p&8@eJHM8SS6+%Kn*C>;^_npX2{n^cz(=(-lN$ zE}`!71O>e0CLkcg)|d7Q=PbPj7HxOkVfR+VC6Ev>!MO9qi2eG7cw+K~L zDI7N~Q(?8mB_ZHiAx0RnwBEu#peZDTnv%>A5_g=Z06CcwVHDUj)1JOf;U zKT$7P!TAt~ZWNnE7G)YEIpZM^0oFY&U&q_XDffLow1S+Sd{I~?OCxULI6DbI%kk41 zhAJ_7(6|tY4?hkFlHE!I{RFhnK2^FDF^%aaRh)FE#`D+{-tF@riys>on%aOdwi(k9 zPTkLW;CfB#hJ?3?;-8r1ba@BI24!n8+K3CsPYy)y--CIexcLO7A)>74f+s^L^Nh7c z{~GaEkt3(;Y98?L`0Udb5jqEe|i8_a!ln2IMUZ&e{$(kw#~2==GK}tfi;clSzZ6 zIJHz01L#|aG5Hi|LB1}3xA)ayE(`2^%zF8*f-v{#Cd1p)_~hXGy+RpjNUqTM+kuQF z2%OH2j&d&1L*_C?f3R!zKKX_>;j0;!v|9^6qpWhoK z9<2f#3?npkYRN2nsF>r73^k_ThKqTCce60Z=9M13cHarpv2m~N2z<&h%lR?S^v-n) z!@mq_)82=Mkh{yO>~y(>@hZjdRWA#*ZZKzaSC}2{1S`OT-#^WE#|j<|k6I#3P1Zq3 zF0PWm`nG7-qV0KZgh9^@Q6q#qdR@+&ap2P&qK+dTq> z+Wo{)sRHbPA>~3r<#Kj8IZq2q?m%#4iqvTV%;ndxMQU`03o70xJdnilC2-83+l%9CRvnUHF<%rL;2D~i87XnONK0@5El&K!%5V%3*M(X|B}2a$vDlAc~W!O zoZjwLma+{qS|#*S6kP#|Yo3P>uh_{rNFj3mW2^!I&$~$6A5)rfs#)kSF@}rvrx#Co zDK*qQ6l)VK0lqr4bw=R56!~5{QN4X$2Py5(Ip1Xz^irhw(^%|FS$4}HB4^p@lC@FA zGefj1rl5`~M$s`uS(wzkQ;YPu6JN@I(|8S|Oi7E8{aNo-Dn0H;Q^TxQj`DrA*>nXe zq3@f!!2K~c>TbH*Ie5Y56W#6rG&*cjOw5!S(~pE;uu)N>ais%1{2b6dLR;g{hJ7|L zj-zT_!5qrix3Yi`(z+b{L^AH@*AMENZy*?p=R>$5X^CWsT*`8*H^U3_X&{9k9=UT% z{yBEUYvvAir{6!o&>X-Sz3g(>EWb53<9i4=(>^3`$J5Mfk?r^$@r2Ji>z+@WX_G@Dz{=af^O{TIFJ zlj@%?S8FaFe?tHpZ}h-w3n3w2`Wxp>CMqbMYBMFU#BnNmSDGHT$EjrG>?IxUz?rUN z*a6|*F>h5xHJz`@@GbcsI&m;U!|{sM9N|u$YYP)_KT?}fg?9eSML4Pz?_F|g;pLE2f}VNP73anVRvV3He(3EZvkz-8(U*U zosJWT|FGPusZNV6v>RI);>B_2J(q3vVtxW1_rI~douxhC$2x1-Hfum^`5cYj7ea`2 z&Y6LFR_=;4x>e0ue=qm0+#b~{Jp&C9{jVzD#%WCJ^_*8{h-gFYssZ9_FML%U@~I) zjvc59K)6*c>PgRlE$E#`Hp%0z)tHP^NSXPC#rWI86^d| zy+pjKR02wf$T;Az!B00~c#>_|_#W;n()vyH$;cbFZ7uEia*ergJkI1D_(gEx z6stzXC6qJcb|h`MQDg3wht@GyNV20|mUD*D4iemz7c0IGo|#Yxn|jlUGKN3I8=pNo zk7CV3hA(x%ZdU>9sw;{^3xMKdg#79FrKDJO&Tn~xLv2e)<$ruv{ zSrZvHGnS$n`x&kgETTQYy<_Bsuhy2XHcu-c*WNL2 z;V&$kh`@Y{c{@DsMF=_rLfS5mU&6uBNBPX)u^sPwc9gWVC_T{3BfJ^tXDd@J!KestH72oCY?!y0(uOE z+0ULKeCLfy;*Ei9HxoWTCdwuEPr2`4PAH}u-APioI%mlR&gSkT8&gN?`+S6_DRqip zeZA@KayYSER~PLVr=OB5{d}{hxBpSk+QAXI3ov(9Oz~RZa56tI?!0P9q7i>W_>@VL zJl9mJ0_2SRDuLuijPGT+6CH~{YdWC$Oh7@k~-uf7`-)fYYE@Wla};p!(OH+9yt^@ebT8` z+Sa~0qZm?>W#kc!RroxmP}wO7N8(fib*Z-Z0Uj$3QE@s>1#0MI&E*;@RqNOv>+gou0215*^M`F!1<(^Wo`K226+$jizy zH{?|$)3Rj8HUs|6X3Xp*@@Tc(RLB{|mPrbam2P|7%8TedxEjuhC*=dV#k<=JtoOgC zuh$HOr9ZvUlkv~3ep6N{I8a$<`~IvyTv!&(8CWxi_RKCWn$aPPmT7O&Ao+L-rMis&m_S=yeJGGoy0*wPs)sQ{K)PYXq{5(f}UZVkpnnMCHkXQ@h zP!>R|jG%9!p8?AbPOIy2qn2R6?B$A+%VKNIO)V{P_;y=nL!f3{X=2EWcK9=m>kXb4(INVf_M%_`~KKve7iW5V-*11D+Y2)SW_Z zVe0Szv{^rUTkxG9%;7F8tl9%Ih_l4H80p<^8R*dS=#9R9=>;%c2fnq*7Mt54md#mR ztv&bIA!y#96`No-FgWvog!BT2Nb&cSc33Y2QgljOTM(+TK;)S&jMzJSown{`HqV@6 zLjQz{oqUCC%IJVZ-^bo-aV-ZH3bmd5EMIu-qWBM2g~DT#|KaX#Vn-YJHbzIM;vsCKCR1O%zqAc<~U!%ea9TPk!8li zL5mlvBe`ov3O3)eOUz)4;lklp}P)Apgb`7I+^RA1b+ zNe_PWA$`Qr61d2=#{4=594Hf|QU{fk-=&-s1Ugj|fe)jfD9141V5a<D ztXoF0Ny%Y4LOkmGf2J1XJFIqPTyX$FS&Kwzunz5S0SspP`a`Y<{gEY_OI_~k|4U+E^^)+}q&njeXm|~#(VPi8XOC8^7+a}CVu8}``KFpqxgq zs#T?Djg@=Av&uTgR;ty5OjM}tBik(QYA1%R*^{&MMCU$x?5mDE1>JFhjjRl_Z`TQV zsMcuB9(x#w_!ZXuRGDz*pJTj>EuuKUc?h4b5GhoFue#u0S-@ z1nKT0U58U%nIM@dz%iga5l~id7_+^KKFE@Cdk2s%dEkAbaTz#X!jMXi16vPY=|=*h zTELGgh}7vM}JN_YZFONn^!NtMfl6et-oF2mOyKEq5!#&o_Jc@U|mb;^&XM*8Ud3O!JBW_q* zC94Pz)np1t8MC3L-!HHgc+`|Xh_^^@tJ_h%_+XBr%6*dEHK5<;(?QLiEwZJN2)2`P zVSGj%w;4R-#5;@Fn!D9?2bpxZ{O~s!TD>4OO5}B|5v0RAEIqR<^ zLmbE!f|qvRS-Z2V^??JIWIduLwp?};7+R>j#NSZdVMc~e#a2_wQA%#V;}%o=0P!b~ z*e*jSJPa<`BCwbzbF)yj&hk4Ha?YH4uJxGMPT*tI1xz3e;Ro zeG|l$!oq=;iz(M!Feg09Ix+YmhL?ewhD;;>VC0ckp@88^!F8`{ z*h^AV$2$<>L}AR5OnIY{*_ER=tY(BUOm%^HN?~vBo3f$K$@eDcwhDGre7QNCDPSow zU%*fB)|kVAXtU)53&Ks1v4q->0?^1J#;%uB-b{OW!#v(ZX>l=VU@Th_WpjKNy%v(L ziSWlgXM26uNg6>QTDvI=)rxsK%2BfcTdz)kEhGn&X7-{MYrDEY?0-yGST zP?}s-BFCJNm`b3}GUT!QU6=l%9`Fcg7h9k=I*f1=03Q6JxGj<#j*6uW?~U_$^tf5gEEC`HVI+#qzL za{X+Nmxr4maG^f!{zHc!p2?_@^oAeoeG74}XF`bmO<@laMB&ANe(E?BMTjLaZBIq# zNpako;a7+nDx`e^&7Co#SY*7WN+`5xCOUX?R+t8mo=+(yc7DsM?q35vV|rioWi_c^ zfQ3EprA)F4mGps%gS8!$C8rP<^DJb=7eMo8+Ao+K z!Sl^5i5XLuRhy|Bioz{RyD5b+^7iK|7SE1cK&A*Qe}4-(fUX`opUy)0tE^;&+gY^k zIZF^w&?F9Ff?xlA12@``!9_i^bv1*1ZQ_Vy{c4)Hh)_M9^fth#V)}+0kCdRXDDHH+ z5#w?7^88JiMGVqZWN6V!QM#9%GW$ApSIb8TW@D&z-wm7MVF8o)Ui%rzBxzwOk1KnR zS#oCm-9jP4;%tt7(WP4RLB47t3GVUpsOOv%Y@$*!4iub;X)+7ZNe8))5v1Rcy^wz&(zN4H2zTmWBc%n;0AXJb!>Ht&zVQ8 zk=NP3nBq?y?{@FZ7b8xFP84tgGtU_HwX#$GnDtRc`xw$Wbs{|1J98hG+u2W{gkUy| z++n10M3Nmeb`(3?cIE|{(P0e9tjf^7apbQ}^d|HKaX0Q_&n@I?2UfsMde~h|7xMvK z8zd;Y^`GR9?DxbJoOib5`tc=ECSX)wv_+3U>Geg#iefU*=RFGsLg{#q)$ht4DRmpm zGw=Wqpd0B@&yLlh)CvRe>)(be1`p8f3II4V0k6?{wee~pnB+j(T+Q%ey4R+^t1=^| zU^`}J*Xqq)vq_Lx?_ILRm|nj>XENB*wYpezS&MO@m;rd%?{=lAt8sY~(R7-9*kp(18O+IpYA%)(m;Z(u@QkkVkX(0%l0N z%i+F>`jIT}n9$|6{NLs{R>1Vtw=4a84=rZt|JOdB@O^2bD;P{fi2L}I_NH+3GC~fZ z;0aPdbnw~0Cl_cY1GO!ZO--T^O3*ivKq$~`*nO*6>^vVb!-#`V%hRwi9|Dt(-;^*` z7xei{lME46%xn?ncC6rk^*bM~90C1GF&nmRV|G>fi7U^`T~)3{Bd81sC3|gBGER7R=0Vaycw%C}wAbHnxWCXDin2oT*Sv!0WSkUn_OhGMaMv?)$a6~=yrjTb zEpg%+w2pX&gz-y)v!|=f2Xt)&ORgGw2SCZ4c)wJ4=#eAWv>Y;}0{%lO-DJmc-|MMHAaAMb(T*GAs~p6iy+Y)y!0W; zrElK6!0n`g%>^ssN&&86m+C%mX*8^UHm@nKQDW=FeaH_CmLS=q0@AOy&I#hki&up@ zA8X>)6PGB#%vBK1tkVMVraMZ3SldazX>f6E=OPik&$k!aIp|Gd`ZT*2Sj4GTL-Tj- zLCfs&&}>*()_yx&Syy8*W`Djl&o>i>lVzkAVsjh?%s^71GG-Cw=V|V4d*|2zdJd-Y zJ4Q!4U#YS*B6q_*F~fFUdJP)=n76LOYoVj9LWz0Ba4nW&o&p;Q^>oA@#&pBFaf}%e z^x7)t8Kc|HOcJP(JM|gysS(B#@2n%EF(!@~yT?uu!8$E_JB6pY z%N0ZzC8&&F%N$c0)Kyf6oP=B%9^45&q`L_=w{0YeQI80L_^va2r92+ysL@9^msnl` z*1c=u((OaM`+Y{fosN?YKHZ&7%7}oWvV_LGA%Do3Aw>ei(s}e zYpJ@f)4SSZ9w)YOl)V2Q&`V0V16acL_KW5uZR5{BtHqkVtzg!k5dDKdd#AZpj~%FY z7ElIP$RE1Cw-YGG4wA#*Fbmilpt`VMW8{4M)|G0$Z#(viMn)gX{6Gn5=&OZ1(Gq|3 zOJf0_0N{RpICtU9cG`LXtdrRggQ5IQ6iuxTbkJj$q8-3W-dwiv z1%W|1(Xs(bdZ9HJ*Mln3oxDu>=JW|h!iE0pe1W8aE?*_r&EsTQ*cnN17A!u^iflnE zyl8(kYuPV_oEmBTY#5-%|Bhg$U&8@64n85^V|ZOB8QY!J;$J&F)?$Q&r_}qCo@*qd zBjy6FRp=r^2{hWHEcGMy=M_<_#pv3Fz4vE6v0E9bEpH)yF0^@)w}pz|k%5sGKakL4 zGMv#3+h)lap;6&rnFiVTpy%J@7Oo#THs65r5a*eu0Xf46vzkH~DMo1v*$9>CP*x)w zJ=<0?%`t+H0T(&o?tE9^+*8v-X+{|Yv2*2XMJ->&byfMbJy_Wu_?oqP>m)&_tbr@P z*6LW`m~+DDg9JMoWRnSQ8V#Ht@>*zMVPEmPqr-eCzYK|8gpq~C<7{kyDwnS@ERYtu ztc80Oz@gtFzaAf}B`l-%BlNqU^BZK~rFnACJC~%F^(VHY=0%&bAKx0x-M0#3Ob1_J zE}(h-3iJ1KA@trVW{jg4M8_oDASCEzVrXL407kWe1uztyYXfVtBrT$zELe$=-5-+M zm%A{^%j~)UsxB+JC$_eUGvVW}H@9AS^c+e{DaovnzK}2Qs*5N6v$6-s4Ee(?D=k+#oPq{}-0lZ zF>kaX2jjVa6aoM<0$!z)0ZqG~ZQ9IcYhamY0(VoBA!BN8D)*f{k9Z^&CO(ARZgy~} z^#2;vbSP2kUdj%8c;^(Xv8LL__4cWe0zwSGpYPh7qk*fn8X@QRI5vF{<8lc3xObWV zx*fQ04>hGRW>Q_bi`+sZ7HC=WhYsp~SdPEQ;HP{`^h+G$Mm*~F)EpBOyBiJ;ZOGUx z^Wx}x%Qzb2by1AJ4(w2B#IT0B4hR>VpiG!05oQ+H;txh!hK3w9YxS>T`R@>}4A%9_ zOw#b_R-_!;(}y7SK@fpj>I5iYF$G|uDS!^QH8`NcrZ#c-Lo-ZVC>&>WkA;qf!bkmv z$Eq5u2*ub5gc8o^)y&ix)a?qSGW~*$9TA)R?zh{!TBjnFy|!x}7VdaCFjg=YZ+>1b z*2O_$R(dtR21TeN0Xj=GWenSxmqoE%OhvaA{{vLQ0v&T+b(4LuL-QHT_9nQV4-K^1 z!IdhB4)49DE3iuH5#_!40TMMq|G|6g)>z%KIIC=Edp)LPnd~0x%6jN9zC0b*R#<1 z-Ca6w>BV@t=}5|Tkz9&$t5fXj_KCCU2k3ix>%@%{(hispq`3(2S=uT|a*4L`+3l-$ z;@0VX3@n3ruBU!-$>eZQ4FBR5Z+3x*Xb5VqYNxFCn>N{G#F*J{&X%$1@D^d#2e6`x*+O1CcMx_d|M2_Kg-w-1pAiiszi z2sD3~0!)lxcIp2D@?R;DlOYM86&|0zJw`}Ru6DS+9?%3JU$7B*2fD^NgMiQS?FWtF z)4AgeBNGdEcZ%ob(3&Ta^Axr-cbmTt*`YFH5hcl@uRp-W0X4AZrmP9-2%quS%&Hiz zmLskRil`u#xE!t|WGb-*oLng@Z-+;bQ8qNGM1_s1dc+1*{T}MjEiUvTO8jBH3Qeen z-|LiN;~VET6m<;2HQ3b|v#U!?NdEru#6)7TE5k4Yn45M@n`()U}5jP{e3YJKiB*2otnMNe_59q*)~2~ zk90Uf8$5&&a8}+4v(Hq}M#2jY&onKxG3(6Dcnv8kX2f55eo;=qc*iWx+mx$s5d_B z4aoML6*aM=r9HH0QfrmlTqmrG4{#2VoeDg6yK%It=*>)M-`Fi18@ep$q9TYJRAiqh zY<_Vv+y!vXnJ6VkfN2qahESoEw8<#ts$p( zucQ2XSl~6?{9g>Q6?>~b!KVEfxAA>h-l@IilNm~GBl8($-@j+eZ}@lI{yK9|#M`_; z)j9$m6^lv7+c6?ap4`fDPd^0dIW;BEpK0uFkpoQpQ|K89E|U`*E4Iq^T99xqv35y< zUs{H=MD;K;(uJfeO|D zB1aG$A-CO+f}3qwTz?nO8bSlUh&~8BYXO{CN*TjCxiD4hY@*n1)wL9h(Cx+|6dqLe z)0;g!dmbihP1W$}ts6P}5a@giKn?bU7|Zy8)6zJWMP9!%E|a#-4vwx_bUJ0e>`)8Byz*k$Nenaj`t z94E8jdmuxZf7w>(=*gqGME>5$#8MMNI1NpH$1b}UjWVhP>>o-}%yuAzR0k~95amE_ zhl3cOo={&pVRKh|I&1AwYkOXNq;2yqywO=TjIQ_fh<2YzT|vBNCd!q4FEO}&>%~E; z!FX3!Lp%^@kX0Akza`C2qZJpuo3Tnz;?Oi*>ii~F%PGW=T0J+gfai2=15dyi`_4%zG3Z!t~_KzID{f> zG9bH15;cKB8~GSUuj@KucQcP#IJ9S=U-pGGU)oJ=giCy|0yPh-?-;Q%VJQm#^tS;e zk^Q3R*=lR_Js={k=T0?aaH#S^Bh{B*900@rj>m1oEl*|Dukk5_m1kaTjOat0JRXob z%d1-+m1(g=_J);BG|#c^ntWD=pnOVa)-KXHMeL7GLDrENj-bX}M$ScRgKC9;VggG% z!soDIBAyROk{GiQwltCPm(s})jyQz@!E(jC3CMySTy5h*^t2fYZ?ESNXylVmI~Fx< znR%>Fx*;p(eLVbq1*OK9zOgh|LHai|rAT0-yy&)0H4J**z`;lgW+*R0og;$AtLMII z(|d26uftlVQO$_B>}h)ocHKhRlj_R{39BpM!()X6h6#g^aa|^}t@-AV`4sE7h-tisHs|% zzSZwkE{0d-;dE+2)rz?k7W>ZJDB#!y$WR0 zAgaZ_cuS(UKToSN$l)D0b$$xSewmQ&Xx#g$GfU!(oj8{>u?^#Cxj(|cEx^~VPPWa- zAn%pxib7<@KT^{Y9L1Zf-h>}yTQr#QKFnF6f zRHvvpw3~JcCT5o!)D?22b0qK=VcO%K@}9wo-e7BDo6+sLqJ!b*uL*lmPy<~BY_DdZ zjEF{4F6Eb(^q9iY-u-0e24`|2LI`p}PUjb$UZCdPMZ*(Jqi6ANeXQA_0*QX`5q~mD z2wfKOBU%AubAZlFKF}`rqi?z}@JxB;Wws_Z`HzvqZvF=|=mgxays8)O^Ks8_@cjlM zacmTh&altwW>dsD32a#DFW7rhL`FO*1f~1{BN%jW-^W?a7=<3d6QL}O!FF~rmyO- zyn$2&y6+suG9VP;IhID@^#jz$&gfgs-FX=C3inVeXp%Azx~yn6KfTqxTt2$=L@R>W7`z-dTm<1#CWS>isg?+8EMtFTcaz?P^%F z@!=}QxRy;8nLI2vQ}_4yhdghB)3l3{KYk!br`AVKdOL^k7tS@E(h==9wL9R! zkLn)0pAmwtaMp!s;b6=WV{?%*D_Pgfeuev=Luszxi6%)6Yr+bPt^D01)-9%c{lyGIA6kgON4u54?la@{x{W4w6?i@<7f zdWt^g99)WPa^y+&2f}A~ilgYSjPDO+{AuUh9Z+cWB}>AwL87VlDpAj06ABCIbifAG z_BZNCf`v;GQUSv6-I4Gjl-R(2MV=K#b{#PsuQiZJOug9hY?qv-g`Mfs5SW1cl7f&2HcPzVVz#P{qsZskv}vA0lMmWfd1Y= z-za5^(^rUTFA$WG6{-^eXAY=4(qlpp*)dq$bjzBhz%cx(0L_7-3!l|#(-Za}j2b^1 zduHGN!Tn@$bi;#QJ}5wow%Cu_t=R*(5;inY=ZHikjE;{pHay?u=c65^7FgCO1M>ce zT`7|aMkVgKL%8SQ-XsdJbbWP(Mnbwhhb{V#7d+3)qUx1^MZH`2JnMS7uCr0_nTbaz zA4mtoel$?r1<1?0Tz;6CnB)1D^NE$Gz2i>*Xu6y3yw{1c5Wa*hZlD?RoVZNiD@}Qa z+mb8Khxq8WdV94%oTg*M5}@c1ha6V?hJFiUoUeAOh2}7=SJ`>sNu@ooM#3Dgb_%Bf z4o`V|(Q@B4_vX39&&-tyX@^oJV}>{F=y>Vk;YBi&jCEHqmWo&p#=C*UC_r&p1#6%3 z*w@wQH<}BauXX-BM@e0H*PmRquJ+lZf*{a)Vgf*CoJY*!1E4JAgqTvo!ykbH)GM5u z%zLViw)&An)zR(Pp22eWiiSp2b0zRi+7f`0_^L$ibm!nK7QW{SKR>FN{qL{7IoaIS z62sItFOLo^KtTyd0KUu?f(u{PZ&b#fz>AZ6aSo>Ms5Qy^dkDXew%aip9;B(QuQVEq zlR9RDU0RsFtN`1tx{6lB^6Cy0!7Y96F{y~Cz0c4p0fMzQN~O2<*(00XC7-sU9>O(X zQXJ8SEEb-Rff_L#z$rXT=SWoaJj&|%lBFxN3?0+kiWi_(Qt>$j9?`|T2RdnBd#qBk z4!N$ab)SH0jKR%KucZ=yiB5ejY0XJY!oG8*qey2=0(zNf2kkLs=?i8@vT|jMPa*zq zFwuTZiA-d(xf#1rQ8qlo9hCRAHl^eLbg7Fx1)w}9x6m|OkM_zZE!zWxVet9ZIMMVD z>ydyWb~GxKWA;qaE4mkxtj-&e21Gq->~b7VjZI?f-Rx~>kUTbl3)rUMmCDb-xwn_Z zel`E@Y#8pwIfAH0oyu@3FKU`#Cj#ly&A5TfrlBk-zlqENhq9WgxUB&!)ANRgMHi?a zJSm6b2-Da5EYKXwTJ{Q-QzzgdRl*WAT5Jl} z%+^mdroafe%qGVTCIKZDbxdzfVg9#fWO*4LP1MvM+zK-SZ$@}z&c`My2^7D^tIBHw z%If}dt-d*h8m*G+ak`Y%}li1dM zz>3ZccpFies`M+Ri++RN;oqgb-Hth?kT*n2RT7(sYse&oMiCQ;*{d*w8PAu~(=NT& zta+-hRgO1z7|Pia>&oK8mzjn#pdZe>De71J4@7c^;t>btT(Umz2tYi}VgZF#Y|+QSg zmj5R&43^7crG5ydXaZA)rv_}6O5(RoubjT7f6@>Qq918ts}$UB3&N7iW`xQ{bhyvt zSjg_BC5~^O$f{pua{@o;z%;PEtrYhjkY%=^fG0xHj7|-W_MrVtmdAm(=(!qi{%#vh zeBa}Rp9DE%{iCVUWUm1mfMN2y!J;i(v9Hr>0#^vL!(wbFKo=vuZrYwC~rJ$P+suO&~RZ zAiyDI&-7=c0a!>>CrUaXWKNtH%bGE#ZByWL%PB^gt#GX9*{k zXhZYWgw;3*3=>a);$!8}^A!@grn?1=iI;LSt07XQvbw*C4|T7TtWv&~_(L_)B$DnF zSx`r7{B!n@v|@hLBvu=YzLMjID}`Crp8<4-2CfAKrqoNl&>DX{=9++vHhFqEvr;H_ zKCn=A*ag7GW)bNTUx~4IZ3#YtpJT1#Eoo|z%q&}Jq?kUywzB3a)EGCFl(?cQU^!*p z#4(+XXeC0HUmYVMxL#0;R_ZIdKZDNMD~HJTONw;wmvX(Ug{G!{lt5eBnjpCV)LQXG zI;6_aDdim=CDwjY2Qhy!3MDov)X_7*?Fim8#E-V<~;Vs z(=_(pSzFOLAREZ;!-J-=-_Hdu-xkt>)1g>ac#|i3=Yl49NoaS|pXMhCKIN^N&g-%@ z3X}RO-vb$ntxgs$Kq^w!Eehy0GM^{5VG}H|OK=_SRFYq2_B3FIw*5!K$Fg_BDiL_~ zCR7syJxh0Q9D0=({$bP41<2}Wfawwd$3-|8-3rfp7RP4U#QPEQ* zy=fcCwhI|-uSDh_z}pkUwtv&lvn|1t|L=UvQIs8;wNCzm%SSh-WcrKjqMFcP=aOfM!x) zT1*eNtT{WRs%eF#RyBp*8tk`;a`B+Rxm zHTPQ_kE5Y~z_NuVd2IYS!?eJAVLorXigP1dD+LPZz$7|}495I+3FFrCu#{EBH zdZi{>{QE*cMgG-9%)kV-E(;1r@@|wK^vRDKW9{et?;l+zxYnG}6Fl*goh4Z!xrP&u zgY#in>IUwrZd)whTjP@62A@KfuSDcDJ2~>?{V8h&b`oCd#2+UQyC!h-ucM*f7y)N%(7zk-+`Hq0{bwi1M`Bk!Q8Wb%afeU@6)pnKovJTQa?_K{1w^`j)_0l3mc)=A-iJII4+op3XIMe_|rzt z5!t=9BkG8J?x&VY&!ZK3#HWa$@6m^YKhKWHlAn`Y(RMbXfhPN#2qu#C)kQ_m{9u+2 zNt3wdX$eYt4`>vkkM{o?iIu&KizTVALF(31MCeL#Hu;%JV|>&L-VP^#vyDK#*4_1- zP%xN~cL|i?ySqeQr$7*O^=_eC_T+bB=2Z+;H53)U@p*p>9p}kTZPjneY;Z5 zonbxfRC6$9hJ!N60Gk`R+MGeJI3mnaGd5BH9`Ik3GQ4(P?*a|kwI3TE^+0ZjQ~a&Q zq8sR`hRPLAsaaY2lP!_b@Q3^(j6Ac5@E#%rq=psW33%#pS$CaN=h>Q}-{p!43k#p6 z?h{eS8l9+^H4y?ZEC10|`>?cmZo8D zW$7%X0r?aL>uV|yi@~u|j=7v3YgHJ;56`ox0Od78?;mil+I(_CfevA5cTDPu4EJbZ=B5CGPJ6Bu8Vqgz ztw5M6`D9?nN4l>sV&Kp!IUqHqSu zI}~Ocu`TNkho~&_JV+gf;@b9*yHLkKH!=b+HxmA}xseG0jE-GHT;2>Yj7d{?WE>zU;kFzF$ zg>f7w&6!M=2w3r>lt7Q8WwRa+D6~{1E8BDG+~4}V3&N=@roqB^U}RD_=h-Qb#KJ4e zA60NKt$ogmcC>MeqQ)b%X_6Fh$2UQyqCs$>!^=7;D-IrnN3eSMl)bl>{2EZn*N6 z&!ZuzQ=`Dmq9l&KYzF^ScmK^+n6 zQoG;fGkqQqyl@qn{_-4lKF60HS+j=4D=!SQQ?`~_0r&lGxXXd>&M2#^s=BN3St^z3 z5L^mg=R9Mu8Bz$2`zdmXozyHSozq>5?}3TQjR7V|+MT(b7|U$2(!)#QF)h6E43rht zozY%57YXH*1`|?-WJUq<#~ojawRwUhN?<3U`A+b9s0lHt7x+K?YJ@3(9M6^e+Oo_! z%cR}CEkSNmDvpM;WZqryF8_f{lb`$J-jyIaiX#^QJ?*c>M`GAdoAb=+!;)Otgnn-4 z%a|INPkA&xA7im-7l6J$zm8;Z_&pgFU5+`OtfWo3D0L{i!Vmt59( z66rL^zEZYS50uLLV6)C48MH2{*>qgm^&Pk&>rO~+T5YnqvN`@z&-aOC*~N@dp^{dfc&Yk;X|dyM zM}Bydb222X694V=3G_<0oL!=zO!gj!pm_>$VtvI53C|+epYK(Ow)KnmjiLENhEDms zd9`-!{NBF9E(M^HeLjH-GA!RVw}pVu>sGO*Z(D4o0`3X7{~A0JE=M(A z99Vpk-((ib6TW(1XKQxy^fcmGHy0s9>7rdGGi+1Fu-+C`qUpPAHntjN4_p2$MV%MwKO#kiBRZc6(tKHs;)I|*moku_u8ePIa!$Y$}Xsl)#Hq}%vFc&$MRuizX zQApVhn~RSLoidV)<>U9Pxd~iMkp*F9Z&NyTk~Fp_%3MzugjIK@kNL>r&~lS6OeM|#W3#ZkWY`2p$U!4ky8XQADHW2RN%Fmw0CQ5ij3C7f>9f?G?Zj#mi1Wr+Gti1k$ z5wkxD++6z}*{KY%lqKNVTwq%-oc98a;l=rFKI}P&7l2Ey;sKv$EH2lwt~_QVdihOI z$?jS#j|OckZ9$jNvDELE9v1|(<}Q#=wlX$87h%O@3PVs!e*tha0N!SODWbt{@kjv4 zU!I%kOaiveE;t2g=ASpNl9RsgCSrbAZE!Mn`07H5kF?2z8-Ts_DmJ{(zJF*8bL|R` z^B<%gIYzJ7EcTk!@Ajdd=1Qx-8f5ac$XkfCVTdJqK$f*FjYM|cp;u6sRD@|{v0O_=@ zmy~30Kpw#ayHtl17G5{DNSLOgpIHY=bu9xhm_56LbOOtjt8qy!{jFpDb`Q)G6ioz| zoBz{9UmYnjhpu9HBP1vZvFwCccwz+7fJ?Wi0cvJ^2@AEMSl2D>{HIRCDcs)5W@ai7 z=-IjBRbG3n(?nmtf+{Zoa*4iYxFC?!1&sK5^kl&qkkR`DiY>`7z^VfloF2H|!UQDr zF_-m&vcv(I{wi4QK_|te>vbLi6EEJG1?HfLJT6eDQLm>S-$@derKq!h7w*l%G^Z|` zIfbg$c=*PiIj;cC?a-j1Bx>zksD?I~JGFB}^?2%6#k2bxH`cZTe1!O`&>+u{9BWQ$ zJQrwZHOw;05v&=FzB2ev3TS+oL^|JlEi~?buH8xm>5L7)0%9@3*PT~1!E~(H4co;3 z3uk5JuRuZC($`VKRlt<*zc&bdmB#qi<#2ad<^_;96nYsZFDRanfqW86q1v0Au-X_( zK2L+b)hW+q*$%q|eNVi=M7?!*;bI$|mDb_W)+4NpD$_MG;cg=+bAFtk2Q6DoP@NM` z$}>cI5BqoxHR$Z?A*`Gl_ipvQ*rCr+G;nVFnq_UP&^G<1$Q&95kL62y^Z`ukO8 zd+LvvAE-n|rYh_1MYi5RO-$9CyD$;LAU^w-&Up#2j_QL+Ks9WbGH+p)V;d87BOs?2 zsphxa-w3Fvf-V`m<7X9maY9MzpTzZN9h9_?nFvUgNIvtVJ|rIw&|H((a;j6^T3XIS zl!6g>bgRiFV!iM}_>vHpB8@h9{UsVgwb)H@!;3J;-P-G;wDrX&J#Z35n5r1fW2%QM zGguw$zBLd15=09bm#e}c1{@WB)6>u$N1jKn48cvCxWQ8L7dye9LX*rQ?F2W=uhq&k zvOCG3uv@5CXtnTz+>wPI$nYbRrwjk-^-@(1!Dk8F=tSM)VKzp}6g1HfLV82b-7Vsp%{Kz31gcmlTAku%3;v{1H{(}+0Q}<=z0P9Aa z?a5i>b34Z3Ko75*2$g13I@)P-j!X%zE>iJz+cie?!wO_0QYrwcE{wFui1AU8C!w$Y z=X1~_k@FL88WSDV!lO0<<+$2mpQ3&HFG?2hsHn!Olui}Z&XeRdMYs*8p6@0=j$%W^ zCO_jY9Y;x|Xky%){}z-TRHOQqmbHnf7T8h-yH&Q@#1ps-Tzw=GjgqSx%UzjLJ)FA{ zX_n8o5BacCPH~3nV?f`8s5aXag|ed^U6=HdVAvbC<)i3fl=+|}6WIvh+;V^E1_$Qe z!OTL*F-e!S_+;G{&6~W6n9`RU)J#ZHJ4-(GM|05_4iwL{q&pS~*Ls_4N$b2G|2 z84~{-$r#1j8)8$j&6SvmvMYK}uDOY}Mw}@oz<JqSIPjdU9*GwX9A=32lS>6Fxu{5Qxt9151Ga0*z6jw3P4&O z4Nq8UKUkNB)y^K*QVkJA{=xRI)unotEA!pSQ5O9<3Hp29z~1f>;Jf zv05mhnXVwe6ADXFQ;h#54%Gmh4}{MAN_O=8cK@K5Du0tR@Tdih27Ihtj#FNFm7SG1 z6GX;HbyA1qCpfx*=P{qN&08`-(cxX$A#l&=)2Q(J>QfFq?0Gg`U{?DhW6k6ZsUnUj zvQ(u^R|!?j3q|XToVyw1W3tuCVY}{bV}QUMWwwCsxqo5QoXHBz1>avzG95>+!h1P6 z-SAUu(kD5(it-~&Mh9?2Z7i7Ac^lSh`7)u*z%4J+gGt@rlUXdXnYBCM0*=S^8{#kv z$hCQzS4WH1Pmk`1$Q9Z|WghUL>)GhQJTY0_n<_<^L&Do7B; zFIXyiv+c;{p|2$rB1pjJsz96AJFPtKlV_i!|A(G;ogOcBy9ko+9TzRM8qfNsf1$~o= zo+*;%DI~kMC_@ikqEKN#-6S$Mq$bi3i(TteFCVtZWxg~Dn5#0 zM@yv4RM>PV0Sl|h`3PUi%yWdcdQNmyM9*Z5-DByv`}J~J zjm2F?Ci}+fsO0qL9pH(8KXbLZOUa)Hx76esT$+%q9xH&=flZ4;@7a7Y9?*r|(k_x5 zmhaPhY?Ys%Xtx#&FF?hXwe1|P{URy#7Wfx?%k$vhhv*6fQ`_b_&>nRnvR)}ukYz5t za?Kw$Hegv3r3?t;xSlGla9S5K+LLfBr#9y1`SEiqg=Hy4o3urth~wG@zMQ60V1Vx~ z9gWT^DrA8@#G}<+^HU5W(j-i$lXEXQKghrEGI6Y?#IUGnMGdF{^Qmh`(hG`15Z)De zMXTkJ$v;R`ma*@a97l{W1VHscJX0ujKfezeUn#&1(#tS0aPo!hIP*&dnF*X}jnD)+WXb;HHN=ZOX1$H>u zb`ObY3w3kd8uypQRu(KHO|t+DYIQQg+|g-UwSwMG(M7hxfyi&bXb3qveUxlY_F%$rH7v~Hyrsv>%THw<1Xy3L2F&dHChm28>NLgx007%Cv +Date: Sun, 8 Nov 2020 12:25:43 +0000 +Subject: [PATCH] Fix kernel 5.10-rc1 + +--- + 3rdparty/rtl8812au/core/rtw_btcoex.c | 7 ++++++- + 3rdparty/rtl8812au/core/rtw_wlan_util.c | 10 ++++++---- + 3rdparty/rtl8812au/os_dep/linux/os_intfs.c | 19 +++++++++++++----- + 3rdparty/rtl8812au/os_dep/osdep_service.c | 43 +++++++++++++++++++++++++++-------------- + 4 files changed, 54 insertions(+), 25 deletions(-) + +diff --git a/3rdparty/rtl8812au/core/rtw_btcoex.c b/3rdparty/rtl8812au/core/rtw_btcoex.c +index d5b89bdc..f5e0f567 100644 +--- a/3rdparty/rtl8812au/core/rtw_btcoex.c ++++ b/3rdparty/rtl8812au/core/rtw_btcoex.c +@@ -1443,7 +1443,9 @@ u8 rtw_btcoex_sendmsgbysocket(_adapter *padapter, u8 *msg, u8 msg_size, bool for + { + u8 error; + struct msghdr udpmsg; ++#ifdef set_fs + mm_segment_t oldfs; ++#endif + struct iovec iov; + struct bt_coex_info *pcoex_info = &padapter->coex_info; + +@@ -1473,15 +1475,18 @@ u8 rtw_btcoex_sendmsgbysocket(_adapter *padapter, u8 *msg, u8 msg_size, bool for + udpmsg.msg_control = NULL; + udpmsg.msg_controllen = 0; + udpmsg.msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL; ++#ifdef set_fs + oldfs = get_fs(); + set_fs(KERNEL_DS); +- ++#endif + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) + error = sock_sendmsg(pcoex_info->udpsock, &udpmsg); + #else + error = sock_sendmsg(pcoex_info->udpsock, &udpmsg, msg_size); + #endif ++#ifdef set_fs + set_fs(oldfs); ++#endif + if (error < 0) { + RTW_INFO("Error when sendimg msg, error:%d\n", error); + return _FAIL; +diff --git a/3rdparty/rtl8812au/core/rtw_wlan_util.c b/3rdparty/rtl8812au/core/rtw_wlan_util.c +index b4cecd11..e465e9b5 100644 +--- a/3rdparty/rtl8812au/core/rtw_wlan_util.c ++++ b/3rdparty/rtl8812au/core/rtw_wlan_util.c +@@ -4744,7 +4744,9 @@ int rtw_dev_nlo_info_set(struct pno_nlo_info *nlo_info, pno_ssid_t *ssid, + + int i = 0; + struct file *fp; ++#ifdef set_fs + mm_segment_t fs; ++#endif + loff_t pos = 0; + u8 *source = NULL; + long len = 0; +@@ -4780,10 +4782,10 @@ int rtw_dev_nlo_info_set(struct pno_nlo_info *nlo_info, pno_ssid_t *ssid, + RTW_INFO("Error, cipher array using default value.\n"); + return 0; + } +- ++#ifdef set_fs + fs = get_fs(); + set_fs(KERNEL_DS); +- ++#endif + source = rtw_zmalloc(2048); + + if (source != NULL) { +@@ -4791,10 +4793,10 @@ int rtw_dev_nlo_info_set(struct pno_nlo_info *nlo_info, pno_ssid_t *ssid, + rtw_parse_cipher_list(nlo_info, source); + rtw_mfree(source, 2048); + } +- ++#ifdef set_fs + set_fs(fs); + filp_close(fp, NULL); +- ++#endif + RTW_INFO("-%s-\n", __func__); + return 0; + } +diff --git a/3rdparty/rtl8812au/os_dep/linux/os_intfs.c b/3rdparty/rtl8812au/os_dep/linux/os_intfs.c +index 1085d6cd..a37e488b 100644 +--- a/3rdparty/rtl8812au/os_dep/linux/os_intfs.c ++++ b/3rdparty/rtl8812au/os_dep/linux/os_intfs.c +@@ -4029,7 +4029,9 @@ static int route_dump(u32 *gw_addr , int *gw_index) + struct msghdr msg; + struct iovec iov; + struct sockaddr_nl nladdr; ++#ifdef set_fs + mm_segment_t oldfs; ++#endif + char *pg; + int size = 0; + +@@ -4067,16 +4069,18 @@ static int route_dump(u32 *gw_addr , int *gw_index) + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = MSG_DONTWAIT; +- ++#ifdef set_fs + oldfs = get_fs(); + set_fs(KERNEL_DS); ++#endif + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) + err = sock_sendmsg(sock, &msg); + #else + err = sock_sendmsg(sock, &msg, sizeof(req)); + #endif ++#ifdef set_fs + set_fs(oldfs); +- ++#endif + if (err < 0) + goto out_sock; + +@@ -4099,16 +4103,18 @@ static int route_dump(u32 *gw_addr , int *gw_index) + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) + iov_iter_init(&msg.msg_iter, READ, &iov, 1, PAGE_SIZE); + #endif +- ++#ifdef set_fs + oldfs = get_fs(); + set_fs(KERNEL_DS); ++#endif + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)) + err = sock_recvmsg(sock, &msg, MSG_DONTWAIT); + #else + err = sock_recvmsg(sock, &msg, PAGE_SIZE, MSG_DONTWAIT); + #endif ++#ifdef set_fs + set_fs(oldfs); +- ++#endif + if (err < 0) + goto out_sock_pg; + +@@ -4178,15 +4184,18 @@ static int route_dump(u32 *gw_addr , int *gw_index) + msg.msg_controllen = 0; + msg.msg_flags = MSG_DONTWAIT; + ++#ifdef set_fs + oldfs = get_fs(); + set_fs(KERNEL_DS); ++#endif + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) + err = sock_sendmsg(sock, &msg); + #else + err = sock_sendmsg(sock, &msg, sizeof(req)); + #endif ++#ifdef set_fs + set_fs(oldfs); +- ++#endif + if (err > 0) + goto restart; + } +diff --git a/3rdparty/rtl8812au/os_dep/osdep_service.c b/3rdparty/rtl8812au/os_dep/osdep_service.c +index 7c6d1208..0769b49d 100644 +--- a/3rdparty/rtl8812au/os_dep/osdep_service.c ++++ b/3rdparty/rtl8812au/os_dep/osdep_service.c +@@ -2164,11 +2164,21 @@ static int writeFile(struct file *fp, char *buf, int len) + { + int wlen = 0, sum = 0; + ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) ++ if (!(fp->f_mode & FMODE_CAN_WRITE)) ++#else + if (!fp->f_op || !fp->f_op->write) ++#endif + return -EPERM; + + while (sum < len) { ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)) ++ wlen = kernel_write(fp, buf + sum, len - sum, &fp->f_pos); ++#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) ++ wlen = __vfs_write(fp, buf + sum, len - sum, &fp->f_pos); ++#else + wlen = fp->f_op->write(fp, buf + sum, len - sum, &fp->f_pos); ++#endif + if (wlen > 0) + sum += wlen; + else if (0 != wlen) +@@ -2191,19 +2201,19 @@ static int isFileReadable(const char *path, u32 *sz) + { + struct file *fp; + int ret = 0; ++#ifdef set_fs + mm_segment_t oldfs; ++#endif + char buf; + + fp = filp_open(path, O_RDONLY, 0); + if (IS_ERR(fp)) + ret = PTR_ERR(fp); + else { ++#ifdef set_fs + oldfs = get_fs(); +- #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)) + set_fs(KERNEL_DS); +- #else +- set_fs(get_ds()); +- #endif ++#endif + + if (1 != readFile(fp, &buf, 1)) + ret = PTR_ERR(fp); +@@ -2215,8 +2225,9 @@ static int isFileReadable(const char *path, u32 *sz) + *sz = i_size_read(fp->f_dentry->d_inode); + #endif + } +- ++#ifdef set_fs + set_fs(oldfs); ++#endif + filp_close(fp, NULL); + } + return ret; +@@ -2232,22 +2243,23 @@ static int isFileReadable(const char *path, u32 *sz) + static int retriveFromFile(const char *path, u8 *buf, u32 sz) + { + int ret = -1; ++#ifdef set_fs + mm_segment_t oldfs; ++#endif + struct file *fp; + + if (path && buf) { + ret = openFile(&fp, path, O_RDONLY, 0); + if (0 == ret) { + RTW_INFO("%s openFile path:%s fp=%p\n", __FUNCTION__, path , fp); +- ++#ifdef set_fs + oldfs = get_fs(); +- #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)) + set_fs(KERNEL_DS); +- #else +- set_fs(get_ds()); +- #endif + ret = readFile(fp, buf, sz); + set_fs(oldfs); ++#else ++ ret = readFile(fp, buf, sz); ++#endif + closeFile(fp); + + RTW_INFO("%s readFile, ret:%d\n", __FUNCTION__, ret); +@@ -2271,22 +2283,23 @@ static int retriveFromFile(const char *path, u8 *buf, u32 sz) + static int storeToFile(const char *path, u8 *buf, u32 sz) + { + int ret = 0; ++#ifdef set_fs + mm_segment_t oldfs; ++#endif + struct file *fp; + + if (path && buf) { + ret = openFile(&fp, path, O_CREAT | O_WRONLY, 0666); + if (0 == ret) { + RTW_INFO("%s openFile path:%s fp=%p\n", __FUNCTION__, path , fp); +- ++#ifdef set_fs + oldfs = get_fs(); +- #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)) + set_fs(KERNEL_DS); +- #else +- set_fs(get_ds()); +- #endif + ret = writeFile(fp, buf, sz); + set_fs(oldfs); ++#else ++ ret = writeFile(fp, buf, sz); ++#endif + closeFile(fp); + + RTW_INFO("%s writeFile, ret:%d\n", __FUNCTION__, ret); diff --git a/kernel/tools/cpupowertools/files/patches/mageia/fs-aufs5.10-symbol-exports.patch b/kernel/tools/cpupowertools/files/patches/mageia/fs-aufs5.10-symbol-exports.patch new file mode 100644 index 00000000..49e6ec39 --- /dev/null +++ b/kernel/tools/cpupowertools/files/patches/mageia/fs-aufs5.10-symbol-exports.patch @@ -0,0 +1,284 @@ +SPDX-License-Identifier: GPL-2.0 +aufs5.x-rcN standalone patch + +diff --git a/fs/dcache.c b/fs/dcache.c +index ddca6240e0db4..30dec552278dc 100644 +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -1390,6 +1390,7 @@ void d_walk(struct dentry *parent, void *data, + seq = 1; + goto again; + } ++EXPORT_SYMBOL_GPL(d_walk); + + struct check_mount { + struct vfsmount *mnt; +@@ -2935,6 +2936,7 @@ void d_exchange(struct dentry *dentry1, struct dentry *dentry2) + + write_sequnlock(&rename_lock); + } ++EXPORT_SYMBOL_GPL(d_exchange); + + /** + * d_ancestor - search for an ancestor +diff --git a/fs/exec.c b/fs/exec.c +index 547a2390baf54..18d51d0face68 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -113,6 +113,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 --git a/fs/fcntl.c b/fs/fcntl.c +index 073ca6af500f3..b18afdf81e762 100644 +--- a/fs/fcntl.c ++++ b/fs/fcntl.c +@@ -85,6 +85,7 @@ int setfl(int fd, struct file *filp, unsigned long arg) + out: + return error; + } ++EXPORT_SYMBOL_GPL(setfl); + + static void f_modown(struct file *filp, struct pid *pid, enum pid_type type, + int force) +diff --git a/fs/file_table.c b/fs/file_table.c +index 709ada3151da5..27a3e3c9f2a82 100644 +--- a/fs/file_table.c ++++ b/fs/file_table.c +@@ -162,6 +162,7 @@ struct file *alloc_empty_file(int flags, const struct cred *cred) + } + return ERR_PTR(-ENFILE); + } ++EXPORT_SYMBOL_GPL(alloc_empty_file); + + /* + * Variant of alloc_empty_file() that doesn't check and modify nr_files. +@@ -376,6 +377,7 @@ void __fput_sync(struct file *file) + } + + EXPORT_SYMBOL(fput); ++EXPORT_SYMBOL_GPL(__fput_sync); + + void __init files_init(void) + { +diff --git a/fs/inode.c b/fs/inode.c +index e7f0c614a58f3..6fe0a92a4c93c 100644 +--- a/fs/inode.c ++++ b/fs/inode.c +@@ -1776,6 +1776,7 @@ int update_time(struct inode *inode, struct timespec64 *time, int flags) + return inode->i_op->update_time(inode, time, flags); + return generic_update_time(inode, time, flags); + } ++EXPORT_SYMBOL_GPL(update_time); + + /** + * touch_atime - update the access time +diff --git a/fs/namespace.c b/fs/namespace.c +index 451dee24a546a..38078cbede431 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -431,6 +431,7 @@ void __mnt_drop_write(struct vfsmount *mnt) + mnt_dec_writers(real_mount(mnt)); + preempt_enable(); + } ++EXPORT_SYMBOL_GPL(__mnt_drop_write); + + /** + * mnt_drop_write - give up write access to a mount +@@ -797,6 +798,7 @@ int is_current_mnt_ns(struct vfsmount *mnt) + { + return check_mnt(real_mount(mnt)); + } ++EXPORT_SYMBOL_GPL(is_current_mnt_ns); + + /* + * vfsmount lock must be held for write +@@ -1961,6 +1963,7 @@ int iterate_mounts(int (*f)(struct vfsmount *, void *), void *arg, + } + return 0; + } ++EXPORT_SYMBOL_GPL(iterate_mounts); + + static void lock_mnt_tree(struct mount *mnt) + { +diff --git a/fs/notify/group.c b/fs/notify/group.c +index a4a4b1c64d32a..86dc2efb1850c 100644 +--- a/fs/notify/group.c ++++ b/fs/notify/group.c +@@ -100,6 +100,7 @@ void fsnotify_get_group(struct fsnotify_group *group) + { + refcount_inc(&group->refcnt); + } ++EXPORT_SYMBOL_GPL(fsnotify_get_group); + + /* + * Drop a reference to a group. Free it if it's through. +diff --git a/fs/open.c b/fs/open.c +index 9af548fb841b0..2ff09b709f7bf 100644 +--- a/fs/open.c ++++ b/fs/open.c +@@ -65,6 +65,7 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, + inode_unlock(dentry->d_inode); + return ret; + } ++EXPORT_SYMBOL_GPL(do_truncate); + + long vfs_truncate(const struct path *path, loff_t length) + { +diff --git a/fs/read_write.c b/fs/read_write.c +index 75f764b434184..7582bb3fb634b 100644 +--- a/fs/read_write.c ++++ b/fs/read_write.c +@@ -503,6 +503,7 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) + inc_syscr(current); + 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) + { +@@ -613,6 +614,7 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_ + file_end_write(file); + return ret; + } ++EXPORT_SYMBOL_GPL(vfs_write); + + /* file_ppos returns &file->f_pos or NULL if file is stream */ + static inline loff_t *file_ppos(struct file *file) +diff --git a/fs/splice.c b/fs/splice.c +index 55b5356262085..c13ac0fbac318 100644 +--- a/fs/splice.c ++++ b/fs/splice.c +@@ -763,6 +763,7 @@ long do_splice_from(struct pipe_inode_info *pipe, struct file *out, + return warn_unsupported(out, "write"); + return out->f_op->splice_write(pipe, out, ppos, len, flags); + } ++EXPORT_SYMBOL_GPL(do_splice_from); + + /* + * Attempt to initiate a splice from a file to a pipe. +@@ -787,6 +788,7 @@ long do_splice_to(struct file *in, loff_t *ppos, + return warn_unsupported(in, "read"); + return in->f_op->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 --git a/fs/sync.c b/fs/sync.c +index b7b5a0a0df6ff..fa5c7fba7f1ba 100644 +--- a/fs/sync.c ++++ b/fs/sync.c +@@ -39,6 +39,7 @@ int __sync_filesystem(struct super_block *sb, int wait) + 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 --git a/fs/xattr.c b/fs/xattr.c +index cd7a563e8bcd4..7d989d57b0f0d 100644 +--- a/fs/xattr.c ++++ b/fs/xattr.c +@@ -360,6 +360,7 @@ vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value, + *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 --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c +index 7f006a47790cf..be002c3a30833 100644 +--- a/kernel/locking/lockdep.c ++++ b/kernel/locking/lockdep.c +@@ -209,6 +209,7 @@ inline struct lock_class *lockdep_hlock_class(struct held_lock *hlock) + */ + return lock_classes + class_idx; + } ++EXPORT_SYMBOL_GPL(lockdep_hlock_class); + #define hlock_class(hlock) lockdep_hlock_class(hlock) + + #ifdef CONFIG_LOCK_STAT +diff --git a/kernel/task_work.c b/kernel/task_work.c +index 8d6e1217c451c..0e73637adda86 100644 +--- a/kernel/task_work.c ++++ b/kernel/task_work.c +@@ -154,3 +154,4 @@ void task_work_run(void) + } while (work); + } + } ++EXPORT_SYMBOL_GPL(task_work_run); +diff --git a/security/security.c b/security/security.c +index a28045dc9e7f6..310cf38efeec7 100644 +--- a/security/security.c ++++ b/security/security.c +@@ -1093,6 +1093,7 @@ int security_path_rmdir(const struct path *dir, struct dentry *dentry) + 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) + { +@@ -1109,6 +1110,7 @@ int security_path_symlink(const struct path *dir, struct dentry *dentry, + 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) +@@ -1117,6 +1119,7 @@ int security_path_link(struct dentry *old_dentry, const struct path *new_dir, + 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, +@@ -1144,6 +1147,7 @@ int security_path_truncate(const struct path *path) + 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) + { +@@ -1151,6 +1155,7 @@ int security_path_chmod(const struct path *path, umode_t mode) + 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) + { +@@ -1158,6 +1163,7 @@ int security_path_chown(const struct path *path, kuid_t uid, kgid_t gid) + 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) + { +@@ -1258,6 +1264,7 @@ int security_inode_permission(struct inode *inode, int mask) + 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) + { +@@ -1450,6 +1457,7 @@ int security_file_permission(struct file *file, int mask) + + return fsnotify_perm(file, mask); + } ++EXPORT_SYMBOL_GPL(security_file_permission); + + int security_file_alloc(struct file *file) + { diff --git a/kernel/tools/cpupowertools/files/patches/mageia/fs-aufs5.10-tristate.patch b/kernel/tools/cpupowertools/files/patches/mageia/fs-aufs5.10-tristate.patch new file mode 100644 index 00000000..f95f4ab6 --- /dev/null +++ b/kernel/tools/cpupowertools/files/patches/mageia/fs-aufs5.10-tristate.patch @@ -0,0 +1,24 @@ + +Allow aufs to be built as module. + +Signed-off-by: Thomas Backlund + +--- a/fs/aufs/Kconfig ++++ b/fs/aufs/Kconfig +@@ -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 +@@ -72,7 +72,7 @@ endchoice + + config AUFS_EXPORT + bool "NFS-exportable aufs" +- depends on EXPORTFS = y ++ depends on EXPORTFS + help + If you want to export your mounted aufs via NFS, then enable this + option. There are several requirements for this configuration. diff --git a/kernel/tools/cpupowertools/files/patches/mageia/fs-aufs5.10.patch b/kernel/tools/cpupowertools/files/patches/mageia/fs-aufs5.10.patch new file mode 100644 index 00000000..34eab23c --- /dev/null +++ b/kernel/tools/cpupowertools/files/patches/mageia/fs-aufs5.10.patch @@ -0,0 +1,37866 @@ + Documentation/ABI/testing/debugfs-aufs | 55 + + Documentation/ABI/testing/sysfs-aufs | 31 + + Documentation/filesystems/aufs/README | 401 ++++ + 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 | 39 + + fs/aufs/aufs.h | 49 + + fs/aufs/branch.c | 1414 +++++++++++++++ + fs/aufs/branch.h | 351 ++++ + fs/aufs/cpup.c | 1432 +++++++++++++++ + fs/aufs/cpup.h | 87 + + fs/aufs/dbgaufs.c | 513 ++++++ + fs/aufs/dbgaufs.h | 40 + + fs/aufs/dcsub.c | 212 +++ + fs/aufs/dcsub.h | 124 ++ + fs/aufs/debug.c | 428 +++++ + fs/aufs/debug.h | 213 +++ + fs/aufs/dentry.c | 1141 ++++++++++++ + fs/aufs/dentry.h | 255 +++ + fs/aufs/dinfo.c | 541 ++++++ + fs/aufs/dir.c | 750 ++++++++ + fs/aufs/dir.h | 121 ++ + fs/aufs/dirren.c | 1303 +++++++++++++ + fs/aufs/dirren.h | 127 ++ + fs/aufs/dynop.c | 355 ++++ + fs/aufs/dynop.h | 64 + + fs/aufs/export.c | 824 +++++++++ + fs/aufs/f_op.c | 749 ++++++++ + fs/aufs/fhsm.c | 413 +++++ + fs/aufs/file.c | 850 +++++++++ + fs/aufs/file.h | 329 ++++ + fs/aufs/finfo.c | 136 ++ + fs/aufs/fstype.h | 388 ++++ + fs/aufs/hbl.h | 52 + + fs/aufs/hfsnotify.c | 275 +++ + fs/aufs/hfsplus.c | 47 + + fs/aufs/hnotify.c | 702 +++++++ + fs/aufs/i_op.c | 1489 +++++++++++++++ + fs/aufs/i_op_add.c | 923 ++++++++++ + fs/aufs/i_op_del.c | 500 +++++ + fs/aufs/i_op_ren.c | 1237 +++++++++++++ + fs/aufs/iinfo.c | 273 +++ + fs/aufs/inode.c | 516 ++++++ + fs/aufs/inode.h | 685 +++++++ + fs/aufs/ioctl.c | 207 +++ + fs/aufs/lcnt.h | 173 ++ + fs/aufs/loop.c | 135 ++ + fs/aufs/loop.h | 42 + + fs/aufs/magic.mk | 31 + + fs/aufs/module.c | 259 +++ + fs/aufs/module.h | 153 ++ + fs/aufs/mvdown.c | 693 +++++++ + fs/aufs/opts.c | 1867 +++++++++++++++++++ + fs/aufs/opts.h | 212 +++ + fs/aufs/plink.c | 503 +++++ + fs/aufs/poll.c | 38 + + fs/aufs/posix_acl.c | 92 + + fs/aufs/procfs.c | 157 ++ + fs/aufs/rdu.c | 371 ++++ + fs/aufs/rwsem.h | 60 + + fs/aufs/sbinfo.c | 301 +++ + fs/aufs/super.c | 1034 +++++++++++ + fs/aufs/super.h | 574 ++++++ + fs/aufs/sysaufs.c | 80 + + fs/aufs/sysaufs.h | 89 + + fs/aufs/sysfs.c | 338 ++++ + fs/aufs/sysrq.c | 136 ++ + fs/aufs/vdir.c | 883 +++++++++ + fs/aufs/vfsub.c | 872 +++++++++ + fs/aufs/vfsub.h | 341 ++++ + fs/aufs/wbr_policy.c | 817 +++++++++ + fs/aufs/whout.c | 1049 +++++++++++ + fs/aufs/whout.h | 73 + + fs/aufs/wkq.c | 359 ++++ + fs/aufs/wkq.h | 76 + + fs/aufs/xattr.c | 343 ++++ + fs/aufs/xino.c | 1912 ++++++++++++++++++++ + 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/splice.c | 10 +- + fs/sync.c | 2 +- + include/linux/fs.h | 4 + + include/linux/lockdep.h | 3 + + include/linux/mm.h | 22 + + include/linux/mm_types.h | 2 + + include/linux/mnt_namespace.h | 3 + + include/linux/splice.h | 6 + + include/uapi/linux/aufs_type.h | 439 +++++ + kernel/fork.c | 2 +- + kernel/locking/lockdep.c | 3 +- + mm/Makefile | 2 +- + mm/filemap.c | 2 +- + mm/mmap.c | 33 +- + mm/nommu.c | 10 +- + mm/prfile.c | 86 + + 118 files changed, 36737 insertions(+), 31 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..3e655d357134 +--- /dev/null ++++ b/Documentation/filesystems/aufs/README +@@ -0,0 +1,401 @@ ++ ++Aufs5 -- advanced multi layered unification filesystem version 5.x ++http://aufs.sf.net ++Junjiro R. Okajima ++ ++ ++0. Introduction ++---------------------------------------- ++In the early days, aufs was entirely re-designed and re-implemented ++Unionfs Version 1.x series. Adding many original ideas, approaches, ++improvements and implementations, it became totally different from ++Unionfs while keeping the basic features. ++Later, Unionfs Version 2.x series began taking some of the same ++approaches to aufs1's. ++Unionfs was being developed by Professor Erez Zadok at Stony Brook ++University and his team. ++ ++Aufs5 supports linux-v5.0 and later, If you want older kernel version ++support, ++- for linux-v4.x series, try aufs4-linux.git or aufs4-standalone.git ++- for linux-v3.x series, try aufs3-linux.git or aufs3-standalone.git ++- for linux-v2.6.16 and later, try aufs2-2.6.git, aufs2-standalone.git ++ or aufs1 from CVS on SourceForge. ++ ++Note: it becomes clear that "Aufs was rejected. Let's give it up." ++ According to Christoph Hellwig, linux rejects all union-type ++ filesystems but UnionMount. ++ ++ ++PS. Al Viro seems have a plan to merge aufs as well as overlayfs and ++ UnionMount, and he pointed out an issue around a directory mutex ++ lock and aufs addressed it. But it is still unsure whether aufs will ++ be merged (or any other union solution). ++ ++ ++ ++1. Features ++---------------------------------------- ++- unite several directories into a single virtual filesystem. The member ++ directory is called as a branch. ++- you can specify the permission flags to the branch, which are 'readonly', ++ 'readwrite' and 'whiteout-able.' ++- by upper writable branch, internal copyup and whiteout, files/dirs on ++ readonly branch are modifiable logically. ++- dynamic branch manipulation, add, del. ++- etc... ++ ++Also there are many enhancements in aufs, such as: ++- test only the highest one for the directory permission (dirperm1) ++- copyup on open (coo=) ++- 'move' policy for copy-up between two writable branches, after ++ checking free space. ++- xattr, acl ++- readdir(3) in userspace. ++- keep inode number by external inode number table ++- keep the timestamps of file/dir in internal copyup operation ++- seekable directory, supporting NFS readdir. ++- whiteout is hardlinked in order to reduce the consumption of inodes ++ on branch ++- do not copyup, nor create a whiteout when it is unnecessary ++- revert a single systemcall when an error occurs in aufs ++- remount interface instead of ioctl ++- maintain /etc/mtab by an external command, /sbin/mount.aufs. ++- loopback mounted filesystem as a branch ++- kernel thread for removing the dir who has a plenty of whiteouts ++- support copyup sparse file (a file which has a 'hole' in it) ++- default permission flags for branches ++- selectable permission flags for ro branch, whether whiteout can ++ exist or not ++- export via NFS. ++- support /fs/aufs and /aufs. ++- support multiple writable branches, some policies to select one ++ among multiple writable branches. ++- a new semantics for link(2) and rename(2) to support multiple ++ writable branches. ++- no glibc changes are required. ++- pseudo hardlink (hardlink over branches) ++- allow a direct access manually to a file on branch, e.g. bypassing aufs. ++ including NFS or remote filesystem branch. ++- userspace wrapper for pathconf(3)/fpathconf(3) with _PC_LINK_MAX. ++- and more... ++ ++Currently these features are dropped temporary from aufs5. ++See design/08plan.txt in detail. ++- nested mount, i.e. aufs as readonly no-whiteout branch of another aufs ++ (robr) ++- statistics of aufs thread (/sys/fs/aufs/stat) ++ ++Features or just an idea in the future (see also design/*.txt), ++- reorder the branch index without del/re-add. ++- permanent xino files for NFSD ++- an option for refreshing the opened files after add/del branches ++- light version, without branch manipulation. (unnecessary?) ++- copyup in userspace ++- inotify in userspace ++- readv/writev ++ ++ ++2. Download ++---------------------------------------- ++There are three GIT trees for aufs5, aufs5-linux.git, ++aufs5-standalone.git, and aufs-util.git. Note that there is no "5" in ++"aufs-util.git." ++While the aufs-util is always necessary, you need either of aufs5-linux ++or aufs5-standalone. ++ ++The aufs5-linux tree includes the whole linux mainline GIT tree, ++git://git.kernel.org/.../torvalds/linux.git. ++And you cannot select CONFIG_AUFS_FS=m for this version, eg. you cannot ++build aufs5 as an external kernel module. ++Several extra patches are not included in this tree. Only ++aufs5-standalone tree contains them. They are described in the later ++section "Configuration and Compilation." ++ ++On the other hand, the aufs5-standalone tree has only aufs source files ++and necessary patches, and you can select CONFIG_AUFS_FS=m. ++But you need to apply all aufs patches manually. ++ ++You will find GIT branches whose name is in form of "aufs5.x" where "x" ++represents the linux kernel version, "linux-5.x". For instance, ++"aufs5.0" is for linux-5.0. For latest "linux-5.x-rcN", use ++"aufs5.x-rcN" branch. ++ ++o aufs5-linux tree ++$ git clone --reference /your/linux/git/tree \ ++ git://github.com/sfjro/aufs5-linux.git aufs5-linux.git ++- if you don't have linux GIT tree, then remove "--reference ..." ++$ cd aufs5-linux.git ++$ git checkout origin/aufs5.0 ++ ++Or You may want to directly git-pull aufs into your linux GIT tree, and ++leave the patch-work to GIT. ++$ cd /your/linux/git/tree ++$ git remote add aufs5 git://github.com/sfjro/aufs5-linux.git ++$ git fetch aufs5 ++$ git checkout -b my5.0 v5.0 ++$ (add your local change...) ++$ git pull aufs5 aufs5.0 ++- now you have v5.0 + your_changes + aufs5.0 in you my5.0 branch. ++- you may need to solve some conflicts between your_changes and ++ aufs5.0. in this case, git-rerere is recommended so that you can ++ solve the similar conflicts automatically when you upgrade to 5.1 or ++ later in the future. ++ ++o aufs5-standalone tree ++$ git clone git://github.com/sfjro/aufs5-standalone.git aufs5-standalone.git ++$ cd aufs5-standalone.git ++$ git checkout origin/aufs5.0 ++ ++o aufs-util tree ++$ git clone git://git.code.sf.net/p/aufs/aufs-util aufs-util.git ++- note that the public aufs-util.git is on SourceForge instead of ++ GitHUB. ++$ cd aufs-util.git ++$ git checkout origin/aufs5.0 ++ ++Note: The 5.x-rcN branch is to be used with `rc' kernel versions ONLY. ++The minor version number, 'x' in '5.x', of aufs may not always ++follow the minor version number of the kernel. ++Because changes in the kernel that cause the use of a new ++minor version number do not always require changes to aufs-util. ++ ++Since aufs-util has its own minor version number, you may not be ++able to find a GIT branch in aufs-util for your kernel's ++exact minor version number. ++In this case, you should git-checkout the branch for the ++nearest lower number. ++ ++For (an unreleased) example: ++If you are using "linux-5.10" and the "aufs5.10" branch ++does not exist in aufs-util repository, then "aufs5.9", "aufs5.8" ++or something numerically smaller is the branch for your kernel. ++ ++Also you can view all branches by ++ $ git branch -a ++ ++ ++3. Configuration and Compilation ++---------------------------------------- ++Make sure you have git-checkout'ed the correct branch. ++ ++For aufs5-linux tree, ++- enable CONFIG_AUFS_FS. ++- set other aufs configurations if necessary. ++ ++For aufs5-standalone tree, ++There are several ways to build. ++ ++1. ++- apply ./aufs5-kbuild.patch to your kernel source files. ++- apply ./aufs5-base.patch too. ++- apply ./aufs5-mmap.patch too. ++- apply ./aufs5-standalone.patch too, if you have a plan to set ++ CONFIG_AUFS_FS=m. otherwise you don't need ./aufs5-standalone.patch. ++- copy ./{Documentation,fs,include/uapi/linux/aufs_type.h} files to your ++ kernel source tree. Never copy $PWD/include/uapi/linux/Kbuild. ++- enable CONFIG_AUFS_FS, you can select either ++ =m or =y. ++- and build your kernel as usual. ++- install the built kernel. ++- install the header files too by "make headers_install" to the ++ directory where you specify. By default, it is $PWD/usr. ++ "make help" shows a brief note for headers_install. ++- and reboot your system. ++ ++2. ++- module only (CONFIG_AUFS_FS=m). ++- apply ./aufs5-base.patch to your kernel source files. ++- apply ./aufs5-mmap.patch too. ++- apply ./aufs5-standalone.patch too. ++- build your kernel, don't forget "make headers_install", and reboot. ++- edit ./config.mk and set other aufs configurations if necessary. ++ Note: You should read $PWD/fs/aufs/Kconfig carefully which describes ++ every aufs configurations. ++- build the module by simple "make". ++- you can specify ${KDIR} make variable which points to your kernel ++ source tree. ++- install the files ++ + run "make install" to install the aufs module, or copy the built ++ $PWD/aufs.ko to /lib/modules/... and run depmod -a (or reboot simply). ++ + run "make install_headers" (instead of headers_install) to install ++ the modified aufs header file (you can specify DESTDIR which is ++ available in aufs standalone version's Makefile only), or copy ++ $PWD/usr/include/linux/aufs_type.h to /usr/include/linux or wherever ++ you like manually. By default, the target directory is $PWD/usr. ++- no need to apply aufs5-kbuild.patch, nor copying source files to your ++ kernel source tree. ++ ++Note: The header file aufs_type.h is necessary to build aufs-util ++ as well as "make headers_install" in the kernel source tree. ++ headers_install is subject to be forgotten, but it is essentially ++ necessary, not only for building aufs-util. ++ You may not meet problems without headers_install in some older ++ version though. ++ ++And then, ++- read README in aufs-util, build and install it ++- note that your distribution may contain an obsoleted version of ++ aufs_type.h in /usr/include/linux or something. When you build aufs ++ utilities, make sure that your compiler refers the correct aufs header ++ file which is built by "make headers_install." ++- if you want to use readdir(3) in userspace or pathconf(3) wrapper, ++ then run "make install_ulib" too. And refer to the aufs manual in ++ detail. ++ ++There several other patches in aufs5-standalone.git. They are all ++optional. When you meet some problems, they will help you. ++- aufs5-loopback.patch ++ Supports a nested loopback mount in a branch-fs. This patch is ++ unnecessary until aufs produces a message like "you may want to try ++ another patch for loopback file". ++- proc_mounts.patch ++ When there are many mountpoints and many mount(2)/umount(2) are ++ running, then /proc/mounts may not show the all mountpoints. This ++ patch makes /proc/mounts always show the full mountpoints list. ++ If you don't want to apply this patch and meet such problem, then you ++ need to increase the value of 'ProcMounts_Times' make-variable in ++ aufs-util.git as a second best solution. ++- vfs-ino.patch ++ Modifies a system global kernel internal function get_next_ino() in ++ order to stop assigning 0 for an inode-number. Not directly related to ++ aufs, but recommended generally. ++- tmpfs-idr.patch ++ Keeps the tmpfs inode number as the lowest value. Effective to reduce ++ the size of aufs XINO files for tmpfs branch. Also it prevents the ++ duplication of inode number, which is important for backup tools and ++ other utilities. When you find aufs XINO files for tmpfs branch ++ growing too much, try this patch. ++- lockdep-debug.patch ++ Because aufs is not only an ordinary filesystem (callee of VFS), but ++ also a caller of VFS functions for branch filesystems, subclassing of ++ the internal locks for LOCKDEP is necessary. LOCKDEP is a debugging ++ feature of linux kernel. If you enable CONFIG_LOCKDEP, then you will ++ need to apply this debug patch to expand several constant values. ++ If you don't know what LOCKDEP is, then you don't have apply this ++ patch. ++ ++ ++4. Usage ++---------------------------------------- ++At first, make sure aufs-util are installed, and please read the aufs ++manual, aufs.5 in aufs-util.git tree. ++$ man -l aufs.5 ++ ++And then, ++$ mkdir /tmp/rw /tmp/aufs ++# mount -t aufs -o br=/tmp/rw:${HOME} none /tmp/aufs ++ ++Here is another example. The result is equivalent. ++# mount -t aufs -o br=/tmp/rw=rw:${HOME}=ro none /tmp/aufs ++ Or ++# mount -t aufs -o br:/tmp/rw none /tmp/aufs ++# mount -o remount,append:${HOME} /tmp/aufs ++ ++Then, you can see whole tree of your home dir through /tmp/aufs. If ++you modify a file under /tmp/aufs, the one on your home directory is ++not affected, instead the same named file will be newly created under ++/tmp/rw. And all of your modification to a file will be applied to ++the one under /tmp/rw. This is called the file based Copy on Write ++(COW) method. ++Aufs mount options are described in aufs.5. ++If you run chroot or something and make your aufs as a root directory, ++then you need to customize the shutdown script. See the aufs manual in ++detail. ++ ++Additionally, there are some sample usages of aufs which are a ++diskless system with network booting, and LiveCD over NFS. ++See sample dir in CVS tree on SourceForge. ++ ++ ++5. Contact ++---------------------------------------- ++When you have any problems or strange behaviour in aufs, please let me ++know with: ++- /proc/mounts (instead of the output of mount(8)) ++- /sys/module/aufs/* ++- /sys/fs/aufs/* (if you have them) ++- /debug/aufs/* (if you have them) ++- linux kernel version ++ if your kernel is not plain, for example modified by distributor, ++ the url where i can download its source is necessary too. ++- aufs version which was printed at loading the module or booting the ++ system, instead of the date you downloaded. ++- configuration (define/undefine CONFIG_AUFS_xxx) ++- kernel configuration or /proc/config.gz (if you have it) ++- LSM (linux security module, if you are using) ++- behaviour which you think to be incorrect ++- actual operation, reproducible one is better ++- mailto: aufs-users at lists.sourceforge.net ++ ++Usually, I don't watch the Public Areas(Bugs, Support Requests, Patches, ++and Feature Requests) on SourceForge. Please join and write to ++aufs-users ML. ++ ++ ++6. Acknowledgements ++---------------------------------------- ++Thanks to everyone who have tried and are using aufs, whoever ++have reported a bug or any feedback. ++ ++Especially donators: ++Tomas Matejicek(slax.org) made a donation (much more than once). ++ Since Apr 2010, Tomas M (the author of Slax and Linux Live ++ scripts) is making "doubling" donations. ++ Unfortunately I cannot list all of the donators, but I really ++ appreciate. ++ It ends Aug 2010, but the ordinary donation URL is still available. ++ ++Dai Itasaka made a donation (2007/8). ++Chuck Smith made a donation (2008/4, 10 and 12). ++Henk Schoneveld made a donation (2008/9). ++Chih-Wei Huang, ASUS, CTC donated Eee PC 4G (2008/10). ++Francois Dupoux made a donation (2008/11). ++Bruno Cesar Ribas and Luis Carlos Erpen de Bona, C3SL serves public ++ aufs2 GIT tree (2009/2). ++William Grant made a donation (2009/3). ++Patrick Lane made a donation (2009/4). ++The Mail Archive (mail-archive.com) made donations (2009/5). ++Nippy Networks (Ed Wildgoose) made a donation (2009/7). ++New Dream Network, LLC (www.dreamhost.com) made a donation (2009/11). ++Pavel Pronskiy made a donation (2011/2). ++Iridium and Inmarsat satellite phone retailer (www.mailasail.com), Nippy ++ Networks (Ed Wildgoose) made a donation for hardware (2011/3). ++Max Lekomcev (DOM-TV project) made a donation (2011/7, 12, 2012/3, 6 and ++11). ++Sam Liddicott made a donation (2011/9). ++Era Scarecrow made a donation (2013/4). ++Bor Ratajc made a donation (2013/4). ++Alessandro Gorreta made a donation (2013/4). ++POIRETTE Marc made a donation (2013/4). ++Alessandro Gorreta made a donation (2013/4). ++lauri kasvandik made a donation (2013/5). ++"pemasu from Finland" made a donation (2013/7). ++The Parted Magic Project made a donation (2013/9 and 11). ++Pavel Barta made a donation (2013/10). ++Nikolay Pertsev made a donation (2014/5). ++James B made a donation (2014/7 and 2015/7). ++Stefano Di Biase made a donation (2014/8). ++Daniel Epellei made a donation (2015/1). ++OmegaPhil made a donation (2016/1, 2018/4). ++Tomasz Szewczyk made a donation (2016/4). ++James Burry made a donation (2016/12). ++Carsten Rose made a donation (2018/9). ++Porteus Kiosk made a donation (2018/10). ++ ++Thank you very much. ++Donations are always, including future donations, very important and ++helpful for me to keep on developing aufs. ++ ++ ++7. ++---------------------------------------- ++If you are an experienced user, no explanation is needed. Aufs is ++just a linux filesystem. ++ ++ ++Enjoy! ++ ++# Local variables: ; ++# mode: text; ++# End: ; +diff --git a/Documentation/filesystems/aufs/design/01intro.txt b/Documentation/filesystems/aufs/design/01intro.txt +new file mode 100644 +index 000000000000..7f75ee4a784c +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/01intro.txt +@@ -0,0 +1,158 @@ ++ ++# Copyright (C) 2005-2020 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..0a948e812796 +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/02struct.txt +@@ -0,0 +1,245 @@ ++ ++# Copyright (C) 2005-2020 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..415205649c4c +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/03atomic_open.txt +@@ -0,0 +1,72 @@ ++ ++# Copyright (C) 2015-2020 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..0b3b22bc999f +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/03lookup.txt +@@ -0,0 +1,100 @@ ++ ++# Copyright (C) 2005-2020 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..0e7bc1075f37 +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/04branch.txt +@@ -0,0 +1,61 @@ ++ ++# Copyright (C) 2005-2020 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..f9741c32cbf2 +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/05wbr_policy.txt +@@ -0,0 +1,51 @@ ++ ++# Copyright (C) 2005-2020 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..e23459758504 +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/06dirren.txt +@@ -0,0 +1,89 @@ ++ ++# Copyright (C) 2017-2020 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..5322ca3b7151 +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/06fhsm.txt +@@ -0,0 +1,105 @@ ++ ++# Copyright (C) 2011-2020 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..03b71096d508 +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/06mmap.txt +@@ -0,0 +1,59 @@ ++ ++# Copyright (C) 2005-2020 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..f4076a04a335 +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/06xattr.txt +@@ -0,0 +1,81 @@ ++ ++# Copyright (C) 2014-2020 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..fcd3a3489bf8 +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/07export.txt +@@ -0,0 +1,45 @@ ++ ++# Copyright (C) 2005-2020 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..f252e17154b1 +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/08shwh.txt +@@ -0,0 +1,39 @@ ++ ++# Copyright (C) 2005-2020 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..2b90eecb267d +--- /dev/null ++++ b/Documentation/filesystems/aufs/design/10dynop.txt +@@ -0,0 +1,34 @@ ++ ++# Copyright (C) 2010-2020 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 281de213ef47..ffc3c1c539ea 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -3009,6 +3009,19 @@ F: include/linux/audit.h + F: include/uapi/linux/audit.h + F: kernel/audit* + ++AUFS (advanced multi layered unification filesystem) FILESYSTEM ++M: "J. R. Okajima" ++L: aufs-users@lists.sourceforge.net (members only) ++L: linux-unionfs@vger.kernel.org ++S: Supported ++W: http://aufs.sourceforge.net ++T: git://github.com/sfjro/aufs4-linux.git ++F: Documentation/ABI/testing/debugfs-aufs ++F: Documentation/ABI/testing/sysfs-aufs ++F: Documentation/filesystems/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 a58084c2ed7c..7be7ca3f5454 100644 +--- a/drivers/block/loop.c ++++ b/drivers/block/loop.c +@@ -765,6 +765,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 aa4c12282301..b29bad13b249 100644 +--- a/fs/Kconfig ++++ b/fs/Kconfig +@@ -288,6 +288,7 @@ source "fs/sysv/Kconfig" + source "fs/ufs/Kconfig" + source "fs/erofs/Kconfig" + source "fs/vboxsf/Kconfig" ++source "fs/aufs/Kconfig" + + endif # MISC_FILESYSTEMS + +diff --git a/fs/Makefile b/fs/Makefile +index 999d1a23f036..0cd76857ca76 100644 +--- a/fs/Makefile ++++ b/fs/Makefile +@@ -136,3 +136,4 @@ obj-$(CONFIG_EFIVAR_FS) += efivarfs/ + obj-$(CONFIG_EROFS_FS) += erofs/ + obj-$(CONFIG_VBOXSF_FS) += vboxsf/ + obj-$(CONFIG_ZONEFS_FS) += zonefs/ ++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..9de70de0f337 +--- /dev/null ++++ b/fs/aufs/Makefile +@@ -0,0 +1,39 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++include ${srctree}/${src}/magic.mk ++-include ${srctree}/${src}/priv_def.mk ++ ++# cf. include/linux/kernel.h ++# enable pr_debug ++ccflags-y += -DDEBUG ++# sparse requires the full pathname ++ccflags-y += -include ${srctree}/include/uapi/linux/aufs_type.h ++ ++obj-$(CONFIG_AUFS_FS) += aufs.o ++aufs-y := module.o sbinfo.o super.o branch.o xino.o sysaufs.o opts.o \ ++ wkq.o vfsub.o dcsub.o \ ++ cpup.o whout.o wbr_policy.o \ ++ dinfo.o dentry.o \ ++ dynop.o \ ++ finfo.o file.o f_op.o \ ++ dir.o vdir.o \ ++ iinfo.o inode.o i_op.o i_op_add.o i_op_del.o i_op_ren.o \ ++ mvdown.o ioctl.o ++ ++# all are boolean ++aufs-$(CONFIG_PROC_FS) += procfs.o plink.o ++aufs-$(CONFIG_SYSFS) += sysfs.o ++aufs-$(CONFIG_DEBUG_FS) += dbgaufs.o ++aufs-$(CONFIG_AUFS_BDEV_LOOP) += loop.o ++aufs-$(CONFIG_AUFS_HNOTIFY) += hnotify.o ++aufs-$(CONFIG_AUFS_HFSNOTIFY) += hfsnotify.o ++aufs-$(CONFIG_AUFS_EXPORT) += export.o ++aufs-$(CONFIG_AUFS_XATTR) += xattr.o ++aufs-$(CONFIG_FS_POSIX_ACL) += posix_acl.o ++aufs-$(CONFIG_AUFS_DIRREN) += dirren.o ++aufs-$(CONFIG_AUFS_FHSM) += fhsm.o ++aufs-$(CONFIG_AUFS_POLL) += poll.o ++aufs-$(CONFIG_AUFS_RDU) += rdu.o ++aufs-$(CONFIG_AUFS_BR_HFSPLUS) += hfsplus.o ++aufs-$(CONFIG_AUFS_DEBUG) += debug.o ++aufs-$(CONFIG_AUFS_MAGIC_SYSRQ) += sysrq.o +diff --git a/fs/aufs/aufs.h b/fs/aufs/aufs.h +new file mode 100644 +index 000000000000..c50f959844e8 +--- /dev/null ++++ b/fs/aufs/aufs.h +@@ -0,0 +1,49 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2020 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..3319245c0361 +--- /dev/null ++++ b/fs/aufs/branch.c +@@ -0,0 +1,1414 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * branch management ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++/* ++ * free a single branch ++ */ ++static void au_br_do_free(struct au_branch *br) ++{ ++ int i; ++ struct au_wbr *wbr; ++ struct au_dykey **key; ++ ++ au_hnotify_fin_br(br); ++ /* always, regardless the mount option */ ++ au_dr_hino_free(&br->br_dirren); ++ au_xino_put(br); ++ ++ AuLCntZero(au_lcnt_read(&br->br_nfiles, /*do_rev*/0)); ++ au_lcnt_fin(&br->br_nfiles, /*do_sync*/0); ++ AuLCntZero(au_lcnt_read(&br->br_count, /*do_rev*/0)); ++ au_lcnt_fin(&br->br_count, /*do_sync*/0); ++ ++ wbr = br->br_wbr; ++ if (wbr) { ++ for (i = 0; i < AuBrWh_Last; i++) ++ dput(wbr->wbr_wh[i]); ++ AuDebugOn(atomic_read(&wbr->wbr_wh_running)); ++ AuRwDestroy(&wbr->wbr_wh_rwsem); ++ } ++ ++ if (br->br_fhsm) { ++ au_br_fhsm_fin(br->br_fhsm); ++ au_kfree_try_rcu(br->br_fhsm); ++ } ++ ++ key = br->br_dykey; ++ for (i = 0; i < AuBrDynOp; i++, key++) ++ if (*key) ++ au_dy_put(*key); ++ else ++ break; ++ ++ /* recursive lock, s_umount of branch's */ ++ /* synchronize_rcu(); */ /* why? */ ++ lockdep_off(); ++ path_put(&br->br_path); ++ lockdep_on(); ++ au_kfree_rcu(wbr); ++ au_lcnt_wait_for_fin(&br->br_nfiles); ++ au_lcnt_wait_for_fin(&br->br_count); ++ /* I don't know why, but percpu_refcount requires this */ ++ /* synchronize_rcu(); */ ++ au_kfree_rcu(br); ++} ++ ++/* ++ * frees all branches ++ */ ++void au_br_free(struct au_sbinfo *sbinfo) ++{ ++ aufs_bindex_t bmax; ++ struct au_branch **br; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ bmax = sbinfo->si_bbot + 1; ++ br = sbinfo->si_branch; ++ while (bmax--) ++ au_br_do_free(*br++); ++} ++ ++/* ++ * find the index of a branch which is specified by @br_id. ++ */ ++int au_br_index(struct super_block *sb, aufs_bindex_t br_id) ++{ ++ aufs_bindex_t bindex, bbot; ++ ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) ++ if (au_sbr_id(sb, bindex) == br_id) ++ return bindex; ++ return -1; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * add a branch ++ */ ++ ++static int test_overlap(struct super_block *sb, struct dentry *h_adding, ++ struct dentry *h_root) ++{ ++ if (unlikely(h_adding == h_root ++ || au_test_loopback_overlap(sb, h_adding))) ++ return 1; ++ if (h_adding->d_sb != h_root->d_sb) ++ return 0; ++ return au_test_subdir(h_adding, h_root) ++ || au_test_subdir(h_root, h_adding); ++} ++ ++/* ++ * returns a newly allocated branch. @new_nbranch is a number of branches ++ * after adding a branch. ++ */ ++static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch, ++ int perm) ++{ ++ struct au_branch *add_branch; ++ struct dentry *root; ++ struct inode *inode; ++ int err; ++ ++ err = -ENOMEM; ++ add_branch = kzalloc(sizeof(*add_branch), GFP_NOFS); ++ if (unlikely(!add_branch)) ++ goto out; ++ add_branch->br_xino = au_xino_alloc(/*nfile*/1); ++ if (unlikely(!add_branch->br_xino)) ++ goto out_br; ++ err = au_hnotify_init_br(add_branch, perm); ++ if (unlikely(err)) ++ goto out_xino; ++ ++ if (au_br_writable(perm)) { ++ /* may be freed separately at changing the branch permission */ ++ add_branch->br_wbr = kzalloc(sizeof(*add_branch->br_wbr), ++ GFP_NOFS); ++ if (unlikely(!add_branch->br_wbr)) ++ goto out_hnotify; ++ } ++ ++ if (au_br_fhsm(perm)) { ++ err = au_fhsm_br_alloc(add_branch); ++ if (unlikely(err)) ++ goto out_wbr; ++ } ++ ++ root = sb->s_root; ++ err = au_sbr_realloc(au_sbi(sb), new_nbranch, /*may_shrink*/0); ++ if (!err) ++ err = au_di_realloc(au_di(root), new_nbranch, /*may_shrink*/0); ++ if (!err) { ++ inode = d_inode(root); ++ err = au_hinode_realloc(au_ii(inode), new_nbranch, ++ /*may_shrink*/0); ++ } ++ if (!err) ++ return add_branch; /* success */ ++ ++out_wbr: ++ au_kfree_rcu(add_branch->br_wbr); ++out_hnotify: ++ au_hnotify_fin_br(add_branch); ++out_xino: ++ au_xino_put(add_branch); ++out_br: ++ au_kfree_rcu(add_branch); ++out: ++ return ERR_PTR(err); ++} ++ ++/* ++ * test if the branch permission is legal or not. ++ */ ++static int test_br(struct inode *inode, int brperm, char *path) ++{ ++ int err; ++ ++ err = (au_br_writable(brperm) && IS_RDONLY(inode)); ++ if (!err) ++ goto out; ++ ++ err = -EINVAL; ++ pr_err("write permission for readonly mount or inode, %s\n", path); ++ ++out: ++ return err; ++} ++ ++/* ++ * returns: ++ * 0: success, the caller will add it ++ * plus: success, it is already unified, the caller should ignore it ++ * minus: error ++ */ ++static int test_add(struct super_block *sb, struct au_opt_add *add, int remount) ++{ ++ int err; ++ aufs_bindex_t bbot, bindex; ++ struct dentry *root, *h_dentry; ++ struct inode *inode, *h_inode; ++ ++ root = sb->s_root; ++ bbot = au_sbbot(sb); ++ if (unlikely(bbot >= 0 ++ && au_find_dbindex(root, add->path.dentry) >= 0)) { ++ err = 1; ++ if (!remount) { ++ err = -EINVAL; ++ pr_err("%s duplicated\n", add->pathname); ++ } ++ goto out; ++ } ++ ++ err = -ENOSPC; /* -E2BIG; */ ++ if (unlikely(AUFS_BRANCH_MAX <= add->bindex ++ || AUFS_BRANCH_MAX - 1 <= bbot)) { ++ pr_err("number of branches exceeded %s\n", add->pathname); ++ goto out; ++ } ++ ++ err = -EDOM; ++ if (unlikely(add->bindex < 0 || bbot + 1 < add->bindex)) { ++ pr_err("bad index %d\n", add->bindex); ++ goto out; ++ } ++ ++ inode = d_inode(add->path.dentry); ++ err = -ENOENT; ++ if (unlikely(!inode->i_nlink)) { ++ pr_err("no existence %s\n", add->pathname); ++ goto out; ++ } ++ ++ err = -EINVAL; ++ if (unlikely(inode->i_sb == sb)) { ++ pr_err("%s must be outside\n", add->pathname); ++ goto out; ++ } ++ ++ if (unlikely(au_test_fs_unsuppoted(inode->i_sb))) { ++ pr_err("unsupported filesystem, %s (%s)\n", ++ add->pathname, au_sbtype(inode->i_sb)); ++ goto out; ++ } ++ ++ if (unlikely(inode->i_sb->s_stack_depth)) { ++ pr_err("already stacked, %s (%s)\n", ++ add->pathname, au_sbtype(inode->i_sb)); ++ goto out; ++ } ++ ++ err = test_br(d_inode(add->path.dentry), add->perm, add->pathname); ++ if (unlikely(err)) ++ goto out; ++ ++ if (bbot < 0) ++ return 0; /* success */ ++ ++ err = -EINVAL; ++ for (bindex = 0; bindex <= bbot; bindex++) ++ if (unlikely(test_overlap(sb, add->path.dentry, ++ au_h_dptr(root, bindex)))) { ++ pr_err("%s is overlapped\n", add->pathname); ++ goto out; ++ } ++ ++ err = 0; ++ if (au_opt_test(au_mntflags(sb), WARN_PERM)) { ++ h_dentry = au_h_dptr(root, 0); ++ h_inode = d_inode(h_dentry); ++ if ((h_inode->i_mode & S_IALLUGO) != (inode->i_mode & S_IALLUGO) ++ || !uid_eq(h_inode->i_uid, inode->i_uid) ++ || !gid_eq(h_inode->i_gid, inode->i_gid)) ++ pr_warn("uid/gid/perm %s %u/%u/0%o, %u/%u/0%o\n", ++ add->pathname, ++ i_uid_read(inode), i_gid_read(inode), ++ (inode->i_mode & S_IALLUGO), ++ i_uid_read(h_inode), i_gid_read(h_inode), ++ (h_inode->i_mode & S_IALLUGO)); ++ } ++ ++out: ++ return err; ++} ++ ++/* ++ * initialize or clean the whiteouts for an adding branch ++ */ ++static int au_br_init_wh(struct super_block *sb, struct au_branch *br, ++ int new_perm) ++{ ++ int err, old_perm; ++ aufs_bindex_t bindex; ++ struct inode *h_inode; ++ struct au_wbr *wbr; ++ struct au_hinode *hdir; ++ struct dentry *h_dentry; ++ ++ err = vfsub_mnt_want_write(au_br_mnt(br)); ++ if (unlikely(err)) ++ goto out; ++ ++ wbr = br->br_wbr; ++ old_perm = br->br_perm; ++ br->br_perm = new_perm; ++ hdir = NULL; ++ h_inode = NULL; ++ bindex = au_br_index(sb, br->br_id); ++ if (0 <= bindex) { ++ hdir = au_hi(d_inode(sb->s_root), bindex); ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ } else { ++ h_dentry = au_br_dentry(br); ++ h_inode = d_inode(h_dentry); ++ inode_lock_nested(h_inode, AuLsc_I_PARENT); ++ } ++ if (!wbr) ++ err = au_wh_init(br, sb); ++ else { ++ wbr_wh_write_lock(wbr); ++ err = au_wh_init(br, sb); ++ wbr_wh_write_unlock(wbr); ++ } ++ if (hdir) ++ au_hn_inode_unlock(hdir); ++ else ++ inode_unlock(h_inode); ++ vfsub_mnt_drop_write(au_br_mnt(br)); ++ br->br_perm = old_perm; ++ ++ if (!err && wbr && !au_br_writable(new_perm)) { ++ au_kfree_rcu(wbr); ++ br->br_wbr = NULL; ++ } ++ ++out: ++ return err; ++} ++ ++static int au_wbr_init(struct au_branch *br, struct super_block *sb, ++ int perm) ++{ ++ int err; ++ struct kstatfs kst; ++ struct au_wbr *wbr; ++ ++ wbr = br->br_wbr; ++ au_rw_init(&wbr->wbr_wh_rwsem); ++ atomic_set(&wbr->wbr_wh_running, 0); ++ ++ /* ++ * a limit for rmdir/rename a dir ++ * cf. AUFS_MAX_NAMELEN in include/uapi/linux/aufs_type.h ++ */ ++ err = vfs_statfs(&br->br_path, &kst); ++ if (unlikely(err)) ++ goto out; ++ err = -EINVAL; ++ if (kst.f_namelen >= NAME_MAX) ++ err = au_br_init_wh(sb, br, perm); ++ else ++ pr_err("%pd(%s), unsupported namelen %ld\n", ++ au_br_dentry(br), ++ au_sbtype(au_br_dentry(br)->d_sb), kst.f_namelen); ++ ++out: ++ return err; ++} ++ ++/* initialize a new branch */ ++static int au_br_init(struct au_branch *br, struct super_block *sb, ++ struct au_opt_add *add) ++{ ++ int err; ++ struct au_branch *brbase; ++ struct file *xf; ++ struct inode *h_inode; ++ ++ err = 0; ++ br->br_perm = add->perm; ++ br->br_path = add->path; /* set first, path_get() later */ ++ spin_lock_init(&br->br_dykey_lock); ++ au_lcnt_init(&br->br_nfiles, /*release*/NULL); ++ au_lcnt_init(&br->br_count, /*release*/NULL); ++ br->br_id = au_new_br_id(sb); ++ AuDebugOn(br->br_id < 0); ++ ++ /* always, regardless the given option */ ++ err = au_dr_br_init(sb, br, &add->path); ++ if (unlikely(err)) ++ goto out_err; ++ ++ if (au_br_writable(add->perm)) { ++ err = au_wbr_init(br, sb, add->perm); ++ if (unlikely(err)) ++ goto out_err; ++ } ++ ++ if (au_opt_test(au_mntflags(sb), XINO)) { ++ brbase = au_sbr(sb, 0); ++ xf = au_xino_file(brbase->br_xino, /*idx*/-1); ++ AuDebugOn(!xf); ++ h_inode = d_inode(add->path.dentry); ++ err = au_xino_init_br(sb, br, h_inode->i_ino, &xf->f_path); ++ if (unlikely(err)) { ++ AuDebugOn(au_xino_file(br->br_xino, /*idx*/-1)); ++ goto out_err; ++ } ++ } ++ ++ sysaufs_br_init(br); ++ path_get(&br->br_path); ++ goto out; /* success */ ++ ++out_err: ++ memset(&br->br_path, 0, sizeof(br->br_path)); ++out: ++ return err; ++} ++ ++static void au_br_do_add_brp(struct au_sbinfo *sbinfo, aufs_bindex_t bindex, ++ struct au_branch *br, aufs_bindex_t bbot, ++ aufs_bindex_t amount) ++{ ++ struct au_branch **brp; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ brp = sbinfo->si_branch + bindex; ++ memmove(brp + 1, brp, sizeof(*brp) * amount); ++ *brp = br; ++ sbinfo->si_bbot++; ++ if (unlikely(bbot < 0)) ++ sbinfo->si_bbot = 0; ++} ++ ++static void au_br_do_add_hdp(struct au_dinfo *dinfo, aufs_bindex_t bindex, ++ aufs_bindex_t bbot, aufs_bindex_t amount) ++{ ++ struct au_hdentry *hdp; ++ ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ hdp = au_hdentry(dinfo, bindex); ++ memmove(hdp + 1, hdp, sizeof(*hdp) * amount); ++ au_h_dentry_init(hdp); ++ dinfo->di_bbot++; ++ if (unlikely(bbot < 0)) ++ dinfo->di_btop = 0; ++} ++ ++static void au_br_do_add_hip(struct au_iinfo *iinfo, aufs_bindex_t bindex, ++ aufs_bindex_t bbot, aufs_bindex_t amount) ++{ ++ struct au_hinode *hip; ++ ++ AuRwMustWriteLock(&iinfo->ii_rwsem); ++ ++ hip = au_hinode(iinfo, bindex); ++ memmove(hip + 1, hip, sizeof(*hip) * amount); ++ au_hinode_init(hip); ++ iinfo->ii_bbot++; ++ if (unlikely(bbot < 0)) ++ iinfo->ii_btop = 0; ++} ++ ++static void au_br_do_add(struct super_block *sb, struct au_branch *br, ++ aufs_bindex_t bindex) ++{ ++ struct dentry *root, *h_dentry; ++ struct inode *root_inode, *h_inode; ++ aufs_bindex_t bbot, amount; ++ ++ root = sb->s_root; ++ root_inode = d_inode(root); ++ bbot = au_sbbot(sb); ++ amount = bbot + 1 - bindex; ++ h_dentry = au_br_dentry(br); ++ au_sbilist_lock(); ++ au_br_do_add_brp(au_sbi(sb), bindex, br, bbot, amount); ++ au_br_do_add_hdp(au_di(root), bindex, bbot, amount); ++ au_br_do_add_hip(au_ii(root_inode), bindex, bbot, amount); ++ au_set_h_dptr(root, bindex, dget(h_dentry)); ++ h_inode = d_inode(h_dentry); ++ au_set_h_iptr(root_inode, bindex, au_igrab(h_inode), /*flags*/0); ++ au_sbilist_unlock(); ++} ++ ++int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount) ++{ ++ int err; ++ aufs_bindex_t bbot, add_bindex; ++ struct dentry *root, *h_dentry; ++ struct inode *root_inode; ++ struct au_branch *add_branch; ++ ++ root = sb->s_root; ++ root_inode = d_inode(root); ++ IMustLock(root_inode); ++ IiMustWriteLock(root_inode); ++ err = test_add(sb, add, remount); ++ if (unlikely(err < 0)) ++ goto out; ++ if (err) { ++ err = 0; ++ goto out; /* success */ ++ } ++ ++ bbot = au_sbbot(sb); ++ add_branch = au_br_alloc(sb, bbot + 2, add->perm); ++ err = PTR_ERR(add_branch); ++ if (IS_ERR(add_branch)) ++ goto out; ++ ++ err = au_br_init(add_branch, sb, add); ++ if (unlikely(err)) { ++ au_br_do_free(add_branch); ++ goto out; ++ } ++ ++ add_bindex = add->bindex; ++ sysaufs_brs_del(sb, add_bindex); /* remove successors */ ++ au_br_do_add(sb, add_branch, add_bindex); ++ sysaufs_brs_add(sb, add_bindex); /* append successors */ ++ dbgaufs_brs_add(sb, add_bindex, /*topdown*/0); /* rename successors */ ++ ++ h_dentry = add->path.dentry; ++ if (!add_bindex) { ++ au_cpup_attr_all(root_inode, /*force*/1); ++ sb->s_maxbytes = h_dentry->d_sb->s_maxbytes; ++ } else ++ au_add_nlink(root_inode, d_inode(h_dentry)); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static unsigned long long au_farray_cb(struct super_block *sb, void *a, ++ unsigned long long max __maybe_unused, ++ void *arg) ++{ ++ unsigned long long n; ++ struct file **p, *f; ++ struct hlist_bl_head *files; ++ struct hlist_bl_node *pos; ++ struct au_finfo *finfo; ++ ++ n = 0; ++ p = a; ++ files = &au_sbi(sb)->si_files; ++ hlist_bl_lock(files); ++ hlist_bl_for_each_entry(finfo, pos, files, fi_hlist) { ++ f = finfo->fi_file; ++ if (file_count(f) ++ && !special_file(file_inode(f)->i_mode)) { ++ get_file(f); ++ *p++ = f; ++ n++; ++ AuDebugOn(n > max); ++ } ++ } ++ hlist_bl_unlock(files); ++ ++ return n; ++} ++ ++static struct file **au_farray_alloc(struct super_block *sb, ++ unsigned long long *max) ++{ ++ struct au_sbinfo *sbi; ++ ++ sbi = au_sbi(sb); ++ *max = au_lcnt_read(&sbi->si_nfiles, /*do_rev*/1); ++ return au_array_alloc(max, au_farray_cb, sb, /*arg*/NULL); ++} ++ ++static void au_farray_free(struct file **a, unsigned long long max) ++{ ++ unsigned long long ull; ++ ++ for (ull = 0; ull < max; ull++) ++ if (a[ull]) ++ fput(a[ull]); ++ kvfree(a); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * delete a branch ++ */ ++ ++/* to show the line number, do not make it inlined function */ ++#define AuVerbose(do_info, fmt, ...) do { \ ++ if (do_info) \ ++ pr_info(fmt, ##__VA_ARGS__); \ ++} while (0) ++ ++static int au_test_ibusy(struct inode *inode, aufs_bindex_t btop, ++ aufs_bindex_t bbot) ++{ ++ return (inode && !S_ISDIR(inode->i_mode)) || btop == bbot; ++} ++ ++static int au_test_dbusy(struct dentry *dentry, aufs_bindex_t btop, ++ aufs_bindex_t bbot) ++{ ++ return au_test_ibusy(d_inode(dentry), btop, bbot); ++} ++ ++/* ++ * test if the branch is deletable or not. ++ */ ++static int test_dentry_busy(struct dentry *root, aufs_bindex_t bindex, ++ unsigned int sigen, const unsigned int verbose) ++{ ++ int err, i, j, ndentry; ++ aufs_bindex_t btop, bbot; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry *d; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, root, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ for (i = 0; !err && i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ ndentry = dpage->ndentry; ++ for (j = 0; !err && j < ndentry; j++) { ++ d = dpage->dentries[j]; ++ AuDebugOn(au_dcount(d) <= 0); ++ if (!au_digen_test(d, sigen)) { ++ di_read_lock_child(d, AuLock_IR); ++ if (unlikely(au_dbrange_test(d))) { ++ di_read_unlock(d, AuLock_IR); ++ continue; ++ } ++ } else { ++ di_write_lock_child(d); ++ if (unlikely(au_dbrange_test(d))) { ++ di_write_unlock(d); ++ continue; ++ } ++ err = au_reval_dpath(d, sigen); ++ if (!err) ++ di_downgrade_lock(d, AuLock_IR); ++ else { ++ di_write_unlock(d); ++ break; ++ } ++ } ++ ++ /* AuDbgDentry(d); */ ++ btop = au_dbtop(d); ++ bbot = au_dbbot(d); ++ if (btop <= bindex ++ && bindex <= bbot ++ && au_h_dptr(d, bindex) ++ && au_test_dbusy(d, btop, bbot)) { ++ err = -EBUSY; ++ AuVerbose(verbose, "busy %pd\n", d); ++ AuDbgDentry(d); ++ } ++ di_read_unlock(d, AuLock_IR); ++ } ++ } ++ ++out_dpages: ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++static int test_inode_busy(struct super_block *sb, aufs_bindex_t bindex, ++ unsigned int sigen, const unsigned int verbose) ++{ ++ int err; ++ unsigned long long max, ull; ++ struct inode *i, **array; ++ aufs_bindex_t btop, bbot; ++ ++ array = au_iarray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ err = 0; ++ AuDbg("b%d\n", bindex); ++ for (ull = 0; !err && ull < max; ull++) { ++ i = array[ull]; ++ if (unlikely(!i)) ++ break; ++ if (i->i_ino == AUFS_ROOT_INO) ++ continue; ++ ++ /* AuDbgInode(i); */ ++ if (au_iigen(i, NULL) == sigen) ++ ii_read_lock_child(i); ++ else { ++ ii_write_lock_child(i); ++ err = au_refresh_hinode_self(i); ++ au_iigen_dec(i); ++ if (!err) ++ ii_downgrade_lock(i); ++ else { ++ ii_write_unlock(i); ++ break; ++ } ++ } ++ ++ btop = au_ibtop(i); ++ bbot = au_ibbot(i); ++ if (btop <= bindex ++ && bindex <= bbot ++ && au_h_iptr(i, bindex) ++ && au_test_ibusy(i, btop, bbot)) { ++ err = -EBUSY; ++ AuVerbose(verbose, "busy i%lu\n", i->i_ino); ++ AuDbgInode(i); ++ } ++ ii_read_unlock(i); ++ } ++ au_iarray_free(array, max); ++ ++out: ++ return err; ++} ++ ++static int test_children_busy(struct dentry *root, aufs_bindex_t bindex, ++ const unsigned int verbose) ++{ ++ int err; ++ unsigned int sigen; ++ ++ sigen = au_sigen(root->d_sb); ++ DiMustNoWaiters(root); ++ IiMustNoWaiters(d_inode(root)); ++ di_write_unlock(root); ++ err = test_dentry_busy(root, bindex, sigen, verbose); ++ if (!err) ++ err = test_inode_busy(root->d_sb, bindex, sigen, verbose); ++ di_write_lock_child(root); /* aufs_write_lock() calls ..._child() */ ++ ++ return err; ++} ++ ++static int test_dir_busy(struct file *file, aufs_bindex_t br_id, ++ struct file **to_free, int *idx) ++{ ++ int err; ++ unsigned char matched, root; ++ aufs_bindex_t bindex, bbot; ++ struct au_fidir *fidir; ++ struct au_hfile *hfile; ++ ++ err = 0; ++ root = IS_ROOT(file->f_path.dentry); ++ if (root) { ++ get_file(file); ++ to_free[*idx] = file; ++ (*idx)++; ++ goto out; ++ } ++ ++ matched = 0; ++ fidir = au_fi(file)->fi_hdir; ++ AuDebugOn(!fidir); ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); bindex <= bbot; bindex++) { ++ hfile = fidir->fd_hfile + bindex; ++ if (!hfile->hf_file) ++ continue; ++ ++ if (hfile->hf_br->br_id == br_id) { ++ matched = 1; ++ break; ++ } ++ } ++ if (matched) ++ err = -EBUSY; ++ ++out: ++ return err; ++} ++ ++static int test_file_busy(struct super_block *sb, aufs_bindex_t br_id, ++ struct file **to_free, int opened) ++{ ++ int err, idx; ++ unsigned long long ull, max; ++ aufs_bindex_t btop; ++ struct file *file, **array; ++ struct dentry *root; ++ struct au_hfile *hfile; ++ ++ array = au_farray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ err = 0; ++ idx = 0; ++ root = sb->s_root; ++ di_write_unlock(root); ++ for (ull = 0; ull < max; ull++) { ++ file = array[ull]; ++ if (unlikely(!file)) ++ break; ++ ++ /* AuDbg("%pD\n", file); */ ++ fi_read_lock(file); ++ btop = au_fbtop(file); ++ if (!d_is_dir(file->f_path.dentry)) { ++ hfile = &au_fi(file)->fi_htop; ++ if (hfile->hf_br->br_id == br_id) ++ err = -EBUSY; ++ } else ++ err = test_dir_busy(file, br_id, to_free, &idx); ++ fi_read_unlock(file); ++ if (unlikely(err)) ++ break; ++ } ++ di_write_lock_child(root); ++ au_farray_free(array, max); ++ AuDebugOn(idx > opened); ++ ++out: ++ return err; ++} ++ ++static void br_del_file(struct file **to_free, unsigned long long opened, ++ aufs_bindex_t br_id) ++{ ++ unsigned long long ull; ++ aufs_bindex_t bindex, btop, bbot, bfound; ++ struct file *file; ++ struct au_fidir *fidir; ++ struct au_hfile *hfile; ++ ++ for (ull = 0; ull < opened; ull++) { ++ file = to_free[ull]; ++ if (unlikely(!file)) ++ break; ++ ++ /* AuDbg("%pD\n", file); */ ++ AuDebugOn(!d_is_dir(file->f_path.dentry)); ++ bfound = -1; ++ fidir = au_fi(file)->fi_hdir; ++ AuDebugOn(!fidir); ++ fi_write_lock(file); ++ btop = au_fbtop(file); ++ bbot = au_fbbot_dir(file); ++ for (bindex = btop; bindex <= bbot; bindex++) { ++ hfile = fidir->fd_hfile + bindex; ++ if (!hfile->hf_file) ++ continue; ++ ++ if (hfile->hf_br->br_id == br_id) { ++ bfound = bindex; ++ break; ++ } ++ } ++ AuDebugOn(bfound < 0); ++ au_set_h_fptr(file, bfound, NULL); ++ if (bfound == btop) { ++ for (btop++; btop <= bbot; btop++) ++ if (au_hf_dir(file, btop)) { ++ au_set_fbtop(file, btop); ++ break; ++ } ++ } ++ fi_write_unlock(file); ++ } ++} ++ ++static void au_br_do_del_brp(struct au_sbinfo *sbinfo, ++ const aufs_bindex_t bindex, ++ const aufs_bindex_t bbot) ++{ ++ struct au_branch **brp, **p; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ brp = sbinfo->si_branch + bindex; ++ if (bindex < bbot) ++ memmove(brp, brp + 1, sizeof(*brp) * (bbot - bindex)); ++ sbinfo->si_branch[0 + bbot] = NULL; ++ sbinfo->si_bbot--; ++ ++ p = au_krealloc(sbinfo->si_branch, sizeof(*p) * bbot, AuGFP_SBILIST, ++ /*may_shrink*/1); ++ if (p) ++ sbinfo->si_branch = p; ++ /* harmless error */ ++} ++ ++static void au_br_do_del_hdp(struct au_dinfo *dinfo, const aufs_bindex_t bindex, ++ const aufs_bindex_t bbot) ++{ ++ struct au_hdentry *hdp, *p; ++ ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ hdp = au_hdentry(dinfo, bindex); ++ if (bindex < bbot) ++ memmove(hdp, hdp + 1, sizeof(*hdp) * (bbot - bindex)); ++ /* au_h_dentry_init(au_hdentry(dinfo, bbot); */ ++ dinfo->di_bbot--; ++ ++ p = au_krealloc(dinfo->di_hdentry, sizeof(*p) * bbot, AuGFP_SBILIST, ++ /*may_shrink*/1); ++ if (p) ++ dinfo->di_hdentry = p; ++ /* harmless error */ ++} ++ ++static void au_br_do_del_hip(struct au_iinfo *iinfo, const aufs_bindex_t bindex, ++ const aufs_bindex_t bbot) ++{ ++ struct au_hinode *hip, *p; ++ ++ AuRwMustWriteLock(&iinfo->ii_rwsem); ++ ++ hip = au_hinode(iinfo, bindex); ++ if (bindex < bbot) ++ memmove(hip, hip + 1, sizeof(*hip) * (bbot - bindex)); ++ /* au_hinode_init(au_hinode(iinfo, bbot)); */ ++ iinfo->ii_bbot--; ++ ++ p = au_krealloc(iinfo->ii_hinode, sizeof(*p) * bbot, AuGFP_SBILIST, ++ /*may_shrink*/1); ++ if (p) ++ iinfo->ii_hinode = p; ++ /* harmless error */ ++} ++ ++static void au_br_do_del(struct super_block *sb, aufs_bindex_t bindex, ++ struct au_branch *br) ++{ ++ aufs_bindex_t bbot; ++ struct au_sbinfo *sbinfo; ++ struct dentry *root, *h_root; ++ struct inode *inode, *h_inode; ++ struct au_hinode *hinode; ++ ++ SiMustWriteLock(sb); ++ ++ root = sb->s_root; ++ inode = d_inode(root); ++ sbinfo = au_sbi(sb); ++ bbot = sbinfo->si_bbot; ++ ++ h_root = au_h_dptr(root, bindex); ++ hinode = au_hi(inode, bindex); ++ h_inode = au_igrab(hinode->hi_inode); ++ au_hiput(hinode); ++ ++ au_sbilist_lock(); ++ au_br_do_del_brp(sbinfo, bindex, bbot); ++ au_br_do_del_hdp(au_di(root), bindex, bbot); ++ au_br_do_del_hip(au_ii(inode), bindex, bbot); ++ au_sbilist_unlock(); ++ ++ /* ignore an error */ ++ au_dr_br_fin(sb, br); /* always, regardless the mount option */ ++ ++ dput(h_root); ++ iput(h_inode); ++ au_br_do_free(br); ++} ++ ++static unsigned long long empty_cb(struct super_block *sb, void *array, ++ unsigned long long max, void *arg) ++{ ++ return max; ++} ++ ++int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount) ++{ ++ int err, rerr, i; ++ unsigned long long opened; ++ unsigned int mnt_flags; ++ aufs_bindex_t bindex, bbot, br_id; ++ unsigned char do_wh, verbose; ++ struct au_branch *br; ++ struct au_wbr *wbr; ++ struct dentry *root; ++ struct file **to_free; ++ ++ err = 0; ++ opened = 0; ++ to_free = NULL; ++ root = sb->s_root; ++ bindex = au_find_dbindex(root, del->h_path.dentry); ++ if (bindex < 0) { ++ if (remount) ++ goto out; /* success */ ++ err = -ENOENT; ++ pr_err("%s no such branch\n", del->pathname); ++ goto out; ++ } ++ AuDbg("bindex b%d\n", bindex); ++ ++ err = -EBUSY; ++ mnt_flags = au_mntflags(sb); ++ verbose = !!au_opt_test(mnt_flags, VERBOSE); ++ bbot = au_sbbot(sb); ++ if (unlikely(!bbot)) { ++ AuVerbose(verbose, "no more branches left\n"); ++ goto out; ++ } ++ ++ br = au_sbr(sb, bindex); ++ AuDebugOn(!path_equal(&br->br_path, &del->h_path)); ++ if (unlikely(au_lcnt_read(&br->br_count, /*do_rev*/1))) { ++ AuVerbose(verbose, "br %pd2 is busy now\n", del->h_path.dentry); ++ goto out; ++ } ++ ++ br_id = br->br_id; ++ opened = au_lcnt_read(&br->br_nfiles, /*do_rev*/1); ++ if (unlikely(opened)) { ++ to_free = au_array_alloc(&opened, empty_cb, sb, NULL); ++ err = PTR_ERR(to_free); ++ if (IS_ERR(to_free)) ++ goto out; ++ ++ err = test_file_busy(sb, br_id, to_free, opened); ++ if (unlikely(err)) { ++ AuVerbose(verbose, "%llu file(s) opened\n", opened); ++ goto out; ++ } ++ } ++ ++ wbr = br->br_wbr; ++ do_wh = wbr && (wbr->wbr_whbase || wbr->wbr_plink || wbr->wbr_orph); ++ if (do_wh) { ++ /* instead of WbrWhMustWriteLock(wbr) */ ++ SiMustWriteLock(sb); ++ for (i = 0; i < AuBrWh_Last; i++) { ++ dput(wbr->wbr_wh[i]); ++ wbr->wbr_wh[i] = NULL; ++ } ++ } ++ ++ err = test_children_busy(root, bindex, verbose); ++ if (unlikely(err)) { ++ if (do_wh) ++ goto out_wh; ++ goto out; ++ } ++ ++ err = 0; ++ if (to_free) { ++ /* ++ * now we confirmed the branch is deletable. ++ * let's free the remaining opened dirs on the branch. ++ */ ++ di_write_unlock(root); ++ br_del_file(to_free, opened, br_id); ++ di_write_lock_child(root); ++ } ++ ++ sysaufs_brs_del(sb, bindex); /* remove successors */ ++ dbgaufs_xino_del(br); /* remove one */ ++ au_br_do_del(sb, bindex, br); ++ sysaufs_brs_add(sb, bindex); /* append successors */ ++ dbgaufs_brs_add(sb, bindex, /*topdown*/1); /* rename successors */ ++ ++ if (!bindex) { ++ au_cpup_attr_all(d_inode(root), /*force*/1); ++ sb->s_maxbytes = au_sbr_sb(sb, 0)->s_maxbytes; ++ } else ++ au_sub_nlink(d_inode(root), d_inode(del->h_path.dentry)); ++ if (au_opt_test(mnt_flags, PLINK)) ++ au_plink_half_refresh(sb, br_id); ++ ++ goto out; /* success */ ++ ++out_wh: ++ /* revert */ ++ rerr = au_br_init_wh(sb, br, br->br_perm); ++ if (rerr) ++ pr_warn("failed re-creating base whiteout, %s. (%d)\n", ++ del->pathname, rerr); ++out: ++ if (to_free) ++ au_farray_free(to_free, opened); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_ibusy(struct super_block *sb, struct aufs_ibusy __user *arg) ++{ ++ int err; ++ aufs_bindex_t btop, bbot; ++ struct aufs_ibusy ibusy; ++ struct inode *inode, *h_inode; ++ ++ err = -EPERM; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = copy_from_user(&ibusy, arg, sizeof(ibusy)); ++ if (!err) ++ /* VERIFY_WRITE */ ++ err = !access_ok(&arg->h_ino, sizeof(arg->h_ino)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ ++ err = -EINVAL; ++ si_read_lock(sb, AuLock_FLUSH); ++ if (unlikely(ibusy.bindex < 0 || ibusy.bindex > au_sbbot(sb))) ++ goto out_unlock; ++ ++ err = 0; ++ ibusy.h_ino = 0; /* invalid */ ++ inode = ilookup(sb, ibusy.ino); ++ if (!inode ++ || inode->i_ino == AUFS_ROOT_INO ++ || au_is_bad_inode(inode)) ++ goto out_unlock; ++ ++ ii_read_lock_child(inode); ++ btop = au_ibtop(inode); ++ bbot = au_ibbot(inode); ++ if (btop <= ibusy.bindex && ibusy.bindex <= bbot) { ++ h_inode = au_h_iptr(inode, ibusy.bindex); ++ if (h_inode && au_test_ibusy(inode, btop, bbot)) ++ ibusy.h_ino = h_inode->i_ino; ++ } ++ ii_read_unlock(inode); ++ iput(inode); ++ ++out_unlock: ++ si_read_unlock(sb); ++ if (!err) { ++ err = __put_user(ibusy.h_ino, &arg->h_ino); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ } ++ } ++out: ++ return err; ++} ++ ++long au_ibusy_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_ibusy(file->f_path.dentry->d_sb, (void __user *)arg); ++} ++ ++#ifdef CONFIG_COMPAT ++long au_ibusy_compat_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_ibusy(file->f_path.dentry->d_sb, compat_ptr(arg)); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * change a branch permission ++ */ ++ ++static void au_warn_ima(void) ++{ ++#ifdef CONFIG_IMA ++ /* since it doesn't support mark_files_ro() */ ++ AuWarn1("RW -> RO makes IMA to produce wrong message\n"); ++#endif ++} ++ ++static int do_need_sigen_inc(int a, int b) ++{ ++ return au_br_whable(a) && !au_br_whable(b); ++} ++ ++static int need_sigen_inc(int old, int new) ++{ ++ return do_need_sigen_inc(old, new) ++ || do_need_sigen_inc(new, old); ++} ++ ++static int au_br_mod_files_ro(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ int err, do_warn; ++ unsigned int mnt_flags; ++ unsigned long long ull, max; ++ aufs_bindex_t br_id; ++ unsigned char verbose, writer; ++ struct file *file, *hf, **array; ++ struct au_hfile *hfile; ++ struct inode *h_inode; ++ ++ mnt_flags = au_mntflags(sb); ++ verbose = !!au_opt_test(mnt_flags, VERBOSE); ++ ++ array = au_farray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ do_warn = 0; ++ br_id = au_sbr_id(sb, bindex); ++ for (ull = 0; ull < max; ull++) { ++ file = array[ull]; ++ if (unlikely(!file)) ++ break; ++ ++ /* AuDbg("%pD\n", file); */ ++ fi_read_lock(file); ++ if (unlikely(au_test_mmapped(file))) { ++ err = -EBUSY; ++ AuVerbose(verbose, "mmapped %pD\n", file); ++ AuDbgFile(file); ++ FiMustNoWaiters(file); ++ fi_read_unlock(file); ++ goto out_array; ++ } ++ ++ hfile = &au_fi(file)->fi_htop; ++ hf = hfile->hf_file; ++ if (!d_is_reg(file->f_path.dentry) ++ || !(file->f_mode & FMODE_WRITE) ++ || hfile->hf_br->br_id != br_id ++ || !(hf->f_mode & FMODE_WRITE)) ++ array[ull] = NULL; ++ else { ++ do_warn = 1; ++ get_file(file); ++ } ++ ++ FiMustNoWaiters(file); ++ fi_read_unlock(file); ++ fput(file); ++ } ++ ++ err = 0; ++ if (do_warn) ++ au_warn_ima(); ++ ++ for (ull = 0; ull < max; ull++) { ++ file = array[ull]; ++ if (!file) ++ continue; ++ ++ /* todo: already flushed? */ ++ /* ++ * fs/super.c:mark_files_ro() is gone, but aufs keeps its ++ * approach which resets f_mode and calls mnt_drop_write() and ++ * file_release_write() for each file, because the branch ++ * attribute in aufs world is totally different from the native ++ * fs rw/ro mode. ++ */ ++ /* fi_read_lock(file); */ ++ hfile = &au_fi(file)->fi_htop; ++ hf = hfile->hf_file; ++ /* fi_read_unlock(file); */ ++ spin_lock(&hf->f_lock); ++ writer = !!(hf->f_mode & FMODE_WRITER); ++ hf->f_mode &= ~(FMODE_WRITE | FMODE_WRITER); ++ spin_unlock(&hf->f_lock); ++ if (writer) { ++ h_inode = file_inode(hf); ++ if (hf->f_mode & FMODE_READ) ++ i_readcount_inc(h_inode); ++ put_write_access(h_inode); ++ __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)) { ++ au_kfree_rcu(br->br_wbr); ++ br->br_wbr = NULL; ++ } ++ } ++ } ++ if (unlikely(err)) ++ goto out_bf; ++ ++ if (au_br_fhsm(br->br_perm)) { ++ if (!au_br_fhsm(mod->perm)) { ++ /* fhsm --> non-fhsm */ ++ au_br_fhsm_fin(br->br_fhsm); ++ au_kfree_rcu(br->br_fhsm); ++ br->br_fhsm = NULL; ++ } ++ } else if (au_br_fhsm(mod->perm)) ++ /* non-fhsm --> fhsm */ ++ br->br_fhsm = bf; ++ ++ *do_refresh |= need_sigen_inc(br->br_perm, mod->perm); ++ br->br_perm = mod->perm; ++ goto out; /* success */ ++ ++out_bf: ++ au_kfree_try_rcu(bf); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_br_stfs(struct au_branch *br, struct aufs_stfs *stfs) ++{ ++ int err; ++ struct kstatfs kstfs; ++ ++ err = vfs_statfs(&br->br_path, &kstfs); ++ if (!err) { ++ stfs->f_blocks = kstfs.f_blocks; ++ stfs->f_bavail = kstfs.f_bavail; ++ stfs->f_files = kstfs.f_files; ++ stfs->f_ffree = kstfs.f_ffree; ++ } ++ ++ return err; ++} +diff --git a/fs/aufs/branch.h b/fs/aufs/branch.h +new file mode 100644 +index 000000000000..5632781b7bcc +--- /dev/null ++++ b/fs/aufs/branch.h +@@ -0,0 +1,351 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * branch filesystems and xino for them ++ */ ++ ++#ifndef __AUFS_BRANCH_H__ ++#define __AUFS_BRANCH_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "dirren.h" ++#include "dynop.h" ++#include "lcnt.h" ++#include "rwsem.h" ++#include "super.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* a xino file */ ++struct au_xino { ++ struct file **xi_file; ++ unsigned int xi_nfile; ++ ++ struct { ++ spinlock_t spin; ++ ino_t *array; ++ int total; ++ /* reserved for future use */ ++ /* unsigned long *bitmap; */ ++ wait_queue_head_t wqh; ++ } xi_nondir; ++ ++ struct mutex xi_mtx; /* protects xi_file array */ ++ struct hlist_bl_head xi_writing; ++ ++ atomic_t xi_truncating; ++ ++ struct kref xi_kref; ++}; ++ ++/* File-based Hierarchical Storage Management */ ++struct au_br_fhsm { ++#ifdef CONFIG_AUFS_FHSM ++ struct mutex bf_lock; ++ unsigned long bf_jiffy; ++ struct aufs_stfs bf_stfs; ++ int bf_readable; ++#endif ++}; ++ ++/* members for writable branch only */ ++enum {AuBrWh_BASE, AuBrWh_PLINK, AuBrWh_ORPH, AuBrWh_Last}; ++struct au_wbr { ++ struct au_rwsem wbr_wh_rwsem; ++ struct dentry *wbr_wh[AuBrWh_Last]; ++ atomic_t wbr_wh_running; ++#define wbr_whbase wbr_wh[AuBrWh_BASE] /* whiteout base */ ++#define wbr_plink wbr_wh[AuBrWh_PLINK] /* pseudo-link dir */ ++#define wbr_orph wbr_wh[AuBrWh_ORPH] /* dir for orphans */ ++ ++ /* mfs mode */ ++ unsigned long long wbr_bytes; ++}; ++ ++/* ext2 has 3 types of operations at least, ext3 has 4 */ ++#define AuBrDynOp (AuDyLast * 4) ++ ++#ifdef CONFIG_AUFS_HFSNOTIFY ++/* support for asynchronous destruction */ ++struct au_br_hfsnotify { ++ struct fsnotify_group *hfsn_group; ++}; ++#endif ++ ++/* sysfs entries */ ++struct au_brsysfs { ++ char name[16]; ++ struct attribute attr; ++}; ++ ++enum { ++ AuBrSysfs_BR, ++ AuBrSysfs_BRID, ++ AuBrSysfs_Last ++}; ++ ++/* protected by superblock rwsem */ ++struct au_branch { ++ struct au_xino *br_xino; ++ ++ aufs_bindex_t br_id; ++ ++ int br_perm; ++ struct path br_path; ++ spinlock_t br_dykey_lock; ++ struct au_dykey *br_dykey[AuBrDynOp]; ++ au_lcnt_t br_nfiles; /* opened files */ ++ au_lcnt_t br_count; /* in-use for other */ ++ ++ struct au_wbr *br_wbr; ++ struct au_br_fhsm *br_fhsm; ++ ++#ifdef CONFIG_AUFS_HFSNOTIFY ++ struct au_br_hfsnotify *br_hfsn; ++#endif ++ ++#ifdef CONFIG_SYSFS ++ /* entries under sysfs per mount-point */ ++ struct au_brsysfs br_sysfs[AuBrSysfs_Last]; ++#endif ++ ++#ifdef CONFIG_DEBUG_FS ++ struct dentry *br_dbgaufs; /* xino */ ++#endif ++ ++ struct au_dr_br br_dirren; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct vfsmount *au_br_mnt(struct au_branch *br) ++{ ++ return br->br_path.mnt; ++} ++ ++static inline struct dentry *au_br_dentry(struct au_branch *br) ++{ ++ return br->br_path.dentry; ++} ++ ++static inline struct super_block *au_br_sb(struct au_branch *br) ++{ ++ return au_br_mnt(br)->mnt_sb; ++} ++ ++static inline int au_br_rdonly(struct au_branch *br) ++{ ++ return (sb_rdonly(au_br_sb(br)) ++ || !au_br_writable(br->br_perm)) ++ ? -EROFS : 0; ++} ++ ++static inline int au_br_hnotifyable(int brperm __maybe_unused) ++{ ++#ifdef CONFIG_AUFS_HNOTIFY ++ return !(brperm & AuBrPerm_RR); ++#else ++ return 0; ++#endif ++} ++ ++static inline int au_br_test_oflag(int oflag, struct au_branch *br) ++{ ++ int err, exec_flag; ++ ++ err = 0; ++ exec_flag = oflag & __FMODE_EXEC; ++ if (unlikely(exec_flag && path_noexec(&br->br_path))) ++ err = -EACCES; ++ ++ return err; ++} ++ ++static inline void au_xino_get(struct au_branch *br) ++{ ++ struct au_xino *xi; ++ ++ xi = br->br_xino; ++ if (xi) ++ kref_get(&xi->xi_kref); ++} ++ ++static inline int au_xino_count(struct au_branch *br) ++{ ++ int v; ++ struct au_xino *xi; ++ ++ v = 0; ++ xi = br->br_xino; ++ if (xi) ++ v = kref_read(&xi->xi_kref); ++ ++ return v; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* branch.c */ ++struct au_sbinfo; ++void au_br_free(struct au_sbinfo *sinfo); ++int au_br_index(struct super_block *sb, aufs_bindex_t br_id); ++struct au_opt_add; ++int au_br_add(struct super_block *sb, struct au_opt_add *add, int remount); ++struct au_opt_del; ++int au_br_del(struct super_block *sb, struct au_opt_del *del, int remount); ++long au_ibusy_ioctl(struct file *file, unsigned long arg); ++#ifdef CONFIG_COMPAT ++long au_ibusy_compat_ioctl(struct file *file, unsigned long arg); ++#endif ++struct au_opt_mod; ++int au_br_mod(struct super_block *sb, struct au_opt_mod *mod, int remount, ++ int *do_refresh); ++struct aufs_stfs; ++int au_br_stfs(struct au_branch *br, struct aufs_stfs *stfs); ++ ++/* xino.c */ ++static const loff_t au_loff_max = LLONG_MAX; ++ ++aufs_bindex_t au_xi_root(struct super_block *sb, struct dentry *dentry); ++struct file *au_xino_create(struct super_block *sb, char *fpath, int silent, ++ int wbrtop); ++struct file *au_xino_create2(struct super_block *sb, struct path *base, ++ struct file *copy_src); ++struct au_xi_new { ++ struct au_xino *xi; /* switch between xino and xigen */ ++ int idx; ++ struct path *base; ++ struct file *copy_src; ++}; ++struct file *au_xi_new(struct super_block *sb, struct au_xi_new *xinew); ++ ++int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t *ino); ++int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t ino); ++ssize_t xino_fread(struct file *file, void *buf, size_t size, loff_t *pos); ++ssize_t xino_fwrite(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..d413ad06ca89 +--- /dev/null ++++ b/fs/aufs/cpup.c +@@ -0,0 +1,1432 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * copy-up functions, see wbr_policy.c for copy-down ++ */ ++ ++#include ++#include ++#include ++#include "aufs.h" ++ ++void au_cpup_attr_flags(struct inode *dst, unsigned int iflags) ++{ ++ const unsigned int mask = S_DEAD | S_SWAPFILE | S_PRIVATE ++ | S_NOATIME | S_NOCMTIME | S_AUTOMOUNT; ++ ++ BUILD_BUG_ON(sizeof(iflags) != sizeof(dst->i_flags)); ++ ++ dst->i_flags |= iflags & ~mask; ++ if (au_test_fs_notime(dst->i_sb)) ++ dst->i_flags |= S_NOATIME | S_NOCMTIME; ++} ++ ++void au_cpup_attr_timesizes(struct inode *inode) ++{ ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ fsstack_copy_attr_times(inode, h_inode); ++ fsstack_copy_inode_size(inode, h_inode); ++} ++ ++void au_cpup_attr_nlink(struct inode *inode, int force) ++{ ++ struct inode *h_inode; ++ struct super_block *sb; ++ aufs_bindex_t bindex, bbot; ++ ++ sb = inode->i_sb; ++ bindex = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, bindex); ++ if (!force ++ && !S_ISDIR(h_inode->i_mode) ++ && au_opt_test(au_mntflags(sb), PLINK) ++ && au_plink_test(inode)) ++ return; ++ ++ /* ++ * 0 can happen in revalidating. ++ * h_inode->i_mutex may not be held here, but it is harmless since once ++ * i_nlink reaches 0, it will never become positive except O_TMPFILE ++ * case. ++ * todo: O_TMPFILE+linkat(AT_SYMLINK_FOLLOW) bypassing aufs may cause ++ * the incorrect link count. ++ */ ++ set_nlink(inode, h_inode->i_nlink); ++ ++ /* ++ * fewer nlink makes find(1) noisy, but larger nlink doesn't. ++ * it may includes whplink directory. ++ */ ++ if (S_ISDIR(h_inode->i_mode)) { ++ bbot = au_ibbot(inode); ++ for (bindex++; bindex <= bbot; bindex++) { ++ h_inode = au_h_iptr(inode, bindex); ++ if (h_inode) ++ au_add_nlink(inode, h_inode); ++ } ++ } ++} ++ ++void au_cpup_attr_changeable(struct inode *inode) ++{ ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ inode->i_mode = h_inode->i_mode; ++ inode->i_uid = h_inode->i_uid; ++ inode->i_gid = h_inode->i_gid; ++ au_cpup_attr_timesizes(inode); ++ au_cpup_attr_flags(inode, h_inode->i_flags); ++} ++ ++void au_cpup_igen(struct inode *inode, struct inode *h_inode) ++{ ++ struct au_iinfo *iinfo = au_ii(inode); ++ ++ IiMustWriteLock(inode); ++ ++ iinfo->ii_higen = h_inode->i_generation; ++ iinfo->ii_hsb1 = h_inode->i_sb; ++} ++ ++void au_cpup_attr_all(struct inode *inode, int force) ++{ ++ struct inode *h_inode; ++ ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ au_cpup_attr_changeable(inode); ++ if (inode->i_nlink > 0) ++ au_cpup_attr_nlink(inode, force); ++ inode->i_rdev = h_inode->i_rdev; ++ inode->i_blkbits = h_inode->i_blkbits; ++ au_cpup_igen(inode, h_inode); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Note: dt_dentry and dt_h_dentry are not dget/dput-ed */ ++ ++/* keep the timestamps of the parent dir when cpup */ ++void au_dtime_store(struct au_dtime *dt, struct dentry *dentry, ++ struct path *h_path) ++{ ++ struct inode *h_inode; ++ ++ dt->dt_dentry = dentry; ++ dt->dt_h_path = *h_path; ++ h_inode = d_inode(h_path->dentry); ++ dt->dt_atime = h_inode->i_atime; ++ dt->dt_mtime = h_inode->i_mtime; ++ /* smp_mb(); */ ++} ++ ++void au_dtime_revert(struct au_dtime *dt) ++{ ++ struct iattr attr; ++ int err; ++ ++ attr.ia_atime = dt->dt_atime; ++ attr.ia_mtime = dt->dt_mtime; ++ attr.ia_valid = ATTR_FORCE | ATTR_MTIME | ATTR_MTIME_SET ++ | ATTR_ATIME | ATTR_ATIME_SET; ++ ++ /* no delegation since this is a directory */ ++ err = vfsub_notify_change(&dt->dt_h_path, &attr, /*delegated*/NULL); ++ if (unlikely(err)) ++ pr_warn("restoring timestamps failed(%d). ignored\n", err); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* internal use only */ ++struct au_cpup_reg_attr { ++ int valid; ++ struct kstat st; ++ unsigned int iflags; /* inode->i_flags */ ++}; ++ ++static noinline_for_stack ++int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct dentry *h_src, ++ struct au_cpup_reg_attr *h_src_attr) ++{ ++ int err, sbits, icex; ++ unsigned int mnt_flags; ++ unsigned char verbose; ++ struct iattr ia; ++ struct path h_path; ++ struct inode *h_isrc, *h_idst; ++ struct kstat *h_st; ++ struct au_branch *br; ++ ++ h_path.dentry = au_h_dptr(dst, bindex); ++ h_idst = d_inode(h_path.dentry); ++ br = au_sbr(dst->d_sb, bindex); ++ h_path.mnt = au_br_mnt(br); ++ h_isrc = d_inode(h_src); ++ ia.ia_valid = ATTR_FORCE | ATTR_UID | ATTR_GID ++ | ATTR_ATIME | ATTR_MTIME ++ | ATTR_ATIME_SET | ATTR_MTIME_SET; ++ if (h_src_attr && h_src_attr->valid) { ++ h_st = &h_src_attr->st; ++ ia.ia_uid = h_st->uid; ++ ia.ia_gid = h_st->gid; ++ ia.ia_atime = h_st->atime; ++ ia.ia_mtime = h_st->mtime; ++ if (h_idst->i_mode != h_st->mode ++ && !S_ISLNK(h_idst->i_mode)) { ++ ia.ia_valid |= ATTR_MODE; ++ ia.ia_mode = h_st->mode; ++ } ++ sbits = !!(h_st->mode & (S_ISUID | S_ISGID)); ++ au_cpup_attr_flags(h_idst, h_src_attr->iflags); ++ } else { ++ ia.ia_uid = h_isrc->i_uid; ++ ia.ia_gid = h_isrc->i_gid; ++ ia.ia_atime = h_isrc->i_atime; ++ ia.ia_mtime = h_isrc->i_mtime; ++ if (h_idst->i_mode != h_isrc->i_mode ++ && !S_ISLNK(h_idst->i_mode)) { ++ ia.ia_valid |= ATTR_MODE; ++ ia.ia_mode = h_isrc->i_mode; ++ } ++ sbits = !!(h_isrc->i_mode & (S_ISUID | S_ISGID)); ++ au_cpup_attr_flags(h_idst, h_isrc->i_flags); ++ } ++ /* no delegation since it is just created */ ++ err = vfsub_notify_change(&h_path, &ia, /*delegated*/NULL); ++ ++ /* is this nfs only? */ ++ if (!err && sbits && au_test_nfs(h_path.dentry->d_sb)) { ++ ia.ia_valid = ATTR_FORCE | ATTR_MODE; ++ ia.ia_mode = h_isrc->i_mode; ++ err = vfsub_notify_change(&h_path, &ia, /*delegated*/NULL); ++ } ++ ++ icex = br->br_perm & AuBrAttr_ICEX; ++ if (!err) { ++ mnt_flags = au_mntflags(dst->d_sb); ++ verbose = !!au_opt_test(mnt_flags, VERBOSE); ++ err = au_cpup_xattr(h_path.dentry, h_src, icex, verbose); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_copy_file(struct file *dst, struct file *src, loff_t len, ++ char *buf, unsigned long blksize) ++{ ++ int err; ++ size_t sz, rbytes, wbytes; ++ unsigned char all_zero; ++ char *p, *zp; ++ struct inode *h_inode; ++ /* reduce stack usage */ ++ struct iattr *ia; ++ ++ zp = page_address(ZERO_PAGE(0)); ++ if (unlikely(!zp)) ++ return -ENOMEM; /* possible? */ ++ ++ err = 0; ++ all_zero = 0; ++ while (len) { ++ AuDbg("len %lld\n", len); ++ sz = blksize; ++ if (len < blksize) ++ sz = len; ++ ++ rbytes = 0; ++ /* todo: signal_pending? */ ++ while (!rbytes || err == -EAGAIN || err == -EINTR) { ++ rbytes = vfsub_read_k(src, buf, sz, &src->f_pos); ++ err = rbytes; ++ } ++ if (unlikely(err < 0)) ++ break; ++ ++ all_zero = 0; ++ if (len >= rbytes && rbytes == blksize) ++ all_zero = !memcmp(buf, zp, rbytes); ++ if (!all_zero) { ++ wbytes = rbytes; ++ p = buf; ++ while (wbytes) { ++ size_t b; ++ ++ b = vfsub_write_k(dst, p, wbytes, &dst->f_pos); ++ err = b; ++ /* todo: signal_pending? */ ++ if (unlikely(err == -EAGAIN || err == -EINTR)) ++ continue; ++ if (unlikely(err < 0)) ++ break; ++ wbytes -= b; ++ p += b; ++ } ++ if (unlikely(err < 0)) ++ break; ++ } else { ++ loff_t res; ++ ++ AuLabel(hole); ++ res = vfsub_llseek(dst, rbytes, SEEK_CUR); ++ err = res; ++ if (unlikely(res < 0)) ++ break; ++ } ++ len -= rbytes; ++ err = 0; ++ } ++ ++ /* the last block may be a hole */ ++ if (!err && all_zero) { ++ AuLabel(last hole); ++ ++ err = 1; ++ if (au_test_nfs(dst->f_path.dentry->d_sb)) { ++ /* nfs requires this step to make last hole */ ++ /* is this only nfs? */ ++ do { ++ /* todo: signal_pending? */ ++ err = vfsub_write_k(dst, "\0", 1, &dst->f_pos); ++ } while (err == -EAGAIN || err == -EINTR); ++ if (err == 1) ++ dst->f_pos--; ++ } ++ ++ if (err == 1) { ++ ia = (void *)buf; ++ ia->ia_size = dst->f_pos; ++ ia->ia_valid = ATTR_SIZE | ATTR_FILE; ++ ia->ia_file = dst; ++ h_inode = file_inode(dst); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD2); ++ /* no delegation since it is just created */ ++ err = vfsub_notify_change(&dst->f_path, ia, ++ /*delegated*/NULL); ++ inode_unlock(h_inode); ++ } ++ } ++ ++ return err; ++} ++ ++int au_copy_file(struct file *dst, struct file *src, loff_t len) ++{ ++ int err; ++ unsigned long blksize; ++ unsigned char do_kfree; ++ char *buf; ++ struct super_block *h_sb; ++ ++ err = -ENOMEM; ++ h_sb = file_inode(dst)->i_sb; ++ blksize = h_sb->s_blocksize; ++ if (!blksize || PAGE_SIZE < blksize) ++ blksize = PAGE_SIZE; ++ AuDbg("blksize %lu\n", blksize); ++ do_kfree = (blksize != PAGE_SIZE && blksize >= sizeof(struct iattr *)); ++ if (do_kfree) ++ buf = kmalloc(blksize, GFP_NOFS); ++ else ++ buf = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!buf)) ++ goto out; ++ ++ if (len > (1 << 22)) ++ AuDbg("copying a large file %lld\n", (long long)len); ++ ++ src->f_pos = 0; ++ dst->f_pos = 0; ++ err = au_do_copy_file(dst, src, len, buf, blksize); ++ if (do_kfree) { ++ AuDebugOn(!au_kfree_do_sz_test(blksize)); ++ au_kfree_do_rcu(buf); ++ } else ++ free_page((unsigned long)buf); ++ ++out: ++ return err; ++} ++ ++static int au_do_copy(struct file *dst, struct file *src, loff_t len) ++{ ++ int err; ++ struct super_block *h_src_sb; ++ struct inode *h_src_inode; ++ ++ h_src_inode = file_inode(src); ++ h_src_sb = h_src_inode->i_sb; ++ ++ /* XFS acquires inode_lock */ ++ if (!au_test_xfs(h_src_sb)) ++ err = au_copy_file(dst, src, len); ++ else { ++ inode_unlock_shared(h_src_inode); ++ err = au_copy_file(dst, src, len); ++ inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); ++ } ++ ++ return err; ++} ++ ++static int au_clone_or_copy(struct file *dst, struct file *src, loff_t len) ++{ ++ int err; ++ loff_t lo; ++ struct super_block *h_src_sb; ++ struct inode *h_src_inode; ++ ++ h_src_inode = file_inode(src); ++ h_src_sb = h_src_inode->i_sb; ++ if (h_src_sb != file_inode(dst)->i_sb ++ || !dst->f_op->remap_file_range) { ++ err = au_do_copy(dst, src, len); ++ goto out; ++ } ++ ++ if (!au_test_nfs(h_src_sb)) { ++ inode_unlock_shared(h_src_inode); ++ lo = vfsub_clone_file_range(src, dst, len); ++ inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); ++ } else ++ lo = vfsub_clone_file_range(src, dst, len); ++ if (lo == len) { ++ err = 0; ++ goto out; /* success */ ++ } else if (lo >= 0) ++ /* todo: possible? */ ++ /* paritially succeeded */ ++ AuDbg("lo %lld, len %lld. Retrying.\n", lo, len); ++ else if (lo != -EOPNOTSUPP) { ++ /* older XFS has a condition in cloning */ ++ err = lo; ++ goto out; ++ } ++ ++ /* the backend fs on NFS may not support cloning */ ++ err = au_do_copy(dst, src, len); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * to support a sparse file which is opened with O_APPEND, ++ * we need to close the file. ++ */ ++static int au_cp_regular(struct au_cp_generic *cpg) ++{ ++ int err, i; ++ enum { SRC, DST }; ++ struct { ++ aufs_bindex_t bindex; ++ unsigned int flags; ++ struct dentry *dentry; ++ int force_wr; ++ struct file *file; ++ } *f, file[] = { ++ { ++ .bindex = cpg->bsrc, ++ .flags = O_RDONLY | O_NOATIME | O_LARGEFILE, ++ }, ++ { ++ .bindex = cpg->bdst, ++ .flags = O_WRONLY | O_NOATIME | O_LARGEFILE, ++ .force_wr = !!au_ftest_cpup(cpg->flags, RWDST), ++ } ++ }; ++ struct au_branch *br; ++ struct super_block *sb, *h_src_sb; ++ struct inode *h_src_inode; ++ struct task_struct *tsk = current; ++ ++ /* bsrc branch can be ro/rw. */ ++ sb = cpg->dentry->d_sb; ++ f = file; ++ for (i = 0; i < 2; i++, f++) { ++ f->dentry = au_h_dptr(cpg->dentry, f->bindex); ++ f->file = au_h_open(cpg->dentry, f->bindex, f->flags, ++ /*file*/NULL, f->force_wr); ++ if (IS_ERR(f->file)) { ++ err = PTR_ERR(f->file); ++ if (i == SRC) ++ goto out; ++ else ++ goto out_src; ++ } ++ } ++ ++ /* try stopping to update while we copyup */ ++ h_src_inode = d_inode(file[SRC].dentry); ++ h_src_sb = h_src_inode->i_sb; ++ if (!au_test_nfs(h_src_sb)) ++ IMustLock(h_src_inode); ++ err = au_clone_or_copy(file[DST].file, file[SRC].file, cpg->len); ++ ++ /* i wonder if we had O_NO_DELAY_FPUT flag */ ++ if (tsk->flags & PF_KTHREAD) ++ __fput_sync(file[DST].file); ++ else { ++ /* it happened actually */ ++ fput(file[DST].file); ++ /* ++ * too bad. ++ * we have to call both since we don't know which place the file ++ * was added to. ++ */ ++ task_work_run(); ++ flush_delayed_fput(); ++ } ++ br = au_sbr(sb, file[DST].bindex); ++ au_lcnt_dec(&br->br_nfiles); ++ ++out_src: ++ fput(file[SRC].file); ++ br = au_sbr(sb, file[SRC].bindex); ++ au_lcnt_dec(&br->br_nfiles); ++out: ++ return err; ++} ++ ++static int au_do_cpup_regular(struct au_cp_generic *cpg, ++ struct au_cpup_reg_attr *h_src_attr) ++{ ++ int err, rerr; ++ loff_t l; ++ struct path h_path; ++ struct inode *h_src_inode, *h_dst_inode; ++ ++ err = 0; ++ h_src_inode = au_h_iptr(d_inode(cpg->dentry), cpg->bsrc); ++ l = i_size_read(h_src_inode); ++ if (cpg->len == -1 || l < cpg->len) ++ cpg->len = l; ++ if (cpg->len) { ++ /* try stopping to update while we are referencing */ ++ inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); ++ au_pin_hdir_unlock(cpg->pin); ++ ++ h_path.dentry = au_h_dptr(cpg->dentry, cpg->bsrc); ++ h_path.mnt = au_sbr_mnt(cpg->dentry->d_sb, cpg->bsrc); ++ h_src_attr->iflags = h_src_inode->i_flags; ++ if (!au_test_nfs(h_src_inode->i_sb)) ++ err = vfsub_getattr(&h_path, &h_src_attr->st); ++ else { ++ inode_unlock_shared(h_src_inode); ++ err = vfsub_getattr(&h_path, &h_src_attr->st); ++ inode_lock_shared_nested(h_src_inode, AuLsc_I_CHILD); ++ } ++ if (unlikely(err)) { ++ inode_unlock_shared(h_src_inode); ++ goto out; ++ } ++ h_src_attr->valid = 1; ++ if (!au_test_nfs(h_src_inode->i_sb)) { ++ err = au_cp_regular(cpg); ++ inode_unlock_shared(h_src_inode); ++ } else { ++ inode_unlock_shared(h_src_inode); ++ err = au_cp_regular(cpg); ++ } ++ rerr = au_pin_hdir_relock(cpg->pin); ++ if (!err && rerr) ++ err = rerr; ++ } ++ if (!err && (h_src_inode->i_state & I_LINKABLE)) { ++ h_path.dentry = au_h_dptr(cpg->dentry, cpg->bdst); ++ h_dst_inode = d_inode(h_path.dentry); ++ spin_lock(&h_dst_inode->i_lock); ++ h_dst_inode->i_state |= I_LINKABLE; ++ spin_unlock(&h_dst_inode->i_lock); ++ } ++ ++out: ++ return err; ++} ++ ++static int au_do_cpup_symlink(struct path *h_path, struct dentry *h_src, ++ struct inode *h_dir) ++{ ++ int err; ++ DEFINE_DELAYED_CALL(done); ++ const char *sym; ++ ++ sym = vfs_get_link(h_src, &done); ++ err = PTR_ERR(sym); ++ if (IS_ERR(sym)) ++ goto out; ++ ++ err = vfsub_symlink(h_dir, h_path, sym); ++ ++out: ++ do_delayed_call(&done); ++ return err; ++} ++ ++/* ++ * regardless 'acl' option, reset all ACL. ++ * All ACL will be copied up later from the original entry on the lower branch. ++ */ ++static int au_reset_acl(struct inode *h_dir, struct path *h_path, umode_t mode) ++{ ++ int err; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ ++ h_dentry = h_path->dentry; ++ h_inode = d_inode(h_dentry); ++ /* forget_all_cached_acls(h_inode)); */ ++ err = vfsub_removexattr(h_dentry, XATTR_NAME_POSIX_ACL_ACCESS); ++ AuTraceErr(err); ++ if (err == -EOPNOTSUPP) ++ err = 0; ++ if (!err) ++ err = vfsub_acl_chmod(h_inode, mode); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_do_cpup_dir(struct au_cp_generic *cpg, struct dentry *dst_parent, ++ struct inode *h_dir, struct path *h_path) ++{ ++ int err; ++ struct inode *dir, *inode; ++ ++ err = vfsub_removexattr(h_path->dentry, XATTR_NAME_POSIX_ACL_DEFAULT); ++ AuTraceErr(err); ++ if (err == -EOPNOTSUPP) ++ err = 0; ++ if (unlikely(err)) ++ goto out; ++ ++ /* ++ * strange behaviour from the users view, ++ * particularly setattr case ++ */ ++ dir = d_inode(dst_parent); ++ if (au_ibtop(dir) == cpg->bdst) ++ au_cpup_attr_nlink(dir, /*force*/1); ++ inode = d_inode(cpg->dentry); ++ au_cpup_attr_nlink(inode, /*force*/1); ++ ++out: ++ return err; ++} ++ ++static noinline_for_stack ++int cpup_entry(struct au_cp_generic *cpg, struct dentry *dst_parent, ++ struct au_cpup_reg_attr *h_src_attr) ++{ ++ int err; ++ umode_t mode; ++ unsigned int mnt_flags; ++ unsigned char isdir, isreg, force; ++ const unsigned char do_dt = !!au_ftest_cpup(cpg->flags, DTIME); ++ struct au_dtime dt; ++ struct path h_path; ++ struct dentry *h_src, *h_dst, *h_parent; ++ struct inode *h_inode, *h_dir; ++ struct super_block *sb; ++ ++ /* bsrc branch can be ro/rw. */ ++ h_src = au_h_dptr(cpg->dentry, cpg->bsrc); ++ h_inode = d_inode(h_src); ++ AuDebugOn(h_inode != au_h_iptr(d_inode(cpg->dentry), cpg->bsrc)); ++ ++ /* try stopping to be referenced while we are creating */ ++ h_dst = au_h_dptr(cpg->dentry, cpg->bdst); ++ if (au_ftest_cpup(cpg->flags, RENAME)) ++ AuDebugOn(strncmp(h_dst->d_name.name, AUFS_WH_PFX, ++ AUFS_WH_PFX_LEN)); ++ h_parent = h_dst->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ AuDebugOn(h_parent != h_dst->d_parent); ++ ++ sb = cpg->dentry->d_sb; ++ h_path.mnt = au_sbr_mnt(sb, cpg->bdst); ++ if (do_dt) { ++ h_path.dentry = h_parent; ++ au_dtime_store(&dt, dst_parent, &h_path); ++ } ++ h_path.dentry = h_dst; ++ ++ isreg = 0; ++ isdir = 0; ++ mode = h_inode->i_mode; ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ isreg = 1; ++ err = vfsub_create(h_dir, &h_path, 0600, /*want_excl*/true); ++ if (!err) ++ err = au_do_cpup_regular(cpg, h_src_attr); ++ break; ++ case S_IFDIR: ++ isdir = 1; ++ err = vfsub_mkdir(h_dir, &h_path, mode); ++ if (!err) ++ err = au_do_cpup_dir(cpg, dst_parent, h_dir, &h_path); ++ break; ++ case S_IFLNK: ++ err = au_do_cpup_symlink(&h_path, h_src, h_dir); ++ break; ++ case S_IFCHR: ++ case S_IFBLK: ++ AuDebugOn(!capable(CAP_MKNOD)); ++ fallthrough; ++ case S_IFIFO: ++ case S_IFSOCK: ++ err = vfsub_mknod(h_dir, &h_path, mode, h_inode->i_rdev); ++ break; ++ default: ++ AuIOErr("Unknown inode type 0%o\n", mode); ++ err = -EIO; ++ } ++ if (!err) ++ err = au_reset_acl(h_dir, &h_path, mode); ++ ++ mnt_flags = au_mntflags(sb); ++ if (!au_opt_test(mnt_flags, UDBA_NONE) ++ && !isdir ++ && au_opt_test(mnt_flags, XINO) ++ && (h_inode->i_nlink == 1 ++ || (h_inode->i_state & I_LINKABLE)) ++ /* todo: unnecessary? */ ++ /* && d_inode(cpg->dentry)->i_nlink == 1 */ ++ && cpg->bdst < cpg->bsrc ++ && !au_ftest_cpup(cpg->flags, KEEPLINO)) ++ au_xino_write(sb, cpg->bsrc, h_inode->i_ino, /*ino*/0); ++ /* ignore this error */ ++ ++ if (!err) { ++ force = 0; ++ if (isreg) { ++ force = !!cpg->len; ++ if (cpg->len == -1) ++ force = !!i_size_read(h_inode); ++ } ++ au_fhsm_wrote(sb, cpg->bdst, force); ++ } ++ ++ if (do_dt) ++ au_dtime_revert(&dt); ++ return err; ++} ++ ++static int au_do_ren_after_cpup(struct au_cp_generic *cpg, struct path *h_path) ++{ ++ int err; ++ struct dentry *dentry, *h_dentry, *h_parent, *parent; ++ struct inode *h_dir; ++ aufs_bindex_t bdst; ++ ++ dentry = cpg->dentry; ++ bdst = cpg->bdst; ++ h_dentry = au_h_dptr(dentry, bdst); ++ if (!au_ftest_cpup(cpg->flags, OVERWRITE)) { ++ dget(h_dentry); ++ au_set_h_dptr(dentry, bdst, NULL); ++ err = au_lkup_neg(dentry, bdst, /*wh*/0); ++ if (!err) ++ h_path->dentry = dget(au_h_dptr(dentry, bdst)); ++ au_set_h_dptr(dentry, bdst, h_dentry); ++ } else { ++ err = 0; ++ parent = dget_parent(dentry); ++ h_parent = au_h_dptr(parent, bdst); ++ dput(parent); ++ h_path->dentry = vfsub_lkup_one(&dentry->d_name, h_parent); ++ if (IS_ERR(h_path->dentry)) ++ err = PTR_ERR(h_path->dentry); ++ } ++ if (unlikely(err)) ++ goto out; ++ ++ h_parent = h_dentry->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ AuDbg("%pd %pd\n", h_dentry, h_path->dentry); ++ /* no delegation since it is just created */ ++ err = vfsub_rename(h_dir, h_dentry, h_dir, h_path, /*delegated*/NULL, ++ /*flags*/0); ++ dput(h_path->dentry); ++ ++out: ++ return err; ++} ++ ++/* ++ * copyup the @dentry from @bsrc to @bdst. ++ * the caller must set the both of lower dentries. ++ * @len is for truncating when it is -1 copyup the entire file. ++ * in link/rename cases, @dst_parent may be different from the real one. ++ * basic->bsrc can be larger than basic->bdst. ++ * aufs doesn't touch the credential so ++ * security_inode_copy_up{,_xattr}() are unnecessary. ++ */ ++static int au_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent) ++{ ++ int err, rerr; ++ aufs_bindex_t old_ibtop; ++ unsigned char isdir, plink; ++ struct dentry *h_src, *h_dst, *h_parent; ++ struct inode *dst_inode, *h_dir, *inode, *delegated, *src_inode; ++ struct super_block *sb; ++ struct au_branch *br; ++ /* to reduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct path h_path; ++ struct au_cpup_reg_attr h_src_attr; ++ } *a; ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ a->h_src_attr.valid = 0; ++ ++ sb = cpg->dentry->d_sb; ++ br = au_sbr(sb, cpg->bdst); ++ a->h_path.mnt = au_br_mnt(br); ++ h_dst = au_h_dptr(cpg->dentry, cpg->bdst); ++ h_parent = h_dst->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ ++ h_src = au_h_dptr(cpg->dentry, cpg->bsrc); ++ inode = d_inode(cpg->dentry); ++ ++ if (!dst_parent) ++ dst_parent = dget_parent(cpg->dentry); ++ else ++ dget(dst_parent); ++ ++ plink = !!au_opt_test(au_mntflags(sb), PLINK); ++ dst_inode = au_h_iptr(inode, cpg->bdst); ++ if (dst_inode) { ++ if (unlikely(!plink)) { ++ err = -EIO; ++ AuIOErr("hi%lu(i%lu) exists on b%d " ++ "but plink is disabled\n", ++ dst_inode->i_ino, inode->i_ino, cpg->bdst); ++ goto out_parent; ++ } ++ ++ if (dst_inode->i_nlink) { ++ const int do_dt = au_ftest_cpup(cpg->flags, DTIME); ++ ++ h_src = au_plink_lkup(inode, cpg->bdst); ++ err = PTR_ERR(h_src); ++ if (IS_ERR(h_src)) ++ goto out_parent; ++ if (unlikely(d_is_negative(h_src))) { ++ err = -EIO; ++ AuIOErr("i%lu exists on b%d " ++ "but not pseudo-linked\n", ++ inode->i_ino, cpg->bdst); ++ dput(h_src); ++ goto out_parent; ++ } ++ ++ if (do_dt) { ++ a->h_path.dentry = h_parent; ++ au_dtime_store(&a->dt, dst_parent, &a->h_path); ++ } ++ ++ a->h_path.dentry = h_dst; ++ delegated = NULL; ++ err = vfsub_link(h_src, h_dir, &a->h_path, &delegated); ++ if (!err && au_ftest_cpup(cpg->flags, RENAME)) ++ err = au_do_ren_after_cpup(cpg, &a->h_path); ++ if (do_dt) ++ au_dtime_revert(&a->dt); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ dput(h_src); ++ goto out_parent; ++ } else ++ /* todo: cpup_wh_file? */ ++ /* udba work */ ++ au_update_ibrange(inode, /*do_put_zero*/1); ++ } ++ ++ isdir = S_ISDIR(inode->i_mode); ++ old_ibtop = au_ibtop(inode); ++ err = cpup_entry(cpg, dst_parent, &a->h_src_attr); ++ if (unlikely(err)) ++ goto out_rev; ++ dst_inode = d_inode(h_dst); ++ inode_lock_nested(dst_inode, AuLsc_I_CHILD2); ++ /* todo: necessary? */ ++ /* au_pin_hdir_unlock(cpg->pin); */ ++ ++ err = cpup_iattr(cpg->dentry, cpg->bdst, h_src, &a->h_src_attr); ++ if (unlikely(err)) { ++ /* todo: necessary? */ ++ /* au_pin_hdir_relock(cpg->pin); */ /* ignore an error */ ++ inode_unlock(dst_inode); ++ goto out_rev; ++ } ++ ++ if (cpg->bdst < old_ibtop) { ++ if (S_ISREG(inode->i_mode)) { ++ err = au_dy_iaop(inode, cpg->bdst, dst_inode); ++ if (unlikely(err)) { ++ /* ignore an error */ ++ /* au_pin_hdir_relock(cpg->pin); */ ++ inode_unlock(dst_inode); ++ goto out_rev; ++ } ++ } ++ au_set_ibtop(inode, cpg->bdst); ++ } else ++ au_set_ibbot(inode, cpg->bdst); ++ au_set_h_iptr(inode, cpg->bdst, au_igrab(dst_inode), ++ au_hi_flags(inode, isdir)); ++ ++ /* todo: necessary? */ ++ /* err = au_pin_hdir_relock(cpg->pin); */ ++ inode_unlock(dst_inode); ++ if (unlikely(err)) ++ goto out_rev; ++ ++ src_inode = d_inode(h_src); ++ if (!isdir ++ && (src_inode->i_nlink > 1 ++ || src_inode->i_state & I_LINKABLE) ++ && plink) ++ au_plink_append(inode, cpg->bdst, h_dst); ++ ++ if (au_ftest_cpup(cpg->flags, RENAME)) { ++ a->h_path.dentry = h_dst; ++ err = au_do_ren_after_cpup(cpg, &a->h_path); ++ } ++ if (!err) ++ goto out_parent; /* success */ ++ ++ /* revert */ ++out_rev: ++ a->h_path.dentry = h_parent; ++ au_dtime_store(&a->dt, dst_parent, &a->h_path); ++ a->h_path.dentry = h_dst; ++ rerr = 0; ++ if (d_is_positive(h_dst)) { ++ if (!isdir) { ++ /* no delegation since it is just created */ ++ rerr = vfsub_unlink(h_dir, &a->h_path, ++ /*delegated*/NULL, /*force*/0); ++ } else ++ rerr = vfsub_rmdir(h_dir, &a->h_path); ++ } ++ au_dtime_revert(&a->dt); ++ if (rerr) { ++ AuIOErr("failed removing broken entry(%d, %d)\n", err, rerr); ++ err = -EIO; ++ } ++out_parent: ++ dput(dst_parent); ++ au_kfree_rcu(a); ++out: ++ return err; ++} ++ ++#if 0 /* reserved */ ++struct au_cpup_single_args { ++ int *errp; ++ struct au_cp_generic *cpg; ++ struct dentry *dst_parent; ++}; ++ ++static void au_call_cpup_single(void *args) ++{ ++ struct au_cpup_single_args *a = args; ++ ++ au_pin_hdir_acquire_nest(a->cpg->pin); ++ *a->errp = au_cpup_single(a->cpg, a->dst_parent); ++ au_pin_hdir_release(a->cpg->pin); ++} ++#endif ++ ++/* ++ * prevent SIGXFSZ in copy-up. ++ * testing CAP_MKNOD is for generic fs, ++ * but CAP_FSETID is for xfs only, currently. ++ */ ++static int au_cpup_sio_test(struct au_pin *pin, umode_t mode) ++{ ++ int do_sio; ++ struct super_block *sb; ++ struct inode *h_dir; ++ ++ do_sio = 0; ++ sb = au_pinned_parent(pin)->d_sb; ++ if (!au_wkq_test() ++ && (!au_sbi(sb)->si_plink_maint_pid ++ || au_plink_maint(sb, AuLock_NOPLM))) { ++ switch (mode & S_IFMT) { ++ case S_IFREG: ++ /* no condition about RLIMIT_FSIZE and the file size */ ++ do_sio = 1; ++ break; ++ case S_IFCHR: ++ case S_IFBLK: ++ do_sio = !capable(CAP_MKNOD); ++ break; ++ } ++ if (!do_sio) ++ do_sio = ((mode & (S_ISUID | S_ISGID)) ++ && !capable(CAP_FSETID)); ++ /* this workaround may be removed in the future */ ++ if (!do_sio) { ++ h_dir = au_pinned_h_dir(pin); ++ do_sio = h_dir->i_mode & S_ISVTX; ++ } ++ } ++ ++ return do_sio; ++} ++ ++#if 0 /* reserved */ ++int au_sio_cpup_single(struct au_cp_generic *cpg, struct dentry *dst_parent) ++{ ++ int err, wkq_err; ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(cpg->dentry, cpg->bsrc); ++ if (!au_cpup_sio_test(pin, d_inode(h_dentry)->i_mode)) ++ err = au_cpup_single(cpg, dst_parent); ++ else { ++ struct au_cpup_single_args args = { ++ .errp = &err, ++ .cpg = cpg, ++ .dst_parent = dst_parent ++ }; ++ wkq_err = au_wkq_wait(au_call_cpup_single, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ return err; ++} ++#endif ++ ++/* ++ * copyup the @dentry from the first active lower branch to @bdst, ++ * using au_cpup_single(). ++ */ ++static int au_cpup_simple(struct au_cp_generic *cpg) ++{ ++ int err; ++ unsigned int flags_orig; ++ struct dentry *dentry; ++ ++ AuDebugOn(cpg->bsrc < 0); ++ ++ dentry = cpg->dentry; ++ DiMustWriteLock(dentry); ++ ++ err = au_lkup_neg(dentry, cpg->bdst, /*wh*/1); ++ if (!err) { ++ flags_orig = cpg->flags; ++ au_fset_cpup(cpg->flags, RENAME); ++ err = au_cpup_single(cpg, NULL); ++ cpg->flags = flags_orig; ++ if (!err) ++ return 0; /* success */ ++ ++ /* revert */ ++ au_set_h_dptr(dentry, cpg->bdst, NULL); ++ au_set_dbtop(dentry, cpg->bsrc); ++ } ++ ++ return err; ++} ++ ++struct au_cpup_simple_args { ++ int *errp; ++ struct au_cp_generic *cpg; ++}; ++ ++static void au_call_cpup_simple(void *args) ++{ ++ struct au_cpup_simple_args *a = args; ++ ++ au_pin_hdir_acquire_nest(a->cpg->pin); ++ *a->errp = au_cpup_simple(a->cpg); ++ au_pin_hdir_release(a->cpg->pin); ++} ++ ++static int au_do_sio_cpup_simple(struct au_cp_generic *cpg) ++{ ++ int err, wkq_err; ++ struct dentry *dentry, *parent; ++ struct file *h_file; ++ struct inode *h_dir; ++ ++ dentry = cpg->dentry; ++ h_file = NULL; ++ if (au_ftest_cpup(cpg->flags, HOPEN)) { ++ AuDebugOn(cpg->bsrc < 0); ++ h_file = au_h_open_pre(dentry, cpg->bsrc, /*force_wr*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ } ++ ++ parent = dget_parent(dentry); ++ h_dir = au_h_iptr(d_inode(parent), cpg->bdst); ++ if (!au_test_h_perm_sio(h_dir, MAY_EXEC | MAY_WRITE) ++ && !au_cpup_sio_test(cpg->pin, d_inode(dentry)->i_mode)) ++ err = au_cpup_simple(cpg); ++ else { ++ struct au_cpup_simple_args args = { ++ .errp = &err, ++ .cpg = cpg ++ }; ++ wkq_err = au_wkq_wait(au_call_cpup_simple, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ dput(parent); ++ if (h_file) ++ au_h_open_post(dentry, cpg->bsrc, h_file); ++ ++out: ++ return err; ++} ++ ++int au_sio_cpup_simple(struct au_cp_generic *cpg) ++{ ++ aufs_bindex_t bsrc, bbot; ++ struct dentry *dentry, *h_dentry; ++ ++ if (cpg->bsrc < 0) { ++ dentry = cpg->dentry; ++ bbot = au_dbbot(dentry); ++ for (bsrc = cpg->bdst + 1; bsrc <= bbot; bsrc++) { ++ h_dentry = au_h_dptr(dentry, bsrc); ++ if (h_dentry) { ++ AuDebugOn(d_is_negative(h_dentry)); ++ break; ++ } ++ } ++ AuDebugOn(bsrc > bbot); ++ cpg->bsrc = bsrc; ++ } ++ AuDebugOn(cpg->bsrc <= cpg->bdst); ++ return au_do_sio_cpup_simple(cpg); ++} ++ ++int au_sio_cpdown_simple(struct au_cp_generic *cpg) ++{ ++ AuDebugOn(cpg->bdst <= cpg->bsrc); ++ return au_do_sio_cpup_simple(cpg); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * copyup the deleted file for writing. ++ */ ++static int au_do_cpup_wh(struct au_cp_generic *cpg, struct dentry *wh_dentry, ++ struct file *file) ++{ ++ int err; ++ unsigned int flags_orig; ++ aufs_bindex_t bsrc_orig; ++ struct au_dinfo *dinfo; ++ struct { ++ struct au_hdentry *hd; ++ struct dentry *h_dentry; ++ } hdst, hsrc; ++ ++ dinfo = au_di(cpg->dentry); ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ bsrc_orig = cpg->bsrc; ++ cpg->bsrc = dinfo->di_btop; ++ hdst.hd = au_hdentry(dinfo, cpg->bdst); ++ hdst.h_dentry = hdst.hd->hd_dentry; ++ hdst.hd->hd_dentry = wh_dentry; ++ dinfo->di_btop = cpg->bdst; ++ ++ hsrc.h_dentry = NULL; ++ if (file) { ++ hsrc.hd = au_hdentry(dinfo, cpg->bsrc); ++ hsrc.h_dentry = hsrc.hd->hd_dentry; ++ hsrc.hd->hd_dentry = au_hf_top(file)->f_path.dentry; ++ } ++ flags_orig = cpg->flags; ++ cpg->flags = !AuCpup_DTIME; ++ err = au_cpup_single(cpg, /*h_parent*/NULL); ++ cpg->flags = flags_orig; ++ if (file) { ++ if (!err) ++ err = au_reopen_nondir(file); ++ hsrc.hd->hd_dentry = hsrc.h_dentry; ++ } ++ hdst.hd->hd_dentry = hdst.h_dentry; ++ dinfo->di_btop = cpg->bsrc; ++ cpg->bsrc = bsrc_orig; ++ ++ return err; ++} ++ ++static int au_cpup_wh(struct au_cp_generic *cpg, struct file *file) ++{ ++ int err; ++ aufs_bindex_t bdst; ++ struct au_dtime dt; ++ struct dentry *dentry, *parent, *h_parent, *wh_dentry; ++ struct au_branch *br; ++ struct path h_path; ++ ++ dentry = cpg->dentry; ++ bdst = cpg->bdst; ++ br = au_sbr(dentry->d_sb, bdst); ++ parent = dget_parent(dentry); ++ h_parent = au_h_dptr(parent, bdst); ++ wh_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out; ++ ++ h_path.dentry = h_parent; ++ h_path.mnt = au_br_mnt(br); ++ au_dtime_store(&dt, parent, &h_path); ++ err = au_do_cpup_wh(cpg, wh_dentry, file); ++ if (unlikely(err)) ++ goto out_wh; ++ ++ dget(wh_dentry); ++ h_path.dentry = wh_dentry; ++ if (!d_is_dir(wh_dentry)) { ++ /* no delegation since it is just created */ ++ err = vfsub_unlink(d_inode(h_parent), &h_path, ++ /*delegated*/NULL, /*force*/0); ++ } else ++ err = vfsub_rmdir(d_inode(h_parent), &h_path); ++ if (unlikely(err)) { ++ AuIOErr("failed remove copied-up tmp file %pd(%d)\n", ++ wh_dentry, err); ++ err = -EIO; ++ } ++ au_dtime_revert(&dt); ++ au_set_hi_wh(d_inode(dentry), bdst, wh_dentry); ++ ++out_wh: ++ dput(wh_dentry); ++out: ++ dput(parent); ++ return err; ++} ++ ++struct au_cpup_wh_args { ++ int *errp; ++ struct au_cp_generic *cpg; ++ struct file *file; ++}; ++ ++static void au_call_cpup_wh(void *args) ++{ ++ struct au_cpup_wh_args *a = args; ++ ++ au_pin_hdir_acquire_nest(a->cpg->pin); ++ *a->errp = au_cpup_wh(a->cpg, a->file); ++ au_pin_hdir_release(a->cpg->pin); ++} ++ ++int au_sio_cpup_wh(struct au_cp_generic *cpg, struct file *file) ++{ ++ int err, wkq_err; ++ aufs_bindex_t bdst; ++ struct dentry *dentry, *parent, *h_orph, *h_parent; ++ struct inode *dir, *h_dir, *h_tmpdir; ++ struct au_wbr *wbr; ++ struct au_pin wh_pin, *pin_orig; ++ ++ dentry = cpg->dentry; ++ bdst = cpg->bdst; ++ parent = dget_parent(dentry); ++ dir = d_inode(parent); ++ h_orph = NULL; ++ h_parent = NULL; ++ h_dir = au_igrab(au_h_iptr(dir, bdst)); ++ h_tmpdir = h_dir; ++ pin_orig = NULL; ++ if (!h_dir->i_nlink) { ++ wbr = au_sbr(dentry->d_sb, bdst)->br_wbr; ++ h_orph = wbr->wbr_orph; ++ ++ h_parent = dget(au_h_dptr(parent, bdst)); ++ au_set_h_dptr(parent, bdst, dget(h_orph)); ++ h_tmpdir = d_inode(h_orph); ++ au_set_h_iptr(dir, bdst, au_igrab(h_tmpdir), /*flags*/0); ++ ++ inode_lock_nested(h_tmpdir, AuLsc_I_PARENT3); ++ /* todo: au_h_open_pre()? */ ++ ++ pin_orig = cpg->pin; ++ au_pin_init(&wh_pin, dentry, bdst, AuLsc_DI_PARENT, ++ AuLsc_I_PARENT3, cpg->pin->udba, AuPin_DI_LOCKED); ++ cpg->pin = &wh_pin; ++ } ++ ++ if (!au_test_h_perm_sio(h_tmpdir, MAY_EXEC | MAY_WRITE) ++ && !au_cpup_sio_test(cpg->pin, d_inode(dentry)->i_mode)) ++ err = au_cpup_wh(cpg, file); ++ else { ++ struct au_cpup_wh_args args = { ++ .errp = &err, ++ .cpg = cpg, ++ .file = file ++ }; ++ wkq_err = au_wkq_wait(au_call_cpup_wh, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ ++ if (h_orph) { ++ inode_unlock(h_tmpdir); ++ /* todo: au_h_open_post()? */ ++ au_set_h_iptr(dir, bdst, au_igrab(h_dir), /*flags*/0); ++ au_set_h_dptr(parent, bdst, h_parent); ++ AuDebugOn(!pin_orig); ++ cpg->pin = pin_orig; ++ } ++ iput(h_dir); ++ dput(parent); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * generic routine for both of copy-up and copy-down. ++ */ ++/* cf. revalidate function in file.c */ ++int au_cp_dirs(struct dentry *dentry, aufs_bindex_t bdst, ++ int (*cp)(struct dentry *dentry, aufs_bindex_t bdst, ++ struct au_pin *pin, ++ struct dentry *h_parent, void *arg), ++ void *arg) ++{ ++ int err; ++ struct au_pin pin; ++ struct dentry *d, *parent, *h_parent, *real_parent, *h_dentry; ++ ++ err = 0; ++ parent = dget_parent(dentry); ++ if (IS_ROOT(parent)) ++ goto out; ++ ++ au_pin_init(&pin, dentry, bdst, AuLsc_DI_PARENT2, AuLsc_I_PARENT2, ++ au_opt_udba(dentry->d_sb), AuPin_MNT_WRITE); ++ ++ /* do not use au_dpage */ ++ real_parent = parent; ++ while (1) { ++ dput(parent); ++ parent = dget_parent(dentry); ++ h_parent = au_h_dptr(parent, bdst); ++ if (h_parent) ++ goto out; /* success */ ++ ++ /* find top dir which is necessary to cpup */ ++ do { ++ d = parent; ++ dput(parent); ++ parent = dget_parent(d); ++ di_read_lock_parent3(parent, !AuLock_IR); ++ h_parent = au_h_dptr(parent, bdst); ++ di_read_unlock(parent, !AuLock_IR); ++ } while (!h_parent); ++ ++ if (d != real_parent) ++ di_write_lock_child3(d); ++ ++ /* somebody else might create while we were sleeping */ ++ h_dentry = au_h_dptr(d, bdst); ++ if (!h_dentry || d_is_negative(h_dentry)) { ++ if (h_dentry) ++ au_update_dbtop(d); ++ ++ au_pin_set_dentry(&pin, d); ++ err = au_do_pin(&pin); ++ if (!err) { ++ err = cp(d, bdst, &pin, h_parent, arg); ++ au_unpin(&pin); ++ } ++ } ++ ++ if (d != real_parent) ++ di_write_unlock(d); ++ if (unlikely(err)) ++ break; ++ } ++ ++out: ++ dput(parent); ++ return err; ++} ++ ++static int au_cpup_dir(struct dentry *dentry, aufs_bindex_t bdst, ++ struct au_pin *pin, ++ struct dentry *h_parent __maybe_unused, ++ void *arg __maybe_unused) ++{ ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = bdst, ++ .bsrc = -1, ++ .len = 0, ++ .pin = pin, ++ .flags = AuCpup_DTIME ++ }; ++ return au_sio_cpup_simple(&cpg); ++} ++ ++int au_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst) ++{ ++ return au_cp_dirs(dentry, bdst, au_cpup_dir, NULL); ++} ++ ++int au_test_and_cpup_dirs(struct dentry *dentry, aufs_bindex_t bdst) ++{ ++ int err; ++ struct dentry *parent; ++ struct inode *dir; ++ ++ parent = dget_parent(dentry); ++ dir = d_inode(parent); ++ err = 0; ++ if (au_h_iptr(dir, bdst)) ++ goto out; ++ ++ di_read_unlock(parent, AuLock_IR); ++ di_write_lock_parent(parent); ++ /* someone else might change our inode while we were sleeping */ ++ if (!au_h_iptr(dir, bdst)) ++ err = au_cpup_dirs(dentry, bdst); ++ di_downgrade_lock(parent, AuLock_IR); ++ ++out: ++ dput(parent); ++ return err; ++} +diff --git a/fs/aufs/cpup.h b/fs/aufs/cpup.h +new file mode 100644 +index 000000000000..c23c1bbcee7e +--- /dev/null ++++ b/fs/aufs/cpup.h +@@ -0,0 +1,87 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2020 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..63f40a324f1b +--- /dev/null ++++ b/fs/aufs/dbgaufs.c +@@ -0,0 +1,513 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * debugfs interface ++ */ ++ ++#include ++#include "aufs.h" ++ ++#ifndef CONFIG_SYSFS ++#error DEBUG_FS depends upon SYSFS ++#endif ++ ++static struct dentry *dbgaufs; ++static const mode_t dbgaufs_mode = 0444; ++ ++/* 20 is max digits length of ulong 64 */ ++struct dbgaufs_arg { ++ int n; ++ char a[20 * 4]; ++}; ++ ++/* ++ * common function for all XINO files ++ */ ++static int dbgaufs_xi_release(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ void *p; ++ ++ p = file->private_data; ++ if (p) { ++ /* this is struct dbgaufs_arg */ ++ AuDebugOn(!au_kfree_sz_test(p)); ++ au_kfree_do_rcu(p); ++ } ++ return 0; ++} ++ ++static int dbgaufs_xi_open(struct file *xf, struct file *file, int do_fcnt, ++ int cnt) ++{ ++ int err; ++ struct kstat st; ++ struct dbgaufs_arg *p; ++ ++ err = -ENOMEM; ++ p = kmalloc(sizeof(*p), GFP_NOFS); ++ if (unlikely(!p)) ++ goto out; ++ ++ err = 0; ++ p->n = 0; ++ file->private_data = p; ++ if (!xf) ++ goto out; ++ ++ err = vfsub_getattr(&xf->f_path, &st); ++ if (!err) { ++ if (do_fcnt) ++ p->n = snprintf ++ (p->a, sizeof(p->a), "%d, %llux%u %lld\n", ++ cnt, st.blocks, st.blksize, ++ (long long)st.size); ++ else ++ p->n = snprintf(p->a, sizeof(p->a), "%llux%u %lld\n", ++ st.blocks, st.blksize, ++ (long long)st.size); ++ AuDebugOn(p->n >= sizeof(p->a)); ++ } else { ++ p->n = snprintf(p->a, sizeof(p->a), "err %d\n", err); ++ err = 0; ++ } ++ ++out: ++ return err; ++} ++ ++static ssize_t dbgaufs_xi_read(struct file *file, char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct dbgaufs_arg *p; ++ ++ p = file->private_data; ++ return simple_read_from_buffer(buf, count, ppos, p->a, p->n); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dbgaufs_plink_arg { ++ int n; ++ char a[]; ++}; ++ ++static int dbgaufs_plink_release(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ free_page((unsigned long)file->private_data); ++ return 0; ++} ++ ++static int dbgaufs_plink_open(struct inode *inode, struct file *file) ++{ ++ int err, i, limit; ++ unsigned long n, sum; ++ struct dbgaufs_plink_arg *p; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ struct hlist_bl_head *hbl; ++ ++ err = -ENOMEM; ++ p = (void *)get_zeroed_page(GFP_NOFS); ++ if (unlikely(!p)) ++ goto out; ++ ++ err = -EFBIG; ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ if (au_opt_test(au_mntflags(sb), PLINK)) { ++ limit = PAGE_SIZE - sizeof(p->n); ++ ++ /* the number of buckets */ ++ n = snprintf(p->a + p->n, limit, "%d\n", AuPlink_NHASH); ++ p->n += n; ++ limit -= n; ++ ++ sum = 0; ++ for (i = 0, hbl = sbinfo->si_plink; i < AuPlink_NHASH; ++ i++, hbl++) { ++ n = au_hbl_count(hbl); ++ sum += n; ++ ++ n = snprintf(p->a + p->n, limit, "%lu ", n); ++ p->n += n; ++ limit -= n; ++ if (unlikely(limit <= 0)) ++ goto out_free; ++ } ++ p->a[p->n - 1] = '\n'; ++ ++ /* the sum of plinks */ ++ n = snprintf(p->a + p->n, limit, "%lu\n", sum); ++ p->n += n; ++ limit -= n; ++ if (unlikely(limit <= 0)) ++ goto out_free; ++ } else { ++#define str "1\n0\n0\n" ++ p->n = sizeof(str) - 1; ++ strcpy(p->a, str); ++#undef str ++ } ++ si_read_unlock(sb); ++ ++ err = 0; ++ file->private_data = p; ++ goto out; /* success */ ++ ++out_free: ++ free_page((unsigned long)p); ++out: ++ return err; ++} ++ ++static ssize_t dbgaufs_plink_read(struct file *file, char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct dbgaufs_plink_arg *p; ++ ++ p = file->private_data; ++ return simple_read_from_buffer(buf, count, ppos, p->a, p->n); ++} ++ ++static const struct file_operations dbgaufs_plink_fop = { ++ .owner = THIS_MODULE, ++ .open = dbgaufs_plink_open, ++ .release = dbgaufs_plink_release, ++ .read = dbgaufs_plink_read ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int dbgaufs_xib_open(struct inode *inode, struct file *file) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ err = dbgaufs_xi_open(sbinfo->si_xib, file, /*do_fcnt*/0, /*cnt*/0); ++ si_read_unlock(sb); ++ return err; ++} ++ ++static const struct file_operations dbgaufs_xib_fop = { ++ .owner = THIS_MODULE, ++ .open = dbgaufs_xib_open, ++ .release = dbgaufs_xi_release, ++ .read = dbgaufs_xi_read ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define DbgaufsXi_PREFIX "xi" ++ ++static int dbgaufs_xino_open(struct inode *inode, struct file *file) ++{ ++ int err, idx; ++ long l; ++ aufs_bindex_t bindex; ++ char *p, a[sizeof(DbgaufsXi_PREFIX) + 8]; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ struct au_xino *xi; ++ struct file *xf; ++ struct qstr *name; ++ struct au_branch *br; ++ ++ err = -ENOENT; ++ name = &file->f_path.dentry->d_name; ++ if (unlikely(name->len < sizeof(DbgaufsXi_PREFIX) ++ || memcmp(name->name, DbgaufsXi_PREFIX, ++ sizeof(DbgaufsXi_PREFIX) - 1))) ++ goto out; ++ ++ AuDebugOn(name->len >= sizeof(a)); ++ memcpy(a, name->name, name->len); ++ a[name->len] = '\0'; ++ p = strchr(a, '-'); ++ if (p) ++ *p = '\0'; ++ err = kstrtol(a + sizeof(DbgaufsXi_PREFIX) - 1, 10, &l); ++ if (unlikely(err)) ++ goto out; ++ bindex = l; ++ idx = 0; ++ if (p) { ++ err = kstrtol(p + 1, 10, &l); ++ if (unlikely(err)) ++ goto out; ++ idx = l; ++ } ++ ++ err = -ENOENT; ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ if (unlikely(bindex < 0 || bindex > au_sbbot(sb))) ++ goto out_si; ++ br = au_sbr(sb, bindex); ++ xi = br->br_xino; ++ if (unlikely(idx >= xi->xi_nfile)) ++ goto out_si; ++ xf = au_xino_file(xi, idx); ++ if (xf) ++ err = dbgaufs_xi_open(xf, file, /*do_fcnt*/1, ++ au_xino_count(br)); ++ ++out_si: ++ si_read_unlock(sb); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static const struct file_operations dbgaufs_xino_fop = { ++ .owner = THIS_MODULE, ++ .open = dbgaufs_xino_open, ++ .release = dbgaufs_xi_release, ++ .read = dbgaufs_xi_read ++}; ++ ++void dbgaufs_xino_del(struct au_branch *br) ++{ ++ struct dentry *dbgaufs; ++ ++ dbgaufs = br->br_dbgaufs; ++ if (!dbgaufs) ++ return; ++ ++ br->br_dbgaufs = NULL; ++ /* debugfs acquires the parent i_mutex */ ++ lockdep_off(); ++ debugfs_remove(dbgaufs); ++ lockdep_on(); ++} ++ ++void dbgaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ aufs_bindex_t bbot; ++ struct au_branch *br; ++ ++ if (!au_sbi(sb)->si_dbgaufs) ++ return; ++ ++ bbot = au_sbbot(sb); ++ for (; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ dbgaufs_xino_del(br); ++ } ++} ++ ++static void dbgaufs_br_do_add(struct super_block *sb, aufs_bindex_t bindex, ++ unsigned int idx, struct dentry *parent, ++ struct au_sbinfo *sbinfo) ++{ ++ struct au_branch *br; ++ struct dentry *d; ++ /* "xi" bindex(5) "-" idx(2) NULL */ ++ char name[sizeof(DbgaufsXi_PREFIX) + 8]; ++ ++ if (!idx) ++ snprintf(name, sizeof(name), DbgaufsXi_PREFIX "%d", bindex); ++ else ++ snprintf(name, sizeof(name), DbgaufsXi_PREFIX "%d-%u", ++ bindex, idx); ++ br = au_sbr(sb, bindex); ++ if (br->br_dbgaufs) { ++ struct qstr qstr = QSTR_INIT(name, strlen(name)); ++ ++ if (!au_qstreq(&br->br_dbgaufs->d_name, &qstr)) { ++ /* debugfs acquires the parent i_mutex */ ++ lockdep_off(); ++ d = debugfs_rename(parent, br->br_dbgaufs, parent, ++ name); ++ lockdep_on(); ++ if (unlikely(!d)) ++ pr_warn("failed renaming %pd/%s, ignored.\n", ++ parent, name); ++ } ++ } else { ++ lockdep_off(); ++ br->br_dbgaufs = debugfs_create_file(name, dbgaufs_mode, parent, ++ sbinfo, &dbgaufs_xino_fop); ++ lockdep_on(); ++ if (unlikely(!br->br_dbgaufs)) ++ pr_warn("failed creating %pd/%s, ignored.\n", ++ parent, name); ++ } ++} ++ ++static void dbgaufs_br_add(struct super_block *sb, aufs_bindex_t bindex, ++ struct dentry *parent, struct au_sbinfo *sbinfo) ++{ ++ struct au_branch *br; ++ struct au_xino *xi; ++ unsigned int u; ++ ++ br = au_sbr(sb, bindex); ++ xi = br->br_xino; ++ for (u = 0; u < xi->xi_nfile; u++) ++ dbgaufs_br_do_add(sb, bindex, u, parent, sbinfo); ++} ++ ++void dbgaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex, int topdown) ++{ ++ struct au_sbinfo *sbinfo; ++ struct dentry *parent; ++ aufs_bindex_t bbot; ++ ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ return; ++ ++ sbinfo = au_sbi(sb); ++ parent = sbinfo->si_dbgaufs; ++ if (!parent) ++ return; ++ ++ bbot = au_sbbot(sb); ++ if (topdown) ++ for (; bindex <= bbot; bindex++) ++ dbgaufs_br_add(sb, bindex, parent, sbinfo); ++ else ++ for (; bbot >= bindex; bbot--) ++ dbgaufs_br_add(sb, bbot, parent, sbinfo); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_EXPORT ++static int dbgaufs_xigen_open(struct inode *inode, struct file *file) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ ++ sbinfo = inode->i_private; ++ sb = sbinfo->si_sb; ++ si_noflush_read_lock(sb); ++ err = dbgaufs_xi_open(sbinfo->si_xigen, file, /*do_fcnt*/0, /*cnt*/0); ++ si_read_unlock(sb); ++ return err; ++} ++ ++static const struct file_operations dbgaufs_xigen_fop = { ++ .owner = THIS_MODULE, ++ .open = dbgaufs_xigen_open, ++ .release = dbgaufs_xi_release, ++ .read = dbgaufs_xi_read ++}; ++ ++static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo) ++{ ++ int err; ++ ++ /* ++ * This function is a dynamic '__init' function actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++ ++ err = -EIO; ++ sbinfo->si_dbgaufs_xigen = debugfs_create_file ++ ("xigen", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, ++ &dbgaufs_xigen_fop); ++ if (sbinfo->si_dbgaufs_xigen) ++ err = 0; ++ ++ return err; ++} ++#else ++static int dbgaufs_xigen_init(struct au_sbinfo *sbinfo) ++{ ++ return 0; ++} ++#endif /* CONFIG_AUFS_EXPORT */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++void dbgaufs_si_fin(struct au_sbinfo *sbinfo) ++{ ++ /* ++ * This function is a dynamic '__fin' function actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++ ++ debugfs_remove_recursive(sbinfo->si_dbgaufs); ++ sbinfo->si_dbgaufs = NULL; ++} ++ ++int dbgaufs_si_init(struct au_sbinfo *sbinfo) ++{ ++ int err; ++ char name[SysaufsSiNameLen]; ++ ++ /* ++ * This function is a dynamic '__init' function actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++ ++ err = -ENOENT; ++ if (!dbgaufs) { ++ AuErr1("/debug/aufs is uninitialized\n"); ++ goto out; ++ } ++ ++ err = -EIO; ++ sysaufs_name(sbinfo, name); ++ sbinfo->si_dbgaufs = debugfs_create_dir(name, dbgaufs); ++ if (unlikely(!sbinfo->si_dbgaufs)) ++ goto out; ++ ++ /* regardless plink/noplink option */ ++ sbinfo->si_dbgaufs_plink = debugfs_create_file ++ ("plink", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, ++ &dbgaufs_plink_fop); ++ if (unlikely(!sbinfo->si_dbgaufs_plink)) ++ goto out_dir; ++ ++ /* regardless xino/noxino option */ ++ sbinfo->si_dbgaufs_xib = debugfs_create_file ++ ("xib", dbgaufs_mode, sbinfo->si_dbgaufs, sbinfo, ++ &dbgaufs_xib_fop); ++ if (unlikely(!sbinfo->si_dbgaufs_xib)) ++ goto out_dir; ++ ++ err = dbgaufs_xigen_init(sbinfo); ++ if (!err) ++ goto out; /* success */ ++ ++out_dir: ++ dbgaufs_si_fin(sbinfo); ++out: ++ if (unlikely(err)) ++ pr_err("debugfs/aufs failed\n"); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void dbgaufs_fin(void) ++{ ++ debugfs_remove(dbgaufs); ++} ++ ++int __init dbgaufs_init(void) ++{ ++ int err; ++ ++ err = -EIO; ++ dbgaufs = debugfs_create_dir(AUFS_NAME, NULL); ++ if (dbgaufs) ++ err = 0; ++ return err; ++} +diff --git a/fs/aufs/dbgaufs.h b/fs/aufs/dbgaufs.h +new file mode 100644 +index 000000000000..ad26624a9345 +--- /dev/null ++++ b/fs/aufs/dbgaufs.h +@@ -0,0 +1,40 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2020 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..000854da9075 +--- /dev/null ++++ b/fs/aufs/dcsub.c +@@ -0,0 +1,212 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * sub-routines for dentry cache ++ */ ++ ++#include "aufs.h" ++ ++static void au_dpage_free(struct au_dpage *dpage) ++{ ++ int i; ++ struct dentry **p; ++ ++ p = dpage->dentries; ++ for (i = 0; i < dpage->ndentry; i++) ++ dput(*p++); ++ free_page((unsigned long)dpage->dentries); ++} ++ ++int au_dpages_init(struct au_dcsub_pages *dpages, gfp_t gfp) ++{ ++ int err; ++ void *p; ++ ++ err = -ENOMEM; ++ dpages->dpages = kmalloc(sizeof(*dpages->dpages), gfp); ++ if (unlikely(!dpages->dpages)) ++ goto out; ++ ++ p = (void *)__get_free_page(gfp); ++ if (unlikely(!p)) ++ goto out_dpages; ++ ++ dpages->dpages[0].ndentry = 0; ++ dpages->dpages[0].dentries = p; ++ dpages->ndpage = 1; ++ return 0; /* success */ ++ ++out_dpages: ++ au_kfree_try_rcu(dpages->dpages); ++out: ++ return err; ++} ++ ++void au_dpages_free(struct au_dcsub_pages *dpages) ++{ ++ int i; ++ struct au_dpage *p; ++ ++ p = dpages->dpages; ++ for (i = 0; i < dpages->ndpage; i++) ++ au_dpage_free(p++); ++ au_kfree_try_rcu(dpages->dpages); ++} ++ ++static int au_dpages_append(struct au_dcsub_pages *dpages, ++ struct dentry *dentry, gfp_t gfp) ++{ ++ int err, sz; ++ struct au_dpage *dpage; ++ void *p; ++ ++ dpage = dpages->dpages + dpages->ndpage - 1; ++ sz = PAGE_SIZE / sizeof(dentry); ++ if (unlikely(dpage->ndentry >= sz)) { ++ AuLabel(new dpage); ++ err = -ENOMEM; ++ sz = dpages->ndpage * sizeof(*dpages->dpages); ++ p = au_kzrealloc(dpages->dpages, sz, ++ sz + sizeof(*dpages->dpages), gfp, ++ /*may_shrink*/0); ++ if (unlikely(!p)) ++ goto out; ++ ++ dpages->dpages = p; ++ dpage = dpages->dpages + dpages->ndpage; ++ p = (void *)__get_free_page(gfp); ++ if (unlikely(!p)) ++ goto out; ++ ++ dpage->ndentry = 0; ++ dpage->dentries = p; ++ dpages->ndpage++; ++ } ++ ++ AuDebugOn(au_dcount(dentry) <= 0); ++ dpage->dentries[dpage->ndentry++] = dget_dlock(dentry); ++ return 0; /* success */ ++ ++out: ++ return err; ++} ++ ++/* todo: BAD approach */ ++/* copied from linux/fs/dcache.c */ ++enum d_walk_ret { ++ D_WALK_CONTINUE, ++ D_WALK_QUIT, ++ D_WALK_NORETRY, ++ D_WALK_SKIP, ++}; ++ ++extern void d_walk(struct dentry *parent, void *data, ++ enum d_walk_ret (*enter)(void *, struct dentry *)); ++ ++struct ac_dpages_arg { ++ int err; ++ struct au_dcsub_pages *dpages; ++ struct super_block *sb; ++ au_dpages_test test; ++ void *arg; ++}; ++ ++static enum d_walk_ret au_call_dpages_append(void *_arg, struct dentry *dentry) ++{ ++ enum d_walk_ret ret; ++ struct ac_dpages_arg *arg = _arg; ++ ++ ret = D_WALK_CONTINUE; ++ if (dentry->d_sb == arg->sb ++ && !IS_ROOT(dentry) ++ && au_dcount(dentry) > 0 ++ && au_di(dentry) ++ && (!arg->test || arg->test(dentry, arg->arg))) { ++ arg->err = au_dpages_append(arg->dpages, dentry, GFP_ATOMIC); ++ if (unlikely(arg->err)) ++ ret = D_WALK_QUIT; ++ } ++ ++ return ret; ++} ++ ++int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root, ++ au_dpages_test test, void *arg) ++{ ++ struct ac_dpages_arg args = { ++ .err = 0, ++ .dpages = dpages, ++ .sb = root->d_sb, ++ .test = test, ++ .arg = arg ++ }; ++ ++ d_walk(root, &args, au_call_dpages_append); ++ ++ return args.err; ++} ++ ++int au_dcsub_pages_rev(struct au_dcsub_pages *dpages, struct dentry *dentry, ++ int do_include, au_dpages_test test, void *arg) ++{ ++ int err; ++ ++ err = 0; ++ write_seqlock(&rename_lock); ++ spin_lock(&dentry->d_lock); ++ if (do_include ++ && au_dcount(dentry) > 0 ++ && (!test || test(dentry, arg))) ++ err = au_dpages_append(dpages, dentry, GFP_ATOMIC); ++ spin_unlock(&dentry->d_lock); ++ if (unlikely(err)) ++ goto out; ++ ++ /* ++ * RCU for vfsmount is unnecessary since this is a traverse in a single ++ * mount ++ */ ++ while (!IS_ROOT(dentry)) { ++ dentry = dentry->d_parent; /* rename_lock is locked */ ++ spin_lock(&dentry->d_lock); ++ if (au_dcount(dentry) > 0 ++ && (!test || test(dentry, arg))) ++ err = au_dpages_append(dpages, dentry, GFP_ATOMIC); ++ spin_unlock(&dentry->d_lock); ++ if (unlikely(err)) ++ break; ++ } ++ ++out: ++ write_sequnlock(&rename_lock); ++ return err; ++} ++ ++static inline int au_dcsub_dpages_aufs(struct dentry *dentry, void *arg) ++{ ++ return au_di(dentry) && dentry->d_sb == arg; ++} ++ ++int au_dcsub_pages_rev_aufs(struct au_dcsub_pages *dpages, ++ struct dentry *dentry, int do_include) ++{ ++ return au_dcsub_pages_rev(dpages, dentry, do_include, ++ au_dcsub_dpages_aufs, dentry->d_sb); ++} ++ ++int au_test_subdir(struct dentry *d1, struct dentry *d2) ++{ ++ struct path path[2] = { ++ { ++ .dentry = d1 ++ }, ++ { ++ .dentry = d2 ++ } ++ }; ++ ++ return path_is_under(path + 0, path + 1); ++} +diff --git a/fs/aufs/dcsub.h b/fs/aufs/dcsub.h +new file mode 100644 +index 000000000000..9d207c2b4666 +--- /dev/null ++++ b/fs/aufs/dcsub.h +@@ -0,0 +1,124 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2020 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..fd0ba9d15742 +--- /dev/null ++++ b/fs/aufs/debug.c +@@ -0,0 +1,428 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * debug print functions ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* Returns 0, or -errno. arg is in kp->arg. */ ++static int param_atomic_t_set(const char *val, const struct kernel_param *kp) ++{ ++ int err, n; ++ ++ err = kstrtoint(val, 0, &n); ++ if (!err) { ++ if (n > 0) ++ au_debug_on(); ++ else ++ au_debug_off(); ++ } ++ return err; ++} ++ ++/* Returns length written or -errno. Buffer is 4k (ie. be short!) */ ++static int param_atomic_t_get(char *buffer, const struct kernel_param *kp) ++{ ++ atomic_t *a; ++ ++ a = kp->arg; ++ return sprintf(buffer, "%d", atomic_read(a)); ++} ++ ++static struct kernel_param_ops param_ops_atomic_t = { ++ .set = param_atomic_t_set, ++ .get = param_atomic_t_get ++ /* void (*free)(void *arg) */ ++}; ++ ++atomic_t aufs_debug = ATOMIC_INIT(0); ++MODULE_PARM_DESC(debug, "debug print"); ++module_param_named(debug, aufs_debug, atomic_t, 0664); ++ ++DEFINE_MUTEX(au_dbg_mtx); /* just to serialize the dbg msgs */ ++char *au_plevel = KERN_DEBUG; ++#define dpri(fmt, ...) do { \ ++ if ((au_plevel \ ++ && strcmp(au_plevel, KERN_DEBUG)) \ ++ || au_debug_test()) \ ++ printk("%s" fmt, au_plevel, ##__VA_ARGS__); \ ++} while (0) ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_dpri_whlist(struct au_nhash *whlist) ++{ ++ unsigned long ul, n; ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ ++ n = whlist->nh_num; ++ head = whlist->nh_head; ++ for (ul = 0; ul < n; ul++) { ++ hlist_for_each_entry(pos, head, wh_hash) ++ dpri("b%d, %.*s, %d\n", ++ pos->wh_bindex, ++ pos->wh_str.len, pos->wh_str.name, ++ pos->wh_str.len); ++ head++; ++ } ++} ++ ++void au_dpri_vdir(struct au_vdir *vdir) ++{ ++ unsigned long ul; ++ union au_vdir_deblk_p p; ++ unsigned char *o; ++ ++ if (!vdir || IS_ERR(vdir)) { ++ dpri("err %ld\n", PTR_ERR(vdir)); ++ return; ++ } ++ ++ dpri("deblk %u, nblk %lu, deblk %p, last{%lu, %p}, ver %llu\n", ++ vdir->vd_deblk_sz, vdir->vd_nblk, vdir->vd_deblk, ++ vdir->vd_last.ul, vdir->vd_last.p.deblk, vdir->vd_version); ++ for (ul = 0; ul < vdir->vd_nblk; ul++) { ++ p.deblk = vdir->vd_deblk[ul]; ++ o = p.deblk; ++ dpri("[%lu]: %p\n", ul, o); ++ } ++} ++ ++static int do_pri_inode(aufs_bindex_t bindex, struct inode *inode, int hn, ++ struct dentry *wh) ++{ ++ char *n = NULL; ++ int l = 0; ++ ++ if (!inode || IS_ERR(inode)) { ++ dpri("i%d: err %ld\n", bindex, PTR_ERR(inode)); ++ return -1; ++ } ++ ++ /* the type of i_blocks depends upon CONFIG_LBDAF */ ++ BUILD_BUG_ON(sizeof(inode->i_blocks) != sizeof(unsigned long) ++ && sizeof(inode->i_blocks) != sizeof(u64)); ++ if (wh) { ++ n = (void *)wh->d_name.name; ++ l = wh->d_name.len; ++ } ++ ++ dpri("i%d: %p, i%lu, %s, cnt %d, nl %u, 0%o, sz %llu, blk %llu," ++ " hn %d, ct %lld, np %lu, st 0x%lx, f 0x%x, v %llu, g %x%s%.*s\n", ++ bindex, inode, ++ inode->i_ino, inode->i_sb ? au_sbtype(inode->i_sb) : "??", ++ atomic_read(&inode->i_count), inode->i_nlink, inode->i_mode, ++ i_size_read(inode), (unsigned long long)inode->i_blocks, ++ hn, (long long)timespec64_to_ns(&inode->i_ctime) & 0x0ffff, ++ inode->i_mapping ? inode->i_mapping->nrpages : 0, ++ inode->i_state, inode->i_flags, inode_peek_iversion(inode), ++ inode->i_generation, ++ l ? ", wh " : "", l, n); ++ return 0; ++} ++ ++void au_dpri_inode(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct au_hinode *hi; ++ aufs_bindex_t bindex; ++ int err, hn; ++ ++ err = do_pri_inode(-1, inode, -1, NULL); ++ if (err || !au_test_aufs(inode->i_sb) || au_is_bad_inode(inode)) ++ return; ++ ++ iinfo = au_ii(inode); ++ dpri("i-1: btop %d, bbot %d, gen %d\n", ++ iinfo->ii_btop, iinfo->ii_bbot, au_iigen(inode, NULL)); ++ if (iinfo->ii_btop < 0) ++ return; ++ hn = 0; ++ for (bindex = iinfo->ii_btop; bindex <= iinfo->ii_bbot; bindex++) { ++ hi = au_hinode(iinfo, bindex); ++ hn = !!au_hn(hi); ++ do_pri_inode(bindex, hi->hi_inode, hn, hi->hi_whdentry); ++ } ++} ++ ++void au_dpri_dalias(struct inode *inode) ++{ ++ struct dentry *d; ++ ++ spin_lock(&inode->i_lock); ++ hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias) ++ au_dpri_dentry(d); ++ spin_unlock(&inode->i_lock); ++} ++ ++static int do_pri_dentry(aufs_bindex_t bindex, struct dentry *dentry) ++{ ++ struct dentry *wh = NULL; ++ int hn; ++ struct inode *inode; ++ struct au_iinfo *iinfo; ++ struct au_hinode *hi; ++ ++ if (!dentry || IS_ERR(dentry)) { ++ dpri("d%d: err %ld\n", bindex, PTR_ERR(dentry)); ++ return -1; ++ } ++ /* do not call dget_parent() here */ ++ /* note: access d_xxx without d_lock */ ++ dpri("d%d: %p, %pd2?, %s, cnt %d, flags 0x%x, %shashed\n", ++ bindex, dentry, dentry, ++ dentry->d_sb ? au_sbtype(dentry->d_sb) : "??", ++ au_dcount(dentry), dentry->d_flags, ++ d_unhashed(dentry) ? "un" : ""); ++ hn = -1; ++ inode = NULL; ++ if (d_is_positive(dentry)) ++ inode = d_inode(dentry); ++ if (inode ++ && au_test_aufs(dentry->d_sb) ++ && bindex >= 0 ++ && !au_is_bad_inode(inode)) { ++ iinfo = au_ii(inode); ++ hi = au_hinode(iinfo, bindex); ++ hn = !!au_hn(hi); ++ wh = hi->hi_whdentry; ++ } ++ do_pri_inode(bindex, inode, hn, wh); ++ return 0; ++} ++ ++void au_dpri_dentry(struct dentry *dentry) ++{ ++ struct au_dinfo *dinfo; ++ aufs_bindex_t bindex; ++ int err; ++ ++ err = do_pri_dentry(-1, dentry); ++ if (err || !au_test_aufs(dentry->d_sb)) ++ return; ++ ++ dinfo = au_di(dentry); ++ if (!dinfo) ++ return; ++ dpri("d-1: btop %d, bbot %d, bwh %d, bdiropq %d, gen %d, tmp %d\n", ++ dinfo->di_btop, dinfo->di_bbot, ++ dinfo->di_bwh, dinfo->di_bdiropq, au_digen(dentry), ++ dinfo->di_tmpfile); ++ if (dinfo->di_btop < 0) ++ return; ++ for (bindex = dinfo->di_btop; bindex <= dinfo->di_bbot; bindex++) ++ do_pri_dentry(bindex, au_hdentry(dinfo, bindex)->hd_dentry); ++} ++ ++static int do_pri_file(aufs_bindex_t bindex, struct file *file) ++{ ++ char a[32]; ++ ++ if (!file || IS_ERR(file)) { ++ dpri("f%d: err %ld\n", bindex, PTR_ERR(file)); ++ return -1; ++ } ++ a[0] = 0; ++ if (bindex < 0 ++ && !IS_ERR_OR_NULL(file->f_path.dentry) ++ && au_test_aufs(file->f_path.dentry->d_sb) ++ && au_fi(file)) ++ snprintf(a, sizeof(a), ", gen %d, mmapped %d", ++ au_figen(file), atomic_read(&au_fi(file)->fi_mmapped)); ++ dpri("f%d: mode 0x%x, flags 0%o, cnt %ld, v %llu, pos %llu%s\n", ++ bindex, file->f_mode, file->f_flags, (long)file_count(file), ++ file->f_version, file->f_pos, a); ++ if (!IS_ERR_OR_NULL(file->f_path.dentry)) ++ do_pri_dentry(bindex, file->f_path.dentry); ++ return 0; ++} ++ ++void au_dpri_file(struct file *file) ++{ ++ struct au_finfo *finfo; ++ struct au_fidir *fidir; ++ struct au_hfile *hfile; ++ aufs_bindex_t bindex; ++ int err; ++ ++ err = do_pri_file(-1, file); ++ if (err ++ || IS_ERR_OR_NULL(file->f_path.dentry) ++ || !au_test_aufs(file->f_path.dentry->d_sb)) ++ return; ++ ++ finfo = au_fi(file); ++ if (!finfo) ++ return; ++ if (finfo->fi_btop < 0) ++ return; ++ fidir = finfo->fi_hdir; ++ if (!fidir) ++ do_pri_file(finfo->fi_btop, finfo->fi_htop.hf_file); ++ else ++ for (bindex = finfo->fi_btop; ++ bindex >= 0 && bindex <= fidir->fd_bbot; ++ bindex++) { ++ hfile = fidir->fd_hfile + bindex; ++ do_pri_file(bindex, hfile ? hfile->hf_file : NULL); ++ } ++} ++ ++static int do_pri_br(aufs_bindex_t bindex, struct au_branch *br) ++{ ++ struct vfsmount *mnt; ++ struct super_block *sb; ++ ++ if (!br || IS_ERR(br)) ++ goto out; ++ mnt = au_br_mnt(br); ++ if (!mnt || IS_ERR(mnt)) ++ goto out; ++ sb = mnt->mnt_sb; ++ if (!sb || IS_ERR(sb)) ++ goto out; ++ ++ dpri("s%d: {perm 0x%x, id %d, wbr %p}, " ++ "%s, dev 0x%02x%02x, flags 0x%lx, cnt %d, active %d, " ++ "xino %d\n", ++ bindex, br->br_perm, br->br_id, br->br_wbr, ++ au_sbtype(sb), MAJOR(sb->s_dev), MINOR(sb->s_dev), ++ sb->s_flags, sb->s_count, ++ atomic_read(&sb->s_active), ++ !!au_xino_file(br->br_xino, /*idx*/-1)); ++ return 0; ++ ++out: ++ dpri("s%d: err %ld\n", bindex, PTR_ERR(br)); ++ return -1; ++} ++ ++void au_dpri_sb(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ aufs_bindex_t bindex; ++ int err; ++ /* to reduce stack size */ ++ struct { ++ struct vfsmount mnt; ++ struct au_branch fake; ++ } *a; ++ ++ /* this function can be called from magic sysrq */ ++ a = kzalloc(sizeof(*a), GFP_ATOMIC); ++ if (unlikely(!a)) { ++ dpri("no memory\n"); ++ return; ++ } ++ ++ a->mnt.mnt_sb = sb; ++ a->fake.br_path.mnt = &a->mnt; ++ err = do_pri_br(-1, &a->fake); ++ au_kfree_rcu(a); ++ dpri("dev 0x%x\n", sb->s_dev); ++ if (err || !au_test_aufs(sb)) ++ return; ++ ++ sbinfo = au_sbi(sb); ++ if (!sbinfo) ++ return; ++ dpri("nw %d, gen %u, kobj %d\n", ++ atomic_read(&sbinfo->si_nowait.nw_len), sbinfo->si_generation, ++ kref_read(&sbinfo->si_kobj.kref)); ++ for (bindex = 0; bindex <= sbinfo->si_bbot; bindex++) ++ do_pri_br(bindex, sbinfo->si_branch[0 + bindex]); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void __au_dbg_verify_dinode(struct dentry *dentry, const char *func, int line) ++{ ++ struct inode *h_inode, *inode = d_inode(dentry); ++ struct dentry *h_dentry; ++ aufs_bindex_t bindex, bbot, bi; ++ ++ if (!inode /* || au_di(dentry)->di_lsc == AuLsc_DI_TMP */) ++ return; ++ ++ bbot = au_dbbot(dentry); ++ bi = au_ibbot(inode); ++ if (bi < bbot) ++ bbot = bi; ++ bindex = au_dbtop(dentry); ++ bi = au_ibtop(inode); ++ if (bi > bindex) ++ bindex = bi; ++ ++ for (; bindex <= bbot; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ h_inode = au_h_iptr(inode, bindex); ++ if (unlikely(h_inode != d_inode(h_dentry))) { ++ au_debug_on(); ++ AuDbg("b%d, %s:%d\n", bindex, func, line); ++ AuDbgDentry(dentry); ++ AuDbgInode(inode); ++ au_debug_off(); ++ BUG(); ++ } ++ } ++} ++ ++void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen) ++{ ++ int err, i, j; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ AuDebugOn(err); ++ err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/1); ++ AuDebugOn(err); ++ for (i = dpages.ndpage - 1; !err && i >= 0; i--) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ for (j = dpage->ndentry - 1; !err && j >= 0; j--) ++ AuDebugOn(au_digen_test(dentries[j], sigen)); ++ } ++ au_dpages_free(&dpages); ++} ++ ++void au_dbg_verify_kthread(void) ++{ ++ if (au_wkq_test()) { ++ au_dbg_blocked(); ++ /* ++ * It may be recursive, but udba=notify between two aufs mounts, ++ * where a single ro branch is shared, is not a problem. ++ */ ++ /* WARN_ON(1); */ ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int __init au_debug_init(void) ++{ ++ aufs_bindex_t bindex; ++ struct au_vdir_destr destr; ++ ++ bindex = -1; ++ AuDebugOn(bindex >= 0); ++ ++ destr.len = -1; ++ AuDebugOn(destr.len < NAME_MAX); ++ ++#ifdef CONFIG_4KSTACKS ++ pr_warn("CONFIG_4KSTACKS is defined.\n"); ++#endif ++ ++ return 0; ++} +diff --git a/fs/aufs/debug.h b/fs/aufs/debug.h +new file mode 100644 +index 000000000000..5799794de0c2 +--- /dev/null ++++ b/fs/aufs/debug.h +@@ -0,0 +1,213 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2020 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..1a029193315a +--- /dev/null ++++ b/fs/aufs/dentry.c +@@ -0,0 +1,1141 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * lookup and dentry operations ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++/* ++ * returns positive/negative dentry, NULL or an error. ++ * NULL means whiteout-ed or not-found. ++ */ ++static struct dentry* ++au_do_lookup(struct dentry *h_parent, struct dentry *dentry, ++ aufs_bindex_t bindex, struct au_do_lookup_args *args) ++{ ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct au_branch *br; ++ int wh_found, opq; ++ unsigned char wh_able; ++ const unsigned char allow_neg = !!au_ftest_lkup(args->flags, ALLOW_NEG); ++ const unsigned char ignore_perm = !!au_ftest_lkup(args->flags, ++ IGNORE_PERM); ++ ++ wh_found = 0; ++ br = au_sbr(dentry->d_sb, bindex); ++ wh_able = !!au_br_whable(br->br_perm); ++ if (wh_able) ++ wh_found = au_wh_test(h_parent, &args->whname, ignore_perm); ++ h_dentry = ERR_PTR(wh_found); ++ if (!wh_found) ++ goto real_lookup; ++ if (unlikely(wh_found < 0)) ++ goto out; ++ ++ /* We found a whiteout */ ++ /* au_set_dbbot(dentry, bindex); */ ++ au_set_dbwh(dentry, bindex); ++ if (!allow_neg) ++ return NULL; /* success */ ++ ++real_lookup: ++ if (!ignore_perm) ++ h_dentry = vfsub_lkup_one(args->name, h_parent); ++ else ++ h_dentry = au_sio_lkup_one(args->name, h_parent); ++ if (IS_ERR(h_dentry)) { ++ if (PTR_ERR(h_dentry) == -ENAMETOOLONG ++ && !allow_neg) ++ h_dentry = NULL; ++ goto out; ++ } ++ ++ h_inode = d_inode(h_dentry); ++ if (d_is_negative(h_dentry)) { ++ if (!allow_neg) ++ goto out_neg; ++ } else if (wh_found ++ || (args->type && args->type != (h_inode->i_mode & S_IFMT))) ++ goto out_neg; ++ else if (au_ftest_lkup(args->flags, DIRREN) ++ /* && h_inode */ ++ && !au_dr_lkup_h_ino(args, bindex, h_inode->i_ino)) { ++ AuDbg("b%d %pd ignored hi%llu\n", bindex, h_dentry, ++ (unsigned long long)h_inode->i_ino); ++ goto out_neg; ++ } ++ ++ if (au_dbbot(dentry) <= bindex) ++ au_set_dbbot(dentry, bindex); ++ if (au_dbtop(dentry) < 0 || bindex < au_dbtop(dentry)) ++ au_set_dbtop(dentry, bindex); ++ au_set_h_dptr(dentry, bindex, h_dentry); ++ ++ if (!d_is_dir(h_dentry) ++ || !wh_able ++ || (d_really_is_positive(dentry) && !d_is_dir(dentry))) ++ goto out; /* success */ ++ ++ inode_lock_shared_nested(h_inode, AuLsc_I_CHILD); ++ opq = au_diropq_test(h_dentry); ++ inode_unlock_shared(h_inode); ++ if (opq > 0) ++ au_set_dbdiropq(dentry, bindex); ++ else if (unlikely(opq < 0)) { ++ au_set_h_dptr(dentry, bindex, NULL); ++ h_dentry = ERR_PTR(opq); ++ } ++ goto out; ++ ++out_neg: ++ dput(h_dentry); ++ h_dentry = NULL; ++out: ++ return h_dentry; ++} ++ ++static int au_test_shwh(struct super_block *sb, const struct qstr *name) ++{ ++ if (unlikely(!au_opt_test(au_mntflags(sb), SHWH) ++ && !strncmp(name->name, AUFS_WH_PFX, AUFS_WH_PFX_LEN))) ++ return -EPERM; ++ return 0; ++} ++ ++/* ++ * returns the number of lower positive dentries, ++ * otherwise an error. ++ * can be called at unlinking with @type is zero. ++ */ ++int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t btop, ++ unsigned int flags) ++{ ++ int npositive, err; ++ aufs_bindex_t bindex, btail, bdiropq; ++ unsigned char isdir, dirperm1, dirren; ++ struct au_do_lookup_args args = { ++ .flags = flags, ++ .name = &dentry->d_name ++ }; ++ struct dentry *parent; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ err = au_test_shwh(sb, args.name); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_wh_name_alloc(&args.whname, args.name); ++ if (unlikely(err)) ++ goto out; ++ ++ isdir = !!d_is_dir(dentry); ++ dirperm1 = !!au_opt_test(au_mntflags(sb), DIRPERM1); ++ dirren = !!au_opt_test(au_mntflags(sb), DIRREN); ++ if (dirren) ++ au_fset_lkup(args.flags, DIRREN); ++ ++ npositive = 0; ++ parent = dget_parent(dentry); ++ btail = au_dbtaildir(parent); ++ for (bindex = btop; bindex <= btail; bindex++) { ++ struct dentry *h_parent, *h_dentry; ++ struct inode *h_inode, *h_dir; ++ struct au_branch *br; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry) { ++ if (d_is_positive(h_dentry)) ++ npositive++; ++ break; ++ } ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || !d_is_dir(h_parent)) ++ continue; ++ ++ if (dirren) { ++ /* if the inum matches, then use the prepared name */ ++ err = au_dr_lkup_name(&args, bindex); ++ if (unlikely(err)) ++ goto out_parent; ++ } ++ ++ h_dir = d_inode(h_parent); ++ inode_lock_shared_nested(h_dir, AuLsc_I_PARENT); ++ h_dentry = au_do_lookup(h_parent, dentry, bindex, &args); ++ inode_unlock_shared(h_dir); ++ err = PTR_ERR(h_dentry); ++ if (IS_ERR(h_dentry)) ++ goto out_parent; ++ if (h_dentry) ++ au_fclr_lkup(args.flags, ALLOW_NEG); ++ if (dirperm1) ++ au_fset_lkup(args.flags, IGNORE_PERM); ++ ++ if (au_dbwh(dentry) == bindex) ++ break; ++ if (!h_dentry) ++ continue; ++ if (d_is_negative(h_dentry)) ++ continue; ++ h_inode = d_inode(h_dentry); ++ npositive++; ++ if (!args.type) ++ args.type = h_inode->i_mode & S_IFMT; ++ if (args.type != S_IFDIR) ++ break; ++ else if (isdir) { ++ /* the type of lower may be different */ ++ bdiropq = au_dbdiropq(dentry); ++ if (bdiropq >= 0 && bdiropq <= bindex) ++ break; ++ } ++ br = au_sbr(sb, bindex); ++ if (dirren ++ && au_dr_hino_test_add(&br->br_dirren, h_inode->i_ino, ++ /*add_ent*/NULL)) { ++ /* prepare next name to lookup */ ++ err = au_dr_lkup(&args, dentry, bindex); ++ if (unlikely(err)) ++ goto out_parent; ++ } ++ } ++ ++ if (npositive) { ++ AuLabel(positive); ++ au_update_dbtop(dentry); ++ } ++ err = npositive; ++ if (unlikely(!au_opt_test(au_mntflags(sb), UDBA_NONE) ++ && au_dbtop(dentry) < 0)) { ++ err = -EIO; ++ AuIOErr("both of real entry and whiteout found, %pd, err %d\n", ++ dentry, err); ++ } ++ ++out_parent: ++ dput(parent); ++ au_kfree_try_rcu(args.whname.name); ++ if (dirren) ++ au_dr_lkup_fin(&args); ++out: ++ return err; ++} ++ ++struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent) ++{ ++ struct dentry *dentry; ++ int wkq_err; ++ ++ if (!au_test_h_perm_sio(d_inode(parent), MAY_EXEC)) ++ dentry = vfsub_lkup_one(name, parent); ++ else { ++ struct vfsub_lkup_one_args args = { ++ .errp = &dentry, ++ .name = name, ++ .parent = parent ++ }; ++ ++ wkq_err = au_wkq_wait(vfsub_call_lkup_one, &args); ++ if (unlikely(wkq_err)) ++ dentry = ERR_PTR(wkq_err); ++ } ++ ++ return dentry; ++} ++ ++/* ++ * lookup @dentry on @bindex which should be negative. ++ */ ++int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex, int wh) ++{ ++ int err; ++ struct dentry *parent, *h_parent, *h_dentry; ++ struct au_branch *br; ++ ++ parent = dget_parent(dentry); ++ h_parent = au_h_dptr(parent, bindex); ++ br = au_sbr(dentry->d_sb, bindex); ++ if (wh) ++ h_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name); ++ else ++ h_dentry = au_sio_lkup_one(&dentry->d_name, h_parent); ++ err = PTR_ERR(h_dentry); ++ if (IS_ERR(h_dentry)) ++ goto out; ++ if (unlikely(d_is_positive(h_dentry))) { ++ err = -EIO; ++ AuIOErr("%pd should be negative on b%d.\n", h_dentry, bindex); ++ dput(h_dentry); ++ goto out; ++ } ++ ++ err = 0; ++ if (bindex < au_dbtop(dentry)) ++ au_set_dbtop(dentry, bindex); ++ if (au_dbbot(dentry) < bindex) ++ au_set_dbbot(dentry, bindex); ++ au_set_h_dptr(dentry, bindex, h_dentry); ++ ++out: ++ dput(parent); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* subset of struct inode */ ++struct au_iattr { ++ unsigned long i_ino; ++ /* unsigned int i_nlink; */ ++ kuid_t i_uid; ++ kgid_t i_gid; ++ u64 i_version; ++/* ++ loff_t i_size; ++ blkcnt_t i_blocks; ++*/ ++ umode_t i_mode; ++}; ++ ++static void au_iattr_save(struct au_iattr *ia, struct inode *h_inode) ++{ ++ ia->i_ino = h_inode->i_ino; ++ /* ia->i_nlink = h_inode->i_nlink; */ ++ ia->i_uid = h_inode->i_uid; ++ ia->i_gid = h_inode->i_gid; ++ ia->i_version = inode_query_iversion(h_inode); ++/* ++ ia->i_size = h_inode->i_size; ++ ia->i_blocks = h_inode->i_blocks; ++*/ ++ ia->i_mode = (h_inode->i_mode & S_IFMT); ++} ++ ++static int au_iattr_test(struct au_iattr *ia, struct inode *h_inode) ++{ ++ return ia->i_ino != h_inode->i_ino ++ /* || ia->i_nlink != h_inode->i_nlink */ ++ || !uid_eq(ia->i_uid, h_inode->i_uid) ++ || !gid_eq(ia->i_gid, h_inode->i_gid) ++ || !inode_eq_iversion(h_inode, ia->i_version) ++/* ++ || ia->i_size != h_inode->i_size ++ || ia->i_blocks != h_inode->i_blocks ++*/ ++ || ia->i_mode != (h_inode->i_mode & S_IFMT); ++} ++ ++static int au_h_verify_dentry(struct dentry *h_dentry, struct dentry *h_parent, ++ struct au_branch *br) ++{ ++ int err; ++ struct au_iattr ia; ++ struct inode *h_inode; ++ struct dentry *h_d; ++ struct super_block *h_sb; ++ ++ err = 0; ++ memset(&ia, -1, sizeof(ia)); ++ h_sb = h_dentry->d_sb; ++ h_inode = NULL; ++ if (d_is_positive(h_dentry)) { ++ h_inode = d_inode(h_dentry); ++ au_iattr_save(&ia, h_inode); ++ } else if (au_test_nfs(h_sb) || au_test_fuse(h_sb)) ++ /* nfs d_revalidate may return 0 for negative dentry */ ++ /* fuse d_revalidate always return 0 for negative dentry */ ++ goto out; ++ ++ /* main purpose is namei.c:cached_lookup() and d_revalidate */ ++ h_d = vfsub_lkup_one(&h_dentry->d_name, h_parent); ++ err = PTR_ERR(h_d); ++ if (IS_ERR(h_d)) ++ goto out; ++ ++ err = 0; ++ if (unlikely(h_d != h_dentry ++ || d_inode(h_d) != h_inode ++ || (h_inode && au_iattr_test(&ia, h_inode)))) ++ err = au_busy_or_stale(); ++ dput(h_d); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir, ++ struct dentry *h_parent, struct au_branch *br) ++{ ++ int err; ++ ++ err = 0; ++ if (udba == AuOpt_UDBA_REVAL ++ && !au_test_fs_remote(h_dentry->d_sb)) { ++ IMustLock(h_dir); ++ err = (d_inode(h_dentry->d_parent) != h_dir); ++ } else if (udba != AuOpt_UDBA_NONE) ++ err = au_h_verify_dentry(h_dentry, h_parent, br); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_refresh_hdentry(struct dentry *dentry, struct dentry *parent) ++{ ++ int err; ++ aufs_bindex_t new_bindex, bindex, bbot, bwh, bdiropq; ++ struct au_hdentry tmp, *p, *q; ++ struct au_dinfo *dinfo; ++ struct super_block *sb; ++ ++ DiMustWriteLock(dentry); ++ ++ sb = dentry->d_sb; ++ dinfo = au_di(dentry); ++ bbot = dinfo->di_bbot; ++ bwh = dinfo->di_bwh; ++ bdiropq = dinfo->di_bdiropq; ++ bindex = dinfo->di_btop; ++ p = au_hdentry(dinfo, bindex); ++ for (; bindex <= bbot; bindex++, p++) { ++ if (!p->hd_dentry) ++ continue; ++ ++ new_bindex = au_br_index(sb, p->hd_id); ++ if (new_bindex == bindex) ++ continue; ++ ++ if (dinfo->di_bwh == bindex) ++ bwh = new_bindex; ++ if (dinfo->di_bdiropq == bindex) ++ bdiropq = new_bindex; ++ if (new_bindex < 0) { ++ au_hdput(p); ++ p->hd_dentry = NULL; ++ continue; ++ } ++ ++ /* swap two lower dentries, and loop again */ ++ q = au_hdentry(dinfo, new_bindex); ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hd_dentry) { ++ bindex--; ++ p--; ++ } ++ } ++ ++ dinfo->di_bwh = -1; ++ if (bwh >= 0 && bwh <= au_sbbot(sb) && au_sbr_whable(sb, bwh)) ++ dinfo->di_bwh = bwh; ++ ++ dinfo->di_bdiropq = -1; ++ if (bdiropq >= 0 ++ && bdiropq <= au_sbbot(sb) ++ && au_sbr_whable(sb, bdiropq)) ++ dinfo->di_bdiropq = bdiropq; ++ ++ err = -EIO; ++ dinfo->di_btop = -1; ++ dinfo->di_bbot = -1; ++ bbot = au_dbbot(parent); ++ bindex = 0; ++ p = au_hdentry(dinfo, bindex); ++ for (; bindex <= bbot; bindex++, p++) ++ if (p->hd_dentry) { ++ dinfo->di_btop = bindex; ++ break; ++ } ++ ++ if (dinfo->di_btop >= 0) { ++ bindex = bbot; ++ p = au_hdentry(dinfo, bindex); ++ for (; bindex >= 0; bindex--, p--) ++ if (p->hd_dentry) { ++ dinfo->di_bbot = bindex; ++ err = 0; ++ break; ++ } ++ } ++ ++ return err; ++} ++ ++static void au_do_hide(struct dentry *dentry) ++{ ++ struct inode *inode; ++ ++ if (d_really_is_positive(dentry)) { ++ inode = d_inode(dentry); ++ if (!d_is_dir(dentry)) { ++ if (inode->i_nlink && !d_unhashed(dentry)) ++ drop_nlink(inode); ++ } else { ++ clear_nlink(inode); ++ /* stop next lookup */ ++ inode->i_flags |= S_DEAD; ++ } ++ smp_mb(); /* necessary? */ ++ } ++ d_drop(dentry); ++} ++ ++static int au_hide_children(struct dentry *parent) ++{ ++ int err, i, j, ndentry; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry *dentry; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, parent, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ /* in reverse order */ ++ for (i = dpages.ndpage - 1; i >= 0; i--) { ++ dpage = dpages.dpages + i; ++ ndentry = dpage->ndentry; ++ for (j = ndentry - 1; j >= 0; j--) { ++ dentry = dpage->dentries[j]; ++ if (dentry != parent) ++ au_do_hide(dentry); ++ } ++ } ++ ++out_dpages: ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++static void au_hide(struct dentry *dentry) ++{ ++ int err; ++ ++ AuDbgDentry(dentry); ++ if (d_is_dir(dentry)) { ++ /* shrink_dcache_parent(dentry); */ ++ err = au_hide_children(dentry); ++ if (unlikely(err)) ++ AuIOErr("%pd, failed hiding children, ignored %d\n", ++ dentry, err); ++ } ++ au_do_hide(dentry); ++} ++ ++/* ++ * By adding a dirty branch, a cached dentry may be affected in various ways. ++ * ++ * a dirty branch is added ++ * - on the top of layers ++ * - in the middle of layers ++ * - to the bottom of layers ++ * ++ * on the added branch there exists ++ * - a whiteout ++ * - a diropq ++ * - a same named entry ++ * + exist ++ * * negative --> positive ++ * * positive --> positive ++ * - type is unchanged ++ * - type is changed ++ * + doesn't exist ++ * * negative --> negative ++ * * positive --> negative (rejected by au_br_del() for non-dir case) ++ * - none ++ */ ++static int au_refresh_by_dinfo(struct dentry *dentry, struct au_dinfo *dinfo, ++ struct au_dinfo *tmp) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct { ++ struct dentry *dentry; ++ struct inode *inode; ++ mode_t mode; ++ } orig_h, tmp_h = { ++ .dentry = NULL ++ }; ++ struct au_hdentry *hd; ++ struct inode *inode, *h_inode; ++ struct dentry *h_dentry; ++ ++ err = 0; ++ AuDebugOn(dinfo->di_btop < 0); ++ orig_h.mode = 0; ++ orig_h.dentry = au_hdentry(dinfo, dinfo->di_btop)->hd_dentry; ++ orig_h.inode = NULL; ++ if (d_is_positive(orig_h.dentry)) { ++ orig_h.inode = d_inode(orig_h.dentry); ++ orig_h.mode = orig_h.inode->i_mode & S_IFMT; ++ } ++ if (tmp->di_btop >= 0) { ++ tmp_h.dentry = au_hdentry(tmp, tmp->di_btop)->hd_dentry; ++ if (d_is_positive(tmp_h.dentry)) { ++ tmp_h.inode = d_inode(tmp_h.dentry); ++ tmp_h.mode = tmp_h.inode->i_mode & S_IFMT; ++ } ++ } ++ ++ inode = NULL; ++ if (d_really_is_positive(dentry)) ++ inode = d_inode(dentry); ++ if (!orig_h.inode) { ++ AuDbg("negative originally\n"); ++ if (inode) { ++ au_hide(dentry); ++ goto out; ++ } ++ AuDebugOn(inode); ++ AuDebugOn(dinfo->di_btop != dinfo->di_bbot); ++ AuDebugOn(dinfo->di_bdiropq != -1); ++ ++ if (!tmp_h.inode) { ++ AuDbg("negative --> negative\n"); ++ /* should have only one negative lower */ ++ if (tmp->di_btop >= 0 ++ && tmp->di_btop < dinfo->di_btop) { ++ AuDebugOn(tmp->di_btop != tmp->di_bbot); ++ AuDebugOn(dinfo->di_btop != dinfo->di_bbot); ++ au_set_h_dptr(dentry, dinfo->di_btop, NULL); ++ au_di_cp(dinfo, tmp); ++ hd = au_hdentry(tmp, tmp->di_btop); ++ au_set_h_dptr(dentry, tmp->di_btop, ++ dget(hd->hd_dentry)); ++ } ++ au_dbg_verify_dinode(dentry); ++ } else { ++ AuDbg("negative --> positive\n"); ++ /* ++ * similar to the behaviour of creating with bypassing ++ * aufs. ++ * unhash it in order to force an error in the ++ * succeeding create operation. ++ * we should not set S_DEAD here. ++ */ ++ d_drop(dentry); ++ /* au_di_swap(tmp, dinfo); */ ++ au_dbg_verify_dinode(dentry); ++ } ++ } else { ++ AuDbg("positive originally\n"); ++ /* inode may be NULL */ ++ AuDebugOn(inode && (inode->i_mode & S_IFMT) != orig_h.mode); ++ if (!tmp_h.inode) { ++ AuDbg("positive --> negative\n"); ++ /* or bypassing aufs */ ++ au_hide(dentry); ++ if (tmp->di_bwh >= 0 && tmp->di_bwh <= dinfo->di_btop) ++ dinfo->di_bwh = tmp->di_bwh; ++ if (inode) ++ err = au_refresh_hinode_self(inode); ++ au_dbg_verify_dinode(dentry); ++ } else if (orig_h.mode == tmp_h.mode) { ++ AuDbg("positive --> positive, same type\n"); ++ if (!S_ISDIR(orig_h.mode) ++ && dinfo->di_btop > tmp->di_btop) { ++ /* ++ * similar to the behaviour of removing and ++ * creating. ++ */ ++ au_hide(dentry); ++ if (inode) ++ err = au_refresh_hinode_self(inode); ++ au_dbg_verify_dinode(dentry); ++ } else { ++ /* fill empty slots */ ++ if (dinfo->di_btop > tmp->di_btop) ++ dinfo->di_btop = tmp->di_btop; ++ if (dinfo->di_bbot < tmp->di_bbot) ++ dinfo->di_bbot = tmp->di_bbot; ++ dinfo->di_bwh = tmp->di_bwh; ++ dinfo->di_bdiropq = tmp->di_bdiropq; ++ bbot = dinfo->di_bbot; ++ bindex = tmp->di_btop; ++ hd = au_hdentry(tmp, bindex); ++ for (; bindex <= bbot; bindex++, hd++) { ++ if (au_h_dptr(dentry, bindex)) ++ continue; ++ h_dentry = hd->hd_dentry; ++ if (!h_dentry) ++ continue; ++ AuDebugOn(d_is_negative(h_dentry)); ++ h_inode = d_inode(h_dentry); ++ AuDebugOn(orig_h.mode ++ != (h_inode->i_mode ++ & S_IFMT)); ++ au_set_h_dptr(dentry, bindex, ++ dget(h_dentry)); ++ } ++ if (inode) ++ err = au_refresh_hinode(inode, dentry); ++ au_dbg_verify_dinode(dentry); ++ } ++ } else { ++ AuDbg("positive --> positive, different type\n"); ++ /* similar to the behaviour of removing and creating */ ++ au_hide(dentry); ++ if (inode) ++ err = au_refresh_hinode_self(inode); ++ au_dbg_verify_dinode(dentry); ++ } ++ } ++ ++out: ++ return err; ++} ++ ++void au_refresh_dop(struct dentry *dentry, int force_reval) ++{ ++ const struct dentry_operations *dop ++ = force_reval ? &aufs_dop : dentry->d_sb->s_d_op; ++ static const unsigned int mask ++ = DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE; ++ ++ BUILD_BUG_ON(sizeof(mask) != sizeof(dentry->d_flags)); ++ ++ if (dentry->d_op == dop) ++ return; ++ ++ AuDbg("%pd\n", dentry); ++ spin_lock(&dentry->d_lock); ++ if (dop == &aufs_dop) ++ dentry->d_flags |= mask; ++ else ++ dentry->d_flags &= ~mask; ++ dentry->d_op = dop; ++ spin_unlock(&dentry->d_lock); ++} ++ ++int au_refresh_dentry(struct dentry *dentry, struct dentry *parent) ++{ ++ int err, ebrange, nbr; ++ unsigned int sigen; ++ struct au_dinfo *dinfo, *tmp; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ DiMustWriteLock(dentry); ++ AuDebugOn(IS_ROOT(dentry)); ++ AuDebugOn(d_really_is_negative(parent)); ++ ++ sb = dentry->d_sb; ++ sigen = au_sigen(sb); ++ err = au_digen_test(parent, sigen); ++ if (unlikely(err)) ++ goto out; ++ ++ nbr = au_sbbot(sb) + 1; ++ dinfo = au_di(dentry); ++ err = au_di_realloc(dinfo, nbr, /*may_shrink*/0); ++ if (unlikely(err)) ++ goto out; ++ ebrange = au_dbrange_test(dentry); ++ if (!ebrange) ++ ebrange = au_do_refresh_hdentry(dentry, parent); ++ ++ if (d_unhashed(dentry) || ebrange /* || dinfo->di_tmpfile */) { ++ AuDebugOn(au_dbtop(dentry) < 0 && au_dbbot(dentry) >= 0); ++ if (d_really_is_positive(dentry)) { ++ inode = d_inode(dentry); ++ err = au_refresh_hinode_self(inode); ++ } ++ au_dbg_verify_dinode(dentry); ++ if (!err) ++ goto out_dgen; /* success */ ++ goto out; ++ } ++ ++ /* temporary dinfo */ ++ AuDbgDentry(dentry); ++ err = -ENOMEM; ++ tmp = au_di_alloc(sb, AuLsc_DI_TMP); ++ if (unlikely(!tmp)) ++ goto out; ++ au_di_swap(tmp, dinfo); ++ /* returns the number of positive dentries */ ++ /* ++ * if current working dir is removed, it returns an error. ++ * but the dentry is legal. ++ */ ++ err = au_lkup_dentry(dentry, /*btop*/0, AuLkup_ALLOW_NEG); ++ AuDbgDentry(dentry); ++ au_di_swap(tmp, dinfo); ++ if (err == -ENOENT) ++ err = 0; ++ if (err >= 0) { ++ /* compare/refresh by dinfo */ ++ AuDbgDentry(dentry); ++ err = au_refresh_by_dinfo(dentry, dinfo, tmp); ++ au_dbg_verify_dinode(dentry); ++ AuTraceErr(err); ++ } ++ au_di_realloc(dinfo, nbr, /*may_shrink*/1); /* harmless if err */ ++ au_rw_write_unlock(&tmp->di_rwsem); ++ au_di_free(tmp); ++ if (unlikely(err)) ++ goto out; ++ ++out_dgen: ++ au_update_digen(dentry); ++out: ++ if (unlikely(err && !(dentry->d_flags & DCACHE_NFSFS_RENAMED))) { ++ AuIOErr("failed refreshing %pd, %d\n", dentry, err); ++ AuDbgDentry(dentry); ++ } ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_do_h_d_reval(struct dentry *h_dentry, unsigned int flags, ++ struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ int err, valid; ++ ++ err = 0; ++ if (!(h_dentry->d_flags & DCACHE_OP_REVALIDATE)) ++ goto out; ++ ++ AuDbg("b%d\n", bindex); ++ /* ++ * gave up supporting LOOKUP_CREATE/OPEN for lower fs, ++ * due to whiteout and branch permission. ++ */ ++ flags &= ~(/*LOOKUP_PARENT |*/ LOOKUP_OPEN | LOOKUP_CREATE ++ | LOOKUP_FOLLOW | LOOKUP_EXCL); ++ /* it may return tri-state */ ++ valid = h_dentry->d_op->d_revalidate(h_dentry, flags); ++ ++ if (unlikely(valid < 0)) ++ err = valid; ++ else if (!valid) ++ err = -EINVAL; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* todo: remove this */ ++static int h_d_revalidate(struct dentry *dentry, struct inode *inode, ++ unsigned int flags, int do_udba, int dirren) ++{ ++ int err; ++ umode_t mode, h_mode; ++ aufs_bindex_t bindex, btail, btop, ibs, ibe; ++ unsigned char plus, unhashed, is_root, h_plus, h_nfs, tmpfile; ++ struct inode *h_inode, *h_cached_inode; ++ struct dentry *h_dentry; ++ struct qstr *name, *h_name; ++ ++ err = 0; ++ plus = 0; ++ mode = 0; ++ ibs = -1; ++ ibe = -1; ++ unhashed = !!d_unhashed(dentry); ++ is_root = !!IS_ROOT(dentry); ++ name = &dentry->d_name; ++ tmpfile = au_di(dentry)->di_tmpfile; ++ ++ /* ++ * Theoretically, REVAL test should be unnecessary in case of ++ * {FS,I}NOTIFY. ++ * But {fs,i}notify doesn't fire some necessary events, ++ * IN_ATTRIB for atime/nlink/pageio ++ * Let's do REVAL test too. ++ */ ++ if (do_udba && inode) { ++ mode = (inode->i_mode & S_IFMT); ++ plus = (inode->i_nlink > 0); ++ ibs = au_ibtop(inode); ++ ibe = au_ibbot(inode); ++ } ++ ++ btop = au_dbtop(dentry); ++ btail = btop; ++ if (inode && S_ISDIR(inode->i_mode)) ++ btail = au_dbtaildir(dentry); ++ for (bindex = btop; bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ ++ AuDbg("b%d, %pd\n", bindex, h_dentry); ++ h_nfs = !!au_test_nfs(h_dentry->d_sb); ++ spin_lock(&h_dentry->d_lock); ++ h_name = &h_dentry->d_name; ++ if (unlikely(do_udba ++ && !is_root ++ && ((!h_nfs ++ && (unhashed != !!d_unhashed(h_dentry) ++ || (!tmpfile && !dirren ++ && !au_qstreq(name, h_name)) ++ )) ++ || (h_nfs ++ && !(flags & LOOKUP_OPEN) ++ && (h_dentry->d_flags ++ & DCACHE_NFSFS_RENAMED))) ++ )) { ++ int h_unhashed; ++ ++ h_unhashed = d_unhashed(h_dentry); ++ spin_unlock(&h_dentry->d_lock); ++ AuDbg("unhash 0x%x 0x%x, %pd %pd\n", ++ unhashed, h_unhashed, dentry, h_dentry); ++ goto err; ++ } ++ spin_unlock(&h_dentry->d_lock); ++ ++ err = au_do_h_d_reval(h_dentry, flags, dentry, bindex); ++ if (unlikely(err)) ++ /* do not goto err, to keep the errno */ ++ break; ++ ++ /* todo: plink too? */ ++ if (!do_udba) ++ continue; ++ ++ /* UDBA tests */ ++ if (unlikely(!!inode != d_is_positive(h_dentry))) ++ goto err; ++ ++ h_inode = NULL; ++ if (d_is_positive(h_dentry)) ++ h_inode = d_inode(h_dentry); ++ h_plus = plus; ++ h_mode = mode; ++ h_cached_inode = h_inode; ++ if (h_inode) { ++ h_mode = (h_inode->i_mode & S_IFMT); ++ h_plus = (h_inode->i_nlink > 0); ++ } ++ if (inode && ibs <= bindex && bindex <= ibe) ++ h_cached_inode = au_h_iptr(inode, bindex); ++ ++ if (!h_nfs) { ++ if (unlikely(plus != h_plus && !tmpfile)) ++ goto err; ++ } else { ++ if (unlikely(!(h_dentry->d_flags & DCACHE_NFSFS_RENAMED) ++ && !is_root ++ && !IS_ROOT(h_dentry) ++ && unhashed != d_unhashed(h_dentry))) ++ goto err; ++ } ++ if (unlikely(mode != h_mode ++ || h_cached_inode != h_inode)) ++ goto err; ++ continue; ++ ++err: ++ err = -EINVAL; ++ break; ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* todo: consolidate with do_refresh() and au_reval_for_attr() */ ++static int simple_reval_dpath(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ struct dentry *parent; ++ ++ if (!au_digen_test(dentry, sigen)) ++ return 0; ++ ++ parent = dget_parent(dentry); ++ di_read_lock_parent(parent, AuLock_IR); ++ AuDebugOn(au_digen_test(parent, sigen)); ++ au_dbg_verify_gen(parent, sigen); ++ err = au_refresh_dentry(dentry, parent); ++ di_read_unlock(parent, AuLock_IR); ++ dput(parent); ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_reval_dpath(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ struct dentry *d, *parent; ++ ++ if (!au_ftest_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR)) ++ return simple_reval_dpath(dentry, sigen); ++ ++ /* slow loop, keep it simple and stupid */ ++ /* cf: au_cpup_dirs() */ ++ err = 0; ++ parent = NULL; ++ while (au_digen_test(dentry, sigen)) { ++ d = dentry; ++ while (1) { ++ dput(parent); ++ parent = dget_parent(d); ++ if (!au_digen_test(parent, sigen)) ++ break; ++ d = parent; ++ } ++ ++ if (d != dentry) ++ di_write_lock_child2(d); ++ ++ /* someone might update our dentry while we were sleeping */ ++ if (au_digen_test(d, sigen)) { ++ /* ++ * todo: consolidate with simple_reval_dpath(), ++ * do_refresh() and au_reval_for_attr(). ++ */ ++ di_read_lock_parent(parent, AuLock_IR); ++ err = au_refresh_dentry(d, parent); ++ di_read_unlock(parent, AuLock_IR); ++ } ++ ++ if (d != dentry) ++ di_write_unlock(d); ++ dput(parent); ++ if (unlikely(err)) ++ break; ++ } ++ ++ return err; ++} ++ ++/* ++ * if valid returns 1, otherwise 0. ++ */ ++static int aufs_d_revalidate(struct dentry *dentry, unsigned int flags) ++{ ++ int valid, err; ++ unsigned int sigen; ++ unsigned char do_udba, dirren; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ /* todo: support rcu-walk? */ ++ if (flags & LOOKUP_RCU) ++ return -ECHILD; ++ ++ valid = 0; ++ if (unlikely(!au_di(dentry))) ++ goto out; ++ ++ valid = 1; ++ sb = dentry->d_sb; ++ /* ++ * todo: very ugly ++ * i_mutex of parent dir may be held, ++ * but we should not return 'invalid' due to busy. ++ */ ++ err = aufs_read_lock(dentry, AuLock_FLUSH | AuLock_DW | AuLock_NOPLM); ++ if (unlikely(err)) { ++ valid = err; ++ AuTraceErr(err); ++ goto out; ++ } ++ inode = NULL; ++ if (d_really_is_positive(dentry)) ++ inode = d_inode(dentry); ++ if (unlikely(inode && au_is_bad_inode(inode))) { ++ err = -EINVAL; ++ AuTraceErr(err); ++ goto out_dgrade; ++ } ++ if (unlikely(au_dbrange_test(dentry))) { ++ err = -EINVAL; ++ AuTraceErr(err); ++ goto out_dgrade; ++ } ++ ++ sigen = au_sigen(sb); ++ if (au_digen_test(dentry, sigen)) { ++ AuDebugOn(IS_ROOT(dentry)); ++ err = au_reval_dpath(dentry, sigen); ++ if (unlikely(err)) { ++ AuTraceErr(err); ++ goto out_dgrade; ++ } ++ } ++ di_downgrade_lock(dentry, AuLock_IR); ++ ++ err = -EINVAL; ++ if (!(flags & (LOOKUP_OPEN | LOOKUP_EMPTY)) ++ && inode ++ && !(inode->i_state && I_LINKABLE) ++ && (IS_DEADDIR(inode) || !inode->i_nlink)) { ++ AuTraceErr(err); ++ goto out_inval; ++ } ++ ++ do_udba = !au_opt_test(au_mntflags(sb), UDBA_NONE); ++ if (do_udba && inode) { ++ aufs_bindex_t btop = au_ibtop(inode); ++ struct inode *h_inode; ++ ++ if (btop >= 0) { ++ h_inode = au_h_iptr(inode, btop); ++ if (h_inode && au_test_higen(inode, h_inode)) { ++ AuTraceErr(err); ++ goto out_inval; ++ } ++ } ++ } ++ ++ dirren = !!au_opt_test(au_mntflags(sb), DIRREN); ++ err = h_d_revalidate(dentry, inode, flags, do_udba, dirren); ++ if (unlikely(!err && do_udba && au_dbtop(dentry) < 0)) { ++ err = -EIO; ++ AuDbg("both of real entry and whiteout found, %p, err %d\n", ++ dentry, err); ++ } ++ goto out_inval; ++ ++out_dgrade: ++ di_downgrade_lock(dentry, AuLock_IR); ++out_inval: ++ aufs_read_unlock(dentry, AuLock_IR); ++ AuTraceErr(err); ++ valid = !err; ++out: ++ if (!valid) { ++ AuDbg("%pd invalid, %d\n", dentry, valid); ++ d_drop(dentry); ++ } ++ return valid; ++} ++ ++static void aufs_d_release(struct dentry *dentry) ++{ ++ if (au_di(dentry)) { ++ au_di_fin(dentry); ++ au_hn_di_reinit(dentry); ++ } ++} ++ ++const struct dentry_operations aufs_dop = { ++ .d_revalidate = aufs_d_revalidate, ++ .d_weak_revalidate = aufs_d_revalidate, ++ .d_release = aufs_d_release ++}; ++ ++/* aufs_dop without d_revalidate */ ++const struct dentry_operations aufs_dop_noreval = { ++ .d_release = aufs_d_release ++}; +diff --git a/fs/aufs/dentry.h b/fs/aufs/dentry.h +new file mode 100644 +index 000000000000..086f6ccf4b15 +--- /dev/null ++++ b/fs/aufs/dentry.h +@@ -0,0 +1,255 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * lookup and dentry operations ++ */ ++ ++#ifndef __AUFS_DENTRY_H__ ++#define __AUFS_DENTRY_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "dirren.h" ++#include "rwsem.h" ++ ++struct au_hdentry { ++ struct dentry *hd_dentry; ++ aufs_bindex_t hd_id; ++}; ++ ++struct au_dinfo { ++ atomic_t di_generation; ++ ++ struct au_rwsem di_rwsem; ++ aufs_bindex_t di_btop, di_bbot, di_bwh, di_bdiropq; ++ unsigned char di_tmpfile; /* to allow the different name */ ++ struct au_hdentry *di_hdentry; ++ struct rcu_head rcu; ++} ____cacheline_aligned_in_smp; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* flags for au_lkup_dentry() */ ++#define AuLkup_ALLOW_NEG 1 ++#define AuLkup_IGNORE_PERM (1 << 1) ++#define AuLkup_DIRREN (1 << 2) ++#define au_ftest_lkup(flags, name) ((flags) & AuLkup_##name) ++#define au_fset_lkup(flags, name) \ ++ do { (flags) |= AuLkup_##name; } while (0) ++#define au_fclr_lkup(flags, name) \ ++ do { (flags) &= ~AuLkup_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_DIRREN ++#undef AuLkup_DIRREN ++#define AuLkup_DIRREN 0 ++#endif ++ ++struct au_do_lookup_args { ++ unsigned int flags; ++ mode_t type; ++ struct qstr whname, *name; ++ struct au_dr_lookup dirren; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dentry.c */ ++extern const struct dentry_operations aufs_dop, aufs_dop_noreval; ++struct au_branch; ++struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent); ++int au_h_verify(struct dentry *h_dentry, unsigned int udba, struct inode *h_dir, ++ struct dentry *h_parent, struct au_branch *br); ++ ++int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t btop, ++ unsigned int flags); ++int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex, int wh); ++int au_refresh_dentry(struct dentry *dentry, struct dentry *parent); ++int au_reval_dpath(struct dentry *dentry, unsigned int sigen); ++void au_refresh_dop(struct dentry *dentry, int force_reval); ++ ++/* dinfo.c */ ++void au_di_init_once(void *_di); ++struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc); ++void au_di_free(struct au_dinfo *dinfo); ++void au_di_swap(struct au_dinfo *a, struct au_dinfo *b); ++void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src); ++int au_di_init(struct dentry *dentry); ++void au_di_fin(struct dentry *dentry); ++int au_di_realloc(struct au_dinfo *dinfo, int nbr, int may_shrink); ++ ++void di_read_lock(struct dentry *d, int flags, unsigned int lsc); ++void di_read_unlock(struct dentry *d, int flags); ++void di_downgrade_lock(struct dentry *d, int flags); ++void di_write_lock(struct dentry *d, unsigned int lsc); ++void di_write_unlock(struct dentry *d); ++void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir); ++void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir); ++void di_write_unlock2(struct dentry *d1, struct dentry *d2); ++ ++struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex); ++struct dentry *au_h_d_alias(struct dentry *dentry, aufs_bindex_t bindex); ++aufs_bindex_t au_dbtail(struct dentry *dentry); ++aufs_bindex_t au_dbtaildir(struct dentry *dentry); ++ ++void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_dentry); ++int au_digen_test(struct dentry *dentry, unsigned int sigen); ++int au_dbrange_test(struct dentry *dentry); ++void au_update_digen(struct dentry *dentry); ++void au_update_dbrange(struct dentry *dentry, int do_put_zero); ++void au_update_dbtop(struct dentry *dentry); ++void au_update_dbbot(struct dentry *dentry); ++int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_dinfo *au_di(struct dentry *dentry) ++{ ++ return dentry->d_fsdata; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for dinfo */ ++enum { ++ AuLsc_DI_CHILD, /* child first */ ++ AuLsc_DI_CHILD2, /* rename(2), link(2), and cpup at hnotify */ ++ AuLsc_DI_CHILD3, /* copyup dirs */ ++ AuLsc_DI_PARENT, ++ AuLsc_DI_PARENT2, ++ AuLsc_DI_PARENT3, ++ AuLsc_DI_TMP /* temp for replacing dinfo */ ++}; ++ ++/* ++ * di_read_lock_child, di_write_lock_child, ++ * di_read_lock_child2, di_write_lock_child2, ++ * di_read_lock_child3, di_write_lock_child3, ++ * di_read_lock_parent, di_write_lock_parent, ++ * di_read_lock_parent2, di_write_lock_parent2, ++ * di_read_lock_parent3, di_write_lock_parent3, ++ */ ++#define AuReadLockFunc(name, lsc) \ ++static inline void di_read_lock_##name(struct dentry *d, int flags) \ ++{ di_read_lock(d, flags, AuLsc_DI_##lsc); } ++ ++#define AuWriteLockFunc(name, lsc) \ ++static inline void di_write_lock_##name(struct dentry *d) \ ++{ di_write_lock(d, AuLsc_DI_##lsc); } ++ ++#define AuRWLockFuncs(name, lsc) \ ++ AuReadLockFunc(name, lsc) \ ++ AuWriteLockFunc(name, lsc) ++ ++AuRWLockFuncs(child, CHILD); ++AuRWLockFuncs(child2, CHILD2); ++AuRWLockFuncs(child3, CHILD3); ++AuRWLockFuncs(parent, PARENT); ++AuRWLockFuncs(parent2, PARENT2); ++AuRWLockFuncs(parent3, PARENT3); ++ ++#undef AuReadLockFunc ++#undef AuWriteLockFunc ++#undef AuRWLockFuncs ++ ++#define DiMustNoWaiters(d) AuRwMustNoWaiters(&au_di(d)->di_rwsem) ++#define DiMustAnyLock(d) AuRwMustAnyLock(&au_di(d)->di_rwsem) ++#define DiMustWriteLock(d) AuRwMustWriteLock(&au_di(d)->di_rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* todo: memory barrier? */ ++static inline unsigned int au_digen(struct dentry *d) ++{ ++ return atomic_read(&au_di(d)->di_generation); ++} ++ ++static inline void au_h_dentry_init(struct au_hdentry *hdentry) ++{ ++ hdentry->hd_dentry = NULL; ++} ++ ++static inline struct au_hdentry *au_hdentry(struct au_dinfo *di, ++ aufs_bindex_t bindex) ++{ ++ return di->di_hdentry + bindex; ++} ++ ++static inline void au_hdput(struct au_hdentry *hd) ++{ ++ if (hd) ++ dput(hd->hd_dentry); ++} ++ ++static inline aufs_bindex_t au_dbtop(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_btop; ++} ++ ++static inline aufs_bindex_t au_dbbot(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_bbot; ++} ++ ++static inline aufs_bindex_t au_dbwh(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_bwh; ++} ++ ++static inline aufs_bindex_t au_dbdiropq(struct dentry *dentry) ++{ ++ DiMustAnyLock(dentry); ++ return au_di(dentry)->di_bdiropq; ++} ++ ++/* todo: hard/soft set? */ ++static inline void au_set_dbtop(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ au_di(dentry)->di_btop = bindex; ++} ++ ++static inline void au_set_dbbot(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ au_di(dentry)->di_bbot = bindex; ++} ++ ++static inline void au_set_dbwh(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ /* dbwh can be outside of btop - bbot range */ ++ au_di(dentry)->di_bwh = bindex; ++} ++ ++static inline void au_set_dbdiropq(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ DiMustWriteLock(dentry); ++ au_di(dentry)->di_bdiropq = bindex; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_HNOTIFY ++static inline void au_digen_dec(struct dentry *d) ++{ ++ atomic_dec(&au_di(d)->di_generation); ++} ++ ++static inline void au_hn_di_reinit(struct dentry *dentry) ++{ ++ dentry->d_fsdata = NULL; ++} ++#else ++AuStubVoid(au_hn_di_reinit, struct dentry *dentry __maybe_unused) ++#endif /* CONFIG_AUFS_HNOTIFY */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DENTRY_H__ */ +diff --git a/fs/aufs/dinfo.c b/fs/aufs/dinfo.c +new file mode 100644 +index 000000000000..aed5314e5e24 +--- /dev/null ++++ b/fs/aufs/dinfo.c +@@ -0,0 +1,541 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * dentry private data ++ */ ++ ++#include "aufs.h" ++ ++void au_di_init_once(void *_dinfo) ++{ ++ struct au_dinfo *dinfo = _dinfo; ++ ++ au_rw_init(&dinfo->di_rwsem); ++} ++ ++struct au_dinfo *au_di_alloc(struct super_block *sb, unsigned int lsc) ++{ ++ struct au_dinfo *dinfo; ++ int nbr, i; ++ ++ dinfo = au_cache_alloc_dinfo(); ++ if (unlikely(!dinfo)) ++ goto out; ++ ++ nbr = au_sbbot(sb) + 1; ++ if (nbr <= 0) ++ nbr = 1; ++ dinfo->di_hdentry = kcalloc(nbr, sizeof(*dinfo->di_hdentry), GFP_NOFS); ++ if (dinfo->di_hdentry) { ++ au_rw_write_lock_nested(&dinfo->di_rwsem, lsc); ++ dinfo->di_btop = -1; ++ dinfo->di_bbot = -1; ++ dinfo->di_bwh = -1; ++ dinfo->di_bdiropq = -1; ++ dinfo->di_tmpfile = 0; ++ for (i = 0; i < nbr; i++) ++ dinfo->di_hdentry[i].hd_id = -1; ++ goto out; ++ } ++ ++ au_cache_free_dinfo(dinfo); ++ dinfo = NULL; ++ ++out: ++ return dinfo; ++} ++ ++void au_di_free(struct au_dinfo *dinfo) ++{ ++ struct au_hdentry *p; ++ aufs_bindex_t bbot, bindex; ++ ++ /* dentry may not be revalidated */ ++ bindex = dinfo->di_btop; ++ if (bindex >= 0) { ++ bbot = dinfo->di_bbot; ++ p = au_hdentry(dinfo, bindex); ++ while (bindex++ <= bbot) ++ au_hdput(p++); ++ } ++ au_kfree_try_rcu(dinfo->di_hdentry); ++ au_cache_free_dinfo(dinfo); ++} ++ ++void au_di_swap(struct au_dinfo *a, struct au_dinfo *b) ++{ ++ struct au_hdentry *p; ++ aufs_bindex_t bi; ++ ++ AuRwMustWriteLock(&a->di_rwsem); ++ AuRwMustWriteLock(&b->di_rwsem); ++ ++#define DiSwap(v, name) \ ++ do { \ ++ v = a->di_##name; \ ++ a->di_##name = b->di_##name; \ ++ b->di_##name = v; \ ++ } while (0) ++ ++ DiSwap(p, hdentry); ++ DiSwap(bi, btop); ++ DiSwap(bi, bbot); ++ DiSwap(bi, bwh); ++ DiSwap(bi, bdiropq); ++ /* smp_mb(); */ ++ ++#undef DiSwap ++} ++ ++void au_di_cp(struct au_dinfo *dst, struct au_dinfo *src) ++{ ++ AuRwMustWriteLock(&dst->di_rwsem); ++ AuRwMustWriteLock(&src->di_rwsem); ++ ++ dst->di_btop = src->di_btop; ++ dst->di_bbot = src->di_bbot; ++ dst->di_bwh = src->di_bwh; ++ dst->di_bdiropq = src->di_bdiropq; ++ /* smp_mb(); */ ++} ++ ++int au_di_init(struct dentry *dentry) ++{ ++ int err; ++ struct super_block *sb; ++ struct au_dinfo *dinfo; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ dinfo = au_di_alloc(sb, AuLsc_DI_CHILD); ++ if (dinfo) { ++ atomic_set(&dinfo->di_generation, au_sigen(sb)); ++ /* smp_mb(); */ /* atomic_set */ ++ dentry->d_fsdata = dinfo; ++ } else ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++void au_di_fin(struct dentry *dentry) ++{ ++ struct au_dinfo *dinfo; ++ ++ dinfo = au_di(dentry); ++ AuRwDestroy(&dinfo->di_rwsem); ++ au_di_free(dinfo); ++} ++ ++int au_di_realloc(struct au_dinfo *dinfo, int nbr, int may_shrink) ++{ ++ int err, sz; ++ struct au_hdentry *hdp; ++ ++ AuRwMustWriteLock(&dinfo->di_rwsem); ++ ++ err = -ENOMEM; ++ sz = sizeof(*hdp) * (dinfo->di_bbot + 1); ++ if (!sz) ++ sz = sizeof(*hdp); ++ hdp = au_kzrealloc(dinfo->di_hdentry, sz, sizeof(*hdp) * nbr, GFP_NOFS, ++ may_shrink); ++ if (hdp) { ++ dinfo->di_hdentry = hdp; ++ err = 0; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void do_ii_write_lock(struct inode *inode, unsigned int lsc) ++{ ++ switch (lsc) { ++ case AuLsc_DI_CHILD: ++ ii_write_lock_child(inode); ++ break; ++ case AuLsc_DI_CHILD2: ++ ii_write_lock_child2(inode); ++ break; ++ case AuLsc_DI_CHILD3: ++ ii_write_lock_child3(inode); ++ break; ++ case AuLsc_DI_PARENT: ++ ii_write_lock_parent(inode); ++ break; ++ case AuLsc_DI_PARENT2: ++ ii_write_lock_parent2(inode); ++ break; ++ case AuLsc_DI_PARENT3: ++ ii_write_lock_parent3(inode); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++static void do_ii_read_lock(struct inode *inode, unsigned int lsc) ++{ ++ switch (lsc) { ++ case AuLsc_DI_CHILD: ++ ii_read_lock_child(inode); ++ break; ++ case AuLsc_DI_CHILD2: ++ ii_read_lock_child2(inode); ++ break; ++ case AuLsc_DI_CHILD3: ++ ii_read_lock_child3(inode); ++ break; ++ case AuLsc_DI_PARENT: ++ ii_read_lock_parent(inode); ++ break; ++ case AuLsc_DI_PARENT2: ++ ii_read_lock_parent2(inode); ++ break; ++ case AuLsc_DI_PARENT3: ++ ii_read_lock_parent3(inode); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++void di_read_lock(struct dentry *d, int flags, unsigned int lsc) ++{ ++ struct inode *inode; ++ ++ au_rw_read_lock_nested(&au_di(d)->di_rwsem, lsc); ++ if (d_really_is_positive(d)) { ++ inode = d_inode(d); ++ if (au_ftest_lock(flags, IW)) ++ do_ii_write_lock(inode, lsc); ++ else if (au_ftest_lock(flags, IR)) ++ do_ii_read_lock(inode, lsc); ++ } ++} ++ ++void di_read_unlock(struct dentry *d, int flags) ++{ ++ struct inode *inode; ++ ++ if (d_really_is_positive(d)) { ++ inode = d_inode(d); ++ if (au_ftest_lock(flags, IW)) { ++ au_dbg_verify_dinode(d); ++ ii_write_unlock(inode); ++ } else if (au_ftest_lock(flags, IR)) { ++ au_dbg_verify_dinode(d); ++ ii_read_unlock(inode); ++ } ++ } ++ au_rw_read_unlock(&au_di(d)->di_rwsem); ++} ++ ++void di_downgrade_lock(struct dentry *d, int flags) ++{ ++ if (d_really_is_positive(d) && au_ftest_lock(flags, IR)) ++ ii_downgrade_lock(d_inode(d)); ++ au_rw_dgrade_lock(&au_di(d)->di_rwsem); ++} ++ ++void di_write_lock(struct dentry *d, unsigned int lsc) ++{ ++ au_rw_write_lock_nested(&au_di(d)->di_rwsem, lsc); ++ if (d_really_is_positive(d)) ++ do_ii_write_lock(d_inode(d), lsc); ++} ++ ++void di_write_unlock(struct dentry *d) ++{ ++ au_dbg_verify_dinode(d); ++ if (d_really_is_positive(d)) ++ ii_write_unlock(d_inode(d)); ++ au_rw_write_unlock(&au_di(d)->di_rwsem); ++} ++ ++void di_write_lock2_child(struct dentry *d1, struct dentry *d2, int isdir) ++{ ++ AuDebugOn(d1 == d2 ++ || d_inode(d1) == d_inode(d2) ++ || d1->d_sb != d2->d_sb); ++ ++ if ((isdir && au_test_subdir(d1, d2)) ++ || d1 < d2) { ++ di_write_lock_child(d1); ++ di_write_lock_child2(d2); ++ } else { ++ di_write_lock_child(d2); ++ di_write_lock_child2(d1); ++ } ++} ++ ++void di_write_lock2_parent(struct dentry *d1, struct dentry *d2, int isdir) ++{ ++ AuDebugOn(d1 == d2 ++ || d_inode(d1) == d_inode(d2) ++ || d1->d_sb != d2->d_sb); ++ ++ if ((isdir && au_test_subdir(d1, d2)) ++ || d1 < d2) { ++ di_write_lock_parent(d1); ++ di_write_lock_parent2(d2); ++ } else { ++ di_write_lock_parent(d2); ++ di_write_lock_parent2(d1); ++ } ++} ++ ++void di_write_unlock2(struct dentry *d1, struct dentry *d2) ++{ ++ di_write_unlock(d1); ++ if (d_inode(d1) == d_inode(d2)) ++ au_rw_write_unlock(&au_di(d2)->di_rwsem); ++ else ++ di_write_unlock(d2); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ struct dentry *d; ++ ++ DiMustAnyLock(dentry); ++ ++ if (au_dbtop(dentry) < 0 || bindex < au_dbtop(dentry)) ++ return NULL; ++ AuDebugOn(bindex < 0); ++ d = au_hdentry(au_di(dentry), bindex)->hd_dentry; ++ AuDebugOn(d && au_dcount(d) <= 0); ++ return d; ++} ++ ++/* ++ * extended version of au_h_dptr(). ++ * returns a hashed and positive (or linkable) h_dentry in bindex, NULL, or ++ * error. ++ */ ++struct dentry *au_h_d_alias(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ struct dentry *h_dentry; ++ struct inode *inode, *h_inode; ++ ++ AuDebugOn(d_really_is_negative(dentry)); ++ ++ h_dentry = NULL; ++ if (au_dbtop(dentry) <= bindex ++ && bindex <= au_dbbot(dentry)) ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && !au_d_linkable(h_dentry)) { ++ dget(h_dentry); ++ goto out; /* success */ ++ } ++ ++ inode = d_inode(dentry); ++ AuDebugOn(bindex < au_ibtop(inode)); ++ AuDebugOn(au_ibbot(inode) < bindex); ++ h_inode = au_h_iptr(inode, bindex); ++ h_dentry = d_find_alias(h_inode); ++ if (h_dentry) { ++ if (!IS_ERR(h_dentry)) { ++ if (!au_d_linkable(h_dentry)) ++ goto out; /* success */ ++ dput(h_dentry); ++ } else ++ goto out; ++ } ++ ++ if (au_opt_test(au_mntflags(dentry->d_sb), PLINK)) { ++ h_dentry = au_plink_lkup(inode, bindex); ++ AuDebugOn(!h_dentry); ++ if (!IS_ERR(h_dentry)) { ++ if (!au_d_hashed_positive(h_dentry)) ++ goto out; /* success */ ++ dput(h_dentry); ++ h_dentry = NULL; ++ } ++ } ++ ++out: ++ AuDbgDentry(h_dentry); ++ return h_dentry; ++} ++ ++aufs_bindex_t au_dbtail(struct dentry *dentry) ++{ ++ aufs_bindex_t bbot, bwh; ++ ++ bbot = au_dbbot(dentry); ++ if (0 <= bbot) { ++ bwh = au_dbwh(dentry); ++ if (!bwh) ++ return bwh; ++ if (0 < bwh && bwh < bbot) ++ return bwh - 1; ++ } ++ return bbot; ++} ++ ++aufs_bindex_t au_dbtaildir(struct dentry *dentry) ++{ ++ aufs_bindex_t bbot, bopq; ++ ++ bbot = au_dbtail(dentry); ++ if (0 <= bbot) { ++ bopq = au_dbdiropq(dentry); ++ if (0 <= bopq && bopq < bbot) ++ bbot = bopq; ++ } ++ return bbot; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_dentry) ++{ ++ struct au_dinfo *dinfo; ++ struct au_hdentry *hd; ++ struct au_branch *br; ++ ++ DiMustWriteLock(dentry); ++ ++ dinfo = au_di(dentry); ++ hd = au_hdentry(dinfo, bindex); ++ au_hdput(hd); ++ hd->hd_dentry = h_dentry; ++ if (h_dentry) { ++ br = au_sbr(dentry->d_sb, bindex); ++ hd->hd_id = br->br_id; ++ } ++} ++ ++int au_dbrange_test(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t btop, bbot; ++ ++ err = 0; ++ btop = au_dbtop(dentry); ++ bbot = au_dbbot(dentry); ++ if (btop >= 0) ++ AuDebugOn(bbot < 0 && btop > bbot); ++ else { ++ err = -EIO; ++ AuDebugOn(bbot >= 0); ++ } ++ ++ return err; ++} ++ ++int au_digen_test(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ ++ err = 0; ++ if (unlikely(au_digen(dentry) != sigen ++ || au_iigen_test(d_inode(dentry), sigen))) ++ err = -EIO; ++ ++ return err; ++} ++ ++void au_update_digen(struct dentry *dentry) ++{ ++ atomic_set(&au_di(dentry)->di_generation, au_sigen(dentry->d_sb)); ++ /* smp_mb(); */ /* atomic_set */ ++} ++ ++void au_update_dbrange(struct dentry *dentry, int do_put_zero) ++{ ++ struct au_dinfo *dinfo; ++ struct dentry *h_d; ++ struct au_hdentry *hdp; ++ aufs_bindex_t bindex, bbot; ++ ++ DiMustWriteLock(dentry); ++ ++ dinfo = au_di(dentry); ++ if (!dinfo || dinfo->di_btop < 0) ++ return; ++ ++ if (do_put_zero) { ++ bbot = dinfo->di_bbot; ++ bindex = dinfo->di_btop; ++ hdp = au_hdentry(dinfo, bindex); ++ for (; bindex <= bbot; bindex++, hdp++) { ++ h_d = hdp->hd_dentry; ++ if (h_d && d_is_negative(h_d)) ++ au_set_h_dptr(dentry, bindex, NULL); ++ } ++ } ++ ++ dinfo->di_btop = 0; ++ hdp = au_hdentry(dinfo, dinfo->di_btop); ++ for (; dinfo->di_btop <= dinfo->di_bbot; dinfo->di_btop++, hdp++) ++ if (hdp->hd_dentry) ++ break; ++ if (dinfo->di_btop > dinfo->di_bbot) { ++ dinfo->di_btop = -1; ++ dinfo->di_bbot = -1; ++ return; ++ } ++ ++ hdp = au_hdentry(dinfo, dinfo->di_bbot); ++ for (; dinfo->di_bbot >= 0; dinfo->di_bbot--, hdp--) ++ if (hdp->hd_dentry) ++ break; ++ AuDebugOn(dinfo->di_btop > dinfo->di_bbot || dinfo->di_bbot < 0); ++} ++ ++void au_update_dbtop(struct dentry *dentry) ++{ ++ aufs_bindex_t bindex, bbot; ++ struct dentry *h_dentry; ++ ++ bbot = au_dbbot(dentry); ++ for (bindex = au_dbtop(dentry); bindex <= bbot; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ if (d_is_positive(h_dentry)) { ++ au_set_dbtop(dentry, bindex); ++ return; ++ } ++ au_set_h_dptr(dentry, bindex, NULL); ++ } ++} ++ ++void au_update_dbbot(struct dentry *dentry) ++{ ++ aufs_bindex_t bindex, btop; ++ struct dentry *h_dentry; ++ ++ btop = au_dbtop(dentry); ++ for (bindex = au_dbbot(dentry); bindex >= btop; bindex--) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ if (d_is_positive(h_dentry)) { ++ au_set_dbbot(dentry, bindex); ++ return; ++ } ++ au_set_h_dptr(dentry, bindex, NULL); ++ } ++} ++ ++int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry) ++{ ++ aufs_bindex_t bindex, bbot; ++ ++ bbot = au_dbbot(dentry); ++ for (bindex = au_dbtop(dentry); bindex <= bbot; bindex++) ++ if (au_h_dptr(dentry, bindex) == h_dentry) ++ return bindex; ++ return -1; ++} +diff --git a/fs/aufs/dir.c b/fs/aufs/dir.c +new file mode 100644 +index 000000000000..44adae19efb1 +--- /dev/null ++++ b/fs/aufs/dir.c +@@ -0,0 +1,750 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * directory operations ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++void au_add_nlink(struct inode *dir, struct inode *h_dir) ++{ ++ unsigned int nlink; ++ ++ AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); ++ ++ nlink = dir->i_nlink; ++ nlink += h_dir->i_nlink - 2; ++ if (h_dir->i_nlink < 2) ++ nlink += 2; ++ smp_mb(); /* for i_nlink */ ++ /* 0 can happen in revaliding */ ++ set_nlink(dir, nlink); ++} ++ ++void au_sub_nlink(struct inode *dir, struct inode *h_dir) ++{ ++ unsigned int nlink; ++ ++ AuDebugOn(!S_ISDIR(dir->i_mode) || !S_ISDIR(h_dir->i_mode)); ++ ++ nlink = dir->i_nlink; ++ nlink -= h_dir->i_nlink - 2; ++ if (h_dir->i_nlink < 2) ++ nlink -= 2; ++ smp_mb(); /* for i_nlink */ ++ /* nlink == 0 means the branch-fs is broken */ ++ set_nlink(dir, nlink); ++} ++ ++loff_t au_dir_size(struct file *file, struct dentry *dentry) ++{ ++ loff_t sz; ++ aufs_bindex_t bindex, bbot; ++ struct file *h_file; ++ struct dentry *h_dentry; ++ ++ sz = 0; ++ if (file) { ++ AuDebugOn(!d_is_dir(file->f_path.dentry)); ++ ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); ++ bindex <= bbot && sz < KMALLOC_MAX_SIZE; ++ bindex++) { ++ h_file = au_hf_dir(file, bindex); ++ if (h_file && file_inode(h_file)) ++ sz += vfsub_f_size_read(h_file); ++ } ++ } else { ++ AuDebugOn(!dentry); ++ AuDebugOn(!d_is_dir(dentry)); ++ ++ bbot = au_dbtaildir(dentry); ++ for (bindex = au_dbtop(dentry); ++ bindex <= bbot && sz < KMALLOC_MAX_SIZE; ++ bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && d_is_positive(h_dentry)) ++ sz += i_size_read(d_inode(h_dentry)); ++ } ++ } ++ if (sz < KMALLOC_MAX_SIZE) ++ sz = roundup_pow_of_two(sz); ++ if (sz > KMALLOC_MAX_SIZE) ++ sz = KMALLOC_MAX_SIZE; ++ else if (sz < NAME_MAX) { ++ BUILD_BUG_ON(AUFS_RDBLK_DEF < NAME_MAX); ++ sz = AUFS_RDBLK_DEF; ++ } ++ return sz; ++} ++ ++struct au_dir_ts_arg { ++ struct dentry *dentry; ++ aufs_bindex_t brid; ++}; ++ ++static void au_do_dir_ts(void *arg) ++{ ++ struct au_dir_ts_arg *a = arg; ++ struct au_dtime dt; ++ struct path h_path; ++ struct inode *dir, *h_dir; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_hinode *hdir; ++ int err; ++ aufs_bindex_t btop, bindex; ++ ++ sb = a->dentry->d_sb; ++ if (d_really_is_negative(a->dentry)) ++ goto out; ++ /* no dir->i_mutex lock */ ++ aufs_read_lock(a->dentry, AuLock_DW); /* noflush */ ++ ++ dir = d_inode(a->dentry); ++ btop = au_ibtop(dir); ++ bindex = au_br_index(sb, a->brid); ++ if (bindex < btop) ++ goto out_unlock; ++ ++ br = au_sbr(sb, bindex); ++ h_path.dentry = au_h_dptr(a->dentry, bindex); ++ if (!h_path.dentry) ++ goto out_unlock; ++ h_path.mnt = au_br_mnt(br); ++ au_dtime_store(&dt, a->dentry, &h_path); ++ ++ br = au_sbr(sb, btop); ++ if (!au_br_writable(br->br_perm)) ++ goto out_unlock; ++ h_path.dentry = au_h_dptr(a->dentry, btop); ++ h_path.mnt = au_br_mnt(br); ++ err = vfsub_mnt_want_write(h_path.mnt); ++ if (err) ++ goto out_unlock; ++ hdir = au_hi(dir, btop); ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ h_dir = au_h_iptr(dir, btop); ++ if (h_dir->i_nlink ++ && timespec64_compare(&h_dir->i_mtime, &dt.dt_mtime) < 0) { ++ dt.dt_h_path = h_path; ++ au_dtime_revert(&dt); ++ } ++ au_hn_inode_unlock(hdir); ++ vfsub_mnt_drop_write(h_path.mnt); ++ au_cpup_attr_timesizes(dir); ++ ++out_unlock: ++ aufs_read_unlock(a->dentry, AuLock_DW); ++out: ++ dput(a->dentry); ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ au_kfree_try_rcu(arg); ++} ++ ++void au_dir_ts(struct inode *dir, aufs_bindex_t bindex) ++{ ++ int perm, wkq_err; ++ aufs_bindex_t btop; ++ struct au_dir_ts_arg *arg; ++ struct dentry *dentry; ++ struct super_block *sb; ++ ++ IMustLock(dir); ++ ++ dentry = d_find_any_alias(dir); ++ AuDebugOn(!dentry); ++ sb = dentry->d_sb; ++ btop = au_ibtop(dir); ++ if (btop == bindex) { ++ au_cpup_attr_timesizes(dir); ++ goto out; ++ } ++ ++ perm = au_sbr_perm(sb, btop); ++ if (!au_br_writable(perm)) ++ goto out; ++ ++ arg = kmalloc(sizeof(*arg), GFP_NOFS); ++ if (!arg) ++ goto out; ++ ++ arg->dentry = dget(dentry); /* will be dput-ted by au_do_dir_ts() */ ++ arg->brid = au_sbr_id(sb, bindex); ++ wkq_err = au_wkq_nowait(au_do_dir_ts, arg, sb, /*flags*/0); ++ if (unlikely(wkq_err)) { ++ pr_err("wkq %d\n", wkq_err); ++ dput(dentry); ++ au_kfree_try_rcu(arg); ++ } ++ ++out: ++ dput(dentry); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int reopen_dir(struct file *file) ++{ ++ int err; ++ unsigned int flags; ++ aufs_bindex_t bindex, btail, btop; ++ struct dentry *dentry, *h_dentry; ++ struct file *h_file; ++ ++ /* open all lower dirs */ ++ dentry = file->f_path.dentry; ++ btop = au_dbtop(dentry); ++ for (bindex = au_fbtop(file); bindex < btop; bindex++) ++ au_set_h_fptr(file, bindex, NULL); ++ au_set_fbtop(file, btop); ++ ++ btail = au_dbtaildir(dentry); ++ for (bindex = au_fbbot_dir(file); btail < bindex; bindex--) ++ au_set_h_fptr(file, bindex, NULL); ++ au_set_fbbot_dir(file, btail); ++ ++ flags = vfsub_file_flags(file); ++ for (bindex = btop; bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ h_file = au_hf_dir(file, bindex); ++ if (h_file) ++ continue; ++ ++ h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; /* close all? */ ++ au_set_h_fptr(file, bindex, h_file); ++ } ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ err = 0; ++ ++out: ++ return err; ++} ++ ++static int do_open_dir(struct file *file, int flags, struct file *h_file) ++{ ++ int err; ++ aufs_bindex_t bindex, btail; ++ struct dentry *dentry, *h_dentry; ++ struct vfsmount *mnt; ++ ++ FiMustWriteLock(file); ++ AuDebugOn(h_file); ++ ++ err = 0; ++ mnt = file->f_path.mnt; ++ dentry = file->f_path.dentry; ++ file->f_version = inode_query_iversion(d_inode(dentry)); ++ bindex = au_dbtop(dentry); ++ au_set_fbtop(file, bindex); ++ btail = au_dbtaildir(dentry); ++ au_set_fbbot_dir(file, btail); ++ for (; !err && bindex <= btail; bindex++) { ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!h_dentry) ++ continue; ++ ++ err = vfsub_test_mntns(mnt, h_dentry->d_sb); ++ if (unlikely(err)) ++ break; ++ h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0); ++ if (IS_ERR(h_file)) { ++ err = PTR_ERR(h_file); ++ break; ++ } ++ au_set_h_fptr(file, bindex, h_file); ++ } ++ au_update_figen(file); ++ /* todo: necessary? */ ++ /* file->f_ra = h_file->f_ra; */ ++ if (!err) ++ return 0; /* success */ ++ ++ /* close all */ ++ for (bindex = au_fbtop(file); bindex <= btail; bindex++) ++ au_set_h_fptr(file, bindex, NULL); ++ au_set_fbtop(file, -1); ++ au_set_fbbot_dir(file, -1); ++ ++ return err; ++} ++ ++static int aufs_open_dir(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ int err; ++ struct super_block *sb; ++ struct au_fidir *fidir; ++ ++ err = -ENOMEM; ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ fidir = au_fidir_alloc(sb); ++ if (fidir) { ++ struct au_do_open_args args = { ++ .open = do_open_dir, ++ .fidir = fidir ++ }; ++ err = au_do_open(file, &args); ++ if (unlikely(err)) ++ au_kfree_rcu(fidir); ++ } ++ si_read_unlock(sb); ++ return err; ++} ++ ++static int aufs_release_dir(struct inode *inode __maybe_unused, ++ struct file *file) ++{ ++ struct au_vdir *vdir_cache; ++ struct au_finfo *finfo; ++ struct au_fidir *fidir; ++ struct au_hfile *hf; ++ aufs_bindex_t bindex, bbot; ++ ++ finfo = au_fi(file); ++ fidir = finfo->fi_hdir; ++ if (fidir) { ++ au_hbl_del(&finfo->fi_hlist, ++ &au_sbi(file->f_path.dentry->d_sb)->si_files); ++ vdir_cache = fidir->fd_vdir_cache; /* lock-free */ ++ if (vdir_cache) ++ au_vdir_free(vdir_cache); ++ ++ bindex = finfo->fi_btop; ++ if (bindex >= 0) { ++ hf = fidir->fd_hfile + bindex; ++ /* ++ * calls fput() instead of filp_close(), ++ * since no dnotify or lock for the lower file. ++ */ ++ bbot = fidir->fd_bbot; ++ for (; bindex <= bbot; bindex++, hf++) ++ if (hf->hf_file) ++ au_hfput(hf, /*execed*/0); ++ } ++ au_kfree_rcu(fidir); ++ finfo->fi_hdir = NULL; ++ } ++ au_finfo_fin(file); ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_flush_dir(struct file *file, fl_owner_t id) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct file *h_file; ++ ++ err = 0; ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); !err && bindex <= bbot; bindex++) { ++ h_file = au_hf_dir(file, bindex); ++ if (h_file) ++ err = vfsub_flush(h_file, id); ++ } ++ return err; ++} ++ ++static int aufs_flush_dir(struct file *file, fl_owner_t id) ++{ ++ return au_do_flush(file, id, au_do_flush_dir); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_do_fsync_dir_no_file(struct dentry *dentry, int datasync) ++{ ++ int err; ++ aufs_bindex_t bbot, bindex; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ bbot = au_dbbot(dentry); ++ for (bindex = au_dbtop(dentry); !err && bindex <= bbot; bindex++) { ++ struct path h_path; ++ ++ if (au_test_ro(sb, bindex, inode)) ++ continue; ++ h_path.dentry = au_h_dptr(dentry, bindex); ++ if (!h_path.dentry) ++ continue; ++ ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ err = vfsub_fsync(NULL, &h_path, datasync); ++ } ++ ++ return err; ++} ++ ++static int au_do_fsync_dir(struct file *file, int datasync) ++{ ++ int err; ++ aufs_bindex_t bbot, bindex; ++ struct file *h_file; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1, /*fi_lsc*/0); ++ if (unlikely(err)) ++ goto out; ++ ++ inode = file_inode(file); ++ sb = inode->i_sb; ++ bbot = au_fbbot_dir(file); ++ for (bindex = au_fbtop(file); !err && bindex <= bbot; bindex++) { ++ h_file = au_hf_dir(file, bindex); ++ if (!h_file || au_test_ro(sb, bindex, inode)) ++ continue; ++ ++ err = vfsub_fsync(h_file, &h_file->f_path, datasync); ++ } ++ ++out: ++ return err; ++} ++ ++/* ++ * @file may be NULL ++ */ ++static int aufs_fsync_dir(struct file *file, loff_t start, loff_t end, ++ int datasync) ++{ ++ int err; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct super_block *sb; ++ ++ err = 0; ++ dentry = file->f_path.dentry; ++ inode = d_inode(dentry); ++ inode_lock(inode); ++ sb = dentry->d_sb; ++ si_noflush_read_lock(sb); ++ if (file) ++ err = au_do_fsync_dir(file, datasync); ++ else { ++ di_write_lock_child(dentry); ++ err = au_do_fsync_dir_no_file(dentry, datasync); ++ } ++ au_cpup_attr_timesizes(inode); ++ di_write_unlock(dentry); ++ if (file) ++ fi_write_unlock(file); ++ ++ si_read_unlock(sb); ++ inode_unlock(inode); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_iterate_shared(struct file *file, struct dir_context *ctx) ++{ ++ int err; ++ struct dentry *dentry; ++ struct inode *inode, *h_inode; ++ struct super_block *sb; ++ ++ AuDbg("%pD, ctx{%ps, %llu}\n", file, ctx->actor, ctx->pos); ++ ++ dentry = file->f_path.dentry; ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ ++ sb = dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ err = au_reval_and_lock_fdi(file, reopen_dir, /*wlock*/1, /*fi_lsc*/0); ++ if (unlikely(err)) ++ goto out; ++ err = au_alive_dir(dentry); ++ if (!err) ++ err = au_vdir_init(file); ++ di_downgrade_lock(dentry, AuLock_IR); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ h_inode = au_h_iptr(inode, au_ibtop(inode)); ++ if (!au_test_nfsd()) { ++ err = au_vdir_fill_de(file, ctx); ++ fsstack_copy_attr_atime(inode, h_inode); ++ } else { ++ /* ++ * nfsd filldir may call lookup_one_len(), vfs_getattr(), ++ * encode_fh() and others. ++ */ ++ atomic_inc(&h_inode->i_count); ++ di_read_unlock(dentry, AuLock_IR); ++ si_read_unlock(sb); ++ err = au_vdir_fill_de(file, ctx); ++ fsstack_copy_attr_atime(inode, h_inode); ++ fi_write_unlock(file); ++ iput(h_inode); ++ ++ AuTraceErr(err); ++ return err; ++ } ++ ++out_unlock: ++ di_read_unlock(dentry, AuLock_IR); ++ fi_write_unlock(file); ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AuTestEmpty_WHONLY 1 ++#define AuTestEmpty_CALLED (1 << 1) ++#define AuTestEmpty_SHWH (1 << 2) ++#define au_ftest_testempty(flags, name) ((flags) & AuTestEmpty_##name) ++#define au_fset_testempty(flags, name) \ ++ do { (flags) |= AuTestEmpty_##name; } while (0) ++#define au_fclr_testempty(flags, name) \ ++ do { (flags) &= ~AuTestEmpty_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_SHWH ++#undef AuTestEmpty_SHWH ++#define AuTestEmpty_SHWH 0 ++#endif ++ ++struct test_empty_arg { ++ struct dir_context ctx; ++ struct au_nhash *whlist; ++ unsigned int flags; ++ int err; ++ aufs_bindex_t bindex; ++}; ++ ++static int test_empty_cb(struct dir_context *ctx, const char *__name, ++ int namelen, loff_t offset __maybe_unused, u64 ino, ++ unsigned int d_type) ++{ ++ struct test_empty_arg *arg = container_of(ctx, struct test_empty_arg, ++ ctx); ++ char *name = (void *)__name; ++ ++ arg->err = 0; ++ au_fset_testempty(arg->flags, CALLED); ++ /* smp_mb(); */ ++ if (name[0] == '.' ++ && (namelen == 1 || (name[1] == '.' && namelen == 2))) ++ goto out; /* success */ ++ ++ if (namelen <= AUFS_WH_PFX_LEN ++ || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { ++ if (au_ftest_testempty(arg->flags, WHONLY) ++ && !au_nhash_test_known_wh(arg->whlist, name, namelen)) ++ arg->err = -ENOTEMPTY; ++ goto out; ++ } ++ ++ name += AUFS_WH_PFX_LEN; ++ namelen -= AUFS_WH_PFX_LEN; ++ if (!au_nhash_test_known_wh(arg->whlist, name, namelen)) ++ arg->err = au_nhash_append_wh ++ (arg->whlist, name, namelen, ino, d_type, arg->bindex, ++ au_ftest_testempty(arg->flags, SHWH)); ++ ++out: ++ /* smp_mb(); */ ++ AuTraceErr(arg->err); ++ return arg->err; ++} ++ ++static int do_test_empty(struct dentry *dentry, struct test_empty_arg *arg) ++{ ++ int err; ++ struct file *h_file; ++ struct au_branch *br; ++ ++ h_file = au_h_open(dentry, arg->bindex, ++ O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_LARGEFILE, ++ /*file*/NULL, /*force_wr*/0); ++ err = PTR_ERR(h_file); ++ if (IS_ERR(h_file)) ++ goto out; ++ ++ err = 0; ++ if (!au_opt_test(au_mntflags(dentry->d_sb), UDBA_NONE) ++ && !file_inode(h_file)->i_nlink) ++ goto out_put; ++ ++ do { ++ arg->err = 0; ++ au_fclr_testempty(arg->flags, CALLED); ++ /* smp_mb(); */ ++ err = vfsub_iterate_dir(h_file, &arg->ctx); ++ if (err >= 0) ++ err = arg->err; ++ } while (!err && au_ftest_testempty(arg->flags, CALLED)); ++ ++out_put: ++ fput(h_file); ++ br = au_sbr(dentry->d_sb, arg->bindex); ++ au_lcnt_dec(&br->br_nfiles); ++out: ++ return err; ++} ++ ++struct do_test_empty_args { ++ int *errp; ++ struct dentry *dentry; ++ struct test_empty_arg *arg; ++}; ++ ++static void call_do_test_empty(void *args) ++{ ++ struct do_test_empty_args *a = args; ++ *a->errp = do_test_empty(a->dentry, a->arg); ++} ++ ++static int sio_test_empty(struct dentry *dentry, struct test_empty_arg *arg) ++{ ++ int err, wkq_err; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ ++ h_dentry = au_h_dptr(dentry, arg->bindex); ++ h_inode = d_inode(h_dentry); ++ /* todo: i_mode changes anytime? */ ++ inode_lock_shared_nested(h_inode, AuLsc_I_CHILD); ++ err = au_test_h_perm_sio(h_inode, MAY_EXEC | MAY_READ); ++ inode_unlock_shared(h_inode); ++ if (!err) ++ err = do_test_empty(dentry, arg); ++ else { ++ struct do_test_empty_args args = { ++ .errp = &err, ++ .dentry = dentry, ++ .arg = arg ++ }; ++ unsigned int flags = arg->flags; ++ ++ wkq_err = au_wkq_wait(call_do_test_empty, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ arg->flags = flags; ++ } ++ ++ return err; ++} ++ ++int au_test_empty_lower(struct dentry *dentry) ++{ ++ int err; ++ unsigned int rdhash; ++ aufs_bindex_t bindex, btop, btail; ++ struct au_nhash whlist; ++ struct test_empty_arg arg = { ++ .ctx = { ++ .actor = test_empty_cb ++ } ++ }; ++ int (*test_empty)(struct dentry *dentry, struct test_empty_arg *arg); ++ ++ SiMustAnyLock(dentry->d_sb); ++ ++ rdhash = au_sbi(dentry->d_sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, dentry)); ++ err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ ++ arg.flags = 0; ++ arg.whlist = &whlist; ++ btop = au_dbtop(dentry); ++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)) ++ au_fset_testempty(arg.flags, SHWH); ++ test_empty = do_test_empty; ++ if (au_opt_test(au_mntflags(dentry->d_sb), DIRPERM1)) ++ test_empty = sio_test_empty; ++ arg.bindex = btop; ++ err = test_empty(dentry, &arg); ++ if (unlikely(err)) ++ goto out_whlist; ++ ++ au_fset_testempty(arg.flags, WHONLY); ++ btail = au_dbtaildir(dentry); ++ for (bindex = btop + 1; !err && bindex <= btail; bindex++) { ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && d_is_positive(h_dentry)) { ++ arg.bindex = bindex; ++ err = test_empty(dentry, &arg); ++ } ++ } ++ ++out_whlist: ++ au_nhash_wh_free(&whlist); ++out: ++ return err; ++} ++ ++int au_test_empty(struct dentry *dentry, struct au_nhash *whlist) ++{ ++ int err; ++ struct test_empty_arg arg = { ++ .ctx = { ++ .actor = test_empty_cb ++ } ++ }; ++ aufs_bindex_t bindex, btail; ++ ++ err = 0; ++ arg.whlist = whlist; ++ arg.flags = AuTestEmpty_WHONLY; ++ if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)) ++ au_fset_testempty(arg.flags, SHWH); ++ btail = au_dbtaildir(dentry); ++ for (bindex = au_dbtop(dentry); !err && bindex <= btail; bindex++) { ++ struct dentry *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (h_dentry && d_is_positive(h_dentry)) { ++ arg.bindex = bindex; ++ err = sio_test_empty(dentry, &arg); ++ } ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++const struct file_operations aufs_dir_fop = { ++ .owner = THIS_MODULE, ++ .llseek = default_llseek, ++ .read = generic_read_dir, ++ .iterate_shared = aufs_iterate_shared, ++ .unlocked_ioctl = aufs_ioctl_dir, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = aufs_compat_ioctl_dir, ++#endif ++ .open = aufs_open_dir, ++ .release = aufs_release_dir, ++ .flush = aufs_flush_dir, ++ .fsync = aufs_fsync_dir ++}; +diff --git a/fs/aufs/dir.h b/fs/aufs/dir.h +new file mode 100644 +index 000000000000..75fad78d2278 +--- /dev/null ++++ b/fs/aufs/dir.h +@@ -0,0 +1,121 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2020 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[]; ++} __packed; ++ ++struct au_vdir_dehstr { ++ struct hlist_node hash; ++ struct au_vdir_destr *str; ++ struct rcu_head rcu; ++} ____cacheline_aligned_in_smp; ++ ++struct au_vdir_de { ++ ino_t de_ino; ++ unsigned char de_type; ++ /* caution: packed */ ++ struct au_vdir_destr de_str; ++} __packed; ++ ++struct au_vdir_wh { ++ struct hlist_node wh_hash; ++#ifdef CONFIG_AUFS_SHWH ++ ino_t wh_ino; ++ aufs_bindex_t wh_bindex; ++ unsigned char wh_type; ++#else ++ aufs_bindex_t wh_bindex; ++#endif ++ /* caution: packed */ ++ struct au_vdir_destr wh_str; ++} __packed; ++ ++union au_vdir_deblk_p { ++ unsigned char *deblk; ++ struct au_vdir_de *de; ++}; ++ ++struct au_vdir { ++ unsigned char **vd_deblk; ++ unsigned long vd_nblk; ++ struct { ++ unsigned long ul; ++ union au_vdir_deblk_p p; ++ } vd_last; ++ ++ u64 vd_version; ++ unsigned int vd_deblk_sz; ++ unsigned long vd_jiffy; ++ struct rcu_head rcu; ++} ____cacheline_aligned_in_smp; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dir.c */ ++extern const struct file_operations aufs_dir_fop; ++void au_add_nlink(struct inode *dir, struct inode *h_dir); ++void au_sub_nlink(struct inode *dir, struct inode *h_dir); ++loff_t au_dir_size(struct file *file, struct dentry *dentry); ++void au_dir_ts(struct inode *dir, aufs_bindex_t bsrc); ++int au_test_empty_lower(struct dentry *dentry); ++int au_test_empty(struct dentry *dentry, struct au_nhash *whlist); ++ ++/* vdir.c */ ++unsigned int au_rdhash_est(loff_t sz); ++int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp); ++void au_nhash_wh_free(struct au_nhash *whlist); ++int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt, ++ int limit); ++int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen); ++int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino, ++ unsigned int d_type, aufs_bindex_t bindex, ++ unsigned char shwh); ++void au_vdir_free(struct au_vdir *vdir); ++int au_vdir_init(struct file *file); ++int au_vdir_fill_de(struct file *file, struct dir_context *ctx); ++ ++/* ioctl.c */ ++long aufs_ioctl_dir(struct file *file, unsigned int cmd, unsigned long arg); ++ ++#ifdef CONFIG_AUFS_RDU ++/* rdu.c */ ++long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg); ++#ifdef CONFIG_COMPAT ++long au_rdu_compat_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg); ++#endif ++#else ++AuStub(long, au_rdu_ioctl, return -EINVAL, struct file *file, ++ unsigned int cmd, unsigned long arg) ++#ifdef CONFIG_COMPAT ++AuStub(long, au_rdu_compat_ioctl, return -EINVAL, struct file *file, ++ unsigned int cmd, unsigned long arg) ++#endif ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DIR_H__ */ +diff --git a/fs/aufs/dirren.c b/fs/aufs/dirren.c +new file mode 100644 +index 000000000000..12b56c47f2dd +--- /dev/null ++++ b/fs/aufs/dirren.c +@@ -0,0 +1,1303 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2017-2020 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 /* debug print */ ++ { ++ struct hlist_bl_node *tmp; ++ ++ hlist_bl_for_each_entry_safe(ent, pos, tmp, hbl, dr_hnode) ++ AuDbg("hi%llu\n", (unsigned long long)ent->dr_h_ino); ++ } ++#endif ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(ent, pos, hbl, dr_hnode) ++ if (ent->dr_h_ino == ino) { ++ found = 1; ++ break; ++ } ++ if (!found && add_ent) ++ hlist_bl_add_head(&add_ent->dr_hnode, hbl); ++ hlist_bl_unlock(hbl); ++ ++ if (!found && add_ent) ++ AuDbg("i%llu added\n", (unsigned long long)add_ent->dr_h_ino); ++ ++ return found; ++} ++ ++void au_dr_hino_free(struct au_dr_br *dr) ++{ ++ int i; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos, *tmp; ++ struct au_dr_hino *ent; ++ ++ /* SiMustWriteLock(sb); */ ++ ++ for (i = 0; i < AuDirren_NHASH; i++) { ++ hbl = dr->dr_h_ino + i; ++ /* no spinlock since sbinfo must be write-locked */ ++ hlist_bl_for_each_entry_safe(ent, pos, tmp, hbl, dr_hnode) ++ au_kfree_rcu(ent); ++ INIT_HLIST_BL_HEAD(hbl); ++ } ++} ++ ++/* returns the number of inodes or an error */ ++static int au_dr_hino_store(struct super_block *sb, struct au_branch *br, ++ struct file *hinofile) ++{ ++ int err, i; ++ ssize_t ssz; ++ loff_t pos, oldsize; ++ __be64 u64; ++ struct inode *hinoinode; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *n1, *n2; ++ struct au_dr_hino *ent; ++ ++ SiMustWriteLock(sb); ++ AuDebugOn(!au_br_writable(br->br_perm)); ++ ++ hinoinode = file_inode(hinofile); ++ oldsize = i_size_read(hinoinode); ++ ++ err = 0; ++ pos = 0; ++ hbl = br->br_dirren.dr_h_ino; ++ for (i = 0; !err && i < AuDirren_NHASH; i++, hbl++) { ++ /* no bit-lock since sbinfo must be write-locked */ ++ hlist_bl_for_each_entry_safe(ent, n1, n2, hbl, dr_hnode) { ++ AuDbg("hi%llu, %pD2\n", ++ (unsigned long long)ent->dr_h_ino, hinofile); ++ u64 = cpu_to_be64(ent->dr_h_ino); ++ ssz = vfsub_write_k(hinofile, &u64, sizeof(u64), &pos); ++ if (ssz == sizeof(u64)) ++ continue; ++ ++ /* write error */ ++ pr_err("ssz %zd, %pD2\n", ssz, hinofile); ++ err = -ENOSPC; ++ if (ssz < 0) ++ err = ssz; ++ break; ++ } ++ } ++ /* regardless the error */ ++ if (pos < oldsize) { ++ err = vfsub_trunc(&hinofile->f_path, pos, /*attr*/0, hinofile); ++ AuTraceErr(err); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_dr_hino_load(struct au_dr_br *dr, struct file *hinofile) ++{ ++ int err, hidx; ++ ssize_t ssz; ++ size_t sz, n; ++ loff_t pos; ++ uint64_t u64; ++ struct au_dr_hino *ent; ++ struct inode *hinoinode; ++ struct hlist_bl_head *hbl; ++ ++ err = 0; ++ pos = 0; ++ hbl = dr->dr_h_ino; ++ hinoinode = file_inode(hinofile); ++ sz = i_size_read(hinoinode); ++ AuDebugOn(sz % sizeof(u64)); ++ n = sz / sizeof(u64); ++ while (n--) { ++ ssz = vfsub_read_k(hinofile, &u64, sizeof(u64), &pos); ++ if (unlikely(ssz != sizeof(u64))) { ++ pr_err("ssz %zd, %pD2\n", ssz, hinofile); ++ err = -EINVAL; ++ if (ssz < 0) ++ err = ssz; ++ goto out_free; ++ } ++ ++ ent = kmalloc(sizeof(*ent), GFP_NOFS); ++ if (!ent) { ++ err = -ENOMEM; ++ AuTraceErr(err); ++ goto out_free; ++ } ++ ent->dr_h_ino = be64_to_cpu((__force __be64)u64); ++ AuDbg("hi%llu, %pD2\n", ++ (unsigned long long)ent->dr_h_ino, hinofile); ++ hidx = au_dr_ihash(ent->dr_h_ino); ++ au_hbl_add(&ent->dr_hnode, hbl + hidx); ++ } ++ goto out; /* success */ ++ ++out_free: ++ au_dr_hino_free(dr); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * @bindex/@br is a switch to distinguish whether suspending hnotify or not. ++ * @path is a switch to distinguish load and store. ++ */ ++static int au_dr_hino(struct super_block *sb, aufs_bindex_t bindex, ++ struct au_branch *br, const struct path *path) ++{ ++ int err, flags; ++ unsigned char load, suspend; ++ struct file *hinofile; ++ struct au_hinode *hdir; ++ struct inode *dir, *delegated; ++ struct path hinopath; ++ struct qstr hinoname = QSTR_INIT(AUFS_WH_DR_BRHINO, ++ sizeof(AUFS_WH_DR_BRHINO) - 1); ++ ++ AuDebugOn(bindex < 0 && !br); ++ AuDebugOn(bindex >= 0 && br); ++ ++ err = -EINVAL; ++ suspend = !br; ++ if (suspend) ++ br = au_sbr(sb, bindex); ++ load = !!path; ++ if (!load) { ++ path = &br->br_path; ++ AuDebugOn(!au_br_writable(br->br_perm)); ++ if (unlikely(!au_br_writable(br->br_perm))) ++ goto out; ++ } ++ ++ hdir = NULL; ++ if (suspend) { ++ dir = d_inode(sb->s_root); ++ hdir = au_hinode(au_ii(dir), bindex); ++ dir = hdir->hi_inode; ++ au_hn_inode_lock_nested(hdir, AuLsc_I_CHILD); ++ } else { ++ dir = d_inode(path->dentry); ++ inode_lock_nested(dir, AuLsc_I_CHILD); ++ } ++ hinopath.dentry = vfsub_lkup_one(&hinoname, path->dentry); ++ err = PTR_ERR(hinopath.dentry); ++ if (IS_ERR(hinopath.dentry)) ++ goto out_unlock; ++ ++ err = 0; ++ flags = O_RDONLY; ++ if (load) { ++ if (d_is_negative(hinopath.dentry)) ++ goto out_dput; /* success */ ++ } else { ++ if (au_dr_hino_test_empty(&br->br_dirren)) { ++ if (d_is_positive(hinopath.dentry)) { ++ delegated = NULL; ++ err = vfsub_unlink(dir, &hinopath, &delegated, ++ /*force*/0); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ pr_err("ignored err %d, %pd2\n", ++ err, hinopath.dentry); ++ if (unlikely(err == -EWOULDBLOCK)) ++ iput(delegated); ++ err = 0; ++ } ++ goto out_dput; ++ } else if (!d_is_positive(hinopath.dentry)) { ++ err = vfsub_create(dir, &hinopath, 0600, ++ /*want_excl*/false); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out_dput; ++ } ++ flags = O_WRONLY; ++ } ++ hinopath.mnt = path->mnt; ++ hinofile = vfsub_dentry_open(&hinopath, flags); ++ if (suspend) ++ au_hn_inode_unlock(hdir); ++ else ++ inode_unlock(dir); ++ dput(hinopath.dentry); ++ AuTraceErrPtr(hinofile); ++ if (IS_ERR(hinofile)) { ++ err = PTR_ERR(hinofile); ++ goto out; ++ } ++ ++ if (load) ++ err = au_dr_hino_load(&br->br_dirren, hinofile); ++ else ++ err = au_dr_hino_store(sb, br, hinofile); ++ fput(hinofile); ++ goto out; ++ ++out_dput: ++ dput(hinopath.dentry); ++out_unlock: ++ if (suspend) ++ au_hn_inode_unlock(hdir); ++ else ++ inode_unlock(dir); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_dr_brid_init(struct au_dr_brid *brid, const struct path *path) ++{ ++ int err; ++ struct kstatfs kstfs; ++ dev_t dev; ++ struct dentry *dentry; ++ struct super_block *sb; ++ ++ err = vfs_statfs((void *)path, &kstfs); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out; ++ ++ /* todo: support for UUID */ ++ ++ if (kstfs.f_fsid.val[0] || kstfs.f_fsid.val[1]) { ++ brid->type = AuBrid_FSID; ++ brid->fsid = kstfs.f_fsid; ++ } else { ++ dentry = path->dentry; ++ sb = dentry->d_sb; ++ dev = sb->s_dev; ++ if (dev) { ++ brid->type = AuBrid_DEV; ++ brid->dev = dev; ++ } ++ } ++ ++out: ++ return err; ++} ++ ++int au_dr_br_init(struct super_block *sb, struct au_branch *br, ++ const struct path *path) ++{ ++ int err, i; ++ struct au_dr_br *dr; ++ struct hlist_bl_head *hbl; ++ ++ dr = &br->br_dirren; ++ hbl = dr->dr_h_ino; ++ for (i = 0; i < AuDirren_NHASH; i++, hbl++) ++ INIT_HLIST_BL_HEAD(hbl); ++ ++ err = au_dr_brid_init(&dr->dr_brid, path); ++ if (unlikely(err)) ++ goto out; ++ ++ if (au_opt_test(au_mntflags(sb), DIRREN)) ++ err = au_dr_hino(sb, /*bindex*/-1, br, path); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_dr_br_fin(struct super_block *sb, struct au_branch *br) ++{ ++ int err; ++ ++ err = 0; ++ if (au_br_writable(br->br_perm)) ++ err = au_dr_hino(sb, /*bindex*/-1, br, /*path*/NULL); ++ if (!err) ++ au_dr_hino_free(&br->br_dirren); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_brid_str(struct au_dr_brid *brid, struct inode *h_inode, ++ char *buf, size_t sz) ++{ ++ int err; ++ unsigned int major, minor; ++ char *p; ++ ++ p = buf; ++ err = snprintf(p, sz, "%d_", brid->type); ++ AuDebugOn(err > sz); ++ p += err; ++ sz -= err; ++ switch (brid->type) { ++ case AuBrid_Unset: ++ return -EINVAL; ++ case AuBrid_UUID: ++ err = snprintf(p, sz, "%pU", brid->uuid.b); ++ break; ++ case AuBrid_FSID: ++ err = snprintf(p, sz, "%08x-%08x", ++ brid->fsid.val[0], brid->fsid.val[1]); ++ break; ++ case AuBrid_DEV: ++ major = MAJOR(brid->dev); ++ minor = MINOR(brid->dev); ++ if (major <= 0xff && minor <= 0xff) ++ err = snprintf(p, sz, "%02x%02x", major, minor); ++ else ++ err = snprintf(p, sz, "%03x:%05x", major, minor); ++ break; ++ } ++ AuDebugOn(err > sz); ++ p += err; ++ sz -= err; ++ err = snprintf(p, sz, "_%llu", (unsigned long long)h_inode->i_ino); ++ AuDebugOn(err > sz); ++ p += err; ++ sz -= err; ++ ++ return p - buf; ++} ++ ++static int au_drinfo_name(struct au_branch *br, char *name, int len) ++{ ++ int rlen; ++ struct dentry *br_dentry; ++ struct inode *br_inode; ++ ++ br_dentry = au_br_dentry(br); ++ br_inode = d_inode(br_dentry); ++ rlen = au_brid_str(&br->br_dirren.dr_brid, br_inode, name, len); ++ AuDebugOn(rlen >= AUFS_DIRREN_ENV_VAL_SZ); ++ AuDebugOn(rlen > len); ++ ++ return rlen; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * from the given @h_dentry, construct drinfo at @*fdata. ++ * when the size of @*fdata is not enough, reallocate and return new @fdata and ++ * @allocated. ++ */ ++static int au_drinfo_construct(struct au_drinfo_fdata **fdata, ++ struct dentry *h_dentry, ++ unsigned char *allocated) ++{ ++ int err, v; ++ struct au_drinfo_fdata *f, *p; ++ struct au_drinfo *drinfo; ++ struct inode *h_inode; ++ struct qstr *qname; ++ ++ err = 0; ++ f = *fdata; ++ h_inode = d_inode(h_dentry); ++ qname = &h_dentry->d_name; ++ drinfo = &f->drinfo; ++ drinfo->ino = (__force uint64_t)cpu_to_be64(h_inode->i_ino); ++ drinfo->oldnamelen = qname->len; ++ if (*allocated < sizeof(*f) + qname->len) { ++ v = roundup_pow_of_two(*allocated + qname->len); ++ p = au_krealloc(f, v, GFP_NOFS, /*may_shrink*/0); ++ if (unlikely(!p)) { ++ err = -ENOMEM; ++ AuTraceErr(err); ++ goto out; ++ } ++ f = p; ++ *fdata = f; ++ *allocated = v; ++ drinfo = &f->drinfo; ++ } ++ memcpy(drinfo->oldname, qname->name, qname->len); ++ AuDbg("i%llu, %.*s\n", ++ be64_to_cpu((__force __be64)drinfo->ino), drinfo->oldnamelen, ++ drinfo->oldname); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* callers have to free the return value */ ++static struct au_drinfo *au_drinfo_read_k(struct file *file, ino_t h_ino) ++{ ++ struct au_drinfo *ret, *drinfo; ++ struct au_drinfo_fdata fdata; ++ int len; ++ loff_t pos; ++ ssize_t ssz; ++ ++ ret = ERR_PTR(-EIO); ++ pos = 0; ++ ssz = vfsub_read_k(file, &fdata, sizeof(fdata), &pos); ++ if (unlikely(ssz != sizeof(fdata))) { ++ AuIOErr("ssz %zd, %u, %pD2\n", ++ ssz, (unsigned int)sizeof(fdata), file); ++ goto out; ++ } ++ ++ fdata.magic = ntohl((__force __be32)fdata.magic); ++ switch (fdata.magic) { ++ case AUFS_DRINFO_MAGIC_V1: ++ break; ++ default: ++ AuIOErr("magic-num 0x%x, 0x%x, %pD2\n", ++ fdata.magic, AUFS_DRINFO_MAGIC_V1, file); ++ goto out; ++ } ++ ++ drinfo = &fdata.drinfo; ++ len = drinfo->oldnamelen; ++ if (!len) { ++ AuIOErr("broken drinfo %pD2\n", file); ++ goto out; ++ } ++ ++ ret = NULL; ++ drinfo->ino = be64_to_cpu((__force __be64)drinfo->ino); ++ if (unlikely(h_ino && drinfo->ino != h_ino)) { ++ AuDbg("ignored i%llu, i%llu, %pD2\n", ++ (unsigned long long)drinfo->ino, ++ (unsigned long long)h_ino, file); ++ goto out; /* success */ ++ } ++ ++ ret = kmalloc(sizeof(*ret) + len, GFP_NOFS); ++ if (unlikely(!ret)) { ++ ret = ERR_PTR(-ENOMEM); ++ AuTraceErrPtr(ret); ++ goto out; ++ } ++ ++ *ret = *drinfo; ++ ssz = vfsub_read_k(file, (void *)ret->oldname, len, &pos); ++ if (unlikely(ssz != len)) { ++ au_kfree_rcu(ret); ++ ret = ERR_PTR(-EIO); ++ AuIOErr("ssz %zd, %u, %pD2\n", ssz, len, file); ++ goto out; ++ } ++ ++ AuDbg("oldname %.*s\n", ret->oldnamelen, ret->oldname); ++ ++out: ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* in order to be revertible */ ++struct au_drinfo_rev_elm { ++ int created; ++ struct dentry *info_dentry; ++ struct au_drinfo *info_last; ++}; ++ ++struct au_drinfo_rev { ++ unsigned char already; ++ aufs_bindex_t nelm; ++ struct au_drinfo_rev_elm elm[]; ++}; ++ ++/* todo: isn't it too large? */ ++struct au_drinfo_store { ++ struct path h_ppath; ++ struct dentry *h_dentry; ++ struct au_drinfo_fdata *fdata; ++ char *infoname; /* inside of whname, just after PFX */ ++ char whname[sizeof(AUFS_WH_DR_INFO_PFX) + AUFS_DIRREN_ENV_VAL_SZ]; ++ aufs_bindex_t btgt, btail; ++ unsigned char no_sio, ++ allocated, /* current size of *fdata */ ++ infonamelen, /* room size for p */ ++ whnamelen, /* length of the generated name */ ++ renameback; /* renamed back */ ++}; ++ ++/* on rename(2) error, the caller should revert it using @elm */ ++static int au_drinfo_do_store(struct au_drinfo_store *w, ++ struct au_drinfo_rev_elm *elm) ++{ ++ int err, len; ++ ssize_t ssz; ++ loff_t pos; ++ struct path infopath = { ++ .mnt = w->h_ppath.mnt ++ }; ++ struct inode *h_dir, *h_inode, *delegated; ++ struct file *infofile; ++ struct qstr *qname; ++ ++ AuDebugOn(elm ++ && memcmp(elm, page_address(ZERO_PAGE(0)), sizeof(*elm))); ++ ++ infopath.dentry = vfsub_lookup_one_len(w->whname, w->h_ppath.dentry, ++ w->whnamelen); ++ AuTraceErrPtr(infopath.dentry); ++ if (IS_ERR(infopath.dentry)) { ++ err = PTR_ERR(infopath.dentry); ++ goto out; ++ } ++ ++ err = 0; ++ h_dir = d_inode(w->h_ppath.dentry); ++ if (elm && d_is_negative(infopath.dentry)) { ++ err = vfsub_create(h_dir, &infopath, 0600, /*want_excl*/true); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out_dput; ++ elm->created = 1; ++ elm->info_dentry = dget(infopath.dentry); ++ } ++ ++ infofile = vfsub_dentry_open(&infopath, O_RDWR); ++ AuTraceErrPtr(infofile); ++ if (IS_ERR(infofile)) { ++ err = PTR_ERR(infofile); ++ goto out_dput; ++ } ++ ++ h_inode = d_inode(infopath.dentry); ++ if (elm && i_size_read(h_inode)) { ++ h_inode = d_inode(w->h_dentry); ++ elm->info_last = au_drinfo_read_k(infofile, h_inode->i_ino); ++ AuTraceErrPtr(elm->info_last); ++ if (IS_ERR(elm->info_last)) { ++ err = PTR_ERR(elm->info_last); ++ elm->info_last = NULL; ++ AuDebugOn(elm->info_dentry); ++ goto out_fput; ++ } ++ } ++ ++ if (elm && w->renameback) { ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, &infopath, &delegated, /*force*/0); ++ AuTraceErr(err); ++ if (unlikely(err == -EWOULDBLOCK)) ++ iput(delegated); ++ goto out_fput; ++ } ++ ++ pos = 0; ++ qname = &w->h_dentry->d_name; ++ len = sizeof(*w->fdata) + qname->len; ++ if (!elm) ++ len = sizeof(*w->fdata) + w->fdata->drinfo.oldnamelen; ++ ssz = vfsub_write_k(infofile, w->fdata, len, &pos); ++ if (ssz == len) { ++ AuDbg("hi%llu, %.*s\n", w->fdata->drinfo.ino, ++ w->fdata->drinfo.oldnamelen, w->fdata->drinfo.oldname); ++ goto out_fput; /* success */ ++ } else { ++ err = -EIO; ++ if (ssz < 0) ++ err = ssz; ++ /* the caller should revert it using @elm */ ++ } ++ ++out_fput: ++ fput(infofile); ++out_dput: ++ dput(infopath.dentry); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++struct au_call_drinfo_do_store_args { ++ int *errp; ++ struct au_drinfo_store *w; ++ struct au_drinfo_rev_elm *elm; ++}; ++ ++static void au_call_drinfo_do_store(void *args) ++{ ++ struct au_call_drinfo_do_store_args *a = args; ++ ++ *a->errp = au_drinfo_do_store(a->w, a->elm); ++} ++ ++static int au_drinfo_store_sio(struct au_drinfo_store *w, ++ struct au_drinfo_rev_elm *elm) ++{ ++ int err, wkq_err; ++ ++ if (w->no_sio) ++ err = au_drinfo_do_store(w, elm); ++ else { ++ struct au_call_drinfo_do_store_args a = { ++ .errp = &err, ++ .w = w, ++ .elm = elm ++ }; ++ wkq_err = au_wkq_wait(au_call_drinfo_do_store, &a); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ AuTraceErr(err); ++ ++ return err; ++} ++ ++static int au_drinfo_store_work_init(struct au_drinfo_store *w, ++ aufs_bindex_t btgt) ++{ ++ int err; ++ ++ memset(w, 0, sizeof(*w)); ++ w->allocated = roundup_pow_of_two(sizeof(*w->fdata) + 40); ++ strcpy(w->whname, AUFS_WH_DR_INFO_PFX); ++ w->infoname = w->whname + sizeof(AUFS_WH_DR_INFO_PFX) - 1; ++ w->infonamelen = sizeof(w->whname) - sizeof(AUFS_WH_DR_INFO_PFX); ++ w->btgt = btgt; ++ w->no_sio = !!uid_eq(current_fsuid(), GLOBAL_ROOT_UID); ++ ++ err = -ENOMEM; ++ w->fdata = kcalloc(1, w->allocated, GFP_NOFS); ++ if (unlikely(!w->fdata)) { ++ AuTraceErr(err); ++ goto out; ++ } ++ w->fdata->magic = (__force uint32_t)htonl(AUFS_DRINFO_MAGIC_V1); ++ err = 0; ++ ++out: ++ return err; ++} ++ ++static void au_drinfo_store_work_fin(struct au_drinfo_store *w) ++{ ++ au_kfree_rcu(w->fdata); ++} ++ ++static void au_drinfo_store_rev(struct au_drinfo_rev *rev, ++ struct au_drinfo_store *w) ++{ ++ struct au_drinfo_rev_elm *elm; ++ struct inode *h_dir, *delegated; ++ int err, nelm; ++ struct path infopath = { ++ .mnt = w->h_ppath.mnt ++ }; ++ ++ h_dir = d_inode(w->h_ppath.dentry); ++ IMustLock(h_dir); ++ ++ err = 0; ++ elm = rev->elm; ++ for (nelm = rev->nelm; nelm > 0; nelm--, elm++) { ++ AuDebugOn(elm->created && elm->info_last); ++ if (elm->created) { ++ AuDbg("here\n"); ++ delegated = NULL; ++ infopath.dentry = elm->info_dentry; ++ err = vfsub_unlink(h_dir, &infopath, &delegated, ++ !w->no_sio); ++ AuTraceErr(err); ++ if (unlikely(err == -EWOULDBLOCK)) ++ iput(delegated); ++ dput(elm->info_dentry); ++ } else if (elm->info_last) { ++ AuDbg("here\n"); ++ w->fdata->drinfo = *elm->info_last; ++ memcpy(w->fdata->drinfo.oldname, ++ elm->info_last->oldname, ++ elm->info_last->oldnamelen); ++ err = au_drinfo_store_sio(w, /*elm*/NULL); ++ au_kfree_rcu(elm->info_last); ++ } ++ if (unlikely(err)) ++ AuIOErr("%d, %s\n", err, w->whname); ++ /* go on even if err */ ++ } ++} ++ ++/* caller has to call au_dr_rename_fin() later */ ++static int au_drinfo_store(struct dentry *dentry, aufs_bindex_t btgt, ++ struct qstr *dst_name, void *_rev) ++{ ++ int err, sz, nelm; ++ aufs_bindex_t bindex, btail; ++ struct au_drinfo_store work; ++ struct au_drinfo_rev *rev, **p; ++ struct au_drinfo_rev_elm *elm; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_hinode *hdir; ++ ++ err = au_drinfo_store_work_init(&work, btgt); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out; ++ ++ err = -ENOMEM; ++ btail = au_dbtaildir(dentry); ++ nelm = btail - btgt; ++ sz = sizeof(*rev) + sizeof(*elm) * nelm; ++ rev = kcalloc(1, sz, GFP_NOFS); ++ if (unlikely(!rev)) { ++ AuTraceErr(err); ++ goto out_args; ++ } ++ rev->nelm = nelm; ++ elm = rev->elm; ++ p = _rev; ++ *p = rev; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ work.h_ppath.dentry = au_h_dptr(dentry, btgt); ++ work.h_ppath.mnt = au_sbr_mnt(sb, btgt); ++ hdir = au_hi(d_inode(dentry), btgt); ++ au_hn_inode_lock_nested(hdir, AuLsc_I_CHILD); ++ for (bindex = btgt + 1; bindex <= btail; bindex++, elm++) { ++ work.h_dentry = au_h_dptr(dentry, bindex); ++ if (!work.h_dentry) ++ continue; ++ ++ err = au_drinfo_construct(&work.fdata, work.h_dentry, ++ &work.allocated); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ break; ++ ++ work.renameback = au_qstreq(&work.h_dentry->d_name, dst_name); ++ br = au_sbr(sb, bindex); ++ work.whnamelen = sizeof(AUFS_WH_DR_INFO_PFX) - 1; ++ work.whnamelen += au_drinfo_name(br, work.infoname, ++ work.infonamelen); ++ AuDbg("whname %.*s, i%llu, %.*s\n", ++ work.whnamelen, work.whname, ++ be64_to_cpu((__force __be64)work.fdata->drinfo.ino), ++ work.fdata->drinfo.oldnamelen, ++ work.fdata->drinfo.oldname); ++ ++ err = au_drinfo_store_sio(&work, elm); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ break; ++ } ++ if (unlikely(err)) { ++ /* revert all drinfo */ ++ au_drinfo_store_rev(rev, &work); ++ au_kfree_try_rcu(rev); ++ *p = NULL; ++ } ++ au_hn_inode_unlock(hdir); ++ ++out_args: ++ au_drinfo_store_work_fin(&work); ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_dr_rename(struct dentry *src, aufs_bindex_t bindex, ++ struct qstr *dst_name, void *_rev) ++{ ++ int err, already; ++ ino_t ino; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_dr_br *dr; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct au_dr_hino *ent; ++ struct au_drinfo_rev *rev, **p; ++ ++ AuDbg("bindex %d\n", bindex); ++ ++ err = -ENOMEM; ++ ent = kmalloc(sizeof(*ent), GFP_NOFS); ++ if (unlikely(!ent)) ++ goto out; ++ ++ sb = src->d_sb; ++ br = au_sbr(sb, bindex); ++ dr = &br->br_dirren; ++ h_dentry = au_h_dptr(src, bindex); ++ h_inode = d_inode(h_dentry); ++ ino = h_inode->i_ino; ++ ent->dr_h_ino = ino; ++ already = au_dr_hino_test_add(dr, ino, ent); ++ AuDbg("b%d, hi%llu, already %d\n", ++ bindex, (unsigned long long)ino, already); ++ ++ err = au_drinfo_store(src, bindex, dst_name, _rev); ++ AuTraceErr(err); ++ if (!err) { ++ p = _rev; ++ rev = *p; ++ rev->already = already; ++ goto out; /* success */ ++ } ++ ++ /* revert */ ++ if (!already) ++ au_dr_hino_del(dr, ent); ++ au_kfree_rcu(ent); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_dr_rename_fin(struct dentry *src, aufs_bindex_t btgt, void *_rev) ++{ ++ struct au_drinfo_rev *rev; ++ struct au_drinfo_rev_elm *elm; ++ int nelm; ++ ++ rev = _rev; ++ elm = rev->elm; ++ for (nelm = rev->nelm; nelm > 0; nelm--, elm++) { ++ dput(elm->info_dentry); ++ au_kfree_rcu(elm->info_last); ++ } ++ au_kfree_try_rcu(rev); ++} ++ ++void au_dr_rename_rev(struct dentry *src, aufs_bindex_t btgt, void *_rev) ++{ ++ int err; ++ struct au_drinfo_store work; ++ struct au_drinfo_rev *rev = _rev; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct inode *h_inode; ++ struct au_dr_br *dr; ++ struct au_dr_hino *ent; ++ ++ err = au_drinfo_store_work_init(&work, btgt); ++ if (unlikely(err)) ++ goto out; ++ ++ sb = src->d_sb; ++ br = au_sbr(sb, btgt); ++ work.h_ppath.dentry = au_h_dptr(src, btgt); ++ work.h_ppath.mnt = au_br_mnt(br); ++ au_drinfo_store_rev(rev, &work); ++ au_drinfo_store_work_fin(&work); ++ if (rev->already) ++ goto out; ++ ++ dr = &br->br_dirren; ++ h_inode = d_inode(work.h_ppath.dentry); ++ ent = au_dr_hino_find(dr, h_inode->i_ino); ++ BUG_ON(!ent); ++ au_dr_hino_del(dr, ent); ++ au_kfree_rcu(ent); ++ ++out: ++ au_kfree_try_rcu(rev); ++ if (unlikely(err)) ++ pr_err("failed to remove dirren info\n"); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct au_drinfo *au_drinfo_do_load(struct path *h_ppath, ++ char *whname, int whnamelen, ++ struct dentry **info_dentry) ++{ ++ struct au_drinfo *drinfo; ++ struct file *f; ++ struct inode *h_dir; ++ struct path infopath; ++ int unlocked; ++ ++ AuDbg("%pd/%.*s\n", h_ppath->dentry, whnamelen, whname); ++ ++ *info_dentry = NULL; ++ drinfo = NULL; ++ unlocked = 0; ++ h_dir = d_inode(h_ppath->dentry); ++ inode_lock_shared_nested(h_dir, AuLsc_I_PARENT); ++ infopath.dentry = vfsub_lookup_one_len(whname, h_ppath->dentry, ++ whnamelen); ++ if (IS_ERR(infopath.dentry)) { ++ drinfo = (void *)infopath.dentry; ++ goto out; ++ } ++ ++ if (d_is_negative(infopath.dentry)) ++ goto out_dput; /* success */ ++ ++ infopath.mnt = h_ppath->mnt; ++ f = vfsub_dentry_open(&infopath, O_RDONLY); ++ inode_unlock_shared(h_dir); ++ unlocked = 1; ++ if (IS_ERR(f)) { ++ drinfo = (void *)f; ++ goto out_dput; ++ } ++ ++ drinfo = au_drinfo_read_k(f, /*h_ino*/0); ++ if (IS_ERR_OR_NULL(drinfo)) ++ goto out_fput; ++ ++ AuDbg("oldname %.*s\n", drinfo->oldnamelen, drinfo->oldname); ++ *info_dentry = dget(infopath.dentry); /* keep it alive */ ++ ++out_fput: ++ fput(f); ++out_dput: ++ dput(infopath.dentry); ++out: ++ if (!unlocked) ++ inode_unlock_shared(h_dir); ++ AuTraceErrPtr(drinfo); ++ return drinfo; ++} ++ ++struct au_drinfo_do_load_args { ++ struct au_drinfo **drinfop; ++ struct path *h_ppath; ++ char *whname; ++ int whnamelen; ++ struct dentry **info_dentry; ++}; ++ ++static void au_call_drinfo_do_load(void *args) ++{ ++ struct au_drinfo_do_load_args *a = args; ++ ++ *a->drinfop = au_drinfo_do_load(a->h_ppath, a->whname, a->whnamelen, ++ a->info_dentry); ++} ++ ++struct au_drinfo_load { ++ struct path h_ppath; ++ struct qstr *qname; ++ unsigned char no_sio; ++ ++ aufs_bindex_t ninfo; ++ struct au_drinfo **drinfo; ++}; ++ ++static int au_drinfo_load(struct au_drinfo_load *w, aufs_bindex_t bindex, ++ struct au_branch *br) ++{ ++ int err, wkq_err, whnamelen, e; ++ char whname[sizeof(AUFS_WH_DR_INFO_PFX) + AUFS_DIRREN_ENV_VAL_SZ] ++ = AUFS_WH_DR_INFO_PFX; ++ struct au_drinfo *drinfo; ++ struct qstr oldname; ++ struct inode *h_dir, *delegated; ++ struct dentry *info_dentry; ++ struct path infopath; ++ ++ whnamelen = sizeof(AUFS_WH_DR_INFO_PFX) - 1; ++ whnamelen += au_drinfo_name(br, whname + whnamelen, ++ sizeof(whname) - whnamelen); ++ if (w->no_sio) ++ drinfo = au_drinfo_do_load(&w->h_ppath, whname, whnamelen, ++ &info_dentry); ++ else { ++ struct au_drinfo_do_load_args args = { ++ .drinfop = &drinfo, ++ .h_ppath = &w->h_ppath, ++ .whname = whname, ++ .whnamelen = whnamelen, ++ .info_dentry = &info_dentry ++ }; ++ wkq_err = au_wkq_wait(au_call_drinfo_do_load, &args); ++ if (unlikely(wkq_err)) ++ drinfo = ERR_PTR(wkq_err); ++ } ++ err = PTR_ERR(drinfo); ++ if (IS_ERR_OR_NULL(drinfo)) ++ goto out; ++ ++ err = 0; ++ oldname.len = drinfo->oldnamelen; ++ oldname.name = drinfo->oldname; ++ if (au_qstreq(w->qname, &oldname)) { ++ /* the name is renamed back */ ++ au_kfree_rcu(drinfo); ++ drinfo = NULL; ++ ++ infopath.dentry = info_dentry; ++ infopath.mnt = w->h_ppath.mnt; ++ h_dir = d_inode(w->h_ppath.dentry); ++ delegated = NULL; ++ inode_lock_nested(h_dir, AuLsc_I_PARENT); ++ e = vfsub_unlink(h_dir, &infopath, &delegated, !w->no_sio); ++ inode_unlock(h_dir); ++ if (unlikely(e)) ++ AuIOErr("ignored %d, %pd2\n", e, &infopath.dentry); ++ if (unlikely(e == -EWOULDBLOCK)) ++ iput(delegated); ++ } ++ au_kfree_rcu(w->drinfo[bindex]); ++ w->drinfo[bindex] = drinfo; ++ dput(info_dentry); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_dr_lkup_free(struct au_drinfo **drinfo, int n) ++{ ++ struct au_drinfo **p = drinfo; ++ ++ while (n-- > 0) ++ au_kfree_rcu(*drinfo++); ++ au_kfree_try_rcu(p); ++} ++ ++int au_dr_lkup(struct au_do_lookup_args *lkup, struct dentry *dentry, ++ aufs_bindex_t btgt) ++{ ++ int err, ninfo; ++ struct au_drinfo_load w; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ struct inode *h_dir; ++ struct au_dr_hino *ent; ++ struct super_block *sb; ++ ++ AuDbg("%.*s, name %.*s, whname %.*s, b%d\n", ++ AuLNPair(&dentry->d_name), AuLNPair(&lkup->dirren.dr_name), ++ AuLNPair(&lkup->whname), btgt); ++ ++ sb = dentry->d_sb; ++ bbot = au_sbbot(sb); ++ w.ninfo = bbot + 1; ++ if (!lkup->dirren.drinfo) { ++ lkup->dirren.drinfo = kcalloc(w.ninfo, ++ sizeof(*lkup->dirren.drinfo), ++ GFP_NOFS); ++ if (unlikely(!lkup->dirren.drinfo)) { ++ err = -ENOMEM; ++ goto out; ++ } ++ lkup->dirren.ninfo = w.ninfo; ++ } ++ w.drinfo = lkup->dirren.drinfo; ++ w.no_sio = !!uid_eq(current_fsuid(), GLOBAL_ROOT_UID); ++ w.h_ppath.dentry = au_h_dptr(dentry, btgt); ++ AuDebugOn(!w.h_ppath.dentry); ++ w.h_ppath.mnt = au_sbr_mnt(sb, btgt); ++ w.qname = &dentry->d_name; ++ ++ ninfo = 0; ++ for (bindex = btgt + 1; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ err = au_drinfo_load(&w, bindex, br); ++ if (unlikely(err)) ++ goto out_free; ++ if (w.drinfo[bindex]) ++ ninfo++; ++ } ++ if (!ninfo) { ++ br = au_sbr(sb, btgt); ++ h_dir = d_inode(w.h_ppath.dentry); ++ ent = au_dr_hino_find(&br->br_dirren, h_dir->i_ino); ++ AuDebugOn(!ent); ++ au_dr_hino_del(&br->br_dirren, ent); ++ au_kfree_rcu(ent); ++ } ++ goto out; /* success */ ++ ++out_free: ++ au_dr_lkup_free(lkup->dirren.drinfo, lkup->dirren.ninfo); ++ lkup->dirren.ninfo = 0; ++ lkup->dirren.drinfo = NULL; ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_dr_lkup_fin(struct au_do_lookup_args *lkup) ++{ ++ au_dr_lkup_free(lkup->dirren.drinfo, lkup->dirren.ninfo); ++} ++ ++int au_dr_lkup_name(struct au_do_lookup_args *lkup, aufs_bindex_t btgt) ++{ ++ int err; ++ struct au_drinfo *drinfo; ++ ++ err = 0; ++ if (!lkup->dirren.drinfo) ++ goto out; ++ AuDebugOn(lkup->dirren.ninfo <= btgt); ++ drinfo = lkup->dirren.drinfo[btgt]; ++ if (!drinfo) ++ goto out; ++ ++ au_kfree_try_rcu(lkup->whname.name); ++ lkup->whname.name = NULL; ++ lkup->dirren.dr_name.len = drinfo->oldnamelen; ++ lkup->dirren.dr_name.name = drinfo->oldname; ++ lkup->name = &lkup->dirren.dr_name; ++ err = au_wh_name_alloc(&lkup->whname, lkup->name); ++ if (!err) ++ AuDbg("name %.*s, whname %.*s, b%d\n", ++ AuLNPair(lkup->name), AuLNPair(&lkup->whname), ++ btgt); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_dr_lkup_h_ino(struct au_do_lookup_args *lkup, aufs_bindex_t bindex, ++ ino_t h_ino) ++{ ++ int match; ++ struct au_drinfo *drinfo; ++ ++ match = 1; ++ if (!lkup->dirren.drinfo) ++ goto out; ++ AuDebugOn(lkup->dirren.ninfo <= bindex); ++ drinfo = lkup->dirren.drinfo[bindex]; ++ 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..ade589d2e75c +--- /dev/null ++++ b/fs/aufs/dirren.h +@@ -0,0 +1,127 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2017-2020 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..5dbb7193591b +--- /dev/null ++++ b/fs/aufs/dynop.c +@@ -0,0 +1,355 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2010-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * dynamically customizable operations for regular files ++ */ ++ ++#include "aufs.h" ++ ++#define DyPrSym(key) AuDbgSym(key->dk_op.dy_hop) ++ ++/* ++ * How large will these lists be? ++ * Usually just a few elements, 20-30 at most for each, I guess. ++ */ ++static struct hlist_bl_head dynop[AuDyLast]; ++ ++static struct au_dykey *dy_gfind_get(struct hlist_bl_head *hbl, ++ const void *h_op) ++{ ++ struct au_dykey *key, *tmp; ++ struct hlist_bl_node *pos; ++ ++ key = NULL; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(tmp, pos, hbl, dk_hnode) ++ if (tmp->dk_op.dy_hop == h_op) { ++ if (kref_get_unless_zero(&tmp->dk_kref)) ++ key = tmp; ++ break; ++ } ++ hlist_bl_unlock(hbl); ++ ++ return key; ++} ++ ++static struct au_dykey *dy_bradd(struct au_branch *br, struct au_dykey *key) ++{ ++ struct au_dykey **k, *found; ++ const void *h_op = key->dk_op.dy_hop; ++ int i; ++ ++ found = NULL; ++ k = br->br_dykey; ++ for (i = 0; i < AuBrDynOp; i++) ++ if (k[i]) { ++ if (k[i]->dk_op.dy_hop == h_op) { ++ found = k[i]; ++ break; ++ } ++ } else ++ break; ++ if (!found) { ++ spin_lock(&br->br_dykey_lock); ++ for (; i < AuBrDynOp; i++) ++ if (k[i]) { ++ if (k[i]->dk_op.dy_hop == h_op) { ++ found = k[i]; ++ break; ++ } ++ } else { ++ k[i] = key; ++ break; ++ } ++ spin_unlock(&br->br_dykey_lock); ++ BUG_ON(i == AuBrDynOp); /* expand the array */ ++ } ++ ++ return found; ++} ++ ++/* kref_get() if @key is already added */ ++static struct au_dykey *dy_gadd(struct hlist_bl_head *hbl, struct au_dykey *key) ++{ ++ struct au_dykey *tmp, *found; ++ struct hlist_bl_node *pos; ++ const void *h_op = key->dk_op.dy_hop; ++ ++ found = NULL; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(tmp, pos, hbl, dk_hnode) ++ if (tmp->dk_op.dy_hop == h_op) { ++ if (kref_get_unless_zero(&tmp->dk_kref)) ++ found = tmp; ++ break; ++ } ++ if (!found) ++ hlist_bl_add_head(&key->dk_hnode, hbl); ++ hlist_bl_unlock(hbl); ++ ++ if (!found) ++ DyPrSym(key); ++ return found; ++} ++ ++static void dy_free_rcu(struct rcu_head *rcu) ++{ ++ struct au_dykey *key; ++ ++ key = container_of(rcu, struct au_dykey, dk_rcu); ++ DyPrSym(key); ++ kfree(key); ++} ++ ++static void dy_free(struct kref *kref) ++{ ++ struct au_dykey *key; ++ struct hlist_bl_head *hbl; ++ ++ key = container_of(kref, struct au_dykey, dk_kref); ++ hbl = dynop + key->dk_op.dy_type; ++ au_hbl_del(&key->dk_hnode, hbl); ++ call_rcu(&key->dk_rcu, dy_free_rcu); ++} ++ ++void au_dy_put(struct au_dykey *key) ++{ ++ kref_put(&key->dk_kref, dy_free); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define DyDbgSize(cnt, op) AuDebugOn(cnt != sizeof(op)/sizeof(void *)) ++ ++#ifdef CONFIG_AUFS_DEBUG ++#define DyDbgDeclare(cnt) unsigned int cnt = 0 ++#define DyDbgInc(cnt) do { cnt++; } while (0) ++#else ++#define DyDbgDeclare(cnt) do {} while (0) ++#define DyDbgInc(cnt) do {} while (0) ++#endif ++ ++#define DySet(func, dst, src, h_op, h_sb) do { \ ++ DyDbgInc(cnt); \ ++ if (h_op->func) { \ ++ if (src.func) \ ++ dst.func = src.func; \ ++ else \ ++ AuDbg("%s %s\n", au_sbtype(h_sb), #func); \ ++ } \ ++} while (0) ++ ++#define DySetForce(func, dst, src) do { \ ++ AuDebugOn(!src.func); \ ++ DyDbgInc(cnt); \ ++ dst.func = src.func; \ ++} while (0) ++ ++#define DySetAop(func) \ ++ DySet(func, dyaop->da_op, aufs_aop, h_aop, h_sb) ++#define DySetAopForce(func) \ ++ DySetForce(func, dyaop->da_op, aufs_aop) ++ ++static void dy_aop(struct au_dykey *key, const void *h_op, ++ struct super_block *h_sb __maybe_unused) ++{ ++ struct au_dyaop *dyaop = (void *)key; ++ const struct address_space_operations *h_aop = h_op; ++ DyDbgDeclare(cnt); ++ ++ AuDbg("%s\n", au_sbtype(h_sb)); ++ ++ DySetAop(writepage); ++ DySetAopForce(readpage); /* force */ ++ DySetAop(writepages); ++ DySetAop(set_page_dirty); ++ DySetAop(readpages); ++ DySetAop(readahead); ++ DySetAop(write_begin); ++ DySetAop(write_end); ++ DySetAop(bmap); ++ DySetAop(invalidatepage); ++ DySetAop(releasepage); ++ DySetAop(freepage); ++ /* this one will be changed according to an aufs mount option */ ++ DySetAop(direct_IO); ++ DySetAop(migratepage); ++ DySetAop(isolate_page); ++ DySetAop(putback_page); ++ DySetAop(launder_page); ++ DySetAop(is_partially_uptodate); ++ DySetAop(is_dirty_writeback); ++ DySetAop(error_remove_page); ++ DySetAop(swap_activate); ++ DySetAop(swap_deactivate); ++ ++ DyDbgSize(cnt, *h_aop); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void dy_bug(struct kref *kref) ++{ ++ BUG(); ++} ++ ++static struct au_dykey *dy_get(struct au_dynop *op, struct au_branch *br) ++{ ++ struct au_dykey *key, *old; ++ struct hlist_bl_head *hbl; ++ struct op { ++ unsigned int sz; ++ void (*set)(struct au_dykey *key, const void *h_op, ++ struct super_block *h_sb __maybe_unused); ++ }; ++ static const struct op a[] = { ++ [AuDy_AOP] = { ++ .sz = sizeof(struct au_dyaop), ++ .set = dy_aop ++ } ++ }; ++ const struct op *p; ++ ++ hbl = dynop + op->dy_type; ++ key = dy_gfind_get(hbl, op->dy_hop); ++ if (key) ++ goto out_add; /* success */ ++ ++ p = a + op->dy_type; ++ key = kzalloc(p->sz, GFP_NOFS); ++ if (unlikely(!key)) { ++ key = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ ++ key->dk_op.dy_hop = op->dy_hop; ++ kref_init(&key->dk_kref); ++ p->set(key, op->dy_hop, au_br_sb(br)); ++ old = dy_gadd(hbl, key); ++ if (old) { ++ au_kfree_rcu(key); ++ key = old; ++ } ++ ++out_add: ++ old = dy_bradd(br, key); ++ if (old) ++ /* its ref-count should never be zero here */ ++ kref_put(&key->dk_kref, dy_bug); ++out: ++ return key; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * Aufs prohibits O_DIRECT by default even if the branch supports it. ++ * This behaviour is necessary to return an error from open(O_DIRECT) instead ++ * of the succeeding I/O. The dio mount option enables O_DIRECT and makes ++ * open(O_DIRECT) always succeed, but the succeeding I/O may return an error. ++ * See the aufs manual in detail. ++ */ ++static void dy_adx(struct au_dyaop *dyaop, int do_dx) ++{ ++ if (!do_dx) ++ dyaop->da_op.direct_IO = NULL; ++ else ++ dyaop->da_op.direct_IO = aufs_aop.direct_IO; ++} ++ ++static struct au_dyaop *dy_aget(struct au_branch *br, ++ const struct address_space_operations *h_aop, ++ int do_dx) ++{ ++ struct au_dyaop *dyaop; ++ struct au_dynop op; ++ ++ op.dy_type = AuDy_AOP; ++ op.dy_haop = h_aop; ++ dyaop = (void *)dy_get(&op, br); ++ if (IS_ERR(dyaop)) ++ goto out; ++ dy_adx(dyaop, do_dx); ++ ++out: ++ return dyaop; ++} ++ ++int au_dy_iaop(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode) ++{ ++ int err, do_dx; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_dyaop *dyaop; ++ ++ AuDebugOn(!S_ISREG(h_inode->i_mode)); ++ IiMustWriteLock(inode); ++ ++ sb = inode->i_sb; ++ br = au_sbr(sb, bindex); ++ do_dx = !!au_opt_test(au_mntflags(sb), DIO); ++ dyaop = dy_aget(br, h_inode->i_mapping->a_ops, do_dx); ++ err = PTR_ERR(dyaop); ++ if (IS_ERR(dyaop)) ++ /* unnecessary to call dy_fput() */ ++ goto out; ++ ++ err = 0; ++ inode->i_mapping->a_ops = &dyaop->da_op; ++ ++out: ++ return err; ++} ++ ++/* ++ * Is it safe to replace a_ops during the inode/file is in operation? ++ * Yes, I hope so. ++ */ ++int au_dy_irefresh(struct inode *inode) ++{ ++ int err; ++ aufs_bindex_t btop; ++ struct inode *h_inode; ++ ++ err = 0; ++ if (S_ISREG(inode->i_mode)) { ++ btop = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, btop); ++ err = au_dy_iaop(inode, btop, h_inode); ++ } ++ return err; ++} ++ ++void au_dy_arefresh(int do_dx) ++{ ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_dykey *key; ++ ++ hbl = dynop + AuDy_AOP; ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry(key, pos, hbl, dk_hnode) ++ dy_adx((void *)key, do_dx); ++ hlist_bl_unlock(hbl); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void __init au_dy_init(void) ++{ ++ int i; ++ ++ for (i = 0; i < AuDyLast; i++) ++ INIT_HLIST_BL_HEAD(dynop + i); ++} ++ ++void au_dy_fin(void) ++{ ++ int i; ++ ++ for (i = 0; i < AuDyLast; i++) ++ WARN_ON(!hlist_bl_empty(dynop + i)); ++} +diff --git a/fs/aufs/dynop.h b/fs/aufs/dynop.h +new file mode 100644 +index 000000000000..66ac96bbf2ff +--- /dev/null ++++ b/fs/aufs/dynop.h +@@ -0,0 +1,64 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2010-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * dynamically customizable operations (for regular files only) ++ */ ++ ++#ifndef __AUFS_DYNOP_H__ ++#define __AUFS_DYNOP_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++ ++enum {AuDy_AOP, AuDyLast}; ++ ++struct au_dynop { ++ int dy_type; ++ union { ++ const void *dy_hop; ++ const struct address_space_operations *dy_haop; ++ }; ++}; ++ ++struct au_dykey { ++ union { ++ struct hlist_bl_node dk_hnode; ++ struct rcu_head dk_rcu; ++ }; ++ struct au_dynop dk_op; ++ ++ /* ++ * during I am in the branch local array, kref is gotten. when the ++ * branch is removed, kref is put. ++ */ ++ struct kref dk_kref; ++}; ++ ++/* stop unioning since their sizes are very different from each other */ ++struct au_dyaop { ++ struct au_dykey da_key; ++ struct address_space_operations da_op; /* not const */ ++}; ++/* make sure that 'struct au_dykey *' can be any type */ ++static_assert(!offsetof(struct au_dyaop, da_key)); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* dynop.c */ ++struct au_branch; ++void au_dy_put(struct au_dykey *key); ++int au_dy_iaop(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode); ++int au_dy_irefresh(struct inode *inode); ++void au_dy_arefresh(int do_dio); ++ ++void __init au_dy_init(void); ++void au_dy_fin(void); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_DYNOP_H__ */ +diff --git a/fs/aufs/export.c b/fs/aufs/export.c +new file mode 100644 +index 000000000000..94005688ac0b +--- /dev/null ++++ b/fs/aufs/export.c +@@ -0,0 +1,824 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 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_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(file, &inode->i_generation, ++ sizeof(inode->i_generation), &pos); ++ } else ++ sz = xino_fread(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..7e9298b963aa +--- /dev/null ++++ b/fs/aufs/f_op.c +@@ -0,0 +1,749 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 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); ++} ++ ++/* ++ * 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 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; /* the branch doesn't have its ->(read|write)_iter() */ ++ 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 /* reserved for future use */ ++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_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 /* reserved for future use */ ++ .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..cb054052cf9a +--- /dev/null ++++ b/fs/aufs/fhsm.c +@@ -0,0 +1,413 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2011-2020 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..3911b2e7e46f +--- /dev/null ++++ b/fs/aufs/file.c +@@ -0,0 +1,850 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 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..8bf8e67650d0 +--- /dev/null ++++ b/fs/aufs/file.h +@@ -0,0 +1,329 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * file operations ++ */ ++ ++#ifndef __AUFS_FILE_H__ ++#define __AUFS_FILE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++#include "rwsem.h" ++ ++struct au_branch; ++struct au_hfile { ++ struct file *hf_file; ++ struct au_branch *hf_br; ++}; ++ ++struct au_vdir; ++struct au_fidir { ++ aufs_bindex_t fd_bbot; ++ aufs_bindex_t fd_nent; ++ struct au_vdir *fd_vdir_cache; ++ struct au_hfile fd_hfile[]; ++}; ++ ++static inline int au_fidir_sz(int nent) ++{ ++ AuDebugOn(nent < 0); ++ return sizeof(struct au_fidir) + sizeof(struct au_hfile) * nent; ++} ++ ++struct au_finfo { ++ atomic_t fi_generation; ++ ++ struct au_rwsem fi_rwsem; ++ aufs_bindex_t fi_btop; ++ ++ /* do not union them */ ++ struct { /* for non-dir */ ++ struct au_hfile fi_htop; ++ atomic_t fi_mmapped; ++ }; ++ struct au_fidir *fi_hdir; /* for dir only */ ++ ++ struct hlist_bl_node fi_hlist; ++ struct file *fi_file; /* very ugly */ ++ struct rcu_head rcu; ++} ____cacheline_aligned_in_smp; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* file.c */ ++extern const struct address_space_operations aufs_aop; ++unsigned int au_file_roflags(unsigned int flags); ++struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags, ++ struct file *file, int force_wr); ++struct au_do_open_args { ++ int aopen; ++ int (*open)(struct file *file, int flags, ++ struct file *h_file); ++ struct au_fidir *fidir; ++ struct file *h_file; ++}; ++int au_do_open(struct file *file, struct au_do_open_args *args); ++int au_reopen_nondir(struct file *file); ++struct au_pin; ++int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin); ++int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file), ++ int wlock, unsigned int fi_lsc); ++int au_do_flush(struct file *file, fl_owner_t id, ++ int (*flush)(struct file *file, fl_owner_t id)); ++ ++/* poll.c */ ++#ifdef CONFIG_AUFS_POLL ++__poll_t aufs_poll(struct file *file, struct poll_table_struct *pt); ++#endif ++ ++#ifdef CONFIG_AUFS_BR_HFSPLUS ++/* hfsplus.c */ ++struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex, ++ int force_wr); ++void au_h_open_post(struct dentry *dentry, aufs_bindex_t bindex, ++ struct file *h_file); ++#else ++AuStub(struct file *, au_h_open_pre, return NULL, struct dentry *dentry, ++ aufs_bindex_t bindex, int force_wr) ++AuStubVoid(au_h_open_post, struct dentry *dentry, aufs_bindex_t bindex, ++ struct file *h_file); ++#endif ++ ++/* f_op.c */ ++extern const struct file_operations aufs_file_fop; ++int au_do_open_nondir(struct file *file, int flags, struct file *h_file); ++int aufs_release_nondir(struct inode *inode __maybe_unused, struct file *file); ++struct file *au_read_pre(struct file *file, int keep_fi, unsigned int lsc); ++ ++/* finfo.c */ ++void au_hfput(struct au_hfile *hf, int execed); ++void au_set_h_fptr(struct file *file, aufs_bindex_t bindex, ++ struct file *h_file); ++ ++void au_update_figen(struct file *file); ++struct au_fidir *au_fidir_alloc(struct super_block *sb); ++int au_fidir_realloc(struct au_finfo *finfo, int nbr, int may_shrink); ++ ++void au_fi_init_once(void *_fi); ++void au_finfo_fin(struct file *file); ++int au_finfo_init(struct file *file, struct au_fidir *fidir); ++ ++/* ioctl.c */ ++long aufs_ioctl_nondir(struct file *file, unsigned int cmd, unsigned long arg); ++#ifdef CONFIG_COMPAT ++long aufs_compat_ioctl_dir(struct file *file, unsigned int cmd, ++ unsigned long arg); ++long aufs_compat_ioctl_nondir(struct file *file, unsigned int cmd, ++ unsigned long arg); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_finfo *au_fi(struct file *file) ++{ ++ return file->private_data; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define fi_read_lock(f) au_rw_read_lock(&au_fi(f)->fi_rwsem) ++#define fi_write_lock(f) au_rw_write_lock(&au_fi(f)->fi_rwsem) ++#define fi_read_trylock(f) au_rw_read_trylock(&au_fi(f)->fi_rwsem) ++#define fi_write_trylock(f) au_rw_write_trylock(&au_fi(f)->fi_rwsem) ++/* ++#define fi_read_trylock_nested(f) \ ++ au_rw_read_trylock_nested(&au_fi(f)->fi_rwsem) ++#define fi_write_trylock_nested(f) \ ++ au_rw_write_trylock_nested(&au_fi(f)->fi_rwsem) ++*/ ++ ++#define fi_read_unlock(f) au_rw_read_unlock(&au_fi(f)->fi_rwsem) ++#define fi_write_unlock(f) au_rw_write_unlock(&au_fi(f)->fi_rwsem) ++#define fi_downgrade_lock(f) au_rw_dgrade_lock(&au_fi(f)->fi_rwsem) ++ ++/* lock subclass for finfo */ ++enum { ++ AuLsc_FI_1, ++ AuLsc_FI_2 ++}; ++ ++static inline void fi_read_lock_nested(struct file *f, unsigned int lsc) ++{ ++ au_rw_read_lock_nested(&au_fi(f)->fi_rwsem, lsc); ++} ++ ++static inline void fi_write_lock_nested(struct file *f, unsigned int lsc) ++{ ++ au_rw_write_lock_nested(&au_fi(f)->fi_rwsem, lsc); ++} ++ ++/* ++ * fi_read_lock_1, fi_write_lock_1, ++ * fi_read_lock_2, fi_write_lock_2 ++ */ ++#define AuReadLockFunc(name) \ ++static inline void fi_read_lock_##name(struct file *f) \ ++{ fi_read_lock_nested(f, AuLsc_FI_##name); } ++ ++#define AuWriteLockFunc(name) \ ++static inline void fi_write_lock_##name(struct file *f) \ ++{ fi_write_lock_nested(f, AuLsc_FI_##name); } ++ ++#define AuRWLockFuncs(name) \ ++ AuReadLockFunc(name) \ ++ AuWriteLockFunc(name) ++ ++AuRWLockFuncs(1); ++AuRWLockFuncs(2); ++ ++#undef AuReadLockFunc ++#undef AuWriteLockFunc ++#undef AuRWLockFuncs ++ ++#define FiMustNoWaiters(f) AuRwMustNoWaiters(&au_fi(f)->fi_rwsem) ++#define FiMustAnyLock(f) AuRwMustAnyLock(&au_fi(f)->fi_rwsem) ++#define FiMustWriteLock(f) AuRwMustWriteLock(&au_fi(f)->fi_rwsem) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* todo: hard/soft set? */ ++static inline aufs_bindex_t au_fbtop(struct file *file) ++{ ++ FiMustAnyLock(file); ++ return au_fi(file)->fi_btop; ++} ++ ++static inline aufs_bindex_t au_fbbot_dir(struct file *file) ++{ ++ FiMustAnyLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ return au_fi(file)->fi_hdir->fd_bbot; ++} ++ ++static inline struct au_vdir *au_fvdir_cache(struct file *file) ++{ ++ FiMustAnyLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ return au_fi(file)->fi_hdir->fd_vdir_cache; ++} ++ ++static inline void au_set_fbtop(struct file *file, aufs_bindex_t bindex) ++{ ++ FiMustWriteLock(file); ++ au_fi(file)->fi_btop = bindex; ++} ++ ++static inline void au_set_fbbot_dir(struct file *file, aufs_bindex_t bindex) ++{ ++ FiMustWriteLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ au_fi(file)->fi_hdir->fd_bbot = bindex; ++} ++ ++static inline void au_set_fvdir_cache(struct file *file, ++ struct au_vdir *vdir_cache) ++{ ++ FiMustWriteLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ au_fi(file)->fi_hdir->fd_vdir_cache = vdir_cache; ++} ++ ++static inline struct file *au_hf_top(struct file *file) ++{ ++ FiMustAnyLock(file); ++ AuDebugOn(au_fi(file)->fi_hdir); ++ return au_fi(file)->fi_htop.hf_file; ++} ++ ++static inline struct file *au_hf_dir(struct file *file, aufs_bindex_t bindex) ++{ ++ FiMustAnyLock(file); ++ AuDebugOn(!au_fi(file)->fi_hdir); ++ return au_fi(file)->fi_hdir->fd_hfile[0 + bindex].hf_file; ++} ++ ++/* todo: memory barrier? */ ++static inline unsigned int au_figen(struct file *f) ++{ ++ return atomic_read(&au_fi(f)->fi_generation); ++} ++ ++static inline void au_set_mmapped(struct file *f) ++{ ++ if (atomic_inc_return(&au_fi(f)->fi_mmapped)) ++ return; ++ pr_warn("fi_mmapped wrapped around\n"); ++ while (!atomic_inc_return(&au_fi(f)->fi_mmapped)) ++ ; ++} ++ ++static inline void au_unset_mmapped(struct file *f) ++{ ++ atomic_dec(&au_fi(f)->fi_mmapped); ++} ++ ++static inline int au_test_mmapped(struct file *f) ++{ ++ return atomic_read(&au_fi(f)->fi_mmapped); ++} ++ ++/* customize vma->vm_file */ ++ ++static inline void au_do_vm_file_reset(struct vm_area_struct *vma, ++ struct file *file) ++{ ++ struct file *f; ++ ++ f = vma->vm_file; ++ get_file(file); ++ vma->vm_file = file; ++ fput(f); ++} ++ ++#ifdef CONFIG_MMU ++#define AuDbgVmRegion(file, vma) do {} while (0) ++ ++static inline void au_vm_file_reset(struct vm_area_struct *vma, ++ struct file *file) ++{ ++ au_do_vm_file_reset(vma, file); ++} ++#else ++#define AuDbgVmRegion(file, vma) \ ++ AuDebugOn((vma)->vm_region && (vma)->vm_region->vm_file != (file)) ++ ++static inline void au_vm_file_reset(struct vm_area_struct *vma, ++ struct file *file) ++{ ++ struct file *f; ++ ++ au_do_vm_file_reset(vma, file); ++ f = vma->vm_region->vm_file; ++ get_file(file); ++ vma->vm_region->vm_file = file; ++ fput(f); ++} ++#endif /* CONFIG_MMU */ ++ ++/* handle vma->vm_prfile */ ++static inline void au_vm_prfile_set(struct vm_area_struct *vma, ++ struct file *file) ++{ ++ get_file(file); ++ vma->vm_prfile = file; ++#ifndef CONFIG_MMU ++ get_file(file); ++ vma->vm_region->vm_prfile = file; ++#endif ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_FILE_H__ */ +diff --git a/fs/aufs/finfo.c b/fs/aufs/finfo.c +new file mode 100644 +index 000000000000..e2d6859850b6 +--- /dev/null ++++ b/fs/aufs/finfo.c +@@ -0,0 +1,136 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 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..7c001dae1859 +--- /dev/null ++++ b/fs/aufs/fstype.h +@@ -0,0 +1,388 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2020 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..571efb1e2300 +--- /dev/null ++++ b/fs/aufs/hbl.h +@@ -0,0 +1,52 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2017-2020 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..db3a2605521b +--- /dev/null ++++ b/fs/aufs/hfsnotify.c +@@ -0,0 +1,275 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * fsnotify for the lower directories ++ */ ++ ++#include "aufs.h" ++ ++/* FS_IN_IGNORED is unnecessary */ ++static const __u32 AuHfsnMask = (FS_MOVED_TO | FS_MOVED_FROM | FS_DELETE ++ | FS_CREATE | FS_EVENT_ON_CHILD); ++static DECLARE_WAIT_QUEUE_HEAD(au_hfsn_wq); ++static __cacheline_aligned_in_smp atomic64_t au_hfsn_ifree = ATOMIC64_INIT(0); ++ ++static void au_hfsn_free_mark(struct fsnotify_mark *mark) ++{ ++ struct au_hnotify *hn = container_of(mark, struct au_hnotify, ++ hn_mark); ++ /* AuDbg("here\n"); */ ++ au_cache_free_hnotify(hn); ++ smp_mb__before_atomic(); /* for atomic64_dec */ ++ if (atomic64_dec_and_test(&au_hfsn_ifree)) ++ wake_up(&au_hfsn_wq); ++} ++ ++static int au_hfsn_alloc(struct au_hinode *hinode) ++{ ++ int err; ++ struct au_hnotify *hn; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct fsnotify_mark *mark; ++ aufs_bindex_t bindex; ++ ++ hn = hinode->hi_notify; ++ sb = hn->hn_aufs_inode->i_sb; ++ bindex = au_br_index(sb, hinode->hi_id); ++ br = au_sbr(sb, bindex); ++ AuDebugOn(!br->br_hfsn); ++ ++ mark = &hn->hn_mark; ++ fsnotify_init_mark(mark, br->br_hfsn->hfsn_group); ++ mark->mask = AuHfsnMask; ++ /* ++ * by udba rename or rmdir, aufs assign a new inode to the known ++ * h_inode, so specify 1 to allow dups. ++ */ ++ lockdep_off(); ++ err = fsnotify_add_inode_mark(mark, hinode->hi_inode, /*allow_dups*/1); ++ lockdep_on(); ++ ++ return err; ++} ++ ++static int au_hfsn_free(struct au_hinode *hinode, struct au_hnotify *hn) ++{ ++ struct fsnotify_mark *mark; ++ unsigned long long ull; ++ struct fsnotify_group *group; ++ ++ ull = atomic64_inc_return(&au_hfsn_ifree); ++ BUG_ON(!ull); ++ ++ mark = &hn->hn_mark; ++ spin_lock(&mark->lock); ++ group = mark->group; ++ fsnotify_get_group(group); ++ spin_unlock(&mark->lock); ++ lockdep_off(); ++ fsnotify_destroy_mark(mark, group); ++ fsnotify_put_mark(mark); ++ fsnotify_put_group(group); ++ lockdep_on(); ++ ++ /* free hn by myself */ ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hfsn_ctl(struct au_hinode *hinode, int do_set) ++{ ++ struct fsnotify_mark *mark; ++ ++ mark = &hinode->hi_notify->hn_mark; ++ spin_lock(&mark->lock); ++ if (do_set) { ++ AuDebugOn(mark->mask & AuHfsnMask); ++ mark->mask |= AuHfsnMask; ++ } else { ++ AuDebugOn(!(mark->mask & AuHfsnMask)); ++ mark->mask &= ~AuHfsnMask; ++ } ++ spin_unlock(&mark->lock); ++ /* fsnotify_recalc_inode_mask(hinode->hi_inode); */ ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* #define AuDbgHnotify */ ++#ifdef AuDbgHnotify ++static char *au_hfsn_name(u32 mask) ++{ ++#ifdef CONFIG_AUFS_DEBUG ++#define test_ret(flag) \ ++ do { \ ++ if (mask & flag) \ ++ return #flag; \ ++ } while (0) ++ test_ret(FS_ACCESS); ++ test_ret(FS_MODIFY); ++ test_ret(FS_ATTRIB); ++ test_ret(FS_CLOSE_WRITE); ++ test_ret(FS_CLOSE_NOWRITE); ++ test_ret(FS_OPEN); ++ test_ret(FS_MOVED_FROM); ++ test_ret(FS_MOVED_TO); ++ test_ret(FS_CREATE); ++ test_ret(FS_DELETE); ++ test_ret(FS_DELETE_SELF); ++ test_ret(FS_MOVE_SELF); ++ test_ret(FS_UNMOUNT); ++ test_ret(FS_Q_OVERFLOW); ++ test_ret(FS_IN_IGNORED); ++ test_ret(FS_ISDIR); ++ test_ret(FS_IN_ONESHOT); ++ test_ret(FS_EVENT_ON_CHILD); ++ return ""; ++#undef test_ret ++#else ++ return "??"; ++#endif ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hfsn_free_group(struct fsnotify_group *group) ++{ ++ struct au_br_hfsnotify *hfsn = group->private; ++ ++ /* AuDbg("here\n"); */ ++ au_kfree_try_rcu(hfsn); ++} ++ ++static int au_hfsn_handle_event(struct fsnotify_group *group, ++ u32 mask, const void *data, int data_type, ++ struct inode *dir, ++ const struct qstr *file_name, u32 cookie, ++ struct fsnotify_iter_info *iter_info) ++{ ++ int err; ++ struct au_hnotify *hnotify; ++ struct inode *h_dir, *h_inode; ++ struct fsnotify_mark *inode_mark; ++ ++ AuDebugOn(data_type != FSNOTIFY_EVENT_INODE); ++ ++ err = 0; ++ /* if FS_UNMOUNT happens, there must be another bug */ ++ AuDebugOn(mask & FS_UNMOUNT); ++ if (mask & (FS_IN_IGNORED | FS_UNMOUNT)) ++ goto out; ++ ++ h_dir = dir; ++ h_inode = NULL; ++#ifdef AuDbgHnotify ++ au_debug_on(); ++ if (1 || h_child_qstr.len != sizeof(AUFS_XINO_FNAME) - 1 ++ || strncmp(h_child_qstr.name, AUFS_XINO_FNAME, h_child_qstr.len)) { ++ AuDbg("i%lu, mask 0x%x %s, hcname %.*s, hi%lu\n", ++ h_dir->i_ino, mask, au_hfsn_name(mask), ++ AuLNPair(&h_child_qstr), h_inode ? h_inode->i_ino : 0); ++ /* WARN_ON(1); */ ++ } ++ au_debug_off(); ++#endif ++ ++ inode_mark = fsnotify_iter_inode_mark(iter_info); ++ AuDebugOn(!inode_mark); ++ hnotify = container_of(inode_mark, struct au_hnotify, hn_mark); ++ err = au_hnotify(h_dir, hnotify, mask, file_name, h_inode); ++ ++out: ++ return err; ++} ++ ++static struct fsnotify_ops au_hfsn_ops = { ++ .handle_event = au_hfsn_handle_event, ++ .free_group_priv = au_hfsn_free_group, ++ .free_mark = au_hfsn_free_mark ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hfsn_fin_br(struct au_branch *br) ++{ ++ struct au_br_hfsnotify *hfsn; ++ ++ hfsn = br->br_hfsn; ++ if (hfsn) { ++ lockdep_off(); ++ fsnotify_put_group(hfsn->hfsn_group); ++ lockdep_on(); ++ } ++} ++ ++static int au_hfsn_init_br(struct au_branch *br, int perm) ++{ ++ int err; ++ struct fsnotify_group *group; ++ struct au_br_hfsnotify *hfsn; ++ ++ err = 0; ++ br->br_hfsn = NULL; ++ if (!au_br_hnotifyable(perm)) ++ goto out; ++ ++ err = -ENOMEM; ++ hfsn = kmalloc(sizeof(*hfsn), GFP_NOFS); ++ if (unlikely(!hfsn)) ++ goto out; ++ ++ err = 0; ++ group = fsnotify_alloc_group(&au_hfsn_ops); ++ if (IS_ERR(group)) { ++ err = PTR_ERR(group); ++ pr_err("fsnotify_alloc_group() failed, %d\n", err); ++ goto out_hfsn; ++ } ++ ++ group->private = hfsn; ++ hfsn->hfsn_group = group; ++ br->br_hfsn = hfsn; ++ goto out; /* success */ ++ ++out_hfsn: ++ au_kfree_try_rcu(hfsn); ++out: ++ return err; ++} ++ ++static int au_hfsn_reset_br(unsigned int udba, struct au_branch *br, int perm) ++{ ++ int err; ++ ++ err = 0; ++ if (!br->br_hfsn) ++ err = au_hfsn_init_br(br, perm); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_hfsn_fin(void) ++{ ++ AuDbg("au_hfsn_ifree %lld\n", (long long)atomic64_read(&au_hfsn_ifree)); ++ wait_event(au_hfsn_wq, !atomic64_read(&au_hfsn_ifree)); ++} ++ ++const struct au_hnotify_op au_hnotify_op = { ++ .ctl = au_hfsn_ctl, ++ .alloc = au_hfsn_alloc, ++ .free = au_hfsn_free, ++ ++ .fin = au_hfsn_fin, ++ ++ .reset_br = au_hfsn_reset_br, ++ .fin_br = au_hfsn_fin_br, ++ .init_br = au_hfsn_init_br ++}; +diff --git a/fs/aufs/hfsplus.c b/fs/aufs/hfsplus.c +new file mode 100644 +index 000000000000..3d4fed48bf16 +--- /dev/null ++++ b/fs/aufs/hfsplus.c +@@ -0,0 +1,47 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2010-2020 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..ea1060fb7de0 +--- /dev/null ++++ b/fs/aufs/hnotify.c +@@ -0,0 +1,702 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * abstraction to notify the direct changes on lower directories ++ */ ++ ++/* #include */ ++#include "aufs.h" ++ ++int au_hn_alloc(struct au_hinode *hinode, struct inode *inode) ++{ ++ int err; ++ struct au_hnotify *hn; ++ ++ err = -ENOMEM; ++ hn = au_cache_alloc_hnotify(); ++ if (hn) { ++ hn->hn_aufs_inode = inode; ++ hinode->hi_notify = hn; ++ err = au_hnotify_op.alloc(hinode); ++ AuTraceErr(err); ++ if (unlikely(err)) { ++ hinode->hi_notify = NULL; ++ au_cache_free_hnotify(hn); ++ /* ++ * The upper dir was removed by udba, but the same named ++ * dir left. In this case, aufs assigns a new inode ++ * number and set the monitor again. ++ * For the lower dir, the old monitor is still left. ++ */ ++ if (err == -EEXIST) ++ err = 0; ++ } ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_hn_free(struct au_hinode *hinode) ++{ ++ struct au_hnotify *hn; ++ ++ hn = hinode->hi_notify; ++ if (hn) { ++ hinode->hi_notify = NULL; ++ if (au_hnotify_op.free(hinode, hn)) ++ au_cache_free_hnotify(hn); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_hn_ctl(struct au_hinode *hinode, int do_set) ++{ ++ if (hinode->hi_notify) ++ au_hnotify_op.ctl(hinode, do_set); ++} ++ ++void au_hn_reset(struct inode *inode, unsigned int flags) ++{ ++ aufs_bindex_t bindex, bbot; ++ struct inode *hi; ++ struct dentry *iwhdentry; ++ ++ bbot = au_ibbot(inode); ++ for (bindex = au_ibtop(inode); bindex <= bbot; bindex++) { ++ hi = au_h_iptr(inode, bindex); ++ if (!hi) ++ continue; ++ ++ /* inode_lock_nested(hi, AuLsc_I_CHILD); */ ++ iwhdentry = au_hi_wh(inode, bindex); ++ if (iwhdentry) ++ dget(iwhdentry); ++ au_igrab(hi); ++ au_set_h_iptr(inode, bindex, NULL, 0); ++ au_set_h_iptr(inode, bindex, au_igrab(hi), ++ flags & ~AuHi_XINO); ++ iput(hi); ++ dput(iwhdentry); ++ /* inode_unlock(hi); */ ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int hn_xino(struct inode *inode, struct inode *h_inode) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot, bfound, btop; ++ struct inode *h_i; ++ ++ err = 0; ++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { ++ pr_warn("branch root dir was changed\n"); ++ goto out; ++ } ++ ++ bfound = -1; ++ bbot = au_ibbot(inode); ++ btop = au_ibtop(inode); ++#if 0 /* reserved for future use */ ++ if (bindex == bbot) { ++ /* keep this ino in rename case */ ++ goto out; ++ } ++#endif ++ for (bindex = btop; bindex <= bbot; bindex++) ++ if (au_h_iptr(inode, bindex) == h_inode) { ++ bfound = bindex; ++ break; ++ } ++ if (bfound < 0) ++ goto out; ++ ++ for (bindex = btop; bindex <= bbot; bindex++) { ++ h_i = au_h_iptr(inode, bindex); ++ if (!h_i) ++ continue; ++ ++ err = au_xino_write(inode->i_sb, bindex, h_i->i_ino, /*ino*/0); ++ /* ignore this error */ ++ /* bad action? */ ++ } ++ ++ /* children inode number will be broken */ ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int hn_gen_tree(struct dentry *dentry) ++{ ++ int err, i, j, ndentry; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, dentry, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ for (i = 0; i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ ndentry = dpage->ndentry; ++ for (j = 0; j < ndentry; j++) { ++ struct dentry *d; ++ ++ d = dentries[j]; ++ if (IS_ROOT(d)) ++ continue; ++ ++ au_digen_dec(d); ++ if (d_really_is_positive(d)) ++ /* todo: reset children xino? ++ cached children only? */ ++ au_iigen_dec(d_inode(d)); ++ } ++ } ++ ++out_dpages: ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++/* ++ * return 0 if processed. ++ */ ++static int hn_gen_by_inode(char *name, unsigned int nlen, struct inode *inode, ++ const unsigned int isdir) ++{ ++ int err; ++ struct dentry *d; ++ struct qstr *dname; ++ ++ err = 1; ++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { ++ pr_warn("branch root dir was changed\n"); ++ err = 0; ++ goto out; ++ } ++ ++ if (!isdir) { ++ AuDebugOn(!name); ++ au_iigen_dec(inode); ++ spin_lock(&inode->i_lock); ++ hlist_for_each_entry(d, &inode->i_dentry, d_u.d_alias) { ++ spin_lock(&d->d_lock); ++ dname = &d->d_name; ++ if (dname->len != nlen ++ && memcmp(dname->name, name, nlen)) { ++ spin_unlock(&d->d_lock); ++ continue; ++ } ++ err = 0; ++ au_digen_dec(d); ++ spin_unlock(&d->d_lock); ++ break; ++ } ++ spin_unlock(&inode->i_lock); ++ } else { ++ au_fset_si(au_sbi(inode->i_sb), FAILED_REFRESH_DIR); ++ d = d_find_any_alias(inode); ++ if (!d) { ++ au_iigen_dec(inode); ++ goto out; ++ } ++ ++ spin_lock(&d->d_lock); ++ dname = &d->d_name; ++ if (dname->len == nlen && !memcmp(dname->name, name, nlen)) { ++ spin_unlock(&d->d_lock); ++ err = hn_gen_tree(d); ++ spin_lock(&d->d_lock); ++ } ++ spin_unlock(&d->d_lock); ++ dput(d); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int hn_gen_by_name(struct dentry *dentry, const unsigned int isdir) ++{ ++ int err; ++ ++ if (IS_ROOT(dentry)) { ++ pr_warn("branch root dir was changed\n"); ++ return 0; ++ } ++ ++ err = 0; ++ if (!isdir) { ++ au_digen_dec(dentry); ++ if (d_really_is_positive(dentry)) ++ au_iigen_dec(d_inode(dentry)); ++ } else { ++ au_fset_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIR); ++ if (d_really_is_positive(dentry)) ++ err = hn_gen_tree(dentry); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* hnotify job flags */ ++#define AuHnJob_XINO0 1 ++#define AuHnJob_GEN (1 << 1) ++#define AuHnJob_DIRENT (1 << 2) ++#define AuHnJob_ISDIR (1 << 3) ++#define AuHnJob_TRYXINO0 (1 << 4) ++#define AuHnJob_MNTPNT (1 << 5) ++#define au_ftest_hnjob(flags, name) ((flags) & AuHnJob_##name) ++#define au_fset_hnjob(flags, name) \ ++ do { (flags) |= AuHnJob_##name; } while (0) ++#define au_fclr_hnjob(flags, name) \ ++ do { (flags) &= ~AuHnJob_##name; } while (0) ++ ++enum { ++ AuHn_CHILD, ++ AuHn_PARENT, ++ AuHnLast ++}; ++ ++struct au_hnotify_args { ++ struct inode *h_dir, *dir, *h_child_inode; ++ u32 mask; ++ unsigned int flags[AuHnLast]; ++ unsigned int h_child_nlen; ++ char h_child_name[]; ++}; ++ ++struct hn_job_args { ++ unsigned int flags; ++ struct inode *inode, *h_inode, *dir, *h_dir; ++ struct dentry *dentry; ++ char *h_name; ++ int h_nlen; ++}; ++ ++static int hn_job(struct hn_job_args *a) ++{ ++ const unsigned int isdir = au_ftest_hnjob(a->flags, ISDIR); ++ int e; ++ ++ /* reset xino */ ++ if (au_ftest_hnjob(a->flags, XINO0) && a->inode) ++ hn_xino(a->inode, a->h_inode); /* ignore this error */ ++ ++ if (au_ftest_hnjob(a->flags, TRYXINO0) ++ && a->inode ++ && a->h_inode) { ++ inode_lock_shared_nested(a->h_inode, AuLsc_I_CHILD); ++ if (!a->h_inode->i_nlink ++ && !(a->h_inode->i_state & I_LINKABLE)) ++ hn_xino(a->inode, a->h_inode); /* ignore this error */ ++ inode_unlock_shared(a->h_inode); ++ } ++ ++ /* make the generation obsolete */ ++ if (au_ftest_hnjob(a->flags, GEN)) { ++ e = -1; ++ if (a->inode) ++ e = hn_gen_by_inode(a->h_name, a->h_nlen, a->inode, ++ isdir); ++ if (e && a->dentry) ++ hn_gen_by_name(a->dentry, isdir); ++ /* ignore this error */ ++ } ++ ++ /* make dir entries obsolete */ ++ if (au_ftest_hnjob(a->flags, DIRENT) && a->inode) { ++ struct au_vdir *vdir; ++ ++ vdir = au_ivdir(a->inode); ++ if (vdir) ++ vdir->vd_jiffy = 0; ++ /* IMustLock(a->inode); */ ++ /* inode_inc_iversion(a->inode); */ ++ } ++ ++ /* can do nothing but warn */ ++ if (au_ftest_hnjob(a->flags, MNTPNT) ++ && a->dentry ++ && d_mountpoint(a->dentry)) ++ pr_warn("mount-point %pd is removed or renamed\n", a->dentry); ++ ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry *lookup_wlock_by_name(char *name, unsigned int nlen, ++ struct inode *dir) ++{ ++ struct dentry *dentry, *d, *parent; ++ struct qstr *dname; ++ ++ parent = d_find_any_alias(dir); ++ if (!parent) ++ return NULL; ++ ++ dentry = NULL; ++ spin_lock(&parent->d_lock); ++ list_for_each_entry(d, &parent->d_subdirs, d_child) { ++ /* AuDbg("%pd\n", d); */ ++ spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED); ++ dname = &d->d_name; ++ if (dname->len != nlen || memcmp(dname->name, name, nlen)) ++ goto cont_unlock; ++ if (au_di(d)) ++ au_digen_dec(d); ++ else ++ goto cont_unlock; ++ if (au_dcount(d) > 0) { ++ dentry = dget_dlock(d); ++ spin_unlock(&d->d_lock); ++ break; ++ } ++ ++cont_unlock: ++ spin_unlock(&d->d_lock); ++ } ++ spin_unlock(&parent->d_lock); ++ dput(parent); ++ ++ if (dentry) ++ di_write_lock_child(dentry); ++ ++ return dentry; ++} ++ ++static struct inode *lookup_wlock_by_ino(struct super_block *sb, ++ aufs_bindex_t bindex, ino_t h_ino) ++{ ++ struct inode *inode; ++ ino_t ino; ++ int err; ++ ++ inode = NULL; ++ err = au_xino_read(sb, bindex, h_ino, &ino); ++ if (!err && ino) ++ inode = ilookup(sb, ino); ++ if (!inode) ++ goto out; ++ ++ if (unlikely(inode->i_ino == AUFS_ROOT_INO)) { ++ pr_warn("wrong root branch\n"); ++ iput(inode); ++ inode = NULL; ++ goto out; ++ } ++ ++ ii_write_lock_child(inode); ++ ++out: ++ return inode; ++} ++ ++static void au_hn_bh(void *_args) ++{ ++ struct au_hnotify_args *a = _args; ++ struct super_block *sb; ++ aufs_bindex_t bindex, bbot, bfound; ++ unsigned char xino, try_iput; ++ int err; ++ struct inode *inode; ++ ino_t h_ino; ++ struct hn_job_args args; ++ struct dentry *dentry; ++ struct au_sbinfo *sbinfo; ++ ++ AuDebugOn(!_args); ++ AuDebugOn(!a->h_dir); ++ AuDebugOn(!a->dir); ++ AuDebugOn(!a->mask); ++ AuDbg("mask 0x%x, i%lu, hi%lu, hci%lu\n", ++ a->mask, a->dir->i_ino, a->h_dir->i_ino, ++ a->h_child_inode ? a->h_child_inode->i_ino : 0); ++ ++ inode = NULL; ++ dentry = NULL; ++ /* ++ * do not lock a->dir->i_mutex here ++ * because of d_revalidate() may cause a deadlock. ++ */ ++ sb = a->dir->i_sb; ++ AuDebugOn(!sb); ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!sbinfo); ++ si_write_lock(sb, AuLock_NOPLMW); ++ ++ if (au_opt_test(sbinfo->si_mntflags, DIRREN)) ++ switch (a->mask & FS_EVENTS_POSS_ON_CHILD) { ++ case FS_MOVED_FROM: ++ case FS_MOVED_TO: ++ AuWarn1("DIRREN with UDBA may not work correctly " ++ "for the direct rename(2)\n"); ++ } ++ ++ ii_read_lock_parent(a->dir); ++ bfound = -1; ++ bbot = au_ibbot(a->dir); ++ for (bindex = au_ibtop(a->dir); bindex <= bbot; bindex++) ++ if (au_h_iptr(a->dir, bindex) == a->h_dir) { ++ bfound = bindex; ++ break; ++ } ++ ii_read_unlock(a->dir); ++ if (unlikely(bfound < 0)) ++ goto out; ++ ++ xino = !!au_opt_test(au_mntflags(sb), XINO); ++ h_ino = 0; ++ if (a->h_child_inode) ++ h_ino = a->h_child_inode->i_ino; ++ ++ if (a->h_child_nlen ++ && (au_ftest_hnjob(a->flags[AuHn_CHILD], GEN) ++ || au_ftest_hnjob(a->flags[AuHn_CHILD], MNTPNT))) ++ dentry = lookup_wlock_by_name(a->h_child_name, a->h_child_nlen, ++ a->dir); ++ try_iput = 0; ++ if (dentry && d_really_is_positive(dentry)) ++ inode = d_inode(dentry); ++ if (xino && !inode && h_ino ++ && (au_ftest_hnjob(a->flags[AuHn_CHILD], XINO0) ++ || au_ftest_hnjob(a->flags[AuHn_CHILD], TRYXINO0) ++ || au_ftest_hnjob(a->flags[AuHn_CHILD], GEN))) { ++ inode = lookup_wlock_by_ino(sb, bfound, h_ino); ++ try_iput = 1; ++ } ++ ++ args.flags = a->flags[AuHn_CHILD]; ++ args.dentry = dentry; ++ args.inode = inode; ++ args.h_inode = a->h_child_inode; ++ args.dir = a->dir; ++ args.h_dir = a->h_dir; ++ args.h_name = a->h_child_name; ++ args.h_nlen = a->h_child_nlen; ++ err = hn_job(&args); ++ if (dentry) { ++ if (au_di(dentry)) ++ di_write_unlock(dentry); ++ dput(dentry); ++ } ++ if (inode && try_iput) { ++ ii_write_unlock(inode); ++ iput(inode); ++ } ++ ++ ii_write_lock_parent(a->dir); ++ args.flags = a->flags[AuHn_PARENT]; ++ args.dentry = NULL; ++ args.inode = a->dir; ++ args.h_inode = a->h_dir; ++ args.dir = NULL; ++ args.h_dir = NULL; ++ args.h_name = NULL; ++ args.h_nlen = 0; ++ err = hn_job(&args); ++ ii_write_unlock(a->dir); ++ ++out: ++ iput(a->h_child_inode); ++ iput(a->h_dir); ++ iput(a->dir); ++ si_write_unlock(sb); ++ au_nwt_done(&sbinfo->si_nowait); ++ au_kfree_rcu(a); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask, ++ const struct qstr *h_child_qstr, struct inode *h_child_inode) ++{ ++ int err, len; ++ unsigned int flags[AuHnLast], f; ++ unsigned char isdir, isroot, wh; ++ struct inode *dir; ++ struct au_hnotify_args *args; ++ char *p, *h_child_name; ++ ++ err = 0; ++ AuDebugOn(!hnotify || !hnotify->hn_aufs_inode); ++ dir = igrab(hnotify->hn_aufs_inode); ++ if (!dir) ++ goto out; ++ ++ isroot = (dir->i_ino == AUFS_ROOT_INO); ++ wh = 0; ++ h_child_name = (void *)h_child_qstr->name; ++ len = h_child_qstr->len; ++ if (h_child_name) { ++ if (len > AUFS_WH_PFX_LEN ++ && !memcmp(h_child_name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { ++ h_child_name += AUFS_WH_PFX_LEN; ++ len -= AUFS_WH_PFX_LEN; ++ wh = 1; ++ } ++ } ++ ++ isdir = 0; ++ if (h_child_inode) ++ isdir = !!S_ISDIR(h_child_inode->i_mode); ++ flags[AuHn_PARENT] = AuHnJob_ISDIR; ++ flags[AuHn_CHILD] = 0; ++ if (isdir) ++ flags[AuHn_CHILD] = AuHnJob_ISDIR; ++ au_fset_hnjob(flags[AuHn_PARENT], DIRENT); ++ au_fset_hnjob(flags[AuHn_CHILD], GEN); ++ switch (mask & ALL_FSNOTIFY_DIRENT_EVENTS) { ++ case FS_MOVED_FROM: ++ case FS_MOVED_TO: ++ au_fset_hnjob(flags[AuHn_CHILD], XINO0); ++ au_fset_hnjob(flags[AuHn_CHILD], MNTPNT); ++ fallthrough; ++ case FS_CREATE: ++ AuDebugOn(!h_child_name); ++ break; ++ ++ case FS_DELETE: ++ /* ++ * aufs never be able to get this child inode. ++ * revalidation should be in d_revalidate() ++ * by checking i_nlink, i_generation or d_unhashed(). ++ */ ++ AuDebugOn(!h_child_name); ++ au_fset_hnjob(flags[AuHn_CHILD], TRYXINO0); ++ au_fset_hnjob(flags[AuHn_CHILD], MNTPNT); ++ break; ++ ++ default: ++ AuDebugOn(1); ++ } ++ ++ if (wh) ++ h_child_inode = NULL; ++ ++ err = -ENOMEM; ++ /* iput() and kfree() will be called in au_hnotify() */ ++ args = kmalloc(sizeof(*args) + len + 1, GFP_NOFS); ++ if (unlikely(!args)) { ++ AuErr1("no memory\n"); ++ iput(dir); ++ goto out; ++ } ++ args->flags[AuHn_PARENT] = flags[AuHn_PARENT]; ++ args->flags[AuHn_CHILD] = flags[AuHn_CHILD]; ++ args->mask = mask; ++ args->dir = dir; ++ args->h_dir = igrab(h_dir); ++ if (h_child_inode) ++ h_child_inode = igrab(h_child_inode); /* can be NULL */ ++ args->h_child_inode = h_child_inode; ++ args->h_child_nlen = len; ++ if (len) { ++ p = (void *)args; ++ p += sizeof(*args); ++ memcpy(p, h_child_name, len); ++ p[len] = 0; ++ } ++ ++ /* NFS fires the event for silly-renamed one from kworker */ ++ f = 0; ++ if (!dir->i_nlink ++ || (au_test_nfs(h_dir->i_sb) && (mask & FS_DELETE))) ++ f = AuWkq_NEST; ++ err = au_wkq_nowait(au_hn_bh, args, dir->i_sb, f); ++ if (unlikely(err)) { ++ pr_err("wkq %d\n", err); ++ iput(args->h_child_inode); ++ iput(args->h_dir); ++ iput(args->dir); ++ au_kfree_rcu(args); ++ } ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm) ++{ ++ int err; ++ ++ AuDebugOn(!(udba & AuOptMask_UDBA)); ++ ++ err = 0; ++ if (au_hnotify_op.reset_br) ++ err = au_hnotify_op.reset_br(udba, br, perm); ++ ++ return err; ++} ++ ++int au_hnotify_init_br(struct au_branch *br, int perm) ++{ ++ int err; ++ ++ err = 0; ++ if (au_hnotify_op.init_br) ++ err = au_hnotify_op.init_br(br, perm); ++ ++ return err; ++} ++ ++void au_hnotify_fin_br(struct au_branch *br) ++{ ++ if (au_hnotify_op.fin_br) ++ au_hnotify_op.fin_br(br); ++} ++ ++static void au_hn_destroy_cache(void) ++{ ++ kmem_cache_destroy(au_cache[AuCache_HNOTIFY]); ++ au_cache[AuCache_HNOTIFY] = NULL; ++} ++ ++int __init au_hnotify_init(void) ++{ ++ int err; ++ ++ err = -ENOMEM; ++ au_cache[AuCache_HNOTIFY] = AuCache(au_hnotify); ++ if (au_cache[AuCache_HNOTIFY]) { ++ err = 0; ++ if (au_hnotify_op.init) ++ err = au_hnotify_op.init(); ++ if (unlikely(err)) ++ au_hn_destroy_cache(); ++ } ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_hnotify_fin(void) ++{ ++ if (au_hnotify_op.fin) ++ au_hnotify_op.fin(); ++ ++ /* cf. au_cache_fin() */ ++ if (au_cache[AuCache_HNOTIFY]) ++ au_hn_destroy_cache(); ++} +diff --git a/fs/aufs/i_op.c b/fs/aufs/i_op.c +new file mode 100644 +index 000000000000..42bc497e2630 +--- /dev/null ++++ b/fs/aufs/i_op.c +@@ -0,0 +1,1489 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode operations (except add/del/rename) ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++static int h_permission(struct inode *h_inode, int mask, ++ struct path *h_path, int brperm) ++{ ++ int err; ++ const unsigned char write_mask = !!(mask & (MAY_WRITE | MAY_APPEND)); ++ ++ err = -EPERM; ++ if (write_mask && IS_IMMUTABLE(h_inode)) ++ goto out; ++ ++ err = -EACCES; ++ if (((mask & MAY_EXEC) ++ && S_ISREG(h_inode->i_mode) ++ && (path_noexec(h_path) ++ || !(h_inode->i_mode & 0111)))) ++ goto out; ++ ++ /* ++ * - skip the lower fs test in the case of write to ro branch. ++ * - nfs dir permission write check is optimized, but a policy for ++ * link/rename requires a real check. ++ * - nfs always sets SB_POSIXACL regardless its mount option 'noacl.' ++ * in this case, generic_permission() returns -EOPNOTSUPP. ++ */ ++ if ((write_mask && !au_br_writable(brperm)) ++ || (au_test_nfs(h_inode->i_sb) && S_ISDIR(h_inode->i_mode) ++ && write_mask && !(mask & MAY_READ)) ++ || !h_inode->i_op->permission) { ++ /* AuLabel(generic_permission); */ ++ /* AuDbg("get_acl %ps\n", h_inode->i_op->get_acl); */ ++ err = generic_permission(h_inode, mask); ++ if (err == -EOPNOTSUPP && au_test_nfs_noacl(h_inode)) ++ err = h_inode->i_op->permission(h_inode, mask); ++ AuTraceErr(err); ++ } else { ++ /* AuLabel(h_inode->permission); */ ++ err = h_inode->i_op->permission(h_inode, mask); ++ AuTraceErr(err); ++ } ++ ++ if (!err) ++ err = devcgroup_inode_permission(h_inode, mask); ++ if (!err) ++ err = security_inode_permission(h_inode, mask); ++ ++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 /* reserved for future use */ ++ /* ++ * This test may be rather 'too much' since the test is essentially done ++ * in the aufs_lookup(). Theoretically it is possible that the inode ++ * generation doesn't match to the superblock's here. But it isn't a ++ * big deal I suppose. ++ */ ++ 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 /* reserved for future use */ ++ if (unlikely(d_need_lookup(dentry))) { ++ spin_lock(&dentry->d_lock); ++ dentry->d_flags &= ~DCACHE_NEED_LOOKUP; ++ spin_unlock(&dentry->d_lock); ++ } else ++#endif ++ if (inode) { ++ if (!IS_ERR(ret)) { ++ iput(inode); ++ if (ret && ret != dentry) ++ ii_write_unlock(inode); ++ } else { ++ ii_write_unlock(inode); ++ iput(inode); ++ inode = NULL; ++ } ++ } ++ ++out_unlock: ++ di_write_unlock(dentry); ++out_si: ++ si_read_unlock(sb); ++out: ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * very dirty and complicated aufs ->atomic_open(). ++ * aufs_atomic_open() ++ * + au_aopen_or_create() ++ * + add_simple() ++ * + vfsub_atomic_open() ++ * + branch fs ->atomic_open() ++ * may call the actual 'open' for h_file ++ * + inc br_nfiles only if opened ++ * + au_aopen_no_open() or au_aopen_do_open() ++ * ++ * au_aopen_do_open() ++ * + finish_open() ++ * + au_do_aopen() ++ * + au_do_open() the body of all 'open' ++ * + au_do_open_nondir() ++ * set the passed h_file ++ * ++ * au_aopen_no_open() ++ * + finish_no_open() ++ */ ++ ++struct aopen_node { ++ struct hlist_bl_node hblist; ++ struct file *file, *h_file; ++}; ++ ++static int au_do_aopen(struct inode *inode, struct file *file) ++{ ++ struct hlist_bl_head *aopen; ++ struct hlist_bl_node *pos; ++ struct aopen_node *node; ++ struct au_do_open_args args = { ++ .aopen = 1, ++ .open = au_do_open_nondir ++ }; ++ ++ aopen = &au_sbi(inode->i_sb)->si_aopen; ++ hlist_bl_lock(aopen); ++ hlist_bl_for_each_entry(node, pos, aopen, hblist) ++ if (node->file == file) { ++ args.h_file = node->h_file; ++ break; ++ } ++ hlist_bl_unlock(aopen); ++ /* AuDebugOn(!args.h_file); */ ++ ++ return au_do_open(file, &args); ++} ++ ++static int au_aopen_do_open(struct file *file, struct dentry *dentry, ++ struct aopen_node *aopen_node) ++{ ++ int err; ++ struct hlist_bl_head *aopen; ++ ++ AuLabel(here); ++ aopen = &au_sbi(dentry->d_sb)->si_aopen; ++ au_hbl_add(&aopen_node->hblist, aopen); ++ err = finish_open(file, dentry, au_do_aopen); ++ au_hbl_del(&aopen_node->hblist, aopen); ++ /* AuDbgFile(file); */ ++ AuDbg("%pd%s%s\n", dentry, ++ (file->f_mode & FMODE_CREATED) ? " created" : "", ++ (file->f_mode & FMODE_OPENED) ? " opened" : ""); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_aopen_no_open(struct file *file, struct dentry *dentry) ++{ ++ int err; ++ ++ AuLabel(here); ++ dget(dentry); ++ err = finish_no_open(file, dentry); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int aufs_atomic_open(struct inode *dir, struct dentry *dentry, ++ struct file *file, unsigned int open_flag, ++ umode_t create_mode) ++{ ++ int err, did_open; ++ unsigned int lkup_flags; ++ aufs_bindex_t bindex; ++ struct super_block *sb; ++ struct dentry *parent, *d; ++ struct vfsub_aopen_args args = { ++ .open_flag = open_flag, ++ .create_mode = create_mode ++ }; ++ struct aopen_node aopen_node = { ++ .file = file ++ }; ++ ++ IMustLock(dir); ++ AuDbg("open_flag 0%o\n", open_flag); ++ AuDbgDentry(dentry); ++ ++ err = 0; ++ if (!au_di(dentry)) { ++ lkup_flags = LOOKUP_OPEN; ++ if (open_flag & O_CREAT) ++ lkup_flags |= LOOKUP_CREATE; ++ d = aufs_lookup(dir, dentry, lkup_flags); ++ if (IS_ERR(d)) { ++ err = PTR_ERR(d); ++ AuTraceErr(err); ++ goto out; ++ } else if (d) { ++ /* ++ * obsoleted dentry found. ++ * another error will be returned later. ++ */ ++ d_drop(d); ++ AuDbgDentry(d); ++ dput(d); ++ } ++ AuDbgDentry(dentry); ++ } ++ ++ if (d_is_positive(dentry) ++ || d_unhashed(dentry) ++ || d_unlinked(dentry) ++ || !(open_flag & O_CREAT)) { ++ err = au_aopen_no_open(file, dentry); ++ goto out; /* success */ ++ } ++ ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_GEN); ++ if (unlikely(err)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ parent = dentry->d_parent; /* dir is locked */ ++ di_write_lock_parent(parent); ++ err = au_lkup_dentry(dentry, /*btop*/0, AuLkup_ALLOW_NEG); ++ if (unlikely(err < 0)) ++ goto out_parent; ++ ++ AuDbgDentry(dentry); ++ if (d_is_positive(dentry)) { ++ err = au_aopen_no_open(file, dentry); ++ goto out_parent; /* success */ ++ } ++ ++ args.file = alloc_empty_file(file->f_flags, current_cred()); ++ err = PTR_ERR(args.file); ++ if (IS_ERR(args.file)) ++ goto out_parent; ++ ++ bindex = au_dbtop(dentry); ++ err = au_aopen_or_create(dir, dentry, &args); ++ AuTraceErr(err); ++ AuDbgFile(args.file); ++ file->f_mode = args.file->f_mode & ~FMODE_OPENED; ++ did_open = !!(args.file->f_mode & FMODE_OPENED); ++ if (!did_open) { ++ fput(args.file); ++ args.file = NULL; ++ } ++ di_write_unlock(parent); ++ di_write_unlock(dentry); ++ if (unlikely(err < 0)) { ++ if (args.file) ++ fput(args.file); ++ goto out_sb; ++ } ++ ++ if (!did_open) ++ err = au_aopen_no_open(file, dentry); ++ else { ++ aopen_node.h_file = args.file; ++ err = au_aopen_do_open(file, dentry, &aopen_node); ++ } ++ if (unlikely(err < 0)) { ++ if (args.file) ++ fput(args.file); ++ if (did_open) ++ au_lcnt_dec(&args.br->br_nfiles); ++ } ++ goto out_sb; /* success */ ++ ++out_parent: ++ di_write_unlock(parent); ++ di_write_unlock(dentry); ++out_sb: ++ si_read_unlock(sb); ++out: ++ AuTraceErr(err); ++ AuDbgFile(file); ++ return err; ++} ++ ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_wr_dir_cpup(struct dentry *dentry, struct dentry *parent, ++ const unsigned char add_entry, aufs_bindex_t bcpup, ++ aufs_bindex_t btop) ++{ ++ int err; ++ struct dentry *h_parent; ++ struct inode *h_dir; ++ ++ if (add_entry) ++ IMustLock(d_inode(parent)); ++ else ++ di_write_lock_parent(parent); ++ ++ err = 0; ++ if (!au_h_dptr(parent, bcpup)) { ++ if (btop > bcpup) ++ err = au_cpup_dirs(dentry, bcpup); ++ else if (btop < bcpup) ++ err = au_cpdown_dirs(dentry, bcpup); ++ else ++ BUG(); ++ } ++ if (!err && add_entry && !au_ftest_wrdir(add_entry, TMPFILE)) { ++ h_parent = au_h_dptr(parent, bcpup); ++ h_dir = d_inode(h_parent); ++ inode_lock_shared_nested(h_dir, AuLsc_I_PARENT); ++ err = au_lkup_neg(dentry, bcpup, /*wh*/0); ++ /* todo: no unlock here */ ++ inode_unlock_shared(h_dir); ++ ++ AuDbg("bcpup %d\n", bcpup); ++ if (!err) { ++ if (d_really_is_negative(dentry)) ++ au_set_h_dptr(dentry, btop, NULL); ++ au_update_dbrange(dentry, /*do_put_zero*/0); ++ } ++ } ++ ++ if (!add_entry) ++ di_write_unlock(parent); ++ if (!err) ++ err = bcpup; /* success */ ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * decide the branch and the parent dir where we will create a new entry. ++ * returns new bindex or an error. ++ * copyup the parent dir if needed. ++ */ ++int au_wr_dir(struct dentry *dentry, struct dentry *src_dentry, ++ struct au_wr_dir_args *args) ++{ ++ int err; ++ unsigned int flags; ++ aufs_bindex_t bcpup, btop, src_btop; ++ const unsigned char add_entry ++ = au_ftest_wrdir(args->flags, ADD_ENTRY) ++ | au_ftest_wrdir(args->flags, TMPFILE); ++ struct super_block *sb; ++ struct dentry *parent; ++ struct au_sbinfo *sbinfo; ++ ++ sb = dentry->d_sb; ++ sbinfo = au_sbi(sb); ++ parent = dget_parent(dentry); ++ btop = au_dbtop(dentry); ++ bcpup = btop; ++ if (args->force_btgt < 0) { ++ if (src_dentry) { ++ src_btop = au_dbtop(src_dentry); ++ if (src_btop < btop) ++ bcpup = src_btop; ++ } else if (add_entry) { ++ flags = 0; ++ if (au_ftest_wrdir(args->flags, ISDIR)) ++ au_fset_wbr(flags, DIR); ++ err = AuWbrCreate(sbinfo, dentry, flags); ++ bcpup = err; ++ } ++ ++ if (bcpup < 0 || au_test_ro(sb, bcpup, d_inode(dentry))) { ++ if (add_entry) ++ err = AuWbrCopyup(sbinfo, dentry); ++ else { ++ if (!IS_ROOT(dentry)) { ++ di_read_lock_parent(parent, !AuLock_IR); ++ err = AuWbrCopyup(sbinfo, dentry); ++ di_read_unlock(parent, !AuLock_IR); ++ } else ++ err = AuWbrCopyup(sbinfo, dentry); ++ } ++ bcpup = err; ++ if (unlikely(err < 0)) ++ goto out; ++ } ++ } else { ++ bcpup = args->force_btgt; ++ AuDebugOn(au_test_ro(sb, bcpup, d_inode(dentry))); ++ } ++ ++ AuDbg("btop %d, bcpup %d\n", btop, bcpup); ++ err = bcpup; ++ if (bcpup == btop) ++ goto out; /* success */ ++ ++ /* copyup the new parent into the branch we process */ ++ err = au_wr_dir_cpup(dentry, parent, add_entry, bcpup, btop); ++ if (err >= 0) { ++ if (d_really_is_negative(dentry)) { ++ au_set_h_dptr(dentry, btop, NULL); ++ au_set_dbtop(dentry, bcpup); ++ au_set_dbbot(dentry, bcpup); ++ } ++ AuDebugOn(add_entry ++ && !au_ftest_wrdir(args->flags, TMPFILE) ++ && !au_h_dptr(dentry, bcpup)); ++ } ++ ++out: ++ dput(parent); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_pin_hdir_unlock(struct au_pin *p) ++{ ++ if (p->hdir) ++ au_hn_inode_unlock(p->hdir); ++} ++ ++int au_pin_hdir_lock(struct au_pin *p) ++{ ++ int err; ++ ++ err = 0; ++ if (!p->hdir) ++ goto out; ++ ++ /* even if an error happens later, keep this lock */ ++ au_hn_inode_lock_nested(p->hdir, p->lsc_hi); ++ ++ err = -EBUSY; ++ if (unlikely(p->hdir->hi_inode != d_inode(p->h_parent))) ++ goto out; ++ ++ err = 0; ++ if (p->h_dentry) ++ err = au_h_verify(p->h_dentry, p->udba, p->hdir->hi_inode, ++ p->h_parent, p->br); ++ ++out: ++ return err; ++} ++ ++int au_pin_hdir_relock(struct au_pin *p) ++{ ++ int err, i; ++ struct inode *h_i; ++ struct dentry *h_d[] = { ++ p->h_dentry, ++ p->h_parent ++ }; ++ ++ err = au_pin_hdir_lock(p); ++ if (unlikely(err)) ++ goto out; ++ ++ for (i = 0; !err && i < sizeof(h_d)/sizeof(*h_d); i++) { ++ if (!h_d[i]) ++ continue; ++ if (d_is_positive(h_d[i])) { ++ h_i = d_inode(h_d[i]); ++ err = !h_i->i_nlink; ++ } ++ } ++ ++out: ++ return err; ++} ++ ++static void au_pin_hdir_set_owner(struct au_pin *p, struct task_struct *task) ++{ ++ atomic_long_set(&p->hdir->hi_inode->i_rwsem.owner, (long)task); ++} ++ ++void au_pin_hdir_acquire_nest(struct au_pin *p) ++{ ++ if (p->hdir) { ++ rwsem_acquire_nest(&p->hdir->hi_inode->i_rwsem.dep_map, ++ p->lsc_hi, 0, NULL, _RET_IP_); ++ au_pin_hdir_set_owner(p, current); ++ } ++} ++ ++void au_pin_hdir_release(struct au_pin *p) ++{ ++ if (p->hdir) { ++ au_pin_hdir_set_owner(p, p->task); ++ rwsem_release(&p->hdir->hi_inode->i_rwsem.dep_map, _RET_IP_); ++ } ++} ++ ++struct dentry *au_pinned_h_parent(struct au_pin *pin) ++{ ++ if (pin && pin->parent) ++ return au_h_dptr(pin->parent, pin->bindex); ++ return NULL; ++} ++ ++void au_unpin(struct au_pin *p) ++{ ++ if (p->hdir) ++ au_pin_hdir_unlock(p); ++ if (p->h_mnt && au_ftest_pin(p->flags, MNT_WRITE)) ++ vfsub_mnt_drop_write(p->h_mnt); ++ if (!p->hdir) ++ return; ++ ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_unlock(p->parent, AuLock_IR); ++ iput(p->hdir->hi_inode); ++ dput(p->parent); ++ p->parent = NULL; ++ p->hdir = NULL; ++ p->h_mnt = NULL; ++ /* do not clear p->task */ ++} ++ ++int au_do_pin(struct au_pin *p) ++{ ++ int err; ++ struct super_block *sb; ++ struct inode *h_dir; ++ ++ err = 0; ++ sb = p->dentry->d_sb; ++ p->br = au_sbr(sb, p->bindex); ++ if (IS_ROOT(p->dentry)) { ++ if (au_ftest_pin(p->flags, MNT_WRITE)) { ++ p->h_mnt = au_br_mnt(p->br); ++ err = vfsub_mnt_want_write(p->h_mnt); ++ if (unlikely(err)) { ++ au_fclr_pin(p->flags, MNT_WRITE); ++ goto out_err; ++ } ++ } ++ goto out; ++ } ++ ++ p->h_dentry = NULL; ++ if (p->bindex <= au_dbbot(p->dentry)) ++ p->h_dentry = au_h_dptr(p->dentry, p->bindex); ++ ++ p->parent = dget_parent(p->dentry); ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_lock(p->parent, AuLock_IR, p->lsc_di); ++ ++ h_dir = NULL; ++ p->h_parent = au_h_dptr(p->parent, p->bindex); ++ p->hdir = au_hi(d_inode(p->parent), p->bindex); ++ if (p->hdir) ++ h_dir = p->hdir->hi_inode; ++ ++ /* ++ * udba case, or ++ * if DI_LOCKED is not set, then p->parent may be different ++ * and h_parent can be NULL. ++ */ ++ if (unlikely(!p->hdir || !h_dir || !p->h_parent)) { ++ err = -EBUSY; ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_unlock(p->parent, AuLock_IR); ++ dput(p->parent); ++ p->parent = NULL; ++ goto out_err; ++ } ++ ++ if (au_ftest_pin(p->flags, MNT_WRITE)) { ++ p->h_mnt = au_br_mnt(p->br); ++ err = vfsub_mnt_want_write(p->h_mnt); ++ if (unlikely(err)) { ++ au_fclr_pin(p->flags, MNT_WRITE); ++ if (!au_ftest_pin(p->flags, DI_LOCKED)) ++ di_read_unlock(p->parent, AuLock_IR); ++ dput(p->parent); ++ p->parent = NULL; ++ goto out_err; ++ } ++ } ++ ++ au_igrab(h_dir); ++ err = au_pin_hdir_lock(p); ++ if (!err) ++ goto out; /* success */ ++ ++ au_unpin(p); ++ ++out_err: ++ pr_err("err %d\n", err); ++ err = au_busy_or_stale(); ++out: ++ return err; ++} ++ ++void au_pin_init(struct au_pin *p, struct dentry *dentry, ++ aufs_bindex_t bindex, int lsc_di, int lsc_hi, ++ unsigned int udba, unsigned char flags) ++{ ++ p->dentry = dentry; ++ p->udba = udba; ++ p->lsc_di = lsc_di; ++ p->lsc_hi = lsc_hi; ++ p->flags = flags; ++ p->bindex = bindex; ++ ++ p->parent = NULL; ++ p->hdir = NULL; ++ p->h_mnt = NULL; ++ ++ p->h_dentry = NULL; ++ p->h_parent = NULL; ++ p->br = NULL; ++ p->task = current; ++} ++ ++int au_pin(struct au_pin *pin, struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int udba, unsigned char flags) ++{ ++ au_pin_init(pin, dentry, bindex, AuLsc_DI_PARENT, AuLsc_I_PARENT2, ++ udba, flags); ++ return au_do_pin(pin); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * ->setattr() and ->getattr() are called in various cases. ++ * chmod, stat: dentry is revalidated. ++ * fchmod, fstat: file and dentry are not revalidated, additionally they may be ++ * unhashed. ++ * for ->setattr(), ia->ia_file is passed from ftruncate only. ++ */ ++/* todo: consolidate with do_refresh() and simple_reval_dpath() */ ++int au_reval_for_attr(struct dentry *dentry, unsigned int sigen) ++{ ++ int err; ++ struct dentry *parent; ++ ++ err = 0; ++ if (au_digen_test(dentry, sigen)) { ++ parent = dget_parent(dentry); ++ di_read_lock_parent(parent, AuLock_IR); ++ err = au_refresh_dentry(dentry, parent); ++ di_read_unlock(parent, AuLock_IR); ++ dput(parent); ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_pin_and_icpup(struct dentry *dentry, struct iattr *ia, ++ struct au_icpup_args *a) ++{ ++ int err; ++ loff_t sz; ++ aufs_bindex_t btop, ibtop; ++ struct dentry *hi_wh, *parent; ++ struct inode *inode; ++ struct au_wr_dir_args wr_dir_args = { ++ .force_btgt = -1, ++ .flags = 0 ++ }; ++ ++ if (d_is_dir(dentry)) ++ au_fset_wrdir(wr_dir_args.flags, ISDIR); ++ /* plink or hi_wh() case */ ++ btop = au_dbtop(dentry); ++ inode = d_inode(dentry); ++ ibtop = au_ibtop(inode); ++ if (btop != ibtop && !au_test_ro(inode->i_sb, ibtop, inode)) ++ wr_dir_args.force_btgt = ibtop; ++ err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args); ++ if (unlikely(err < 0)) ++ goto out; ++ a->btgt = err; ++ if (err != btop) ++ au_fset_icpup(a->flags, DID_CPUP); ++ ++ err = 0; ++ a->pin_flags = AuPin_MNT_WRITE; ++ parent = NULL; ++ if (!IS_ROOT(dentry)) { ++ au_fset_pin(a->pin_flags, DI_LOCKED); ++ parent = dget_parent(dentry); ++ di_write_lock_parent(parent); ++ } ++ ++ err = au_pin(&a->pin, dentry, a->btgt, a->udba, a->pin_flags); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ sz = -1; ++ a->h_path.dentry = au_h_dptr(dentry, btop); ++ a->h_inode = d_inode(a->h_path.dentry); ++ if (ia && (ia->ia_valid & ATTR_SIZE)) { ++ inode_lock_shared_nested(a->h_inode, AuLsc_I_CHILD); ++ if (ia->ia_size < i_size_read(a->h_inode)) ++ sz = ia->ia_size; ++ inode_unlock_shared(a->h_inode); ++ } ++ ++ hi_wh = NULL; ++ if (au_ftest_icpup(a->flags, DID_CPUP) && d_unlinked(dentry)) { ++ hi_wh = au_hi_wh(inode, a->btgt); ++ if (!hi_wh) { ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = a->btgt, ++ .bsrc = -1, ++ .len = sz, ++ .pin = &a->pin ++ }; ++ err = au_sio_cpup_wh(&cpg, /*file*/NULL); ++ if (unlikely(err)) ++ goto out_unlock; ++ hi_wh = au_hi_wh(inode, a->btgt); ++ /* todo: revalidate hi_wh? */ ++ } ++ } ++ ++ if (parent) { ++ au_pin_set_parent_lflag(&a->pin, /*lflag*/0); ++ di_downgrade_lock(parent, AuLock_IR); ++ dput(parent); ++ parent = NULL; ++ } ++ if (!au_ftest_icpup(a->flags, DID_CPUP)) ++ goto out; /* success */ ++ ++ if (!d_unhashed(dentry)) { ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = a->btgt, ++ .bsrc = btop, ++ .len = sz, ++ .pin = &a->pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ err = au_sio_cpup_simple(&cpg); ++ if (!err) ++ a->h_path.dentry = au_h_dptr(dentry, a->btgt); ++ } else if (!hi_wh) ++ a->h_path.dentry = au_h_dptr(dentry, a->btgt); ++ else ++ a->h_path.dentry = hi_wh; /* do not dget here */ ++ ++out_unlock: ++ a->h_inode = d_inode(a->h_path.dentry); ++ if (!err) ++ goto out; /* success */ ++ au_unpin(&a->pin); ++out_parent: ++ if (parent) { ++ di_write_unlock(parent); ++ dput(parent); ++ } ++out: ++ if (!err) ++ inode_lock_nested(a->h_inode, AuLsc_I_CHILD); ++ return err; ++} ++ ++static int aufs_setattr(struct dentry *dentry, struct iattr *ia) ++{ ++ int err; ++ struct inode *inode, *delegated; ++ struct super_block *sb; ++ struct file *file; ++ struct au_icpup_args *a; ++ ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ ++ err = setattr_prepare(dentry, ia); ++ if (unlikely(err)) ++ goto out; ++ ++ err = -ENOMEM; ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ if (ia->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) ++ ia->ia_valid &= ~ATTR_MODE; ++ ++ file = NULL; ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out_kfree; ++ ++ if (ia->ia_valid & ATTR_FILE) { ++ /* currently ftruncate(2) only */ ++ AuDebugOn(!d_is_reg(dentry)); ++ file = ia->ia_file; ++ err = au_reval_and_lock_fdi(file, au_reopen_nondir, /*wlock*/1, ++ /*fi_lsc*/0); ++ if (unlikely(err)) ++ goto out_si; ++ ia->ia_file = au_hf_top(file); ++ a->udba = AuOpt_UDBA_NONE; ++ } else { ++ /* fchmod() doesn't pass ia_file */ ++ a->udba = au_opt_udba(sb); ++ di_write_lock_child(dentry); ++ /* no d_unlinked(), to set UDBA_NONE for root */ ++ if (d_unhashed(dentry)) ++ a->udba = AuOpt_UDBA_NONE; ++ if (a->udba != AuOpt_UDBA_NONE) { ++ AuDebugOn(IS_ROOT(dentry)); ++ err = au_reval_for_attr(dentry, au_sigen(sb)); ++ if (unlikely(err)) ++ goto out_dentry; ++ } ++ } ++ ++ err = au_pin_and_icpup(dentry, ia, a); ++ if (unlikely(err < 0)) ++ goto out_dentry; ++ if (au_ftest_icpup(a->flags, DID_CPUP)) { ++ ia->ia_file = NULL; ++ ia->ia_valid &= ~ATTR_FILE; ++ } ++ ++ a->h_path.mnt = au_sbr_mnt(sb, a->btgt); ++ if ((ia->ia_valid & (ATTR_MODE | ATTR_CTIME)) ++ == (ATTR_MODE | ATTR_CTIME)) { ++ err = security_path_chmod(&a->h_path, ia->ia_mode); ++ if (unlikely(err)) ++ goto out_unlock; ++ } else if ((ia->ia_valid & (ATTR_UID | ATTR_GID)) ++ && (ia->ia_valid & ATTR_CTIME)) { ++ err = security_path_chown(&a->h_path, ia->ia_uid, ia->ia_gid); ++ if (unlikely(err)) ++ goto out_unlock; ++ } ++ ++ if (ia->ia_valid & ATTR_SIZE) { ++ struct file *f; ++ ++ if (ia->ia_size < i_size_read(inode)) ++ /* unmap only */ ++ truncate_setsize(inode, ia->ia_size); ++ ++ f = NULL; ++ if (ia->ia_valid & ATTR_FILE) ++ f = ia->ia_file; ++ inode_unlock(a->h_inode); ++ err = vfsub_trunc(&a->h_path, ia->ia_size, ia->ia_valid, f); ++ inode_lock_nested(a->h_inode, AuLsc_I_CHILD); ++ } else { ++ delegated = NULL; ++ while (1) { ++ err = vfsub_notify_change(&a->h_path, ia, &delegated); ++ if (delegated) { ++ err = break_deleg_wait(&delegated); ++ if (!err) ++ continue; ++ } ++ break; ++ } ++ } ++ /* ++ * regardless aufs 'acl' option setting. ++ * why don't all acl-aware fs call this func from their ->setattr()? ++ */ ++ if (!err && (ia->ia_valid & ATTR_MODE)) ++ err = vfsub_acl_chmod(a->h_inode, ia->ia_mode); ++ if (!err) ++ au_cpup_attr_changeable(inode); ++ ++out_unlock: ++ inode_unlock(a->h_inode); ++ au_unpin(&a->pin); ++ if (unlikely(err)) ++ au_update_dbtop(dentry); ++out_dentry: ++ di_write_unlock(dentry); ++ if (file) { ++ fi_write_unlock(file); ++ ia->ia_file = file; ++ ia->ia_valid |= ATTR_FILE; ++ } ++out_si: ++ si_read_unlock(sb); ++out_kfree: ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++#if IS_ENABLED(CONFIG_AUFS_XATTR) || IS_ENABLED(CONFIG_FS_POSIX_ACL) ++static int au_h_path_to_set_attr(struct dentry *dentry, ++ struct au_icpup_args *a, struct path *h_path) ++{ ++ int err; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ a->udba = au_opt_udba(sb); ++ /* no d_unlinked(), to set UDBA_NONE for root */ ++ if (d_unhashed(dentry)) ++ a->udba = AuOpt_UDBA_NONE; ++ if (a->udba != AuOpt_UDBA_NONE) { ++ AuDebugOn(IS_ROOT(dentry)); ++ err = au_reval_for_attr(dentry, au_sigen(sb)); ++ if (unlikely(err)) ++ goto out; ++ } ++ err = au_pin_and_icpup(dentry, /*ia*/NULL, a); ++ if (unlikely(err < 0)) ++ goto out; ++ ++ h_path->dentry = a->h_path.dentry; ++ h_path->mnt = au_sbr_mnt(sb, a->btgt); ++ ++out: ++ return err; ++} ++ ++ssize_t au_sxattr(struct dentry *dentry, struct inode *inode, ++ struct au_sxattr *arg) ++{ ++ int err; ++ struct path h_path; ++ struct super_block *sb; ++ struct au_icpup_args *a; ++ struct inode *h_inode; ++ ++ IMustLock(inode); ++ ++ err = -ENOMEM; ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out_kfree; ++ ++ h_path.dentry = NULL; /* silence gcc */ ++ di_write_lock_child(dentry); ++ err = au_h_path_to_set_attr(dentry, a, &h_path); ++ if (unlikely(err)) ++ goto out_di; ++ ++ inode_unlock(a->h_inode); ++ switch (arg->type) { ++ case AU_XATTR_SET: ++ AuDebugOn(d_is_negative(h_path.dentry)); ++ err = vfsub_setxattr(h_path.dentry, ++ arg->u.set.name, arg->u.set.value, ++ arg->u.set.size, arg->u.set.flags); ++ break; ++ case AU_ACL_SET: ++ err = -EOPNOTSUPP; ++ h_inode = d_inode(h_path.dentry); ++ if (h_inode->i_op->set_acl) ++ /* this will call posix_acl_update_mode */ ++ err = h_inode->i_op->set_acl(h_inode, ++ arg->u.acl_set.acl, ++ arg->u.acl_set.type); ++ break; ++ } ++ if (!err) ++ au_cpup_attr_timesizes(inode); ++ ++ au_unpin(&a->pin); ++ if (unlikely(err)) ++ au_update_dbtop(dentry); ++ ++out_di: ++ di_write_unlock(dentry); ++ si_read_unlock(sb); ++out_kfree: ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++#endif ++ ++static void au_refresh_iattr(struct inode *inode, struct kstat *st, ++ unsigned int nlink) ++{ ++ unsigned int n; ++ ++ inode->i_mode = st->mode; ++ /* don't i_[ug]id_write() here */ ++ inode->i_uid = st->uid; ++ inode->i_gid = st->gid; ++ inode->i_atime = st->atime; ++ inode->i_mtime = st->mtime; ++ inode->i_ctime = st->ctime; ++ ++ au_cpup_attr_nlink(inode, /*force*/0); ++ if (S_ISDIR(inode->i_mode)) { ++ n = inode->i_nlink; ++ n -= nlink; ++ n += st->nlink; ++ smp_mb(); /* for i_nlink */ ++ /* 0 can happen */ ++ set_nlink(inode, n); ++ } ++ ++ spin_lock(&inode->i_lock); ++ inode->i_blocks = st->blocks; ++ i_size_write(inode, st->size); ++ spin_unlock(&inode->i_lock); ++} ++ ++/* ++ * common routine for aufs_getattr() and au_getxattr(). ++ * returns zero or negative (an error). ++ * @dentry will be read-locked in success. ++ */ ++int au_h_path_getattr(struct dentry *dentry, struct inode *inode, 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; ++ ++ 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: ++ if (!inode) { ++ inode = d_inode(dentry); ++ if (unlikely(!inode)) ++ goto out; ++ } ++ 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, /*inode*/NULL, /*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..853c99e200da +--- /dev/null ++++ b/fs/aufs/i_op_add.c +@@ -0,0 +1,923 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode operations (add entry) ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* ++ * final procedure of adding a new entry, except link(2). ++ * remove whiteout, instantiate, copyup the parent dir's times and size ++ * and update version. ++ * if it failed, re-create the removed whiteout. ++ */ ++static int epilog(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct dentry *dentry) ++{ ++ int err, rerr; ++ aufs_bindex_t bwh; ++ struct path h_path; ++ struct super_block *sb; ++ struct inode *inode, *h_dir; ++ struct dentry *wh; ++ ++ bwh = -1; ++ sb = dir->i_sb; ++ if (wh_dentry) { ++ h_dir = d_inode(wh_dentry->d_parent); /* dir inode is locked */ ++ IMustLock(h_dir); ++ AuDebugOn(au_h_iptr(dir, bindex) != h_dir); ++ bwh = au_dbwh(dentry); ++ h_path.dentry = wh_dentry; ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ err = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path, ++ dentry); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ inode = au_new_inode(dentry, /*must_new*/1); ++ if (!IS_ERR(inode)) { ++ d_instantiate(dentry, inode); ++ dir = d_inode(dentry->d_parent); /* dir inode is locked */ ++ IMustLock(dir); ++ au_dir_ts(dir, bindex); ++ inode_inc_iversion(dir); ++ au_fhsm_wrote(sb, bindex, /*force*/0); ++ return 0; /* success */ ++ } ++ ++ err = PTR_ERR(inode); ++ if (!wh_dentry) ++ goto out; ++ ++ /* revert */ ++ /* dir inode is locked */ ++ wh = au_wh_create(dentry, bwh, wh_dentry->d_parent); ++ rerr = PTR_ERR(wh); ++ if (IS_ERR(wh)) { ++ AuIOErr("%pd reverting whiteout failed(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } else ++ dput(wh); ++ ++out: ++ return err; ++} ++ ++static int au_d_may_add(struct dentry *dentry) ++{ ++ int err; ++ ++ err = 0; ++ if (unlikely(d_unhashed(dentry))) ++ err = -ENOENT; ++ if (unlikely(d_really_is_positive(dentry))) ++ err = -EEXIST; ++ return err; ++} ++ ++/* ++ * simple tests for the adding inode operations. ++ * following the checks in vfs, plus the parent-child relationship. ++ */ ++int au_may_add(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir) ++{ ++ int err; ++ umode_t h_mode; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ ++ err = -ENAMETOOLONG; ++ if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ goto out; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (d_really_is_negative(dentry)) { ++ err = -EEXIST; ++ if (unlikely(d_is_positive(h_dentry))) ++ goto out; ++ } else { ++ /* rename(2) case */ ++ err = -EIO; ++ if (unlikely(d_is_negative(h_dentry))) ++ goto out; ++ h_inode = d_inode(h_dentry); ++ if (unlikely(!h_inode->i_nlink)) ++ goto out; ++ ++ h_mode = h_inode->i_mode; ++ if (!isdir) { ++ err = -EISDIR; ++ if (unlikely(S_ISDIR(h_mode))) ++ goto out; ++ } else if (unlikely(!S_ISDIR(h_mode))) { ++ err = -ENOTDIR; ++ goto out; ++ } ++ } ++ ++ err = 0; ++ /* expected parent dir is locked */ ++ if (unlikely(h_parent != h_dentry->d_parent)) ++ err = -EIO; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * initial procedure of adding a new entry. ++ * prepare writable branch and the parent dir, lock it, ++ * and lookup whiteout for the new entry. ++ */ ++static struct dentry* ++lock_hdir_lkup_wh(struct dentry *dentry, struct au_dtime *dt, ++ struct dentry *src_dentry, struct au_pin *pin, ++ struct au_wr_dir_args *wr_dir_args) ++{ ++ struct dentry *wh_dentry, *h_parent; ++ struct super_block *sb; ++ struct au_branch *br; ++ int err; ++ unsigned int udba; ++ aufs_bindex_t bcpup; ++ ++ AuDbg("%pd\n", dentry); ++ ++ err = au_wr_dir(dentry, src_dentry, wr_dir_args); ++ bcpup = err; ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err < 0)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ udba = au_opt_udba(sb); ++ err = au_pin(pin, dentry, bcpup, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ h_parent = au_pinned_h_parent(pin); ++ if (udba != AuOpt_UDBA_NONE ++ && au_dbtop(dentry) == bcpup) ++ err = au_may_add(dentry, bcpup, h_parent, ++ au_ftest_wrdir(wr_dir_args->flags, ISDIR)); ++ else if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ err = -ENAMETOOLONG; ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_unpin; ++ ++ br = au_sbr(sb, bcpup); ++ if (dt) { ++ struct path tmp = { ++ .dentry = h_parent, ++ .mnt = au_br_mnt(br) ++ }; ++ au_dtime_store(dt, au_pinned_parent(pin), &tmp); ++ } ++ ++ wh_dentry = NULL; ++ if (bcpup != au_dbwh(dentry)) ++ goto out; /* success */ ++ ++ /* ++ * ENAMETOOLONG here means that if we allowed create such name, then it ++ * would not be able to removed in the future. So we don't allow such ++ * name here and we don't handle ENAMETOOLONG differently here. ++ */ ++ wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, br); ++ ++out_unpin: ++ if (IS_ERR(wh_dentry)) ++ au_unpin(pin); ++out: ++ return wh_dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++enum { Mknod, Symlink, Creat }; ++struct simple_arg { ++ int type; ++ union { ++ struct { ++ umode_t mode; ++ bool want_excl; ++ bool try_aopen; ++ struct vfsub_aopen_args *aopen; ++ } c; ++ struct { ++ const char *symname; ++ } s; ++ struct { ++ umode_t mode; ++ dev_t dev; ++ } m; ++ } u; ++}; ++ ++static int add_simple(struct inode *dir, struct dentry *dentry, ++ struct simple_arg *arg) ++{ ++ int err, rerr; ++ aufs_bindex_t btop; ++ unsigned char created; ++ const unsigned char try_aopen ++ = (arg->type == Creat && arg->u.c.try_aopen); ++ struct vfsub_aopen_args *aopen = arg->u.c.aopen; ++ struct dentry *wh_dentry, *parent; ++ struct inode *h_dir; ++ struct super_block *sb; ++ struct au_branch *br; ++ /* to reduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct au_pin pin; ++ struct path h_path; ++ struct au_wr_dir_args wr_dir_args; ++ } *a; ++ ++ AuDbg("%pd\n", dentry); ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ a->wr_dir_args.force_btgt = -1; ++ a->wr_dir_args.flags = AuWrDir_ADD_ENTRY; ++ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ if (!try_aopen) { ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_free; ++ } ++ err = au_d_may_add(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ if (!try_aopen) ++ di_write_lock_parent(parent); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL, ++ &a->pin, &a->wr_dir_args); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ btop = au_dbtop(dentry); ++ sb = dentry->d_sb; ++ br = au_sbr(sb, btop); ++ a->h_path.dentry = au_h_dptr(dentry, btop); ++ a->h_path.mnt = au_br_mnt(br); ++ h_dir = au_pinned_h_dir(&a->pin); ++ switch (arg->type) { ++ case Creat: ++ if (!try_aopen || !h_dir->i_op->atomic_open) { ++ err = vfsub_create(h_dir, &a->h_path, arg->u.c.mode, ++ arg->u.c.want_excl); ++ created = !err; ++ if (!err && try_aopen) ++ aopen->file->f_mode |= FMODE_CREATED; ++ } else { ++ aopen->br = br; ++ err = vfsub_atomic_open(h_dir, a->h_path.dentry, aopen); ++ AuDbg("err %d\n", err); ++ AuDbgFile(aopen->file); ++ created = err >= 0 ++ && !!(aopen->file->f_mode & FMODE_CREATED); ++ } ++ break; ++ case Symlink: ++ err = vfsub_symlink(h_dir, &a->h_path, arg->u.s.symname); ++ created = !err; ++ break; ++ case Mknod: ++ err = vfsub_mknod(h_dir, &a->h_path, arg->u.m.mode, ++ arg->u.m.dev); ++ created = !err; ++ break; ++ default: ++ BUG(); ++ } ++ if (unlikely(err < 0)) ++ goto out_unpin; ++ ++ err = epilog(dir, btop, wh_dentry, dentry); ++ if (!err) ++ goto out_unpin; /* success */ ++ ++ /* revert */ ++ if (created /* && d_is_positive(a->h_path.dentry) */) { ++ /* no delegation since it is just created */ ++ rerr = vfsub_unlink(h_dir, &a->h_path, /*delegated*/NULL, ++ /*force*/0); ++ if (rerr) { ++ AuIOErr("%pd revert failure(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } ++ au_dtime_revert(&a->dt); ++ } ++ if (try_aopen && h_dir->i_op->atomic_open ++ && (aopen->file->f_mode & FMODE_OPENED)) ++ /* aopen->file is still opened */ ++ au_lcnt_dec(&aopen->br->br_nfiles); ++ ++out_unpin: ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++out_parent: ++ if (!try_aopen) ++ di_write_unlock(parent); ++out_unlock: ++ if (unlikely(err)) { ++ au_update_dbtop(dentry); ++ d_drop(dentry); ++ } ++ if (!try_aopen) ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ au_kfree_rcu(a); ++out: ++ return err; ++} ++ ++int aufs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, ++ dev_t dev) ++{ ++ struct simple_arg arg = { ++ .type = Mknod, ++ .u.m = { ++ .mode = mode, ++ .dev = dev ++ } ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int aufs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) ++{ ++ struct simple_arg arg = { ++ .type = Symlink, ++ .u.s.symname = symname ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int aufs_create(struct inode *dir, struct dentry *dentry, umode_t mode, ++ bool want_excl) ++{ ++ struct simple_arg arg = { ++ .type = Creat, ++ .u.c = { ++ .mode = mode, ++ .want_excl = want_excl ++ } ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int au_aopen_or_create(struct inode *dir, struct dentry *dentry, ++ struct vfsub_aopen_args *aopen_args) ++{ ++ struct simple_arg arg = { ++ .type = Creat, ++ .u.c = { ++ .mode = aopen_args->create_mode, ++ .want_excl = aopen_args->open_flag & O_EXCL, ++ .try_aopen = true, ++ .aopen = aopen_args ++ } ++ }; ++ return add_simple(dir, dentry, &arg); ++} ++ ++int aufs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct super_block *sb; ++ struct dentry *parent, *h_parent, *h_dentry; ++ struct inode *h_dir, *inode; ++ struct vfsmount *h_mnt; ++ struct au_wr_dir_args wr_dir_args = { ++ .force_btgt = -1, ++ .flags = AuWrDir_TMPFILE ++ }; ++ ++ /* copy-up may happen */ ++ inode_lock(dir); ++ ++ sb = dir->i_sb; ++ err = si_read_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_di_init(dentry); ++ if (unlikely(err)) ++ goto out_si; ++ ++ err = -EBUSY; ++ parent = d_find_any_alias(dir); ++ AuDebugOn(!parent); ++ di_write_lock_parent(parent); ++ if (unlikely(d_inode(parent) != dir)) ++ goto out_parent; ++ ++ err = au_digen_test(parent, au_sigen(sb)); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ bindex = au_dbtop(parent); ++ au_set_dbtop(dentry, bindex); ++ au_set_dbbot(dentry, bindex); ++ err = au_wr_dir(dentry, /*src_dentry*/NULL, &wr_dir_args); ++ bindex = err; ++ if (unlikely(err < 0)) ++ goto out_parent; ++ ++ err = -EOPNOTSUPP; ++ h_dir = au_h_iptr(dir, bindex); ++ if (unlikely(!h_dir->i_op->tmpfile)) ++ goto out_parent; ++ ++ h_mnt = au_sbr_mnt(sb, bindex); ++ err = vfsub_mnt_want_write(h_mnt); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ h_parent = au_h_dptr(parent, bindex); ++ h_dentry = vfs_tmpfile(h_parent, mode, /*open_flag*/0); ++ if (IS_ERR(h_dentry)) { ++ err = PTR_ERR(h_dentry); ++ goto out_mnt; ++ } ++ ++ au_set_dbtop(dentry, bindex); ++ au_set_dbbot(dentry, bindex); ++ au_set_h_dptr(dentry, bindex, dget(h_dentry)); ++ inode = au_new_inode(dentry, /*must_new*/1); ++ if (IS_ERR(inode)) { ++ err = PTR_ERR(inode); ++ au_set_h_dptr(dentry, bindex, NULL); ++ au_set_dbtop(dentry, -1); ++ au_set_dbbot(dentry, -1); ++ } else { ++ if (!inode->i_nlink) ++ set_nlink(inode, 1); ++ d_tmpfile(dentry, inode); ++ au_di(dentry)->di_tmpfile = 1; ++ ++ /* update without i_mutex */ ++ if (au_ibtop(dir) == au_dbtop(dentry)) ++ au_cpup_attr_timesizes(dir); ++ } ++ dput(h_dentry); ++ ++out_mnt: ++ vfsub_mnt_drop_write(h_mnt); ++out_parent: ++ di_write_unlock(parent); ++ dput(parent); ++ di_write_unlock(dentry); ++ if (unlikely(err)) { ++ au_di_fin(dentry); ++ dentry->d_fsdata = NULL; ++ } ++out_si: ++ si_read_unlock(sb); ++out: ++ inode_unlock(dir); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_link_args { ++ aufs_bindex_t bdst, bsrc; ++ struct au_pin pin; ++ struct path h_path; ++ struct dentry *src_parent, *parent; ++}; ++ ++static int au_cpup_before_link(struct dentry *src_dentry, ++ struct au_link_args *a) ++{ ++ int err; ++ struct dentry *h_src_dentry; ++ struct au_cp_generic cpg = { ++ .dentry = src_dentry, ++ .bdst = a->bdst, ++ .bsrc = a->bsrc, ++ .len = -1, ++ .pin = &a->pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN /* | AuCpup_KEEPLINO */ ++ }; ++ ++ di_read_lock_parent(a->src_parent, AuLock_IR); ++ err = au_test_and_cpup_dirs(src_dentry, a->bdst); ++ if (unlikely(err)) ++ goto out; ++ ++ h_src_dentry = au_h_dptr(src_dentry, a->bsrc); ++ err = au_pin(&a->pin, src_dentry, a->bdst, ++ au_opt_udba(src_dentry->d_sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&a->pin); ++ ++out: ++ di_read_unlock(a->src_parent, AuLock_IR); ++ return err; ++} ++ ++static int au_cpup_or_link(struct dentry *src_dentry, struct dentry *dentry, ++ struct au_link_args *a) ++{ ++ int err; ++ unsigned char plink; ++ aufs_bindex_t bbot; ++ struct dentry *h_src_dentry; ++ struct inode *h_inode, *inode, *delegated; ++ struct super_block *sb; ++ struct file *h_file; ++ ++ plink = 0; ++ h_inode = NULL; ++ sb = src_dentry->d_sb; ++ inode = d_inode(src_dentry); ++ if (au_ibtop(inode) <= a->bdst) ++ h_inode = au_h_iptr(inode, a->bdst); ++ if (!h_inode || !h_inode->i_nlink) { ++ /* copyup src_dentry as the name of dentry. */ ++ bbot = au_dbbot(dentry); ++ if (bbot < a->bsrc) ++ au_set_dbbot(dentry, a->bsrc); ++ au_set_h_dptr(dentry, a->bsrc, ++ dget(au_h_dptr(src_dentry, a->bsrc))); ++ dget(a->h_path.dentry); ++ au_set_h_dptr(dentry, a->bdst, NULL); ++ AuDbg("temporary d_inode...\n"); ++ spin_lock(&dentry->d_lock); ++ dentry->d_inode = d_inode(src_dentry); /* tmp */ ++ spin_unlock(&dentry->d_lock); ++ h_file = au_h_open_pre(dentry, a->bsrc, /*force_wr*/0); ++ if (IS_ERR(h_file)) ++ err = PTR_ERR(h_file); ++ else { ++ struct au_cp_generic cpg = { ++ .dentry = dentry, ++ .bdst = a->bdst, ++ .bsrc = -1, ++ .len = -1, ++ .pin = &a->pin, ++ .flags = AuCpup_KEEPLINO ++ }; ++ err = au_sio_cpup_simple(&cpg); ++ au_h_open_post(dentry, a->bsrc, h_file); ++ if (!err) { ++ dput(a->h_path.dentry); ++ a->h_path.dentry = au_h_dptr(dentry, a->bdst); ++ } else ++ au_set_h_dptr(dentry, a->bdst, ++ a->h_path.dentry); ++ } ++ spin_lock(&dentry->d_lock); ++ dentry->d_inode = NULL; /* restore */ ++ spin_unlock(&dentry->d_lock); ++ AuDbg("temporary d_inode...done\n"); ++ au_set_h_dptr(dentry, a->bsrc, NULL); ++ au_set_dbbot(dentry, bbot); ++ } else { ++ /* the inode of src_dentry already exists on a.bdst branch */ ++ h_src_dentry = d_find_alias(h_inode); ++ if (!h_src_dentry && au_plink_test(inode)) { ++ plink = 1; ++ h_src_dentry = au_plink_lkup(inode, a->bdst); ++ err = PTR_ERR(h_src_dentry); ++ if (IS_ERR(h_src_dentry)) ++ goto out; ++ ++ if (unlikely(d_is_negative(h_src_dentry))) { ++ dput(h_src_dentry); ++ h_src_dentry = NULL; ++ } ++ ++ } ++ if (h_src_dentry) { ++ delegated = NULL; ++ err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), ++ &a->h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ dput(h_src_dentry); ++ } else { ++ AuIOErr("no dentry found for hi%lu on b%d\n", ++ h_inode->i_ino, a->bdst); ++ err = -EIO; ++ } ++ } ++ ++ if (!err && !plink) ++ au_plink_append(inode, a->bdst, a->h_path.dentry); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int aufs_link(struct dentry *src_dentry, struct inode *dir, ++ struct dentry *dentry) ++{ ++ int err, rerr; ++ struct au_dtime dt; ++ struct au_link_args *a; ++ struct dentry *wh_dentry, *h_src_dentry; ++ struct inode *inode, *delegated; ++ struct super_block *sb; ++ struct au_wr_dir_args wr_dir_args = { ++ /* .force_btgt = -1, */ ++ .flags = AuWrDir_ADD_ENTRY ++ }; ++ ++ IMustLock(dir); ++ inode = d_inode(src_dentry); ++ IMustLock(inode); ++ ++ err = -ENOMEM; ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ a->parent = dentry->d_parent; /* dir inode is locked */ ++ err = aufs_read_and_write_lock2(dentry, src_dentry, ++ AuLock_NOPLM | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_kfree; ++ err = au_d_linkable(src_dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ err = au_d_may_add(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ a->src_parent = dget_parent(src_dentry); ++ wr_dir_args.force_btgt = au_ibtop(inode); ++ ++ di_write_lock_parent(a->parent); ++ wr_dir_args.force_btgt = au_wbr(dentry, wr_dir_args.force_btgt); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &dt, src_dentry, &a->pin, ++ &wr_dir_args); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ err = 0; ++ sb = dentry->d_sb; ++ a->bdst = au_dbtop(dentry); ++ a->h_path.dentry = au_h_dptr(dentry, a->bdst); ++ a->h_path.mnt = au_sbr_mnt(sb, a->bdst); ++ a->bsrc = au_ibtop(inode); ++ h_src_dentry = au_h_d_alias(src_dentry, a->bsrc); ++ if (!h_src_dentry && au_di(src_dentry)->di_tmpfile) ++ h_src_dentry = dget(au_hi_wh(inode, a->bsrc)); ++ if (!h_src_dentry) { ++ a->bsrc = au_dbtop(src_dentry); ++ h_src_dentry = au_h_d_alias(src_dentry, a->bsrc); ++ AuDebugOn(!h_src_dentry); ++ } else if (IS_ERR(h_src_dentry)) { ++ err = PTR_ERR(h_src_dentry); ++ goto out_parent; ++ } ++ ++ /* ++ * aufs doesn't touch the credential so ++ * security_dentry_create_files_as() is unnecessary. ++ */ ++ if (au_opt_test(au_mntflags(sb), PLINK)) { ++ if (a->bdst < a->bsrc ++ /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) ++ err = au_cpup_or_link(src_dentry, dentry, a); ++ else { ++ delegated = NULL; ++ err = vfsub_link(h_src_dentry, au_pinned_h_dir(&a->pin), ++ &a->h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ } ++ dput(h_src_dentry); ++ } else { ++ /* ++ * copyup src_dentry to the branch we process, ++ * and then link(2) to it. ++ */ ++ dput(h_src_dentry); ++ if (a->bdst < a->bsrc ++ /* && h_src_dentry->d_sb != a->h_path.dentry->d_sb */) { ++ au_unpin(&a->pin); ++ di_write_unlock(a->parent); ++ err = au_cpup_before_link(src_dentry, a); ++ di_write_lock_parent(a->parent); ++ if (!err) ++ err = au_pin(&a->pin, dentry, a->bdst, ++ au_opt_udba(sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (unlikely(err)) ++ goto out_wh; ++ } ++ if (!err) { ++ h_src_dentry = au_h_dptr(src_dentry, a->bdst); ++ err = -ENOENT; ++ if (h_src_dentry && d_is_positive(h_src_dentry)) { ++ delegated = NULL; ++ err = vfsub_link(h_src_dentry, ++ au_pinned_h_dir(&a->pin), ++ &a->h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry" ++ " for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ } ++ } ++ } ++ if (unlikely(err)) ++ goto out_unpin; ++ ++ if (wh_dentry) { ++ a->h_path.dentry = wh_dentry; ++ err = au_wh_unlink_dentry(au_pinned_h_dir(&a->pin), &a->h_path, ++ dentry); ++ if (unlikely(err)) ++ goto out_revert; ++ } ++ ++ au_dir_ts(dir, a->bdst); ++ inode_inc_iversion(dir); ++ inc_nlink(inode); ++ inode->i_ctime = dir->i_ctime; ++ d_instantiate(dentry, au_igrab(inode)); ++ if (d_unhashed(a->h_path.dentry)) ++ /* some filesystem calls d_drop() */ ++ d_drop(dentry); ++ /* some filesystems consume an inode even hardlink */ ++ au_fhsm_wrote(sb, a->bdst, /*force*/0); ++ goto out_unpin; /* success */ ++ ++out_revert: ++ /* no delegation since it is just created */ ++ rerr = vfsub_unlink(au_pinned_h_dir(&a->pin), &a->h_path, ++ /*delegated*/NULL, /*force*/0); ++ if (unlikely(rerr)) { ++ AuIOErr("%pd reverting failed(%d, %d)\n", dentry, err, rerr); ++ err = -EIO; ++ } ++ au_dtime_revert(&dt); ++out_unpin: ++ au_unpin(&a->pin); ++out_wh: ++ dput(wh_dentry); ++out_parent: ++ di_write_unlock(a->parent); ++ dput(a->src_parent); ++out_unlock: ++ if (unlikely(err)) { ++ au_update_dbtop(dentry); ++ d_drop(dentry); ++ } ++ aufs_read_and_write_unlock2(dentry, src_dentry); ++out_kfree: ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int aufs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ++{ ++ int err, rerr; ++ aufs_bindex_t bindex; ++ unsigned char diropq; ++ struct path h_path; ++ struct dentry *wh_dentry, *parent, *opq_dentry; ++ struct inode *h_inode; ++ struct super_block *sb; ++ struct { ++ struct au_pin pin; ++ struct au_dtime dt; ++ } *a; /* reduce the stack usage */ ++ struct au_wr_dir_args wr_dir_args = { ++ .force_btgt = -1, ++ .flags = AuWrDir_ADD_ENTRY | AuWrDir_ISDIR ++ }; ++ ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_free; ++ err = au_d_may_add(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_write_lock_parent(parent); ++ wh_dentry = lock_hdir_lkup_wh(dentry, &a->dt, /*src_dentry*/NULL, ++ &a->pin, &wr_dir_args); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ sb = dentry->d_sb; ++ bindex = au_dbtop(dentry); ++ h_path.dentry = au_h_dptr(dentry, bindex); ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ err = vfsub_mkdir(au_pinned_h_dir(&a->pin), &h_path, mode); ++ if (unlikely(err)) ++ goto out_unpin; ++ ++ /* make the dir opaque */ ++ diropq = 0; ++ h_inode = d_inode(h_path.dentry); ++ if (wh_dentry ++ || au_opt_test(au_mntflags(sb), ALWAYS_DIROPQ)) { ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ opq_dentry = au_diropq_create(dentry, bindex); ++ inode_unlock(h_inode); ++ err = PTR_ERR(opq_dentry); ++ if (IS_ERR(opq_dentry)) ++ goto out_dir; ++ dput(opq_dentry); ++ diropq = 1; ++ } ++ ++ err = epilog(dir, bindex, wh_dentry, dentry); ++ if (!err) { ++ inc_nlink(dir); ++ goto out_unpin; /* success */ ++ } ++ ++ /* revert */ ++ if (diropq) { ++ AuLabel(revert opq); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ rerr = au_diropq_remove(dentry, bindex); ++ inode_unlock(h_inode); ++ if (rerr) { ++ AuIOErr("%pd reverting diropq failed(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } ++ } ++ ++out_dir: ++ AuLabel(revert dir); ++ rerr = vfsub_rmdir(au_pinned_h_dir(&a->pin), &h_path); ++ if (rerr) { ++ AuIOErr("%pd reverting dir failed(%d, %d)\n", ++ dentry, err, rerr); ++ err = -EIO; ++ } ++ au_dtime_revert(&a->dt); ++out_unpin: ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++out_parent: ++ di_write_unlock(parent); ++out_unlock: ++ if (unlikely(err)) { ++ au_update_dbtop(dentry); ++ d_drop(dentry); ++ } ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ au_kfree_rcu(a); ++out: ++ return err; ++} +diff --git a/fs/aufs/i_op_del.c b/fs/aufs/i_op_del.c +new file mode 100644 +index 000000000000..05f5d4219b41 +--- /dev/null ++++ b/fs/aufs/i_op_del.c +@@ -0,0 +1,500 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode operations (del entry) ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* ++ * decide if a new whiteout for @dentry is necessary or not. ++ * when it is necessary, prepare the parent dir for the upper branch whose ++ * branch index is @bcpup for creation. the actual creation of the whiteout will ++ * be done by caller. ++ * return value: ++ * 0: wh is unnecessary ++ * plus: wh is necessary ++ * minus: error ++ */ ++int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup) ++{ ++ int need_wh, err; ++ aufs_bindex_t btop; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ btop = au_dbtop(dentry); ++ if (*bcpup < 0) { ++ *bcpup = btop; ++ if (au_test_ro(sb, btop, d_inode(dentry))) { ++ err = AuWbrCopyup(au_sbi(sb), dentry); ++ *bcpup = err; ++ if (unlikely(err < 0)) ++ goto out; ++ } ++ } else ++ AuDebugOn(btop < *bcpup ++ || au_test_ro(sb, *bcpup, d_inode(dentry))); ++ AuDbg("bcpup %d, btop %d\n", *bcpup, btop); ++ ++ if (*bcpup != btop) { ++ err = au_cpup_dirs(dentry, *bcpup); ++ if (unlikely(err)) ++ goto out; ++ need_wh = 1; ++ } else { ++ struct au_dinfo *dinfo, *tmp; ++ ++ need_wh = -ENOMEM; ++ dinfo = au_di(dentry); ++ tmp = au_di_alloc(sb, AuLsc_DI_TMP); ++ if (tmp) { ++ au_di_cp(tmp, dinfo); ++ au_di_swap(tmp, dinfo); ++ /* returns the number of positive dentries */ ++ need_wh = au_lkup_dentry(dentry, btop + 1, ++ /* AuLkup_IGNORE_PERM */ 0); ++ au_di_swap(tmp, dinfo); ++ au_rw_write_unlock(&tmp->di_rwsem); ++ au_di_free(tmp); ++ } ++ } ++ AuDbg("need_wh %d\n", need_wh); ++ err = need_wh; ++ ++out: ++ return err; ++} ++ ++/* ++ * simple tests for the del-entry operations. ++ * following the checks in vfs, plus the parent-child relationship. ++ */ ++int au_may_del(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent, int isdir) ++{ ++ int err; ++ umode_t h_mode; ++ struct dentry *h_dentry, *h_latest; ++ struct inode *h_inode; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (d_really_is_positive(dentry)) { ++ err = -ENOENT; ++ if (unlikely(d_is_negative(h_dentry))) ++ goto out; ++ h_inode = d_inode(h_dentry); ++ if (unlikely(!h_inode->i_nlink)) ++ goto out; ++ ++ h_mode = h_inode->i_mode; ++ if (!isdir) { ++ err = -EISDIR; ++ if (unlikely(S_ISDIR(h_mode))) ++ goto out; ++ } else if (unlikely(!S_ISDIR(h_mode))) { ++ err = -ENOTDIR; ++ goto out; ++ } ++ } else { ++ /* rename(2) case */ ++ err = -EIO; ++ if (unlikely(d_is_positive(h_dentry))) ++ goto out; ++ } ++ ++ err = -ENOENT; ++ /* expected parent dir is locked */ ++ if (unlikely(h_parent != h_dentry->d_parent)) ++ goto out; ++ err = 0; ++ ++ /* ++ * rmdir a dir may break the consistency on some filesystem. ++ * let's try heavy test. ++ */ ++ err = -EACCES; ++ if (unlikely(!au_opt_test(au_mntflags(dentry->d_sb), DIRPERM1) ++ && au_test_h_perm(d_inode(h_parent), ++ MAY_EXEC | MAY_WRITE))) ++ goto out; ++ ++ h_latest = au_sio_lkup_one(&dentry->d_name, h_parent); ++ err = -EIO; ++ if (IS_ERR(h_latest)) ++ goto out; ++ if (h_latest == h_dentry) ++ err = 0; ++ dput(h_latest); ++ ++out: ++ return err; ++} ++ ++/* ++ * decide the branch where we operate for @dentry. the branch index will be set ++ * @rbcpup. after deciding it, 'pin' it and store the timestamps of the parent ++ * dir for reverting. ++ * when a new whiteout is necessary, create it. ++ */ ++static struct dentry* ++lock_hdir_create_wh(struct dentry *dentry, int isdir, aufs_bindex_t *rbcpup, ++ struct au_dtime *dt, struct au_pin *pin) ++{ ++ struct dentry *wh_dentry; ++ struct super_block *sb; ++ struct path h_path; ++ int err, need_wh; ++ unsigned int udba; ++ aufs_bindex_t bcpup; ++ ++ need_wh = au_wr_dir_need_wh(dentry, isdir, rbcpup); ++ wh_dentry = ERR_PTR(need_wh); ++ if (unlikely(need_wh < 0)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ udba = au_opt_udba(sb); ++ bcpup = *rbcpup; ++ err = au_pin(pin, dentry, bcpup, udba, ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out; ++ ++ h_path.dentry = au_pinned_h_parent(pin); ++ if (udba != AuOpt_UDBA_NONE ++ && au_dbtop(dentry) == bcpup) { ++ err = au_may_del(dentry, bcpup, h_path.dentry, isdir); ++ wh_dentry = ERR_PTR(err); ++ if (unlikely(err)) ++ goto out_unpin; ++ } ++ ++ h_path.mnt = au_sbr_mnt(sb, bcpup); ++ au_dtime_store(dt, au_pinned_parent(pin), &h_path); ++ wh_dentry = NULL; ++ if (!need_wh) ++ goto out; /* success, no need to create whiteout */ ++ ++ wh_dentry = au_wh_create(dentry, bcpup, h_path.dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_unpin; ++ ++ /* returns with the parent is locked and wh_dentry is dget-ed */ ++ goto out; /* success */ ++ ++out_unpin: ++ au_unpin(pin); ++out: ++ return wh_dentry; ++} ++ ++/* ++ * when removing a dir, rename it to a unique temporary whiteout-ed name first ++ * in order to be revertible and save time for removing many child whiteouts ++ * under the dir. ++ * returns 1 when there are too many child whiteout and caller should remove ++ * them asynchronously. returns 0 when the number of children is enough small to ++ * remove now or the branch fs is a remote fs. ++ * otherwise return an error. ++ */ ++static int renwh_and_rmdir(struct dentry *dentry, aufs_bindex_t bindex, ++ struct au_nhash *whlist, struct inode *dir) ++{ ++ int rmdir_later, err, dirwh; ++ struct dentry *h_dentry; ++ struct super_block *sb; ++ struct inode *inode; ++ ++ sb = dentry->d_sb; ++ SiMustAnyLock(sb); ++ h_dentry = au_h_dptr(dentry, bindex); ++ err = au_whtmp_ren(h_dentry, au_sbr(sb, bindex)); ++ if (unlikely(err)) ++ goto out; ++ ++ /* stop monitoring */ ++ inode = d_inode(dentry); ++ au_hn_free(au_hi(inode, bindex)); ++ ++ if (!au_test_fs_remote(h_dentry->d_sb)) { ++ dirwh = au_sbi(sb)->si_dirwh; ++ rmdir_later = (dirwh <= 1); ++ if (!rmdir_later) ++ rmdir_later = au_nhash_test_longer_wh(whlist, bindex, ++ dirwh); ++ if (rmdir_later) ++ return rmdir_later; ++ } ++ ++ err = au_whtmp_rmdir(dir, bindex, h_dentry, whlist); ++ if (unlikely(err)) { ++ AuIOErr("rmdir %pd, b%d failed, %d. ignored\n", ++ h_dentry, bindex, err); ++ err = 0; ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * final procedure for deleting a entry. ++ * maintain dentry and iattr. ++ */ ++static void epilog(struct inode *dir, struct dentry *dentry, ++ aufs_bindex_t bindex) ++{ ++ struct inode *inode; ++ ++ inode = d_inode(dentry); ++ d_drop(dentry); ++ inode->i_ctime = dir->i_ctime; ++ ++ au_dir_ts(dir, bindex); ++ inode_inc_iversion(dir); ++} ++ ++/* ++ * when an error happened, remove the created whiteout and revert everything. ++ */ ++static int do_revert(int err, struct inode *dir, aufs_bindex_t bindex, ++ aufs_bindex_t bwh, struct dentry *wh_dentry, ++ struct dentry *dentry, struct au_dtime *dt) ++{ ++ int rerr; ++ struct path h_path = { ++ .dentry = wh_dentry, ++ .mnt = au_sbr_mnt(dir->i_sb, bindex) ++ }; ++ ++ rerr = au_wh_unlink_dentry(au_h_iptr(dir, bindex), &h_path, dentry); ++ if (!rerr) { ++ au_set_dbwh(dentry, bwh); ++ au_dtime_revert(dt); ++ return 0; ++ } ++ ++ AuIOErr("%pd reverting whiteout failed(%d, %d)\n", dentry, err, rerr); ++ return -EIO; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int aufs_unlink(struct inode *dir, struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bwh, bindex, btop; ++ struct inode *inode, *h_dir, *delegated; ++ struct dentry *parent, *wh_dentry; ++ /* to reduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct au_pin pin; ++ struct path h_path; ++ } *a; ++ ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_free; ++ err = au_d_hashed_positive(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ err = -EISDIR; ++ if (unlikely(d_is_dir(dentry))) ++ goto out_unlock; /* possible? */ ++ ++ btop = au_dbtop(dentry); ++ bwh = au_dbwh(dentry); ++ bindex = -1; ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_write_lock_parent(parent); ++ wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/0, &bindex, &a->dt, ++ &a->pin); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ a->h_path.mnt = au_sbr_mnt(dentry->d_sb, btop); ++ a->h_path.dentry = au_h_dptr(dentry, btop); ++ dget(a->h_path.dentry); ++ if (bindex == btop) { ++ h_dir = au_pinned_h_dir(&a->pin); ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, &a->h_path, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ } else { ++ /* dir inode is locked */ ++ h_dir = d_inode(wh_dentry->d_parent); ++ IMustLock(h_dir); ++ err = 0; ++ } ++ ++ if (!err) { ++ vfsub_drop_nlink(inode); ++ epilog(dir, dentry, bindex); ++ ++ /* update target timestamps */ ++ if (bindex == btop) { ++ vfsub_update_h_iattr(&a->h_path, /*did*/NULL); ++ /*ignore*/ ++ inode->i_ctime = d_inode(a->h_path.dentry)->i_ctime; ++ } else ++ /* todo: this timestamp may be reverted later */ ++ inode->i_ctime = h_dir->i_ctime; ++ goto out_unpin; /* success */ ++ } ++ ++ /* revert */ ++ if (wh_dentry) { ++ int rerr; ++ ++ rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry, ++ &a->dt); ++ if (rerr) ++ err = rerr; ++ } ++ ++out_unpin: ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++ dput(a->h_path.dentry); ++out_parent: ++ di_write_unlock(parent); ++out_unlock: ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ au_kfree_rcu(a); ++out: ++ return err; ++} ++ ++int aufs_rmdir(struct inode *dir, struct dentry *dentry) ++{ ++ int err, rmdir_later; ++ aufs_bindex_t bwh, bindex, btop; ++ struct inode *inode; ++ struct dentry *parent, *wh_dentry, *h_dentry; ++ struct au_whtmp_rmdir *args; ++ /* to reduce stack size */ ++ struct { ++ struct au_dtime dt; ++ struct au_pin pin; ++ } *a; ++ ++ IMustLock(dir); ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_GEN); ++ if (unlikely(err)) ++ goto out_free; ++ err = au_alive_dir(dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ inode = d_inode(dentry); ++ IMustLock(inode); ++ err = -ENOTDIR; ++ if (unlikely(!d_is_dir(dentry))) ++ goto out_unlock; /* possible? */ ++ ++ err = -ENOMEM; ++ args = au_whtmp_rmdir_alloc(dir->i_sb, GFP_NOFS); ++ if (unlikely(!args)) ++ goto out_unlock; ++ ++ parent = dentry->d_parent; /* dir inode is locked */ ++ di_write_lock_parent(parent); ++ err = au_test_empty(dentry, &args->whlist); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ btop = au_dbtop(dentry); ++ bwh = au_dbwh(dentry); ++ bindex = -1; ++ wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/1, &bindex, &a->dt, ++ &a->pin); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) ++ goto out_parent; ++ ++ h_dentry = au_h_dptr(dentry, btop); ++ dget(h_dentry); ++ rmdir_later = 0; ++ if (bindex == btop) { ++ err = renwh_and_rmdir(dentry, btop, &args->whlist, dir); ++ if (err > 0) { ++ rmdir_later = err; ++ err = 0; ++ } ++ } else { ++ /* stop monitoring */ ++ au_hn_free(au_hi(inode, btop)); ++ ++ /* dir inode is locked */ ++ IMustLock(d_inode(wh_dentry->d_parent)); ++ err = 0; ++ } ++ ++ if (!err) { ++ vfsub_dead_dir(inode); ++ au_set_dbdiropq(dentry, -1); ++ epilog(dir, dentry, bindex); ++ ++ if (rmdir_later) { ++ au_whtmp_kick_rmdir(dir, btop, h_dentry, args); ++ args = NULL; ++ } ++ ++ goto out_unpin; /* success */ ++ } ++ ++ /* revert */ ++ AuLabel(revert); ++ if (wh_dentry) { ++ int rerr; ++ ++ rerr = do_revert(err, dir, bindex, bwh, wh_dentry, dentry, ++ &a->dt); ++ if (rerr) ++ err = rerr; ++ } ++ ++out_unpin: ++ au_unpin(&a->pin); ++ dput(wh_dentry); ++ dput(h_dentry); ++out_parent: ++ di_write_unlock(parent); ++ if (args) ++ au_whtmp_rmdir_free(args); ++out_unlock: ++ aufs_read_unlock(dentry, AuLock_DW); ++out_free: ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff --git a/fs/aufs/i_op_ren.c b/fs/aufs/i_op_ren.c +new file mode 100644 +index 000000000000..37c52390034a +--- /dev/null ++++ b/fs/aufs/i_op_ren.c +@@ -0,0 +1,1237 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode operation (rename entry) ++ * todo: this is crazy monster ++ */ ++ ++#include ++#include "aufs.h" ++ ++enum { AuSRC, AuDST, AuSrcDst }; ++enum { AuPARENT, AuCHILD, AuParentChild }; ++ ++#define AuRen_ISDIR_SRC 1 ++#define AuRen_ISDIR_DST (1 << 1) ++#define AuRen_ISSAMEDIR (1 << 2) ++#define AuRen_WHSRC (1 << 3) ++#define AuRen_WHDST (1 << 4) ++#define AuRen_MNT_WRITE (1 << 5) ++#define AuRen_DT_DSTDIR (1 << 6) ++#define AuRen_DIROPQ_SRC (1 << 7) ++#define AuRen_DIROPQ_DST (1 << 8) ++#define AuRen_DIRREN (1 << 9) ++#define AuRen_DROPPED_SRC (1 << 10) ++#define AuRen_DROPPED_DST (1 << 11) ++#define au_ftest_ren(flags, name) ((flags) & AuRen_##name) ++#define au_fset_ren(flags, name) \ ++ do { (flags) |= AuRen_##name; } while (0) ++#define au_fclr_ren(flags, name) \ ++ do { (flags) &= ~AuRen_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_DIRREN ++#undef AuRen_DIRREN ++#define AuRen_DIRREN 0 ++#endif ++ ++struct au_ren_args { ++ struct { ++ struct dentry *dentry, *h_dentry, *parent, *h_parent, ++ *wh_dentry; ++ struct inode *dir, *inode; ++ struct au_hinode *hdir, *hinode; ++ struct au_dtime dt[AuParentChild]; ++ aufs_bindex_t btop, bdiropq; ++ } sd[AuSrcDst]; ++ ++#define src_dentry sd[AuSRC].dentry ++#define src_dir sd[AuSRC].dir ++#define src_inode sd[AuSRC].inode ++#define src_h_dentry sd[AuSRC].h_dentry ++#define src_parent sd[AuSRC].parent ++#define src_h_parent sd[AuSRC].h_parent ++#define src_wh_dentry sd[AuSRC].wh_dentry ++#define src_hdir sd[AuSRC].hdir ++#define src_hinode sd[AuSRC].hinode ++#define src_h_dir sd[AuSRC].hdir->hi_inode ++#define src_dt sd[AuSRC].dt ++#define src_btop sd[AuSRC].btop ++#define src_bdiropq sd[AuSRC].bdiropq ++ ++#define dst_dentry sd[AuDST].dentry ++#define dst_dir sd[AuDST].dir ++#define dst_inode sd[AuDST].inode ++#define dst_h_dentry sd[AuDST].h_dentry ++#define dst_parent sd[AuDST].parent ++#define dst_h_parent sd[AuDST].h_parent ++#define dst_wh_dentry sd[AuDST].wh_dentry ++#define dst_hdir sd[AuDST].hdir ++#define dst_hinode sd[AuDST].hinode ++#define dst_h_dir sd[AuDST].hdir->hi_inode ++#define dst_dt sd[AuDST].dt ++#define dst_btop sd[AuDST].btop ++#define dst_bdiropq sd[AuDST].bdiropq ++ ++ struct dentry *h_trap; ++ struct au_branch *br; ++ struct path h_path; ++ struct au_nhash whlist; ++ aufs_bindex_t btgt, src_bwh; ++ ++ struct { ++ unsigned short auren_flags; ++ unsigned char flags; /* syscall parameter */ ++ unsigned char exchange; ++ } __packed; ++ ++ struct au_whtmp_rmdir *thargs; ++ struct dentry *h_dst; ++ struct au_hinode *h_root; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * functions for reverting. ++ * when an error happened in a single rename systemcall, we should revert ++ * everything as if nothing happened. ++ * we don't need to revert the copied-up/down the parent dir since they are ++ * harmless. ++ */ ++ ++#define RevertFailure(fmt, ...) do { \ ++ AuIOErr("revert failure: " fmt " (%d, %d)\n", \ ++ ##__VA_ARGS__, err, rerr); \ ++ err = -EIO; \ ++} while (0) ++ ++static void au_ren_do_rev_diropq(int err, struct au_ren_args *a, int idx) ++{ ++ int rerr; ++ struct dentry *d; ++#define src_or_dst(member) a->sd[idx].member ++ ++ d = src_or_dst(dentry); /* {src,dst}_dentry */ ++ au_hn_inode_lock_nested(src_or_dst(hinode), AuLsc_I_CHILD); ++ rerr = au_diropq_remove(d, a->btgt); ++ au_hn_inode_unlock(src_or_dst(hinode)); ++ au_set_dbdiropq(d, src_or_dst(bdiropq)); ++ if (rerr) ++ RevertFailure("remove diropq %pd", d); ++ ++#undef src_or_dst_ ++} ++ ++static void au_ren_rev_diropq(int err, struct au_ren_args *a) ++{ ++ if (au_ftest_ren(a->auren_flags, DIROPQ_SRC)) ++ au_ren_do_rev_diropq(err, a, AuSRC); ++ if (au_ftest_ren(a->auren_flags, DIROPQ_DST)) ++ au_ren_do_rev_diropq(err, a, AuDST); ++} ++ ++static void au_ren_rev_rename(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ struct inode *delegated; ++ ++ a->h_path.dentry = vfsub_lkup_one(&a->src_dentry->d_name, ++ a->src_h_parent); ++ rerr = PTR_ERR(a->h_path.dentry); ++ if (IS_ERR(a->h_path.dentry)) { ++ RevertFailure("lkup one %pd", a->src_dentry); ++ return; ++ } ++ ++ delegated = NULL; ++ rerr = vfsub_rename(a->dst_h_dir, ++ au_h_dptr(a->src_dentry, a->btgt), ++ a->src_h_dir, &a->h_path, &delegated, a->flags); ++ if (unlikely(rerr == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ d_drop(a->h_path.dentry); ++ dput(a->h_path.dentry); ++ /* au_set_h_dptr(a->src_dentry, a->btgt, NULL); */ ++ if (rerr) ++ RevertFailure("rename %pd", a->src_dentry); ++} ++ ++static void au_ren_rev_whtmp(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ struct inode *delegated; ++ ++ a->h_path.dentry = vfsub_lkup_one(&a->dst_dentry->d_name, ++ a->dst_h_parent); ++ rerr = PTR_ERR(a->h_path.dentry); ++ if (IS_ERR(a->h_path.dentry)) { ++ RevertFailure("lkup one %pd", a->dst_dentry); ++ return; ++ } ++ if (d_is_positive(a->h_path.dentry)) { ++ d_drop(a->h_path.dentry); ++ dput(a->h_path.dentry); ++ return; ++ } ++ ++ delegated = NULL; ++ rerr = vfsub_rename(a->dst_h_dir, a->h_dst, a->dst_h_dir, &a->h_path, ++ &delegated, a->flags); ++ if (unlikely(rerr == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ d_drop(a->h_path.dentry); ++ dput(a->h_path.dentry); ++ if (!rerr) ++ au_set_h_dptr(a->dst_dentry, a->btgt, dget(a->h_dst)); ++ else ++ RevertFailure("rename %pd", a->h_dst); ++} ++ ++static void au_ren_rev_whsrc(int err, struct au_ren_args *a) ++{ ++ int rerr; ++ ++ a->h_path.dentry = a->src_wh_dentry; ++ rerr = au_wh_unlink_dentry(a->src_h_dir, &a->h_path, a->src_dentry); ++ au_set_dbwh(a->src_dentry, a->src_bwh); ++ if (rerr) ++ RevertFailure("unlink %pd", a->src_wh_dentry); ++} ++#undef RevertFailure ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * when we have to copyup the renaming entry, do it with the rename-target name ++ * in order to minimize the cost (the later actual rename is unnecessary). ++ * otherwise rename it on the target branch. ++ */ ++static int au_ren_or_cpup(struct au_ren_args *a) ++{ ++ int err; ++ struct dentry *d; ++ struct inode *delegated; ++ ++ d = a->src_dentry; ++ if (au_dbtop(d) == a->btgt) { ++ a->h_path.dentry = a->dst_h_dentry; ++ AuDebugOn(au_dbtop(d) != a->btgt); ++ delegated = NULL; ++ err = vfsub_rename(a->src_h_dir, au_h_dptr(d, a->btgt), ++ a->dst_h_dir, &a->h_path, &delegated, ++ a->flags); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ } else ++ BUG(); ++ ++ if (!err && a->h_dst) ++ /* it will be set to dinfo later */ ++ dget(a->h_dst); ++ ++ return err; ++} ++ ++/* cf. aufs_rmdir() */ ++static int au_ren_del_whtmp(struct au_ren_args *a) ++{ ++ int err; ++ struct inode *dir; ++ ++ dir = a->dst_dir; ++ SiMustAnyLock(dir->i_sb); ++ if (!au_nhash_test_longer_wh(&a->whlist, a->btgt, ++ au_sbi(dir->i_sb)->si_dirwh) ++ || au_test_fs_remote(a->h_dst->d_sb)) { ++ err = au_whtmp_rmdir(dir, a->btgt, a->h_dst, &a->whlist); ++ if (unlikely(err)) ++ pr_warn("failed removing whtmp dir %pd (%d), " ++ "ignored.\n", a->h_dst, err); ++ } else { ++ au_nhash_wh_free(&a->thargs->whlist); ++ a->thargs->whlist = a->whlist; ++ a->whlist.nh_num = 0; ++ au_whtmp_kick_rmdir(dir, a->btgt, a->h_dst, a->thargs); ++ dput(a->h_dst); ++ a->thargs = NULL; ++ } ++ ++ return 0; ++} ++ ++/* make it 'opaque' dir. */ ++static int au_ren_do_diropq(struct au_ren_args *a, int idx) ++{ ++ int err; ++ struct dentry *d, *diropq; ++#define src_or_dst(member) a->sd[idx].member ++ ++ err = 0; ++ d = src_or_dst(dentry); /* {src,dst}_dentry */ ++ src_or_dst(bdiropq) = au_dbdiropq(d); ++ src_or_dst(hinode) = au_hi(src_or_dst(inode), a->btgt); ++ au_hn_inode_lock_nested(src_or_dst(hinode), AuLsc_I_CHILD); ++ diropq = au_diropq_create(d, a->btgt); ++ au_hn_inode_unlock(src_or_dst(hinode)); ++ if (IS_ERR(diropq)) ++ err = PTR_ERR(diropq); ++ else ++ dput(diropq); ++ ++#undef src_or_dst_ ++ return err; ++} ++ ++static int au_ren_diropq(struct au_ren_args *a) ++{ ++ int err; ++ unsigned char always; ++ struct dentry *d; ++ ++ err = 0; ++ d = a->dst_dentry; /* already renamed on the branch */ ++ always = !!au_opt_test(au_mntflags(d->d_sb), ALWAYS_DIROPQ); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC) ++ && !au_ftest_ren(a->auren_flags, DIRREN) ++ && a->btgt != au_dbdiropq(a->src_dentry) ++ && (a->dst_wh_dentry ++ || a->btgt <= au_dbdiropq(d) ++ /* hide the lower to keep xino */ ++ /* the lowers may not be a dir, but we hide them anyway */ ++ || a->btgt < au_dbbot(d) ++ || always)) { ++ AuDbg("here\n"); ++ err = au_ren_do_diropq(a, AuSRC); ++ if (unlikely(err)) ++ goto out; ++ au_fset_ren(a->auren_flags, DIROPQ_SRC); ++ } ++ if (!a->exchange) ++ goto out; /* success */ ++ ++ d = a->src_dentry; /* already renamed on the branch */ ++ if (au_ftest_ren(a->auren_flags, ISDIR_DST) ++ && a->btgt != au_dbdiropq(a->dst_dentry) ++ && (a->btgt < au_dbdiropq(d) ++ || a->btgt < au_dbbot(d) ++ || always)) { ++ AuDbgDentry(a->src_dentry); ++ AuDbgDentry(a->dst_dentry); ++ err = au_ren_do_diropq(a, AuDST); ++ if (unlikely(err)) ++ goto out_rev_src; ++ au_fset_ren(a->auren_flags, DIROPQ_DST); ++ } ++ goto out; /* success */ ++ ++out_rev_src: ++ AuDbg("err %d, reverting src\n", err); ++ au_ren_rev_diropq(err, a); ++out: ++ return err; ++} ++ ++static int do_rename(struct au_ren_args *a) ++{ ++ int err; ++ struct dentry *d, *h_d; ++ ++ if (!a->exchange) { ++ /* prepare workqueue args for asynchronous rmdir */ ++ h_d = a->dst_h_dentry; ++ if (au_ftest_ren(a->auren_flags, ISDIR_DST) ++ /* && !au_ftest_ren(a->auren_flags, DIRREN) */ ++ && d_is_positive(h_d)) { ++ err = -ENOMEM; ++ a->thargs = au_whtmp_rmdir_alloc(a->src_dentry->d_sb, ++ GFP_NOFS); ++ if (unlikely(!a->thargs)) ++ goto out; ++ a->h_dst = dget(h_d); ++ } ++ ++ /* create whiteout for src_dentry */ ++ if (au_ftest_ren(a->auren_flags, WHSRC)) { ++ a->src_bwh = au_dbwh(a->src_dentry); ++ AuDebugOn(a->src_bwh >= 0); ++ a->src_wh_dentry = au_wh_create(a->src_dentry, a->btgt, ++ a->src_h_parent); ++ err = PTR_ERR(a->src_wh_dentry); ++ if (IS_ERR(a->src_wh_dentry)) ++ goto out_thargs; ++ } ++ ++ /* lookup whiteout for dentry */ ++ if (au_ftest_ren(a->auren_flags, WHDST)) { ++ h_d = au_wh_lkup(a->dst_h_parent, ++ &a->dst_dentry->d_name, a->br); ++ err = PTR_ERR(h_d); ++ if (IS_ERR(h_d)) ++ goto out_whsrc; ++ if (d_is_negative(h_d)) ++ dput(h_d); ++ else ++ a->dst_wh_dentry = h_d; ++ } ++ ++ /* rename dentry to tmpwh */ ++ if (a->thargs) { ++ err = au_whtmp_ren(a->dst_h_dentry, a->br); ++ if (unlikely(err)) ++ goto out_whdst; ++ ++ d = a->dst_dentry; ++ au_set_h_dptr(d, a->btgt, NULL); ++ err = au_lkup_neg(d, a->btgt, /*wh*/0); ++ if (unlikely(err)) ++ goto out_whtmp; ++ a->dst_h_dentry = au_h_dptr(d, a->btgt); ++ } ++ } ++ ++ BUG_ON(d_is_positive(a->dst_h_dentry) && a->src_btop != a->btgt); ++#if 0 /* debugging */ ++ BUG_ON(!au_ftest_ren(a->auren_flags, DIRREN) ++ && d_is_positive(a->dst_h_dentry) ++ && a->src_btop != a->btgt); ++#endif ++ ++ /* rename by vfs_rename or cpup */ ++ err = au_ren_or_cpup(a); ++ if (unlikely(err)) ++ /* leave the copied-up one */ ++ goto out_whtmp; ++ ++ /* make dir opaque */ ++ err = au_ren_diropq(a); ++ if (unlikely(err)) ++ goto out_rename; ++ ++ /* update target timestamps */ ++ if (a->exchange) { ++ AuDebugOn(au_dbtop(a->dst_dentry) != a->btgt); ++ a->h_path.dentry = au_h_dptr(a->dst_dentry, a->btgt); ++ vfsub_update_h_iattr(&a->h_path, /*did*/NULL); /*ignore*/ ++ a->dst_inode->i_ctime = d_inode(a->h_path.dentry)->i_ctime; ++ } ++ AuDebugOn(au_dbtop(a->src_dentry) != a->btgt); ++ a->h_path.dentry = au_h_dptr(a->src_dentry, a->btgt); ++ vfsub_update_h_iattr(&a->h_path, /*did*/NULL); /*ignore*/ ++ a->src_inode->i_ctime = d_inode(a->h_path.dentry)->i_ctime; ++ ++ if (!a->exchange) { ++ /* remove whiteout for dentry */ ++ if (a->dst_wh_dentry) { ++ a->h_path.dentry = a->dst_wh_dentry; ++ err = au_wh_unlink_dentry(a->dst_h_dir, &a->h_path, ++ a->dst_dentry); ++ if (unlikely(err)) ++ goto out_diropq; ++ } ++ ++ /* remove whtmp */ ++ if (a->thargs) ++ au_ren_del_whtmp(a); /* ignore this error */ ++ ++ au_fhsm_wrote(a->src_dentry->d_sb, a->btgt, /*force*/0); ++ } ++ err = 0; ++ goto out_success; ++ ++out_diropq: ++ au_ren_rev_diropq(err, a); ++out_rename: ++ au_ren_rev_rename(err, a); ++ dput(a->h_dst); ++out_whtmp: ++ if (a->thargs) ++ au_ren_rev_whtmp(err, a); ++out_whdst: ++ dput(a->dst_wh_dentry); ++ a->dst_wh_dentry = NULL; ++out_whsrc: ++ if (a->src_wh_dentry) ++ au_ren_rev_whsrc(err, a); ++out_success: ++ dput(a->src_wh_dentry); ++ dput(a->dst_wh_dentry); ++out_thargs: ++ if (a->thargs) { ++ dput(a->h_dst); ++ au_whtmp_rmdir_free(a->thargs); ++ a->thargs = NULL; ++ } ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * test if @dentry dir can be rename destination or not. ++ * success means, it is a logically empty dir. ++ */ ++static int may_rename_dstdir(struct dentry *dentry, struct au_nhash *whlist) ++{ ++ return au_test_empty(dentry, whlist); ++} ++ ++/* ++ * test if @a->src_dentry dir can be rename source or not. ++ * if it can, return 0. ++ * success means, ++ * - it is a logically empty dir. ++ * - or, it exists on writable branch and has no children including whiteouts ++ * on the lower branch unless DIRREN is on. ++ */ ++static int may_rename_srcdir(struct au_ren_args *a) ++{ ++ int err; ++ unsigned int rdhash; ++ aufs_bindex_t btop, btgt; ++ struct dentry *dentry; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++ dentry = a->src_dentry; ++ sb = dentry->d_sb; ++ sbinfo = au_sbi(sb); ++ if (au_opt_test(sbinfo->si_mntflags, DIRREN)) ++ au_fset_ren(a->auren_flags, DIRREN); ++ ++ btgt = a->btgt; ++ btop = au_dbtop(dentry); ++ if (btop != btgt) { ++ struct au_nhash whlist; ++ ++ SiMustAnyLock(sb); ++ rdhash = sbinfo->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, ++ dentry)); ++ err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_test_empty(dentry, &whlist); ++ au_nhash_wh_free(&whlist); ++ goto out; ++ } ++ ++ if (btop == au_dbtaildir(dentry)) ++ return 0; /* success */ ++ ++ err = au_test_empty_lower(dentry); ++ ++out: ++ if (err == -ENOTEMPTY) { ++ if (au_ftest_ren(a->auren_flags, DIRREN)) { ++ err = 0; ++ } else { ++ AuWarn1("renaming dir who has child(ren) on multiple " ++ "branches, is not supported\n"); ++ err = -EXDEV; ++ } ++ } ++ return err; ++} ++ ++/* side effect: sets whlist and h_dentry */ ++static int au_ren_may_dir(struct au_ren_args *a) ++{ ++ int err; ++ unsigned int rdhash; ++ struct dentry *d; ++ ++ d = a->dst_dentry; ++ SiMustAnyLock(d->d_sb); ++ ++ err = 0; ++ if (au_ftest_ren(a->auren_flags, ISDIR_DST) && a->dst_inode) { ++ rdhash = au_sbi(d->d_sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, d)); ++ err = au_nhash_alloc(&a->whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ ++ if (!a->exchange) { ++ au_set_dbtop(d, a->dst_btop); ++ err = may_rename_dstdir(d, &a->whlist); ++ au_set_dbtop(d, a->btgt); ++ } else ++ err = may_rename_srcdir(a); ++ } ++ a->dst_h_dentry = au_h_dptr(d, au_dbtop(d)); ++ if (unlikely(err)) ++ goto out; ++ ++ d = a->src_dentry; ++ a->src_h_dentry = au_h_dptr(d, au_dbtop(d)); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC)) { ++ err = may_rename_srcdir(a); ++ if (unlikely(err)) { ++ au_nhash_wh_free(&a->whlist); ++ a->whlist.nh_num = 0; ++ } ++ } ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * simple tests for rename. ++ * following the checks in vfs, plus the parent-child relationship. ++ */ ++static int au_may_ren(struct au_ren_args *a) ++{ ++ int err, isdir; ++ struct inode *h_inode; ++ ++ if (a->src_btop == a->btgt) { ++ err = au_may_del(a->src_dentry, a->btgt, a->src_h_parent, ++ au_ftest_ren(a->auren_flags, ISDIR_SRC)); ++ if (unlikely(err)) ++ goto out; ++ err = -EINVAL; ++ if (unlikely(a->src_h_dentry == a->h_trap)) ++ goto out; ++ } ++ ++ err = 0; ++ if (a->dst_btop != a->btgt) ++ goto out; ++ ++ err = -ENOTEMPTY; ++ if (unlikely(a->dst_h_dentry == a->h_trap)) ++ goto out; ++ ++ err = -EIO; ++ isdir = !!au_ftest_ren(a->auren_flags, ISDIR_DST); ++ if (d_really_is_negative(a->dst_dentry)) { ++ if (d_is_negative(a->dst_h_dentry)) ++ err = au_may_add(a->dst_dentry, a->btgt, ++ a->dst_h_parent, isdir); ++ } else { ++ if (unlikely(d_is_negative(a->dst_h_dentry))) ++ goto out; ++ h_inode = d_inode(a->dst_h_dentry); ++ if (h_inode->i_nlink) ++ err = au_may_del(a->dst_dentry, a->btgt, ++ a->dst_h_parent, isdir); ++ } ++ ++out: ++ if (unlikely(err == -ENOENT || err == -EEXIST)) ++ err = -EIO; ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * locking order ++ * (VFS) ++ * - src_dir and dir by lock_rename() ++ * - inode if exists ++ * (aufs) ++ * - lock all ++ * + src_dentry and dentry by aufs_read_and_write_lock2() which calls, ++ * + si_read_lock ++ * + di_write_lock2_child() ++ * + di_write_lock_child() ++ * + ii_write_lock_child() ++ * + di_write_lock_child2() ++ * + ii_write_lock_child2() ++ * + src_parent and parent ++ * + di_write_lock_parent() ++ * + ii_write_lock_parent() ++ * + di_write_lock_parent2() ++ * + ii_write_lock_parent2() ++ * + lower src_dir and dir by vfsub_lock_rename() ++ * + verify the every relationships between child and parent. if any ++ * of them failed, unlock all and return -EBUSY. ++ */ ++static void au_ren_unlock(struct au_ren_args *a) ++{ ++ vfsub_unlock_rename(a->src_h_parent, a->src_hdir, ++ a->dst_h_parent, a->dst_hdir); ++ if (au_ftest_ren(a->auren_flags, DIRREN) ++ && a->h_root) ++ au_hn_inode_unlock(a->h_root); ++ if (au_ftest_ren(a->auren_flags, MNT_WRITE)) ++ vfsub_mnt_drop_write(au_br_mnt(a->br)); ++} ++ ++static int au_ren_lock(struct au_ren_args *a) ++{ ++ int err; ++ unsigned int udba; ++ ++ err = 0; ++ a->src_h_parent = au_h_dptr(a->src_parent, a->btgt); ++ a->src_hdir = au_hi(a->src_dir, a->btgt); ++ a->dst_h_parent = au_h_dptr(a->dst_parent, a->btgt); ++ a->dst_hdir = au_hi(a->dst_dir, a->btgt); ++ ++ err = vfsub_mnt_want_write(au_br_mnt(a->br)); ++ if (unlikely(err)) ++ goto out; ++ au_fset_ren(a->auren_flags, MNT_WRITE); ++ if (au_ftest_ren(a->auren_flags, DIRREN)) { ++ struct dentry *root; ++ struct inode *dir; ++ ++ /* ++ * sbinfo is already locked, so this ii_read_lock is ++ * unnecessary. but our debugging feature checks it. ++ */ ++ root = a->src_inode->i_sb->s_root; ++ if (root != a->src_parent && root != a->dst_parent) { ++ dir = d_inode(root); ++ ii_read_lock_parent3(dir); ++ a->h_root = au_hi(dir, a->btgt); ++ ii_read_unlock(dir); ++ au_hn_inode_lock_nested(a->h_root, AuLsc_I_PARENT3); ++ } ++ } ++ a->h_trap = vfsub_lock_rename(a->src_h_parent, a->src_hdir, ++ a->dst_h_parent, a->dst_hdir); ++ udba = au_opt_udba(a->src_dentry->d_sb); ++ if (unlikely(a->src_hdir->hi_inode != d_inode(a->src_h_parent) ++ || a->dst_hdir->hi_inode != d_inode(a->dst_h_parent))) ++ err = au_busy_or_stale(); ++ if (!err && au_dbtop(a->src_dentry) == a->btgt) ++ err = au_h_verify(a->src_h_dentry, udba, ++ d_inode(a->src_h_parent), a->src_h_parent, ++ a->br); ++ if (!err && au_dbtop(a->dst_dentry) == a->btgt) ++ err = au_h_verify(a->dst_h_dentry, udba, ++ d_inode(a->dst_h_parent), a->dst_h_parent, ++ a->br); ++ if (!err) ++ goto out; /* success */ ++ ++ err = au_busy_or_stale(); ++ au_ren_unlock(a); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static void au_ren_refresh_dir(struct au_ren_args *a) ++{ ++ struct inode *dir; ++ ++ dir = a->dst_dir; ++ inode_inc_iversion(dir); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC)) { ++ /* is this updating defined in POSIX? */ ++ au_cpup_attr_timesizes(a->src_inode); ++ au_cpup_attr_nlink(dir, /*force*/1); ++ } ++ au_dir_ts(dir, a->btgt); ++ ++ if (a->exchange) { ++ dir = a->src_dir; ++ inode_inc_iversion(dir); ++ if (au_ftest_ren(a->auren_flags, ISDIR_DST)) { ++ /* is this updating defined in POSIX? */ ++ au_cpup_attr_timesizes(a->dst_inode); ++ au_cpup_attr_nlink(dir, /*force*/1); ++ } ++ au_dir_ts(dir, a->btgt); ++ } ++ ++ if (au_ftest_ren(a->auren_flags, ISSAMEDIR)) ++ return; ++ ++ dir = a->src_dir; ++ inode_inc_iversion(dir); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC)) ++ au_cpup_attr_nlink(dir, /*force*/1); ++ au_dir_ts(dir, a->btgt); ++} ++ ++static void au_ren_refresh(struct au_ren_args *a) ++{ ++ aufs_bindex_t bbot, bindex; ++ struct dentry *d, *h_d; ++ struct inode *i, *h_i; ++ struct super_block *sb; ++ ++ d = a->dst_dentry; ++ d_drop(d); ++ if (a->h_dst) ++ /* already dget-ed by au_ren_or_cpup() */ ++ au_set_h_dptr(d, a->btgt, a->h_dst); ++ ++ i = a->dst_inode; ++ if (i) { ++ if (!a->exchange) { ++ if (!au_ftest_ren(a->auren_flags, ISDIR_DST)) ++ vfsub_drop_nlink(i); ++ else { ++ vfsub_dead_dir(i); ++ au_cpup_attr_timesizes(i); ++ } ++ au_update_dbrange(d, /*do_put_zero*/1); ++ } else ++ au_cpup_attr_nlink(i, /*force*/1); ++ } else { ++ bbot = a->btgt; ++ for (bindex = au_dbtop(d); bindex < bbot; bindex++) ++ au_set_h_dptr(d, bindex, NULL); ++ bbot = au_dbbot(d); ++ for (bindex = a->btgt + 1; bindex <= bbot; bindex++) ++ au_set_h_dptr(d, bindex, NULL); ++ au_update_dbrange(d, /*do_put_zero*/0); ++ } ++ ++ if (a->exchange ++ || au_ftest_ren(a->auren_flags, DIRREN)) { ++ d_drop(a->src_dentry); ++ if (au_ftest_ren(a->auren_flags, DIRREN)) ++ au_set_dbwh(a->src_dentry, -1); ++ return; ++ } ++ ++ d = a->src_dentry; ++ au_set_dbwh(d, -1); ++ bbot = au_dbbot(d); ++ for (bindex = a->btgt + 1; bindex <= bbot; bindex++) { ++ h_d = au_h_dptr(d, bindex); ++ if (h_d) ++ au_set_h_dptr(d, bindex, NULL); ++ } ++ au_set_dbbot(d, a->btgt); ++ ++ sb = d->d_sb; ++ i = a->src_inode; ++ if (au_opt_test(au_mntflags(sb), PLINK) && au_plink_test(i)) ++ return; /* success */ ++ ++ bbot = au_ibbot(i); ++ for (bindex = a->btgt + 1; bindex <= bbot; bindex++) { ++ h_i = au_h_iptr(i, bindex); ++ if (h_i) { ++ au_xino_write(sb, bindex, h_i->i_ino, /*ino*/0); ++ /* ignore this error */ ++ au_set_h_iptr(i, bindex, NULL, 0); ++ } ++ } ++ au_set_ibbot(i, a->btgt); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* mainly for link(2) and rename(2) */ ++int au_wbr(struct dentry *dentry, aufs_bindex_t btgt) ++{ ++ aufs_bindex_t bdiropq, bwh; ++ struct dentry *parent; ++ struct au_branch *br; ++ ++ parent = dentry->d_parent; ++ IMustLock(d_inode(parent)); /* dir is locked */ ++ ++ bdiropq = au_dbdiropq(parent); ++ bwh = au_dbwh(dentry); ++ br = au_sbr(dentry->d_sb, btgt); ++ if (au_br_rdonly(br) ++ || (0 <= bdiropq && bdiropq < btgt) ++ || (0 <= bwh && bwh < btgt)) ++ btgt = -1; ++ ++ AuDbg("btgt %d\n", btgt); ++ return btgt; ++} ++ ++/* sets src_btop, dst_btop and btgt */ ++static int au_ren_wbr(struct au_ren_args *a) ++{ ++ int err; ++ struct au_wr_dir_args wr_dir_args = { ++ /* .force_btgt = -1, */ ++ .flags = AuWrDir_ADD_ENTRY ++ }; ++ ++ a->src_btop = au_dbtop(a->src_dentry); ++ a->dst_btop = au_dbtop(a->dst_dentry); ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC) ++ || au_ftest_ren(a->auren_flags, ISDIR_DST)) ++ au_fset_wrdir(wr_dir_args.flags, ISDIR); ++ wr_dir_args.force_btgt = a->src_btop; ++ if (a->dst_inode && a->dst_btop < a->src_btop) ++ wr_dir_args.force_btgt = a->dst_btop; ++ wr_dir_args.force_btgt = au_wbr(a->dst_dentry, wr_dir_args.force_btgt); ++ err = au_wr_dir(a->dst_dentry, a->src_dentry, &wr_dir_args); ++ a->btgt = err; ++ if (a->exchange) ++ au_update_dbtop(a->dst_dentry); ++ ++ return err; ++} ++ ++static void au_ren_dt(struct au_ren_args *a) ++{ ++ a->h_path.dentry = a->src_h_parent; ++ au_dtime_store(a->src_dt + AuPARENT, a->src_parent, &a->h_path); ++ if (!au_ftest_ren(a->auren_flags, ISSAMEDIR)) { ++ a->h_path.dentry = a->dst_h_parent; ++ au_dtime_store(a->dst_dt + AuPARENT, a->dst_parent, &a->h_path); ++ } ++ ++ au_fclr_ren(a->auren_flags, DT_DSTDIR); ++ if (!au_ftest_ren(a->auren_flags, ISDIR_SRC) ++ && !a->exchange) ++ return; ++ ++ a->h_path.dentry = a->src_h_dentry; ++ au_dtime_store(a->src_dt + AuCHILD, a->src_dentry, &a->h_path); ++ if (d_is_positive(a->dst_h_dentry)) { ++ au_fset_ren(a->auren_flags, DT_DSTDIR); ++ a->h_path.dentry = a->dst_h_dentry; ++ au_dtime_store(a->dst_dt + AuCHILD, a->dst_dentry, &a->h_path); ++ } ++} ++ ++static void au_ren_rev_dt(int err, struct au_ren_args *a) ++{ ++ struct dentry *h_d; ++ struct inode *h_inode; ++ ++ au_dtime_revert(a->src_dt + AuPARENT); ++ if (!au_ftest_ren(a->auren_flags, ISSAMEDIR)) ++ au_dtime_revert(a->dst_dt + AuPARENT); ++ ++ if (au_ftest_ren(a->auren_flags, ISDIR_SRC) && err != -EIO) { ++ h_d = a->src_dt[AuCHILD].dt_h_path.dentry; ++ h_inode = d_inode(h_d); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ au_dtime_revert(a->src_dt + AuCHILD); ++ inode_unlock(h_inode); ++ ++ if (au_ftest_ren(a->auren_flags, DT_DSTDIR)) { ++ h_d = a->dst_dt[AuCHILD].dt_h_path.dentry; ++ h_inode = d_inode(h_d); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ au_dtime_revert(a->dst_dt + AuCHILD); ++ inode_unlock(h_inode); ++ } ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int aufs_rename(struct inode *_src_dir, struct dentry *_src_dentry, ++ struct inode *_dst_dir, struct dentry *_dst_dentry, ++ unsigned int _flags) ++{ ++ int err, lock_flags; ++ void *rev; ++ /* reduce stack space */ ++ struct au_ren_args *a; ++ struct au_pin pin; ++ ++ AuDbg("%pd, %pd, 0x%x\n", _src_dentry, _dst_dentry, _flags); ++ IMustLock(_src_dir); ++ IMustLock(_dst_dir); ++ ++ err = -EINVAL; ++ if (unlikely(_flags & RENAME_WHITEOUT)) ++ goto out; ++ ++ err = -ENOMEM; ++ BUILD_BUG_ON(sizeof(*a) > PAGE_SIZE); ++ a = kzalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ a->flags = _flags; ++ BUILD_BUG_ON(sizeof(a->exchange) == sizeof(u8) ++ && RENAME_EXCHANGE > U8_MAX); ++ a->exchange = _flags & RENAME_EXCHANGE; ++ a->src_dir = _src_dir; ++ a->src_dentry = _src_dentry; ++ a->src_inode = NULL; ++ if (d_really_is_positive(a->src_dentry)) ++ a->src_inode = d_inode(a->src_dentry); ++ a->src_parent = a->src_dentry->d_parent; /* dir inode is locked */ ++ a->dst_dir = _dst_dir; ++ a->dst_dentry = _dst_dentry; ++ a->dst_inode = NULL; ++ if (d_really_is_positive(a->dst_dentry)) ++ a->dst_inode = d_inode(a->dst_dentry); ++ a->dst_parent = a->dst_dentry->d_parent; /* dir inode is locked */ ++ if (a->dst_inode) { ++ /* ++ * if EXCHANGE && src is non-dir && dst is dir, ++ * dst is not locked. ++ */ ++ /* IMustLock(a->dst_inode); */ ++ au_igrab(a->dst_inode); ++ } ++ ++ err = -ENOTDIR; ++ lock_flags = AuLock_FLUSH | AuLock_NOPLM | AuLock_GEN; ++ if (d_is_dir(a->src_dentry)) { ++ au_fset_ren(a->auren_flags, ISDIR_SRC); ++ if (unlikely(!a->exchange ++ && d_really_is_positive(a->dst_dentry) ++ && !d_is_dir(a->dst_dentry))) ++ goto out_free; ++ lock_flags |= AuLock_DIRS; ++ } ++ if (a->dst_inode && d_is_dir(a->dst_dentry)) { ++ au_fset_ren(a->auren_flags, ISDIR_DST); ++ if (unlikely(!a->exchange ++ && d_really_is_positive(a->src_dentry) ++ && !d_is_dir(a->src_dentry))) ++ goto out_free; ++ lock_flags |= AuLock_DIRS; ++ } ++ err = aufs_read_and_write_lock2(a->dst_dentry, a->src_dentry, ++ lock_flags); ++ if (unlikely(err)) ++ goto out_free; ++ ++ err = au_d_hashed_positive(a->src_dentry); ++ if (unlikely(err)) ++ goto out_unlock; ++ err = -ENOENT; ++ if (a->dst_inode) { ++ /* ++ * If it is a dir, VFS unhash it before this ++ * function. It means we cannot rely upon d_unhashed(). ++ */ ++ if (unlikely(!a->dst_inode->i_nlink)) ++ goto out_unlock; ++ if (!au_ftest_ren(a->auren_flags, ISDIR_DST)) { ++ err = au_d_hashed_positive(a->dst_dentry); ++ if (unlikely(err && !a->exchange)) ++ goto out_unlock; ++ } else if (unlikely(IS_DEADDIR(a->dst_inode))) ++ goto out_unlock; ++ } else if (unlikely(d_unhashed(a->dst_dentry))) ++ goto out_unlock; ++ ++ /* ++ * is it possible? ++ * yes, it happened (in linux-3.3-rcN) but I don't know why. ++ * there may exist a problem somewhere else. ++ */ ++ err = -EINVAL; ++ if (unlikely(d_inode(a->dst_parent) == d_inode(a->src_dentry))) ++ goto out_unlock; ++ ++ au_fset_ren(a->auren_flags, ISSAMEDIR); /* temporary */ ++ di_write_lock_parent(a->dst_parent); ++ ++ /* which branch we process */ ++ err = au_ren_wbr(a); ++ if (unlikely(err < 0)) ++ goto out_parent; ++ a->br = au_sbr(a->dst_dentry->d_sb, a->btgt); ++ a->h_path.mnt = au_br_mnt(a->br); ++ ++ /* are they available to be renamed */ ++ err = au_ren_may_dir(a); ++ if (unlikely(err)) ++ goto out_children; ++ ++ /* prepare the writable parent dir on the same branch */ ++ if (a->dst_btop == a->btgt) { ++ au_fset_ren(a->auren_flags, WHDST); ++ } else { ++ err = au_cpup_dirs(a->dst_dentry, a->btgt); ++ if (unlikely(err)) ++ goto out_children; ++ } ++ ++ err = 0; ++ if (!a->exchange) { ++ if (a->src_dir != a->dst_dir) { ++ /* ++ * this temporary unlock is safe, ++ * because both dir->i_mutex are locked. ++ */ ++ di_write_unlock(a->dst_parent); ++ di_write_lock_parent(a->src_parent); ++ err = au_wr_dir_need_wh(a->src_dentry, ++ au_ftest_ren(a->auren_flags, ++ ISDIR_SRC), ++ &a->btgt); ++ di_write_unlock(a->src_parent); ++ di_write_lock2_parent(a->src_parent, a->dst_parent, ++ /*isdir*/1); ++ au_fclr_ren(a->auren_flags, ISSAMEDIR); ++ } else ++ err = au_wr_dir_need_wh(a->src_dentry, ++ au_ftest_ren(a->auren_flags, ++ ISDIR_SRC), ++ &a->btgt); ++ } ++ if (unlikely(err < 0)) ++ goto out_children; ++ if (err) ++ au_fset_ren(a->auren_flags, WHSRC); ++ ++ /* cpup src */ ++ if (a->src_btop != a->btgt) { ++ err = au_pin(&pin, a->src_dentry, a->btgt, ++ au_opt_udba(a->src_dentry->d_sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (!err) { ++ struct au_cp_generic cpg = { ++ .dentry = a->src_dentry, ++ .bdst = a->btgt, ++ .bsrc = a->src_btop, ++ .len = -1, ++ .pin = &pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ AuDebugOn(au_dbtop(a->src_dentry) != a->src_btop); ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&pin); ++ } ++ if (unlikely(err)) ++ goto out_children; ++ a->src_btop = a->btgt; ++ a->src_h_dentry = au_h_dptr(a->src_dentry, a->btgt); ++ if (!a->exchange) ++ au_fset_ren(a->auren_flags, WHSRC); ++ } ++ ++ /* cpup dst */ ++ if (a->exchange && a->dst_inode ++ && a->dst_btop != a->btgt) { ++ err = au_pin(&pin, a->dst_dentry, a->btgt, ++ au_opt_udba(a->dst_dentry->d_sb), ++ AuPin_DI_LOCKED | AuPin_MNT_WRITE); ++ if (!err) { ++ struct au_cp_generic cpg = { ++ .dentry = a->dst_dentry, ++ .bdst = a->btgt, ++ .bsrc = a->dst_btop, ++ .len = -1, ++ .pin = &pin, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ err = au_sio_cpup_simple(&cpg); ++ au_unpin(&pin); ++ } ++ if (unlikely(err)) ++ goto out_children; ++ a->dst_btop = a->btgt; ++ a->dst_h_dentry = au_h_dptr(a->dst_dentry, a->btgt); ++ } ++ ++ /* lock them all */ ++ err = au_ren_lock(a); ++ if (unlikely(err)) ++ /* leave the copied-up one */ ++ goto out_children; ++ ++ if (!a->exchange) { ++ if (!au_opt_test(au_mntflags(a->dst_dir->i_sb), UDBA_NONE)) ++ err = au_may_ren(a); ++ else if (unlikely(a->dst_dentry->d_name.len > AUFS_MAX_NAMELEN)) ++ err = -ENAMETOOLONG; ++ if (unlikely(err)) ++ goto out_hdir; ++ } ++ ++ /* store timestamps to be revertible */ ++ au_ren_dt(a); ++ ++ /* store dirren info */ ++ if (au_ftest_ren(a->auren_flags, DIRREN)) { ++ err = au_dr_rename(a->src_dentry, a->btgt, ++ &a->dst_dentry->d_name, &rev); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out_dt; ++ } ++ ++ /* here we go */ ++ err = do_rename(a); ++ if (unlikely(err)) ++ goto out_dirren; ++ ++ if (au_ftest_ren(a->auren_flags, DIRREN)) ++ au_dr_rename_fin(a->src_dentry, a->btgt, rev); ++ ++ /* update dir attributes */ ++ au_ren_refresh_dir(a); ++ ++ /* dput/iput all lower dentries */ ++ au_ren_refresh(a); ++ ++ goto out_hdir; /* success */ ++ ++out_dirren: ++ if (au_ftest_ren(a->auren_flags, DIRREN)) ++ au_dr_rename_rev(a->src_dentry, a->btgt, rev); ++out_dt: ++ au_ren_rev_dt(err, a); ++out_hdir: ++ au_ren_unlock(a); ++out_children: ++ au_nhash_wh_free(&a->whlist); ++ if (err && a->dst_inode && a->dst_btop != a->btgt) { ++ AuDbg("btop %d, btgt %d\n", a->dst_btop, a->btgt); ++ au_set_h_dptr(a->dst_dentry, a->btgt, NULL); ++ au_set_dbtop(a->dst_dentry, a->dst_btop); ++ } ++out_parent: ++ if (!err) { ++ if (d_unhashed(a->src_dentry)) ++ au_fset_ren(a->auren_flags, DROPPED_SRC); ++ if (d_unhashed(a->dst_dentry)) ++ au_fset_ren(a->auren_flags, DROPPED_DST); ++ if (!a->exchange) ++ d_move(a->src_dentry, a->dst_dentry); ++ else { ++ d_exchange(a->src_dentry, a->dst_dentry); ++ if (au_ftest_ren(a->auren_flags, DROPPED_DST)) ++ d_drop(a->dst_dentry); ++ } ++ if (au_ftest_ren(a->auren_flags, DROPPED_SRC)) ++ d_drop(a->src_dentry); ++ } else { ++ au_update_dbtop(a->dst_dentry); ++ if (!a->dst_inode) ++ d_drop(a->dst_dentry); ++ } ++ if (au_ftest_ren(a->auren_flags, ISSAMEDIR)) ++ di_write_unlock(a->dst_parent); ++ else ++ di_write_unlock2(a->src_parent, a->dst_parent); ++out_unlock: ++ aufs_read_and_write_unlock2(a->dst_dentry, a->src_dentry); ++out_free: ++ iput(a->dst_inode); ++ if (a->thargs) ++ au_whtmp_rmdir_free(a->thargs); ++ au_kfree_rcu(a); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff --git a/fs/aufs/iinfo.c b/fs/aufs/iinfo.c +new file mode 100644 +index 000000000000..5a837d7d0a33 +--- /dev/null ++++ b/fs/aufs/iinfo.c +@@ -0,0 +1,273 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode private data ++ */ ++ ++#include "aufs.h" ++ ++struct inode *au_h_iptr(struct inode *inode, aufs_bindex_t bindex) ++{ ++ struct inode *h_inode; ++ struct au_hinode *hinode; ++ ++ IiMustAnyLock(inode); ++ ++ hinode = au_hinode(au_ii(inode), bindex); ++ h_inode = hinode->hi_inode; ++ AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0); ++ return h_inode; ++} ++ ++/* todo: hard/soft set? */ ++void au_hiput(struct au_hinode *hinode) ++{ ++ au_hn_free(hinode); ++ dput(hinode->hi_whdentry); ++ iput(hinode->hi_inode); ++} ++ ++unsigned int au_hi_flags(struct inode *inode, int isdir) ++{ ++ unsigned int flags; ++ const unsigned int mnt_flags = au_mntflags(inode->i_sb); ++ ++ flags = 0; ++ if (au_opt_test(mnt_flags, XINO)) ++ au_fset_hi(flags, XINO); ++ if (isdir && au_opt_test(mnt_flags, UDBA_HNOTIFY)) ++ au_fset_hi(flags, HNOTIFY); ++ return flags; ++} ++ ++void au_set_h_iptr(struct inode *inode, aufs_bindex_t bindex, ++ struct inode *h_inode, unsigned int flags) ++{ ++ struct au_hinode *hinode; ++ struct inode *hi; ++ struct au_iinfo *iinfo = au_ii(inode); ++ ++ IiMustWriteLock(inode); ++ ++ hinode = au_hinode(iinfo, bindex); ++ hi = hinode->hi_inode; ++ AuDebugOn(h_inode && atomic_read(&h_inode->i_count) <= 0); ++ ++ if (hi) ++ au_hiput(hinode); ++ hinode->hi_inode = h_inode; ++ if (h_inode) { ++ int err; ++ struct super_block *sb = inode->i_sb; ++ struct au_branch *br; ++ ++ AuDebugOn(inode->i_mode ++ && (h_inode->i_mode & S_IFMT) ++ != (inode->i_mode & S_IFMT)); ++ if (bindex == iinfo->ii_btop) ++ au_cpup_igen(inode, h_inode); ++ br = au_sbr(sb, bindex); ++ hinode->hi_id = br->br_id; ++ if (au_ftest_hi(flags, XINO)) { ++ err = au_xino_write(sb, bindex, h_inode->i_ino, ++ inode->i_ino); ++ if (unlikely(err)) ++ AuIOErr1("failed au_xino_write() %d\n", err); ++ } ++ ++ if (au_ftest_hi(flags, HNOTIFY) ++ && au_br_hnotifyable(br->br_perm)) { ++ err = au_hn_alloc(hinode, inode); ++ if (unlikely(err)) ++ AuIOErr1("au_hn_alloc() %d\n", err); ++ } ++ } ++} ++ ++void au_set_hi_wh(struct inode *inode, aufs_bindex_t bindex, ++ struct dentry *h_wh) ++{ ++ struct au_hinode *hinode; ++ ++ IiMustWriteLock(inode); ++ ++ hinode = au_hinode(au_ii(inode), bindex); ++ AuDebugOn(hinode->hi_whdentry); ++ hinode->hi_whdentry = h_wh; ++} ++ ++void au_update_iigen(struct inode *inode, int half) ++{ ++ struct au_iinfo *iinfo; ++ struct au_iigen *iigen; ++ unsigned int sigen; ++ ++ sigen = au_sigen(inode->i_sb); ++ iinfo = au_ii(inode); ++ iigen = &iinfo->ii_generation; ++ spin_lock(&iigen->ig_spin); ++ iigen->ig_generation = sigen; ++ if (half) ++ au_ig_fset(iigen->ig_flags, HALF_REFRESHED); ++ else ++ au_ig_fclr(iigen->ig_flags, HALF_REFRESHED); ++ spin_unlock(&iigen->ig_spin); ++} ++ ++/* it may be called at remount time, too */ ++void au_update_ibrange(struct inode *inode, int do_put_zero) ++{ ++ struct au_iinfo *iinfo; ++ aufs_bindex_t bindex, bbot; ++ ++ AuDebugOn(au_is_bad_inode(inode)); ++ IiMustWriteLock(inode); ++ ++ iinfo = au_ii(inode); ++ if (do_put_zero && iinfo->ii_btop >= 0) { ++ for (bindex = iinfo->ii_btop; bindex <= iinfo->ii_bbot; ++ bindex++) { ++ struct inode *h_i; ++ ++ h_i = au_hinode(iinfo, bindex)->hi_inode; ++ if (h_i ++ && !h_i->i_nlink ++ && !(h_i->i_state & I_LINKABLE)) ++ au_set_h_iptr(inode, bindex, NULL, 0); ++ } ++ } ++ ++ iinfo->ii_btop = -1; ++ iinfo->ii_bbot = -1; ++ bbot = au_sbbot(inode->i_sb); ++ for (bindex = 0; bindex <= bbot; bindex++) ++ if (au_hinode(iinfo, bindex)->hi_inode) { ++ iinfo->ii_btop = bindex; ++ break; ++ } ++ if (iinfo->ii_btop >= 0) ++ for (bindex = bbot; bindex >= iinfo->ii_btop; bindex--) ++ if (au_hinode(iinfo, bindex)->hi_inode) { ++ iinfo->ii_bbot = bindex; ++ break; ++ } ++ AuDebugOn(iinfo->ii_btop > iinfo->ii_bbot); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_icntnr_init_once(void *_c) ++{ ++ struct au_icntnr *c = _c; ++ struct au_iinfo *iinfo = &c->iinfo; ++ ++ spin_lock_init(&iinfo->ii_generation.ig_spin); ++ au_rw_init(&iinfo->ii_rwsem); ++ inode_init_once(&c->vfs_inode); ++} ++ ++void au_hinode_init(struct au_hinode *hinode) ++{ ++ hinode->hi_inode = NULL; ++ hinode->hi_id = -1; ++ au_hn_init(hinode); ++ hinode->hi_whdentry = NULL; ++} ++ ++int au_iinfo_init(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct super_block *sb; ++ struct au_hinode *hi; ++ int nbr, i; ++ ++ sb = inode->i_sb; ++ iinfo = &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); ++ nbr = au_sbbot(sb) + 1; ++ if (unlikely(nbr <= 0)) ++ nbr = 1; ++ hi = kmalloc_array(nbr, sizeof(*iinfo->ii_hinode), GFP_NOFS); ++ if (hi) { ++ au_lcnt_inc(&au_sbi(sb)->si_ninodes); ++ ++ iinfo->ii_hinode = hi; ++ for (i = 0; i < nbr; i++, hi++) ++ au_hinode_init(hi); ++ ++ iinfo->ii_generation.ig_generation = au_sigen(sb); ++ iinfo->ii_btop = -1; ++ iinfo->ii_bbot = -1; ++ iinfo->ii_vdir = NULL; ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++int au_hinode_realloc(struct au_iinfo *iinfo, int nbr, int may_shrink) ++{ ++ int err, i; ++ struct au_hinode *hip; ++ ++ AuRwMustWriteLock(&iinfo->ii_rwsem); ++ ++ err = -ENOMEM; ++ hip = au_krealloc(iinfo->ii_hinode, sizeof(*hip) * nbr, GFP_NOFS, ++ may_shrink); ++ if (hip) { ++ iinfo->ii_hinode = hip; ++ i = iinfo->ii_bbot + 1; ++ hip += i; ++ for (; i < nbr; i++, hip++) ++ au_hinode_init(hip); ++ err = 0; ++ } ++ ++ return err; ++} ++ ++void au_iinfo_fin(struct inode *inode) ++{ ++ struct au_iinfo *iinfo; ++ struct au_hinode *hi; ++ struct super_block *sb; ++ aufs_bindex_t bindex, bbot; ++ const unsigned char unlinked = !inode->i_nlink; ++ ++ AuDebugOn(au_is_bad_inode(inode)); ++ ++ sb = inode->i_sb; ++ au_lcnt_dec(&au_sbi(sb)->si_ninodes); ++ if (si_pid_test(sb)) ++ au_xino_delete_inode(inode, unlinked); ++ else { ++ /* ++ * it is safe to hide the dependency between sbinfo and ++ * sb->s_umount. ++ */ ++ lockdep_off(); ++ si_noflush_read_lock(sb); ++ au_xino_delete_inode(inode, unlinked); ++ si_read_unlock(sb); ++ lockdep_on(); ++ } ++ ++ iinfo = au_ii(inode); ++ if (iinfo->ii_vdir) ++ au_vdir_free(iinfo->ii_vdir); ++ ++ bindex = iinfo->ii_btop; ++ if (bindex >= 0) { ++ hi = au_hinode(iinfo, bindex); ++ bbot = iinfo->ii_bbot; ++ while (bindex++ <= bbot) { ++ if (hi->hi_inode) ++ au_hiput(hi); ++ hi++; ++ } ++ } ++ au_kfree_rcu(iinfo->ii_hinode); ++ AuRwDestroy(&iinfo->ii_rwsem); ++} +diff --git a/fs/aufs/inode.c b/fs/aufs/inode.c +new file mode 100644 +index 000000000000..c071e525f499 +--- /dev/null ++++ b/fs/aufs/inode.c +@@ -0,0 +1,516 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode functions ++ */ ++ ++#include ++#include "aufs.h" ++ ++struct inode *au_igrab(struct inode *inode) ++{ ++ if (inode) { ++ AuDebugOn(!atomic_read(&inode->i_count)); ++ ihold(inode); ++ } ++ return inode; ++} ++ ++static void au_refresh_hinode_attr(struct inode *inode, int do_version) ++{ ++ au_cpup_attr_all(inode, /*force*/0); ++ au_update_iigen(inode, /*half*/1); ++ if (do_version) ++ inode_inc_iversion(inode); ++} ++ ++static int au_ii_refresh(struct inode *inode, int *update) ++{ ++ int err, e, nbr; ++ umode_t type; ++ aufs_bindex_t bindex, new_bindex; ++ struct super_block *sb; ++ struct au_iinfo *iinfo; ++ struct au_hinode *p, *q, tmp; ++ ++ AuDebugOn(au_is_bad_inode(inode)); ++ IiMustWriteLock(inode); ++ ++ *update = 0; ++ sb = inode->i_sb; ++ nbr = au_sbbot(sb) + 1; ++ type = inode->i_mode & S_IFMT; ++ iinfo = au_ii(inode); ++ err = au_hinode_realloc(iinfo, nbr, /*may_shrink*/0); ++ if (unlikely(err)) ++ goto out; ++ ++ AuDebugOn(iinfo->ii_btop < 0); ++ p = au_hinode(iinfo, iinfo->ii_btop); ++ for (bindex = iinfo->ii_btop; bindex <= iinfo->ii_bbot; ++ bindex++, p++) { ++ if (!p->hi_inode) ++ continue; ++ ++ AuDebugOn(type != (p->hi_inode->i_mode & S_IFMT)); ++ new_bindex = au_br_index(sb, p->hi_id); ++ if (new_bindex == bindex) ++ continue; ++ ++ if (new_bindex < 0) { ++ *update = 1; ++ au_hiput(p); ++ p->hi_inode = NULL; ++ continue; ++ } ++ ++ if (new_bindex < iinfo->ii_btop) ++ iinfo->ii_btop = new_bindex; ++ if (iinfo->ii_bbot < new_bindex) ++ iinfo->ii_bbot = new_bindex; ++ /* swap two lower inode, and loop again */ ++ q = au_hinode(iinfo, new_bindex); ++ tmp = *q; ++ *q = *p; ++ *p = tmp; ++ if (tmp.hi_inode) { ++ bindex--; ++ p--; ++ } ++ } ++ au_update_ibrange(inode, /*do_put_zero*/0); ++ au_hinode_realloc(iinfo, nbr, /*may_shrink*/1); /* harmless if err */ ++ e = au_dy_irefresh(inode); ++ if (unlikely(e && !err)) ++ err = e; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_refresh_iop(struct inode *inode, int force_getattr) ++{ ++ int type; ++ struct au_sbinfo *sbi = au_sbi(inode->i_sb); ++ const struct inode_operations *iop ++ = force_getattr ? aufs_iop : sbi->si_iop_array; ++ ++ if (inode->i_op == iop) ++ return; ++ ++ switch (inode->i_mode & S_IFMT) { ++ case S_IFDIR: ++ type = AuIop_DIR; ++ break; ++ case S_IFLNK: ++ type = AuIop_SYMLINK; ++ break; ++ default: ++ type = AuIop_OTHER; ++ break; ++ } ++ ++ inode->i_op = iop + type; ++ /* unnecessary smp_wmb() */ ++} ++ ++int au_refresh_hinode_self(struct inode *inode) ++{ ++ int err, update; ++ ++ err = au_ii_refresh(inode, &update); ++ if (!err) ++ au_refresh_hinode_attr(inode, update && S_ISDIR(inode->i_mode)); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_refresh_hinode(struct inode *inode, struct dentry *dentry) ++{ ++ int err, e, update; ++ unsigned int flags; ++ umode_t mode; ++ aufs_bindex_t bindex, bbot; ++ unsigned char isdir; ++ struct au_hinode *p; ++ struct au_iinfo *iinfo; ++ ++ err = au_ii_refresh(inode, &update); ++ if (unlikely(err)) ++ goto out; ++ ++ update = 0; ++ iinfo = au_ii(inode); ++ p = au_hinode(iinfo, iinfo->ii_btop); ++ mode = (inode->i_mode & S_IFMT); ++ isdir = S_ISDIR(mode); ++ flags = au_hi_flags(inode, isdir); ++ bbot = au_dbbot(dentry); ++ for (bindex = au_dbtop(dentry); bindex <= bbot; bindex++) { ++ struct inode *h_i, *h_inode; ++ struct dentry *h_d; ++ ++ h_d = au_h_dptr(dentry, bindex); ++ if (!h_d || d_is_negative(h_d)) ++ continue; ++ ++ h_inode = d_inode(h_d); ++ AuDebugOn(mode != (h_inode->i_mode & S_IFMT)); ++ if (iinfo->ii_btop <= bindex && bindex <= iinfo->ii_bbot) { ++ h_i = au_h_iptr(inode, bindex); ++ if (h_i) { ++ if (h_i == h_inode) ++ continue; ++ err = -EIO; ++ break; ++ } ++ } ++ if (bindex < iinfo->ii_btop) ++ iinfo->ii_btop = bindex; ++ if (iinfo->ii_bbot < bindex) ++ iinfo->ii_bbot = bindex; ++ au_set_h_iptr(inode, bindex, au_igrab(h_inode), flags); ++ update = 1; ++ } ++ au_update_ibrange(inode, /*do_put_zero*/0); ++ e = au_dy_irefresh(inode); ++ if (unlikely(e && !err)) ++ err = e; ++ if (!err) ++ au_refresh_hinode_attr(inode, update && isdir); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int set_inode(struct inode *inode, struct dentry *dentry) ++{ ++ int err; ++ unsigned int flags; ++ umode_t mode; ++ aufs_bindex_t bindex, btop, btail; ++ unsigned char isdir; ++ struct dentry *h_dentry; ++ struct inode *h_inode; ++ struct au_iinfo *iinfo; ++ const 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..7f1992a3ef5c +--- /dev/null ++++ b/fs/aufs/inode.h +@@ -0,0 +1,685 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * inode operations ++ */ ++ ++#ifndef __AUFS_INODE_H__ ++#define __AUFS_INODE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "rwsem.h" ++ ++struct vfsmount; ++ ++struct au_hnotify { ++#ifdef CONFIG_AUFS_HNOTIFY ++#ifdef CONFIG_AUFS_HFSNOTIFY ++ /* never use fsnotify_add_vfsmount_mark() */ ++ struct fsnotify_mark hn_mark; ++#endif ++ struct inode *hn_aufs_inode; /* no get/put */ ++ struct rcu_head rcu; ++#endif ++} ____cacheline_aligned_in_smp; ++ ++struct au_hinode { ++ struct inode *hi_inode; ++ aufs_bindex_t hi_id; ++#ifdef CONFIG_AUFS_HNOTIFY ++ struct au_hnotify *hi_notify; ++#endif ++ ++ /* reference to the copied-up whiteout with get/put */ ++ struct dentry *hi_whdentry; ++}; ++ ++/* ig_flags */ ++#define AuIG_HALF_REFRESHED 1 ++#define au_ig_ftest(flags, name) ((flags) & AuIG_##name) ++#define au_ig_fset(flags, name) \ ++ do { (flags) |= AuIG_##name; } while (0) ++#define au_ig_fclr(flags, name) \ ++ do { (flags) &= ~AuIG_##name; } while (0) ++ ++struct au_iigen { ++ spinlock_t ig_spin; ++ __u32 ig_generation, ig_flags; ++}; ++ ++struct au_vdir; ++struct au_iinfo { ++ struct au_iigen ii_generation; ++ struct super_block *ii_hsb1; /* no get/put */ ++ ++ struct au_rwsem ii_rwsem; ++ aufs_bindex_t ii_btop, ii_bbot; ++ __u32 ii_higen; ++ struct au_hinode *ii_hinode; ++ struct au_vdir *ii_vdir; ++}; ++ ++struct au_icntnr { ++ struct au_iinfo iinfo; ++ struct inode vfs_inode; ++ struct hlist_bl_node plink; ++ struct rcu_head rcu; ++} ____cacheline_aligned_in_smp; ++ ++/* au_pin flags */ ++#define AuPin_DI_LOCKED 1 ++#define AuPin_MNT_WRITE (1 << 1) ++#define au_ftest_pin(flags, name) ((flags) & AuPin_##name) ++#define au_fset_pin(flags, name) \ ++ do { (flags) |= AuPin_##name; } while (0) ++#define au_fclr_pin(flags, name) \ ++ do { (flags) &= ~AuPin_##name; } while (0) ++ ++struct au_pin { ++ /* input */ ++ struct dentry *dentry; ++ unsigned int udba; ++ unsigned char lsc_di, lsc_hi, flags; ++ aufs_bindex_t bindex; ++ ++ /* output */ ++ struct dentry *parent; ++ struct au_hinode *hdir; ++ struct vfsmount *h_mnt; ++ ++ /* temporary unlock/relock for copyup */ ++ struct dentry *h_dentry, *h_parent; ++ struct au_branch *br; ++ struct task_struct *task; ++}; ++ ++void au_pin_hdir_unlock(struct au_pin *p); ++int au_pin_hdir_lock(struct au_pin *p); ++int au_pin_hdir_relock(struct au_pin *p); ++void au_pin_hdir_acquire_nest(struct au_pin *p); ++void au_pin_hdir_release(struct au_pin *p); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_iinfo *au_ii(struct inode *inode) ++{ ++ BUG_ON(is_bad_inode(inode)); ++ return &(container_of(inode, struct au_icntnr, vfs_inode)->iinfo); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* inode.c */ ++struct inode *au_igrab(struct inode *inode); ++void au_refresh_iop(struct inode *inode, int force_getattr); ++int au_refresh_hinode_self(struct inode *inode); ++int au_refresh_hinode(struct inode *inode, struct dentry *dentry); ++int au_ino(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ unsigned int d_type, ino_t *ino); ++struct inode *au_new_inode(struct dentry *dentry, int must_new); ++int au_test_ro(struct super_block *sb, aufs_bindex_t bindex, ++ struct inode *inode); ++int au_test_h_perm(struct inode *h_inode, int mask); ++int au_test_h_perm_sio(struct inode *h_inode, int mask); ++ ++static inline int au_wh_ino(struct super_block *sb, aufs_bindex_t bindex, ++ ino_t h_ino, unsigned int d_type, ino_t *ino) ++{ ++#ifdef CONFIG_AUFS_SHWH ++ return au_ino(sb, bindex, h_ino, d_type, ino); ++#else ++ return 0; ++#endif ++} ++ ++/* i_op.c */ ++enum { ++ AuIop_SYMLINK, ++ AuIop_DIR, ++ AuIop_OTHER, ++ AuIop_Last ++}; ++extern struct inode_operations aufs_iop[AuIop_Last], /* not const */ ++ 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, struct inode *inode, 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 caller should free hinode->hi_notify, ++ * otherwise ->free() frees it. ++ */ ++ int (*free)(struct au_hinode *hinode, ++ struct au_hnotify *hn) __must_check; ++ ++ void (*fin)(void); ++ int (*init)(void); ++ ++ int (*reset_br)(unsigned int udba, struct au_branch *br, int perm); ++ void (*fin_br)(struct au_branch *br); ++ int (*init_br)(struct au_branch *br, int perm); ++}; ++ ++/* hnotify.c */ ++int au_hn_alloc(struct au_hinode *hinode, struct inode *inode); ++void au_hn_free(struct au_hinode *hinode); ++void au_hn_ctl(struct au_hinode *hinode, int do_set); ++void au_hn_reset(struct inode *inode, unsigned int flags); ++int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask, ++ const struct qstr *h_child_qstr, struct inode *h_child_inode); ++int au_hnotify_reset_br(unsigned int udba, struct au_branch *br, int perm); ++int au_hnotify_init_br(struct au_branch *br, int perm); ++void au_hnotify_fin_br(struct au_branch *br); ++int __init au_hnotify_init(void); ++void au_hnotify_fin(void); ++ ++/* hfsnotify.c */ ++extern const struct au_hnotify_op au_hnotify_op; ++ ++static inline ++void au_hn_init(struct au_hinode *hinode) ++{ ++ hinode->hi_notify = NULL; ++} ++ ++static inline struct au_hnotify *au_hn(struct au_hinode *hinode) ++{ ++ return hinode->hi_notify; ++} ++ ++#else ++AuStub(int, au_hn_alloc, return -EOPNOTSUPP, ++ struct au_hinode *hinode __maybe_unused, ++ struct inode *inode __maybe_unused) ++AuStub(struct au_hnotify *, au_hn, return NULL, struct au_hinode *hinode) ++AuStubVoid(au_hn_free, struct au_hinode *hinode __maybe_unused) ++AuStubVoid(au_hn_ctl, struct au_hinode *hinode __maybe_unused, ++ int do_set __maybe_unused) ++AuStubVoid(au_hn_reset, struct inode *inode __maybe_unused, ++ unsigned int flags __maybe_unused) ++AuStubInt0(au_hnotify_reset_br, unsigned int udba __maybe_unused, ++ struct au_branch *br __maybe_unused, ++ int perm __maybe_unused) ++AuStubInt0(au_hnotify_init_br, struct au_branch *br __maybe_unused, ++ int perm __maybe_unused) ++AuStubVoid(au_hnotify_fin_br, struct au_branch *br __maybe_unused) ++AuStubInt0(__init au_hnotify_init, void) ++AuStubVoid(au_hnotify_fin, void) ++AuStubVoid(au_hn_init, struct au_hinode *hinode __maybe_unused) ++#endif /* CONFIG_AUFS_HNOTIFY */ ++ ++static inline void au_hn_suspend(struct au_hinode *hdir) ++{ ++ au_hn_ctl(hdir, /*do_set*/0); ++} ++ ++static inline void au_hn_resume(struct au_hinode *hdir) ++{ ++ au_hn_ctl(hdir, /*do_set*/1); ++} ++ ++static inline void au_hn_inode_lock(struct au_hinode *hdir) ++{ ++ inode_lock(hdir->hi_inode); ++ au_hn_suspend(hdir); ++} ++ ++static inline void au_hn_inode_lock_nested(struct au_hinode *hdir, ++ unsigned int sc __maybe_unused) ++{ ++ inode_lock_nested(hdir->hi_inode, sc); ++ au_hn_suspend(hdir); ++} ++ ++#if 0 /* unused */ ++#include "vfsub.h" ++static inline void au_hn_inode_lock_shared_nested(struct au_hinode *hdir, ++ unsigned int sc) ++{ ++ inode_lock_shared_nested(hdir->hi_inode, sc); ++ au_hn_suspend(hdir); ++} ++#endif ++ ++static inline void au_hn_inode_unlock(struct au_hinode *hdir) ++{ ++ au_hn_resume(hdir); ++ inode_unlock(hdir->hi_inode); ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_INODE_H__ */ +diff --git a/fs/aufs/ioctl.c b/fs/aufs/ioctl.c +new file mode 100644 +index 000000000000..9d0e969217a9 +--- /dev/null ++++ b/fs/aufs/ioctl.c +@@ -0,0 +1,207 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 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..c7db43d9e260 +--- /dev/null ++++ b/fs/aufs/lcnt.h +@@ -0,0 +1,173 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2018-2020 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..a8b63acc6204 +--- /dev/null ++++ b/fs/aufs/loop.c +@@ -0,0 +1,135 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * support for loopback block device as a branch ++ */ ++ ++#include "aufs.h" ++ ++/* added into drivers/block/loop.c */ ++static struct file *(*backing_file_func)(struct super_block *sb); ++ ++/* ++ * test if two lower dentries have overlapping branches. ++ */ ++int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_adding) ++{ ++ struct super_block *h_sb; ++ struct file *backing_file; ++ ++ if (unlikely(!backing_file_func)) { ++ /* don't load "loop" module here */ ++ backing_file_func = symbol_get(loop_backing_file); ++ if (unlikely(!backing_file_func)) ++ /* "loop" module is not loaded */ ++ return 0; ++ } ++ ++ h_sb = h_adding->d_sb; ++ backing_file = backing_file_func(h_sb); ++ if (!backing_file) ++ return 0; ++ ++ h_adding = backing_file->f_path.dentry; ++ /* ++ * h_adding can be local NFS. ++ * in this case aufs cannot detect the loop. ++ */ ++ if (unlikely(h_adding->d_sb == sb)) ++ return 1; ++ return !!au_test_subdir(h_adding, sb->s_root); ++} ++ ++/* true if a kernel thread named 'loop[0-9].*' accesses a file */ ++int au_test_loopback_kthread(void) ++{ ++ int ret; ++ struct task_struct *tsk = current; ++ char c, comm[sizeof(tsk->comm)]; ++ ++ ret = 0; ++ if (tsk->flags & PF_KTHREAD) { ++ get_task_comm(comm, tsk); ++ c = comm[4]; ++ ret = ('0' <= c && c <= '9' ++ && !strncmp(comm, "loop", 4)); ++ } ++ ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define au_warn_loopback_step 16 ++static int au_warn_loopback_nelem = au_warn_loopback_step; ++static unsigned long *au_warn_loopback_array; ++ ++void au_warn_loopback(struct super_block *h_sb) ++{ ++ int i, new_nelem; ++ unsigned long *a, magic; ++ static DEFINE_SPINLOCK(spin); ++ ++ magic = h_sb->s_magic; ++ spin_lock(&spin); ++ a = au_warn_loopback_array; ++ for (i = 0; i < au_warn_loopback_nelem && *a; i++) ++ if (a[i] == magic) { ++ spin_unlock(&spin); ++ return; ++ } ++ ++ /* h_sb is new to us, print it */ ++ if (i < au_warn_loopback_nelem) { ++ a[i] = magic; ++ goto pr; ++ } ++ ++ /* expand the array */ ++ new_nelem = au_warn_loopback_nelem + au_warn_loopback_step; ++ a = au_kzrealloc(au_warn_loopback_array, ++ au_warn_loopback_nelem * sizeof(unsigned long), ++ new_nelem * sizeof(unsigned long), GFP_ATOMIC, ++ /*may_shrink*/0); ++ if (a) { ++ au_warn_loopback_nelem = new_nelem; ++ au_warn_loopback_array = a; ++ a[i] = magic; ++ goto pr; ++ } ++ ++ spin_unlock(&spin); ++ AuWarn1("realloc failed, ignored\n"); ++ return; ++ ++pr: ++ spin_unlock(&spin); ++ pr_warn("you may want to try another patch for loopback file " ++ "on %s(0x%lx) branch\n", au_sbtype(h_sb), magic); ++} ++ ++int au_loopback_init(void) ++{ ++ int err; ++ struct super_block *sb __maybe_unused; ++ ++ BUILD_BUG_ON(sizeof(sb->s_magic) != sizeof(*au_warn_loopback_array)); ++ ++ err = 0; ++ au_warn_loopback_array = kcalloc(au_warn_loopback_step, ++ sizeof(unsigned long), GFP_NOFS); ++ if (unlikely(!au_warn_loopback_array)) ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++void au_loopback_fin(void) ++{ ++ if (backing_file_func) ++ symbol_put(loop_backing_file); ++ au_kfree_try_rcu(au_warn_loopback_array); ++} +diff --git a/fs/aufs/loop.h b/fs/aufs/loop.h +new file mode 100644 +index 000000000000..94f4f80ae33b +--- /dev/null ++++ b/fs/aufs/loop.h +@@ -0,0 +1,42 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * support for loopback mount as a branch ++ */ ++ ++#ifndef __AUFS_LOOP_H__ ++#define __AUFS_LOOP_H__ ++ ++#ifdef __KERNEL__ ++ ++struct dentry; ++struct super_block; ++ ++#ifdef CONFIG_AUFS_BDEV_LOOP ++/* drivers/block/loop.c */ ++struct file *loop_backing_file(struct super_block *sb); ++ ++/* loop.c */ ++int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_adding); ++int au_test_loopback_kthread(void); ++void au_warn_loopback(struct super_block *h_sb); ++ ++int au_loopback_init(void); ++void au_loopback_fin(void); ++#else ++AuStub(struct file *, loop_backing_file, return NULL, struct super_block *sb) ++ ++AuStubInt0(au_test_loopback_overlap, struct super_block *sb, ++ struct dentry *h_adding) ++AuStubInt0(au_test_loopback_kthread, void) ++AuStubVoid(au_warn_loopback, struct super_block *h_sb) ++ ++AuStubInt0(au_loopback_init, void) ++AuStubVoid(au_loopback_fin, void) ++#endif /* BLK_DEV_LOOP */ ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_LOOP_H__ */ +diff --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..18039801580f +--- /dev/null ++++ b/fs/aufs/module.c +@@ -0,0 +1,259 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * module global variables and operations ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++/* shrinkable realloc */ ++void *au_krealloc(void *p, unsigned int new_sz, gfp_t gfp, int may_shrink) ++{ ++ size_t sz; ++ int diff; ++ ++ sz = 0; ++ diff = -1; ++ if (p) { ++#if 0 /* unused */ ++ if (!new_sz) { ++ au_kfree_rcu(p); ++ p = NULL; ++ goto out; ++ } ++#else ++ AuDebugOn(!new_sz); ++#endif ++ sz = ksize(p); ++ diff = au_kmidx_sub(sz, new_sz); ++ } ++ if (sz && !diff) ++ goto out; ++ ++ if (sz < new_sz) ++ /* expand or SLOB */ ++ p = krealloc(p, new_sz, gfp); ++ else if (new_sz < sz && may_shrink) { ++ /* shrink */ ++ void *q; ++ ++ q = kmalloc(new_sz, gfp); ++ if (q) { ++ if (p) { ++ memcpy(q, p, new_sz); ++ au_kfree_try_rcu(p); ++ } ++ p = q; ++ } else ++ p = NULL; ++ } ++ ++out: ++ return p; ++} ++ ++void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp, ++ int may_shrink) ++{ ++ p = au_krealloc(p, new_sz, gfp, may_shrink); ++ if (p && new_sz > nused) ++ memset(p + nused, 0, new_sz - nused); ++ return p; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * aufs caches ++ */ ++struct kmem_cache *au_cache[AuCache_Last]; ++ ++static void au_cache_fin(void) ++{ ++ int i; ++ ++ /* ++ * Make sure all delayed rcu free inodes are flushed before we ++ * destroy cache. ++ */ ++ rcu_barrier(); ++ ++ /* excluding AuCache_HNOTIFY */ ++ BUILD_BUG_ON(AuCache_HNOTIFY + 1 != AuCache_Last); ++ for (i = 0; i < AuCache_HNOTIFY; i++) { ++ kmem_cache_destroy(au_cache[i]); ++ au_cache[i] = NULL; ++ } ++} ++ ++static int __init au_cache_init(void) ++{ ++ au_cache[AuCache_DINFO] = AuCacheCtor(au_dinfo, au_di_init_once); ++ if (au_cache[AuCache_DINFO]) ++ /* SLAB_DESTROY_BY_RCU */ ++ au_cache[AuCache_ICNTNR] = AuCacheCtor(au_icntnr, ++ au_icntnr_init_once); ++ if (au_cache[AuCache_ICNTNR]) ++ au_cache[AuCache_FINFO] = AuCacheCtor(au_finfo, ++ au_fi_init_once); ++ if (au_cache[AuCache_FINFO]) ++ au_cache[AuCache_VDIR] = AuCache(au_vdir); ++ if (au_cache[AuCache_VDIR]) ++ au_cache[AuCache_DEHSTR] = AuCache(au_vdir_dehstr); ++ if (au_cache[AuCache_DEHSTR]) ++ return 0; ++ ++ au_cache_fin(); ++ return -ENOMEM; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_dir_roflags; ++ ++#ifdef CONFIG_AUFS_SBILIST ++/* ++ * iterate_supers_type() doesn't protect us from ++ * remounting (branch management) ++ */ ++struct hlist_bl_head au_sbilist; ++#endif ++ ++/* ++ * functions for module interface. ++ */ ++MODULE_LICENSE("GPL"); ++/* MODULE_LICENSE("GPL v2"); */ ++MODULE_AUTHOR("Junjiro R. Okajima "); ++MODULE_DESCRIPTION(AUFS_NAME ++ " -- Advanced multi layered unification filesystem"); ++MODULE_VERSION(AUFS_VERSION); ++ ++/* this module parameter has no meaning when SYSFS is disabled */ ++int sysaufs_brs = 1; ++MODULE_PARM_DESC(brs, "use /fs/aufs/si_*/brN"); ++module_param_named(brs, sysaufs_brs, int, 0444); ++ ++/* this module parameter has no meaning when USER_NS is disabled */ ++bool au_userns; ++MODULE_PARM_DESC(allow_userns, "allow unprivileged to mount under userns"); ++module_param_named(allow_userns, au_userns, bool, 0444); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static char au_esc_chars[0x20 + 3]; /* 0x01-0x20, backslash, del, and NULL */ ++ ++int au_seq_path(struct seq_file *seq, struct path *path) ++{ ++ int err; ++ ++ err = seq_path(seq, path, au_esc_chars); ++ if (err >= 0) ++ err = 0; ++ else ++ err = -ENOMEM; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int __init aufs_init(void) ++{ ++ int err, i; ++ char *p; ++ ++ p = au_esc_chars; ++ for (i = 1; i <= ' '; i++) ++ *p++ = i; ++ *p++ = '\\'; ++ *p++ = '\x7f'; ++ *p = 0; ++ ++ au_dir_roflags = au_file_roflags(O_DIRECTORY | O_LARGEFILE); ++ ++ memcpy(aufs_iop_nogetattr, aufs_iop, sizeof(aufs_iop)); ++ for (i = 0; i < AuIop_Last; i++) ++ aufs_iop_nogetattr[i].getattr = NULL; ++ ++ memset(au_cache, 0, sizeof(au_cache)); /* including hnotify */ ++ ++ au_sbilist_init(); ++ sysaufs_brs_init(); ++ au_debug_init(); ++ au_dy_init(); ++ err = sysaufs_init(); ++ if (unlikely(err)) ++ goto out; ++ err = dbgaufs_init(); ++ if (unlikely(err)) ++ goto out_sysaufs; ++ err = au_procfs_init(); ++ if (unlikely(err)) ++ goto out_dbgaufs; ++ err = au_wkq_init(); ++ if (unlikely(err)) ++ goto out_procfs; ++ err = au_loopback_init(); ++ if (unlikely(err)) ++ goto out_wkq; ++ err = au_hnotify_init(); ++ if (unlikely(err)) ++ goto out_loopback; ++ err = au_sysrq_init(); ++ if (unlikely(err)) ++ goto out_hin; ++ err = au_cache_init(); ++ if (unlikely(err)) ++ goto out_sysrq; ++ ++ aufs_fs_type.fs_flags |= au_userns ? FS_USERNS_MOUNT : 0; ++ err = register_filesystem(&aufs_fs_type); ++ if (unlikely(err)) ++ goto out_cache; ++ ++ /* since we define pr_fmt, call printk directly */ ++ printk(KERN_INFO AUFS_NAME " " AUFS_VERSION "\n"); ++ goto out; /* success */ ++ ++out_cache: ++ au_cache_fin(); ++out_sysrq: ++ au_sysrq_fin(); ++out_hin: ++ au_hnotify_fin(); ++out_loopback: ++ au_loopback_fin(); ++out_wkq: ++ au_wkq_fin(); ++out_procfs: ++ au_procfs_fin(); ++out_dbgaufs: ++ dbgaufs_fin(); ++out_sysaufs: ++ sysaufs_fin(); ++ au_dy_fin(); ++out: ++ return err; ++} ++ ++static void __exit aufs_exit(void) ++{ ++ unregister_filesystem(&aufs_fs_type); ++ au_cache_fin(); ++ au_sysrq_fin(); ++ au_hnotify_fin(); ++ au_loopback_fin(); ++ au_wkq_fin(); ++ au_procfs_fin(); ++ dbgaufs_fin(); ++ sysaufs_fin(); ++ au_dy_fin(); ++} ++ ++module_init(aufs_init); ++module_exit(aufs_exit); +diff --git a/fs/aufs/module.h b/fs/aufs/module.h +new file mode 100644 +index 000000000000..cf4679c65542 +--- /dev/null ++++ b/fs/aufs/module.h +@@ -0,0 +1,153 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * module initialization and module-global ++ */ ++ ++#ifndef __AUFS_MODULE_H__ ++#define __AUFS_MODULE_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include "debug.h" ++#include "dentry.h" ++#include "dir.h" ++#include "file.h" ++#include "inode.h" ++ ++struct path; ++struct seq_file; ++ ++/* module parameters */ ++extern int sysaufs_brs; ++extern bool au_userns; ++ ++/* ---------------------------------------------------------------------- */ ++ ++extern int au_dir_roflags; ++ ++void *au_krealloc(void *p, unsigned int new_sz, gfp_t gfp, int may_shrink); ++void *au_kzrealloc(void *p, unsigned int nused, unsigned int new_sz, gfp_t gfp, ++ int may_shrink); ++ ++/* ++ * Comparing the size of the object with sizeof(struct rcu_head) ++ * case 1: object is always larger ++ * --> au_kfree_rcu() or au_kfree_do_rcu() ++ * case 2: object is always smaller ++ * --> au_kfree_small() ++ * case 3: object can be any size ++ * --> au_kfree_try_rcu() ++ */ ++ ++static inline void au_kfree_do_rcu(const void *p) ++{ ++ struct { ++ struct rcu_head rcu; ++ } *a = (void *)p; ++ ++ kfree_rcu(a, rcu); ++} ++ ++#define au_kfree_rcu(_p) do { \ ++ typeof(_p) p = (_p); \ ++ BUILD_BUG_ON(sizeof(*p) < sizeof(struct rcu_head)); \ ++ if (p) \ ++ au_kfree_do_rcu(p); \ ++ } while (0) ++ ++#define au_kfree_do_sz_test(sz) (sz >= sizeof(struct rcu_head)) ++#define au_kfree_sz_test(p) (p && au_kfree_do_sz_test(ksize(p))) ++ ++static inline void au_kfree_try_rcu(const void *p) ++{ ++ if (!p) ++ return; ++ if (au_kfree_sz_test(p)) ++ au_kfree_do_rcu(p); ++ else ++ kfree(p); ++} ++ ++static inline void au_kfree_small(const void *p) ++{ ++ if (!p) ++ return; ++ AuDebugOn(au_kfree_sz_test(p)); ++ kfree(p); ++} ++ ++static inline int au_kmidx_sub(size_t sz, size_t new_sz) ++{ ++#ifndef CONFIG_SLOB ++ return kmalloc_index(sz) - kmalloc_index(new_sz); ++#else ++ return -1; /* SLOB is untested */ ++#endif ++} ++ ++int au_seq_path(struct seq_file *seq, struct path *path); ++ ++#ifdef CONFIG_PROC_FS ++/* procfs.c */ ++int __init au_procfs_init(void); ++void au_procfs_fin(void); ++#else ++AuStubInt0(au_procfs_init, void); ++AuStubVoid(au_procfs_fin, void); ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* kmem cache */ ++enum { ++ AuCache_DINFO, ++ AuCache_ICNTNR, ++ AuCache_FINFO, ++ AuCache_VDIR, ++ AuCache_DEHSTR, ++ AuCache_HNOTIFY, /* must be last */ ++ AuCache_Last ++}; ++ ++extern struct kmem_cache *au_cache[AuCache_Last]; ++ ++#define AuCacheFlags (SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD) ++#define AuCache(type) KMEM_CACHE(type, AuCacheFlags) ++#define AuCacheCtor(type, ctor) \ ++ kmem_cache_create(#type, sizeof(struct type), \ ++ __alignof__(struct type), AuCacheFlags, ctor) ++ ++#define AuCacheFuncs(name, index) \ ++ static inline struct au_##name *au_cache_alloc_##name(void) \ ++ { return kmem_cache_alloc(au_cache[AuCache_##index], GFP_NOFS); } \ ++ static inline void au_cache_free_##name##_norcu(struct au_##name *p) \ ++ { kmem_cache_free(au_cache[AuCache_##index], p); } \ ++ \ ++ static inline void au_cache_free_##name##_rcu_cb(struct rcu_head *rcu) \ ++ { void *p = rcu; \ ++ p -= offsetof(struct au_##name, rcu); \ ++ kmem_cache_free(au_cache[AuCache_##index], p); } \ ++ static inline void au_cache_free_##name##_rcu(struct au_##name *p) \ ++ { BUILD_BUG_ON(sizeof(struct au_##name) < sizeof(struct rcu_head)); \ ++ call_rcu(&p->rcu, au_cache_free_##name##_rcu_cb); } \ ++ \ ++ static inline void au_cache_free_##name(struct au_##name *p) \ ++ { /* au_cache_free_##name##_norcu(p); */ \ ++ au_cache_free_##name##_rcu(p); } ++ ++AuCacheFuncs(dinfo, DINFO); ++AuCacheFuncs(icntnr, ICNTNR); ++AuCacheFuncs(finfo, FINFO); ++AuCacheFuncs(vdir, VDIR); ++AuCacheFuncs(vdir_dehstr, DEHSTR); ++#ifdef CONFIG_AUFS_HNOTIFY ++AuCacheFuncs(hnotify, HNOTIFY); ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_MODULE_H__ */ +diff --git a/fs/aufs/mvdown.c b/fs/aufs/mvdown.c +new file mode 100644 +index 000000000000..d28a33f4a944 +--- /dev/null ++++ b/fs/aufs/mvdown.c +@@ -0,0 +1,693 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2011-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * move-down, opposite of copy-up ++ */ ++ ++#include "aufs.h" ++ ++struct au_mvd_args { ++ struct { ++ struct super_block *h_sb; ++ struct dentry *h_parent; ++ struct au_hinode *hdir; ++ struct inode *h_dir, *h_inode; ++ struct au_pin pin; ++ } info[AUFS_MVDOWN_NARRAY]; ++ ++ struct aufs_mvdown mvdown; ++ struct dentry *dentry, *parent; ++ struct inode *inode, *dir; ++ struct super_block *sb; ++ aufs_bindex_t bopq, bwh, bfound; ++ unsigned char rename_lock; ++}; ++ ++#define mvd_errno mvdown.au_errno ++#define mvd_bsrc mvdown.stbr[AUFS_MVDOWN_UPPER].bindex ++#define mvd_src_brid mvdown.stbr[AUFS_MVDOWN_UPPER].brid ++#define mvd_bdst mvdown.stbr[AUFS_MVDOWN_LOWER].bindex ++#define mvd_dst_brid mvdown.stbr[AUFS_MVDOWN_LOWER].brid ++ ++#define mvd_h_src_sb info[AUFS_MVDOWN_UPPER].h_sb ++#define mvd_h_src_parent info[AUFS_MVDOWN_UPPER].h_parent ++#define mvd_hdir_src info[AUFS_MVDOWN_UPPER].hdir ++#define mvd_h_src_dir info[AUFS_MVDOWN_UPPER].h_dir ++#define mvd_h_src_inode info[AUFS_MVDOWN_UPPER].h_inode ++#define mvd_pin_src info[AUFS_MVDOWN_UPPER].pin ++ ++#define mvd_h_dst_sb info[AUFS_MVDOWN_LOWER].h_sb ++#define mvd_h_dst_parent info[AUFS_MVDOWN_LOWER].h_parent ++#define mvd_hdir_dst info[AUFS_MVDOWN_LOWER].hdir ++#define mvd_h_dst_dir info[AUFS_MVDOWN_LOWER].h_dir ++#define mvd_h_dst_inode info[AUFS_MVDOWN_LOWER].h_inode ++#define mvd_pin_dst info[AUFS_MVDOWN_LOWER].pin ++ ++#define AU_MVD_PR(flag, ...) do { \ ++ if (flag) \ ++ pr_err(__VA_ARGS__); \ ++ } while (0) ++ ++static int find_lower_writable(struct au_mvd_args *a) ++{ ++ struct super_block *sb; ++ aufs_bindex_t bindex, bbot; ++ struct au_branch *br; ++ ++ sb = a->sb; ++ bindex = a->mvd_bsrc; ++ bbot = au_sbbot(sb); ++ if (a->mvdown.flags & AUFS_MVDOWN_FHSM_LOWER) ++ for (bindex++; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm) ++ && !sb_rdonly(au_br_sb(br))) ++ return bindex; ++ } ++ else if (!(a->mvdown.flags & AUFS_MVDOWN_ROLOWER)) ++ for (bindex++; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!au_br_rdonly(br)) ++ return bindex; ++ } ++ else ++ for (bindex++; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!sb_rdonly(au_br_sb(br))) { ++ if (au_br_rdonly(br)) ++ a->mvdown.flags ++ |= AUFS_MVDOWN_ROLOWER_R; ++ return bindex; ++ } ++ } ++ ++ return -1; ++} ++ ++/* make the parent dir on bdst */ ++static int au_do_mkdir(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ ++ err = 0; ++ a->mvd_hdir_src = au_hi(a->dir, a->mvd_bsrc); ++ a->mvd_hdir_dst = au_hi(a->dir, a->mvd_bdst); ++ a->mvd_h_src_parent = au_h_dptr(a->parent, a->mvd_bsrc); ++ a->mvd_h_dst_parent = NULL; ++ if (au_dbbot(a->parent) >= a->mvd_bdst) ++ a->mvd_h_dst_parent = au_h_dptr(a->parent, a->mvd_bdst); ++ if (!a->mvd_h_dst_parent) { ++ err = au_cpdown_dirs(a->dentry, a->mvd_bdst); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "cpdown_dirs failed\n"); ++ goto out; ++ } ++ a->mvd_h_dst_parent = au_h_dptr(a->parent, a->mvd_bdst); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* lock them all */ ++static int au_do_lock(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct dentry *h_trap; ++ ++ a->mvd_h_src_sb = au_sbr_sb(a->sb, a->mvd_bsrc); ++ a->mvd_h_dst_sb = au_sbr_sb(a->sb, a->mvd_bdst); ++ err = au_pin(&a->mvd_pin_dst, a->dentry, a->mvd_bdst, ++ au_opt_udba(a->sb), ++ AuPin_MNT_WRITE | AuPin_DI_LOCKED); ++ AuTraceErr(err); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "pin_dst failed\n"); ++ goto out; ++ } ++ ++ if (a->mvd_h_src_sb != a->mvd_h_dst_sb) { ++ a->rename_lock = 0; ++ au_pin_init(&a->mvd_pin_src, a->dentry, a->mvd_bsrc, ++ AuLsc_DI_PARENT, AuLsc_I_PARENT3, ++ au_opt_udba(a->sb), ++ AuPin_MNT_WRITE | AuPin_DI_LOCKED); ++ err = au_do_pin(&a->mvd_pin_src); ++ AuTraceErr(err); ++ a->mvd_h_src_dir = d_inode(a->mvd_h_src_parent); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "pin_src failed\n"); ++ goto out_dst; ++ } ++ goto out; /* success */ ++ } ++ ++ a->rename_lock = 1; ++ au_pin_hdir_unlock(&a->mvd_pin_dst); ++ err = au_pin(&a->mvd_pin_src, a->dentry, a->mvd_bsrc, ++ au_opt_udba(a->sb), ++ AuPin_MNT_WRITE | AuPin_DI_LOCKED); ++ AuTraceErr(err); ++ a->mvd_h_src_dir = d_inode(a->mvd_h_src_parent); ++ if (unlikely(err)) { ++ AU_MVD_PR(dmsg, "pin_src failed\n"); ++ au_pin_hdir_lock(&a->mvd_pin_dst); ++ goto out_dst; ++ } ++ au_pin_hdir_unlock(&a->mvd_pin_src); ++ h_trap = vfsub_lock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, ++ a->mvd_h_dst_parent, a->mvd_hdir_dst); ++ if (h_trap) { ++ err = (h_trap != a->mvd_h_src_parent); ++ if (err) ++ err = (h_trap != a->mvd_h_dst_parent); ++ } ++ BUG_ON(err); /* it should never happen */ ++ if (unlikely(a->mvd_h_src_dir != au_pinned_h_dir(&a->mvd_pin_src))) { ++ err = -EBUSY; ++ AuTraceErr(err); ++ vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, ++ a->mvd_h_dst_parent, a->mvd_hdir_dst); ++ au_pin_hdir_lock(&a->mvd_pin_src); ++ au_unpin(&a->mvd_pin_src); ++ au_pin_hdir_lock(&a->mvd_pin_dst); ++ goto out_dst; ++ } ++ goto out; /* success */ ++ ++out_dst: ++ au_unpin(&a->mvd_pin_dst); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static void au_do_unlock(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ if (!a->rename_lock) ++ au_unpin(&a->mvd_pin_src); ++ else { ++ vfsub_unlock_rename(a->mvd_h_src_parent, a->mvd_hdir_src, ++ a->mvd_h_dst_parent, a->mvd_hdir_dst); ++ au_pin_hdir_lock(&a->mvd_pin_src); ++ au_unpin(&a->mvd_pin_src); ++ au_pin_hdir_lock(&a->mvd_pin_dst); ++ } ++ au_unpin(&a->mvd_pin_dst); ++} ++ ++/* copy-down the file */ ++static int au_do_cpdown(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct au_cp_generic cpg = { ++ .dentry = a->dentry, ++ .bdst = a->mvd_bdst, ++ .bsrc = a->mvd_bsrc, ++ .len = -1, ++ .pin = &a->mvd_pin_dst, ++ .flags = AuCpup_DTIME | AuCpup_HOPEN ++ }; ++ ++ AuDbg("b%d, b%d\n", cpg.bsrc, cpg.bdst); ++ if (a->mvdown.flags & AUFS_MVDOWN_OWLOWER) ++ au_fset_cpup(cpg.flags, OVERWRITE); ++ if (a->mvdown.flags & AUFS_MVDOWN_ROLOWER) ++ au_fset_cpup(cpg.flags, RWDST); ++ err = au_sio_cpdown_simple(&cpg); ++ if (unlikely(err)) ++ AU_MVD_PR(dmsg, "cpdown failed\n"); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * unlink the whiteout on bdst if exist which may be created by UDBA while we ++ * were sleeping ++ */ ++static int au_do_unlink_wh(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct path h_path; ++ struct au_branch *br; ++ struct inode *delegated; ++ ++ br = au_sbr(a->sb, a->mvd_bdst); ++ h_path.dentry = au_wh_lkup(a->mvd_h_dst_parent, &a->dentry->d_name, br); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) { ++ AU_MVD_PR(dmsg, "wh_lkup failed\n"); ++ goto out; ++ } ++ ++ err = 0; ++ if (d_is_positive(h_path.dentry)) { ++ h_path.mnt = au_br_mnt(br); ++ delegated = NULL; ++ err = vfsub_unlink(d_inode(a->mvd_h_dst_parent), &h_path, ++ &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) ++ AU_MVD_PR(dmsg, "wh_unlink failed\n"); ++ } ++ dput(h_path.dentry); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ++ * unlink the topmost h_dentry ++ */ ++static int au_do_unlink(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct path h_path; ++ struct inode *delegated; ++ ++ h_path.mnt = au_sbr_mnt(a->sb, a->mvd_bsrc); ++ h_path.dentry = au_h_dptr(a->dentry, a->mvd_bsrc); ++ delegated = NULL; ++ err = vfsub_unlink(a->mvd_h_src_dir, &h_path, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) ++ AU_MVD_PR(dmsg, "unlink failed\n"); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++/* Since mvdown succeeded, we ignore an error of this function */ ++static void au_do_stfs(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct au_branch *br; ++ ++ a->mvdown.flags |= AUFS_MVDOWN_STFS_FAILED; ++ br = au_sbr(a->sb, a->mvd_bsrc); ++ err = au_br_stfs(br, &a->mvdown.stbr[AUFS_MVDOWN_UPPER].stfs); ++ if (!err) { ++ br = au_sbr(a->sb, a->mvd_bdst); ++ a->mvdown.stbr[AUFS_MVDOWN_LOWER].brid = br->br_id; ++ err = au_br_stfs(br, &a->mvdown.stbr[AUFS_MVDOWN_LOWER].stfs); ++ } ++ if (!err) ++ a->mvdown.flags &= ~AUFS_MVDOWN_STFS_FAILED; ++ else ++ AU_MVD_PR(dmsg, "statfs failed (%d), ignored\n", err); ++} ++ ++/* ++ * copy-down the file and unlink the bsrc file. ++ * - unlink the bdst whout if exist ++ * - copy-down the file (with whtmp name and rename) ++ * - unlink the bsrc file ++ */ ++static int au_do_mvdown(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ ++ err = au_do_mkdir(dmsg, a); ++ if (!err) ++ err = au_do_lock(dmsg, a); ++ if (unlikely(err)) ++ goto out; ++ ++ /* ++ * do not revert the activities we made on bdst since they should be ++ * harmless in aufs. ++ */ ++ ++ err = au_do_cpdown(dmsg, a); ++ if (!err) ++ err = au_do_unlink_wh(dmsg, a); ++ if (!err && !(a->mvdown.flags & AUFS_MVDOWN_KUPPER)) ++ err = au_do_unlink(dmsg, a); ++ if (unlikely(err)) ++ goto out_unlock; ++ ++ AuDbg("%pd2, 0x%x, %d --> %d\n", ++ a->dentry, a->mvdown.flags, a->mvd_bsrc, a->mvd_bdst); ++ if (find_lower_writable(a) < 0) ++ a->mvdown.flags |= AUFS_MVDOWN_BOTTOM; ++ ++ if (a->mvdown.flags & AUFS_MVDOWN_STFS) ++ au_do_stfs(dmsg, a); ++ ++ /* maintain internal array */ ++ if (!(a->mvdown.flags & AUFS_MVDOWN_KUPPER)) { ++ au_set_h_dptr(a->dentry, a->mvd_bsrc, NULL); ++ au_set_dbtop(a->dentry, a->mvd_bdst); ++ au_set_h_iptr(a->inode, a->mvd_bsrc, NULL, /*flags*/0); ++ au_set_ibtop(a->inode, a->mvd_bdst); ++ } else { ++ /* hide the lower */ ++ au_set_h_dptr(a->dentry, a->mvd_bdst, NULL); ++ au_set_dbbot(a->dentry, a->mvd_bsrc); ++ au_set_h_iptr(a->inode, a->mvd_bdst, NULL, /*flags*/0); ++ au_set_ibbot(a->inode, a->mvd_bsrc); ++ } ++ if (au_dbbot(a->dentry) < a->mvd_bdst) ++ au_set_dbbot(a->dentry, a->mvd_bdst); ++ if (au_ibbot(a->inode) < a->mvd_bdst) ++ au_set_ibbot(a->inode, a->mvd_bdst); ++ ++out_unlock: ++ au_do_unlock(dmsg, a); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* make sure the file is idle */ ++static int au_mvd_args_busy(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err, plinked; ++ ++ err = 0; ++ plinked = !!au_opt_test(au_mntflags(a->sb), PLINK); ++ if (au_dbtop(a->dentry) == a->mvd_bsrc ++ && au_dcount(a->dentry) == 1 ++ && atomic_read(&a->inode->i_count) == 1 ++ /* && a->mvd_h_src_inode->i_nlink == 1 */ ++ && (!plinked || !au_plink_test(a->inode)) ++ && a->inode->i_nlink == 1) ++ goto out; ++ ++ err = -EBUSY; ++ AU_MVD_PR(dmsg, ++ "b%d, d{b%d, c%d?}, i{c%d?, l%u}, hi{l%u}, p{%d, %d}\n", ++ a->mvd_bsrc, au_dbtop(a->dentry), au_dcount(a->dentry), ++ atomic_read(&a->inode->i_count), a->inode->i_nlink, ++ a->mvd_h_src_inode->i_nlink, ++ plinked, plinked ? au_plink_test(a->inode) : 0); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* make sure the parent dir is fine */ ++static int au_mvd_args_parent(const unsigned char dmsg, ++ struct au_mvd_args *a) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ ++ err = 0; ++ if (unlikely(au_alive_dir(a->parent))) { ++ err = -ENOENT; ++ AU_MVD_PR(dmsg, "parent dir is dead\n"); ++ goto out; ++ } ++ ++ a->bopq = au_dbdiropq(a->parent); ++ bindex = au_wbr_nonopq(a->dentry, a->mvd_bdst); ++ AuDbg("b%d\n", bindex); ++ if (unlikely((bindex >= 0 && bindex < a->mvd_bdst) ++ || (a->bopq != -1 && a->bopq < a->mvd_bdst))) { ++ err = -EINVAL; ++ a->mvd_errno = EAU_MVDOWN_OPAQUE; ++ AU_MVD_PR(dmsg, "ancestor is opaque b%d, b%d\n", ++ a->bopq, a->mvd_bdst); ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_mvd_args_intermediate(const unsigned char dmsg, ++ struct au_mvd_args *a) ++{ ++ int err; ++ struct au_dinfo *dinfo, *tmp; ++ ++ /* lookup the next lower positive entry */ ++ err = -ENOMEM; ++ tmp = au_di_alloc(a->sb, AuLsc_DI_TMP); ++ if (unlikely(!tmp)) ++ goto out; ++ ++ a->bfound = -1; ++ a->bwh = -1; ++ dinfo = au_di(a->dentry); ++ au_di_cp(tmp, dinfo); ++ au_di_swap(tmp, dinfo); ++ ++ /* returns the number of positive dentries */ ++ err = au_lkup_dentry(a->dentry, a->mvd_bsrc + 1, ++ /* AuLkup_IGNORE_PERM */ 0); ++ if (!err) ++ a->bwh = au_dbwh(a->dentry); ++ else if (err > 0) ++ a->bfound = au_dbtop(a->dentry); ++ ++ au_di_swap(tmp, dinfo); ++ au_rw_write_unlock(&tmp->di_rwsem); ++ au_di_free(tmp); ++ if (unlikely(err < 0)) ++ AU_MVD_PR(dmsg, "failed look-up lower\n"); ++ ++ /* ++ * here, we have these cases. ++ * bfound == -1 ++ * no positive dentry under bsrc. there are more sub-cases. ++ * bwh < 0 ++ * there no whiteout, we can safely move-down. ++ * bwh <= bsrc ++ * impossible ++ * bsrc < bwh && bwh < bdst ++ * there is a whiteout on RO branch. cannot proceed. ++ * bwh == bdst ++ * there is a whiteout on the RW target branch. it should ++ * be removed. ++ * bdst < bwh ++ * there is a whiteout somewhere unrelated branch. ++ * -1 < bfound && bfound <= bsrc ++ * impossible. ++ * bfound < bdst ++ * found, but it is on RO branch between bsrc and bdst. cannot ++ * proceed. ++ * bfound == bdst ++ * found, replace it if AUFS_MVDOWN_FORCE is set. otherwise return ++ * error. ++ * bdst < bfound ++ * found, after we create the file on bdst, it will be hidden. ++ */ ++ ++ AuDebugOn(a->bfound == -1 ++ && a->bwh != -1 ++ && a->bwh <= a->mvd_bsrc); ++ AuDebugOn(-1 < a->bfound ++ && a->bfound <= a->mvd_bsrc); ++ ++ err = -EINVAL; ++ if (a->bfound == -1 ++ && a->mvd_bsrc < a->bwh ++ && a->bwh != -1 ++ && a->bwh < a->mvd_bdst) { ++ a->mvd_errno = EAU_MVDOWN_WHITEOUT; ++ AU_MVD_PR(dmsg, "bsrc %d, bdst %d, bfound %d, bwh %d\n", ++ a->mvd_bsrc, a->mvd_bdst, a->bfound, a->bwh); ++ goto out; ++ } else if (a->bfound != -1 && a->bfound < a->mvd_bdst) { ++ a->mvd_errno = EAU_MVDOWN_UPPER; ++ AU_MVD_PR(dmsg, "bdst %d, bfound %d\n", ++ a->mvd_bdst, a->bfound); ++ goto out; ++ } ++ ++ err = 0; /* success */ ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_mvd_args_exist(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ ++ err = 0; ++ if (!(a->mvdown.flags & AUFS_MVDOWN_OWLOWER) ++ && a->bfound == a->mvd_bdst) ++ err = -EEXIST; ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_mvd_args(const unsigned char dmsg, struct au_mvd_args *a) ++{ ++ int err; ++ struct au_branch *br; ++ ++ err = -EISDIR; ++ if (unlikely(S_ISDIR(a->inode->i_mode))) ++ goto out; ++ ++ err = -EINVAL; ++ if (!(a->mvdown.flags & AUFS_MVDOWN_BRID_UPPER)) ++ a->mvd_bsrc = au_ibtop(a->inode); ++ else { ++ a->mvd_bsrc = au_br_index(a->sb, a->mvd_src_brid); ++ if (unlikely(a->mvd_bsrc < 0 ++ || (a->mvd_bsrc < au_dbtop(a->dentry) ++ || au_dbbot(a->dentry) < a->mvd_bsrc ++ || !au_h_dptr(a->dentry, a->mvd_bsrc)) ++ || (a->mvd_bsrc < au_ibtop(a->inode) ++ || au_ibbot(a->inode) < a->mvd_bsrc ++ || !au_h_iptr(a->inode, a->mvd_bsrc)))) { ++ a->mvd_errno = EAU_MVDOWN_NOUPPER; ++ AU_MVD_PR(dmsg, "no upper\n"); ++ goto out; ++ } ++ } ++ if (unlikely(a->mvd_bsrc == au_sbbot(a->sb))) { ++ a->mvd_errno = EAU_MVDOWN_BOTTOM; ++ AU_MVD_PR(dmsg, "on the bottom\n"); ++ goto out; ++ } ++ a->mvd_h_src_inode = au_h_iptr(a->inode, a->mvd_bsrc); ++ br = au_sbr(a->sb, a->mvd_bsrc); ++ err = au_br_rdonly(br); ++ if (!(a->mvdown.flags & AUFS_MVDOWN_ROUPPER)) { ++ if (unlikely(err)) ++ goto out; ++ } else if (!(vfsub_native_ro(a->mvd_h_src_inode) ++ || IS_APPEND(a->mvd_h_src_inode))) { ++ if (err) ++ a->mvdown.flags |= AUFS_MVDOWN_ROUPPER_R; ++ /* go on */ ++ } else ++ goto out; ++ ++ err = -EINVAL; ++ if (!(a->mvdown.flags & AUFS_MVDOWN_BRID_LOWER)) { ++ a->mvd_bdst = find_lower_writable(a); ++ if (unlikely(a->mvd_bdst < 0)) { ++ a->mvd_errno = EAU_MVDOWN_BOTTOM; ++ AU_MVD_PR(dmsg, "no writable lower branch\n"); ++ goto out; ++ } ++ } else { ++ a->mvd_bdst = au_br_index(a->sb, a->mvd_dst_brid); ++ if (unlikely(a->mvd_bdst < 0 ++ || au_sbbot(a->sb) < a->mvd_bdst)) { ++ a->mvd_errno = EAU_MVDOWN_NOLOWERBR; ++ AU_MVD_PR(dmsg, "no lower brid\n"); ++ goto out; ++ } ++ } ++ ++ err = au_mvd_args_busy(dmsg, a); ++ if (!err) ++ err = au_mvd_args_parent(dmsg, a); ++ if (!err) ++ err = au_mvd_args_intermediate(dmsg, a); ++ if (!err) ++ err = au_mvd_args_exist(dmsg, a); ++ if (!err) ++ AuDbg("b%d, b%d\n", a->mvd_bsrc, a->mvd_bdst); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *uarg) ++{ ++ int err, e; ++ unsigned char dmsg; ++ struct au_mvd_args *args; ++ struct inode *inode; ++ ++ inode = d_inode(dentry); ++ err = -EPERM; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = -ENOMEM; ++ args = kmalloc(sizeof(*args), GFP_NOFS); ++ if (unlikely(!args)) ++ goto out; ++ ++ err = copy_from_user(&args->mvdown, uarg, sizeof(args->mvdown)); ++ if (!err) ++ /* VERIFY_WRITE */ ++ err = !access_ok(uarg, sizeof(*uarg)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out_free; ++ } ++ AuDbg("flags 0x%x\n", args->mvdown.flags); ++ args->mvdown.flags &= ~(AUFS_MVDOWN_ROLOWER_R | AUFS_MVDOWN_ROUPPER_R); ++ args->mvdown.au_errno = 0; ++ args->dentry = dentry; ++ args->inode = inode; ++ args->sb = dentry->d_sb; ++ ++ err = -ENOENT; ++ dmsg = !!(args->mvdown.flags & AUFS_MVDOWN_DMSG); ++ args->parent = dget_parent(dentry); ++ args->dir = d_inode(args->parent); ++ inode_lock_nested(args->dir, I_MUTEX_PARENT); ++ dput(args->parent); ++ if (unlikely(args->parent != dentry->d_parent)) { ++ AU_MVD_PR(dmsg, "parent dir is moved\n"); ++ goto out_dir; ++ } ++ ++ inode_lock_nested(inode, I_MUTEX_CHILD); ++ err = aufs_read_lock(dentry, AuLock_DW | AuLock_FLUSH | AuLock_NOPLMW); ++ if (unlikely(err)) ++ goto out_inode; ++ ++ di_write_lock_parent(args->parent); ++ err = au_mvd_args(dmsg, args); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ err = au_do_mvdown(dmsg, args); ++ if (unlikely(err)) ++ goto out_parent; ++ ++ au_cpup_attr_timesizes(args->dir); ++ au_cpup_attr_timesizes(inode); ++ if (!(args->mvdown.flags & AUFS_MVDOWN_KUPPER)) ++ au_cpup_igen(inode, au_h_iptr(inode, args->mvd_bdst)); ++ /* au_digen_dec(dentry); */ ++ ++out_parent: ++ di_write_unlock(args->parent); ++ aufs_read_unlock(dentry, AuLock_DW); ++out_inode: ++ inode_unlock(inode); ++out_dir: ++ inode_unlock(args->dir); ++out_free: ++ e = copy_to_user(uarg, &args->mvdown, sizeof(args->mvdown)); ++ if (unlikely(e)) ++ err = -EFAULT; ++ au_kfree_rcu(args); ++out: ++ AuTraceErr(err); ++ return err; ++} +diff --git a/fs/aufs/opts.c b/fs/aufs/opts.c +new file mode 100644 +index 000000000000..26ecf5604117 +--- /dev/null ++++ b/fs/aufs/opts.c +@@ -0,0 +1,1867 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * mount options/flags ++ */ ++ ++#include ++#include /* a distribution requires */ ++#include ++#include "aufs.h" ++ ++/* ---------------------------------------------------------------------- */ ++ ++enum { ++ Opt_br, ++ Opt_add, Opt_del, Opt_mod, Opt_append, Opt_prepend, ++ Opt_idel, Opt_imod, ++ Opt_dirwh, Opt_rdcache, Opt_rdblk, Opt_rdhash, ++ Opt_rdblk_def, Opt_rdhash_def, ++ Opt_xino, Opt_noxino, ++ Opt_trunc_xino, Opt_trunc_xino_v, Opt_notrunc_xino, ++ Opt_trunc_xino_path, Opt_itrunc_xino, ++ Opt_trunc_xib, Opt_notrunc_xib, ++ Opt_shwh, Opt_noshwh, ++ Opt_plink, Opt_noplink, Opt_list_plink, ++ Opt_udba, ++ Opt_dio, Opt_nodio, ++ Opt_diropq_a, Opt_diropq_w, ++ Opt_warn_perm, Opt_nowarn_perm, ++ Opt_wbr_copyup, Opt_wbr_create, ++ Opt_fhsm_sec, ++ Opt_verbose, Opt_noverbose, ++ Opt_sum, Opt_nosum, Opt_wsum, ++ Opt_dirperm1, Opt_nodirperm1, ++ Opt_dirren, Opt_nodirren, ++ Opt_acl, Opt_noacl, ++ Opt_tail, Opt_ignore, Opt_ignore_silent, Opt_err ++}; ++ ++static match_table_t options = { ++ {Opt_br, "br=%s"}, ++ {Opt_br, "br:%s"}, ++ ++ {Opt_add, "add=%d:%s"}, ++ {Opt_add, "add:%d:%s"}, ++ {Opt_add, "ins=%d:%s"}, ++ {Opt_add, "ins:%d:%s"}, ++ {Opt_append, "append=%s"}, ++ {Opt_append, "append:%s"}, ++ {Opt_prepend, "prepend=%s"}, ++ {Opt_prepend, "prepend:%s"}, ++ ++ {Opt_del, "del=%s"}, ++ {Opt_del, "del:%s"}, ++ /* {Opt_idel, "idel:%d"}, */ ++ {Opt_mod, "mod=%s"}, ++ {Opt_mod, "mod:%s"}, ++ /* {Opt_imod, "imod:%d:%s"}, */ ++ ++ {Opt_dirwh, "dirwh=%d"}, ++ ++ {Opt_xino, "xino=%s"}, ++ {Opt_noxino, "noxino"}, ++ {Opt_trunc_xino, "trunc_xino"}, ++ {Opt_trunc_xino_v, "trunc_xino_v=%d:%d"}, ++ {Opt_notrunc_xino, "notrunc_xino"}, ++ {Opt_trunc_xino_path, "trunc_xino=%s"}, ++ {Opt_itrunc_xino, "itrunc_xino=%d"}, ++ /* {Opt_zxino, "zxino=%s"}, */ ++ {Opt_trunc_xib, "trunc_xib"}, ++ {Opt_notrunc_xib, "notrunc_xib"}, ++ ++#ifdef CONFIG_PROC_FS ++ {Opt_plink, "plink"}, ++#else ++ {Opt_ignore_silent, "plink"}, ++#endif ++ ++ {Opt_noplink, "noplink"}, ++ ++#ifdef CONFIG_AUFS_DEBUG ++ {Opt_list_plink, "list_plink"}, ++#endif ++ ++ {Opt_udba, "udba=%s"}, ++ ++ {Opt_dio, "dio"}, ++ {Opt_nodio, "nodio"}, ++ ++#ifdef CONFIG_AUFS_DIRREN ++ {Opt_dirren, "dirren"}, ++ {Opt_nodirren, "nodirren"}, ++#else ++ {Opt_ignore, "dirren"}, ++ {Opt_ignore_silent, "nodirren"}, ++#endif ++ ++#ifdef CONFIG_AUFS_FHSM ++ {Opt_fhsm_sec, "fhsm_sec=%d"}, ++#else ++ {Opt_ignore, "fhsm_sec=%d"}, ++#endif ++ ++ {Opt_diropq_a, "diropq=always"}, ++ {Opt_diropq_a, "diropq=a"}, ++ {Opt_diropq_w, "diropq=whiteouted"}, ++ {Opt_diropq_w, "diropq=w"}, ++ ++ {Opt_warn_perm, "warn_perm"}, ++ {Opt_nowarn_perm, "nowarn_perm"}, ++ ++ /* keep them temporary */ ++ {Opt_ignore_silent, "nodlgt"}, ++ {Opt_ignore, "clean_plink"}, ++ ++#ifdef CONFIG_AUFS_SHWH ++ {Opt_shwh, "shwh"}, ++#endif ++ {Opt_noshwh, "noshwh"}, ++ ++ {Opt_dirperm1, "dirperm1"}, ++ {Opt_nodirperm1, "nodirperm1"}, ++ ++ {Opt_verbose, "verbose"}, ++ {Opt_verbose, "v"}, ++ {Opt_noverbose, "noverbose"}, ++ {Opt_noverbose, "quiet"}, ++ {Opt_noverbose, "q"}, ++ {Opt_noverbose, "silent"}, ++ ++ {Opt_sum, "sum"}, ++ {Opt_nosum, "nosum"}, ++ {Opt_wsum, "wsum"}, ++ ++ {Opt_rdcache, "rdcache=%d"}, ++ {Opt_rdblk, "rdblk=%d"}, ++ {Opt_rdblk_def, "rdblk=def"}, ++ {Opt_rdhash, "rdhash=%d"}, ++ {Opt_rdhash_def, "rdhash=def"}, ++ ++ {Opt_wbr_create, "create=%s"}, ++ {Opt_wbr_create, "create_policy=%s"}, ++ {Opt_wbr_copyup, "cpup=%s"}, ++ {Opt_wbr_copyup, "copyup=%s"}, ++ {Opt_wbr_copyup, "copyup_policy=%s"}, ++ ++ /* generic VFS flag */ ++#ifdef CONFIG_FS_POSIX_ACL ++ {Opt_acl, "acl"}, ++ {Opt_noacl, "noacl"}, ++#else ++ {Opt_ignore, "acl"}, ++ {Opt_ignore_silent, "noacl"}, ++#endif ++ ++ /* internal use for the scripts */ ++ {Opt_ignore_silent, "si=%s"}, ++ ++ {Opt_br, "dirs=%s"}, ++ {Opt_ignore, "debug=%d"}, ++ {Opt_ignore, "delete=whiteout"}, ++ {Opt_ignore, "delete=all"}, ++ {Opt_ignore, "imap=%s"}, ++ ++ /* temporary workaround, due to old mount(8)? */ ++ {Opt_ignore_silent, "relatime"}, ++ ++ {Opt_err, NULL} ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static const char *au_parser_pattern(int val, match_table_t tbl) ++{ ++ struct match_token *p; ++ ++ p = tbl; ++ while (p->pattern) { ++ if (p->token == val) ++ return p->pattern; ++ p++; ++ } ++ BUG(); ++ return "??"; ++} ++ ++static const char *au_optstr(int *val, match_table_t tbl) ++{ ++ struct match_token *p; ++ int v; ++ ++ v = *val; ++ if (!v) ++ goto out; ++ p = tbl; ++ while (p->pattern) { ++ if (p->token ++ && (v & p->token) == p->token) { ++ *val &= ~p->token; ++ return p->pattern; ++ } ++ p++; ++ } ++ ++out: ++ return NULL; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static match_table_t brperm = { ++ {AuBrPerm_RO, AUFS_BRPERM_RO}, ++ {AuBrPerm_RR, AUFS_BRPERM_RR}, ++ {AuBrPerm_RW, AUFS_BRPERM_RW}, ++ {0, NULL} ++}; ++ ++static match_table_t brattr = { ++ /* general */ ++ {AuBrAttr_COO_REG, AUFS_BRATTR_COO_REG}, ++ {AuBrAttr_COO_ALL, AUFS_BRATTR_COO_ALL}, ++ /* 'unpin' attrib is meaningless since linux-3.18-rc1 */ ++ {AuBrAttr_UNPIN, AUFS_BRATTR_UNPIN}, ++#ifdef CONFIG_AUFS_FHSM ++ {AuBrAttr_FHSM, AUFS_BRATTR_FHSM}, ++#endif ++#ifdef CONFIG_AUFS_XATTR ++ {AuBrAttr_ICEX, AUFS_BRATTR_ICEX}, ++ {AuBrAttr_ICEX_SEC, AUFS_BRATTR_ICEX_SEC}, ++ {AuBrAttr_ICEX_SYS, AUFS_BRATTR_ICEX_SYS}, ++ {AuBrAttr_ICEX_TR, AUFS_BRATTR_ICEX_TR}, ++ {AuBrAttr_ICEX_USR, AUFS_BRATTR_ICEX_USR}, ++ {AuBrAttr_ICEX_OTH, AUFS_BRATTR_ICEX_OTH}, ++#endif ++ ++ /* ro/rr branch */ ++ {AuBrRAttr_WH, AUFS_BRRATTR_WH}, ++ ++ /* rw branch */ ++ {AuBrWAttr_MOO, AUFS_BRWATTR_MOO}, ++ {AuBrWAttr_NoLinkWH, AUFS_BRWATTR_NLWH}, ++ ++ {0, NULL} ++}; ++ ++static int br_attr_val(char *str, match_table_t table, substring_t args[]) ++{ ++ int attr, v; ++ char *p; ++ ++ attr = 0; ++ do { ++ p = strchr(str, '+'); ++ if (p) ++ *p = 0; ++ v = match_token(str, table, args); ++ if (v) { ++ if (v & AuBrAttr_CMOO_Mask) ++ attr &= ~AuBrAttr_CMOO_Mask; ++ attr |= v; ++ } else { ++ if (p) ++ *p = '+'; ++ pr_warn("ignored branch attribute %s\n", str); ++ break; ++ } ++ if (p) ++ str = p + 1; ++ } while (p); ++ ++ return attr; ++} ++ ++static int au_do_optstr_br_attr(au_br_perm_str_t *str, int perm) ++{ ++ int sz; ++ const char *p; ++ char *q; ++ ++ q = str->a; ++ *q = 0; ++ p = au_optstr(&perm, brattr); ++ if (p) { ++ sz = strlen(p); ++ memcpy(q, p, sz + 1); ++ q += sz; ++ } else ++ goto out; ++ ++ do { ++ p = au_optstr(&perm, brattr); ++ if (p) { ++ *q++ = '+'; ++ sz = strlen(p); ++ memcpy(q, p, sz + 1); ++ q += sz; ++ } ++ } while (p); ++ ++out: ++ return q - str->a; ++} ++ ++static int noinline_for_stack br_perm_val(char *perm) ++{ ++ int val, bad, sz; ++ char *p; ++ substring_t args[MAX_OPT_ARGS]; ++ au_br_perm_str_t attr; ++ ++ p = strchr(perm, '+'); ++ if (p) ++ *p = 0; ++ val = match_token(perm, brperm, args); ++ if (!val) { ++ if (p) ++ *p = '+'; ++ pr_warn("ignored branch permission %s\n", perm); ++ val = AuBrPerm_RO; ++ goto out; ++ } ++ if (!p) ++ goto out; ++ ++ val |= br_attr_val(p + 1, brattr, args); ++ ++ bad = 0; ++ switch (val & AuBrPerm_Mask) { ++ case AuBrPerm_RO: ++ case AuBrPerm_RR: ++ bad = val & AuBrWAttr_Mask; ++ val &= ~AuBrWAttr_Mask; ++ break; ++ case AuBrPerm_RW: ++ bad = val & AuBrRAttr_Mask; ++ val &= ~AuBrRAttr_Mask; ++ break; ++ } ++ ++ /* ++ * 'unpin' attrib becomes meaningless since linux-3.18-rc1, but aufs ++ * does not treat it as an error, just warning. ++ * this is a tiny guard for the user operation. ++ */ ++ if (val & AuBrAttr_UNPIN) { ++ bad |= AuBrAttr_UNPIN; ++ val &= ~AuBrAttr_UNPIN; ++ } ++ ++ if (unlikely(bad)) { ++ sz = au_do_optstr_br_attr(&attr, bad); ++ AuDebugOn(!sz); ++ pr_warn("ignored branch attribute %s\n", attr.a); ++ } ++ ++out: ++ return val; ++} ++ ++void au_optstr_br_perm(au_br_perm_str_t *str, int perm) ++{ ++ au_br_perm_str_t attr; ++ const char *p; ++ char *q; ++ int sz; ++ ++ q = str->a; ++ p = au_optstr(&perm, brperm); ++ AuDebugOn(!p || !*p); ++ sz = strlen(p); ++ memcpy(q, p, sz + 1); ++ q += sz; ++ ++ sz = au_do_optstr_br_attr(&attr, perm); ++ if (sz) { ++ *q++ = '+'; ++ memcpy(q, attr.a, sz + 1); ++ } ++ ++ AuDebugOn(strlen(str->a) >= sizeof(str->a)); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static match_table_t udbalevel = { ++ {AuOpt_UDBA_REVAL, "reval"}, ++ {AuOpt_UDBA_NONE, "none"}, ++#ifdef CONFIG_AUFS_HNOTIFY ++ {AuOpt_UDBA_HNOTIFY, "notify"}, /* abstraction */ ++#ifdef CONFIG_AUFS_HFSNOTIFY ++ {AuOpt_UDBA_HNOTIFY, "fsnotify"}, ++#endif ++#endif ++ {-1, NULL} ++}; ++ ++static int noinline_for_stack udba_val(char *str) ++{ ++ substring_t args[MAX_OPT_ARGS]; ++ ++ return match_token(str, udbalevel, args); ++} ++ ++const char *au_optstr_udba(int udba) ++{ ++ return au_parser_pattern(udba, udbalevel); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static match_table_t au_wbr_create_policy = { ++ {AuWbrCreate_TDP, "tdp"}, ++ {AuWbrCreate_TDP, "top-down-parent"}, ++ {AuWbrCreate_RR, "rr"}, ++ {AuWbrCreate_RR, "round-robin"}, ++ {AuWbrCreate_MFS, "mfs"}, ++ {AuWbrCreate_MFS, "most-free-space"}, ++ {AuWbrCreate_MFSV, "mfs:%d"}, ++ {AuWbrCreate_MFSV, "most-free-space:%d"}, ++ ++ /* top-down regardless the parent, and then mfs */ ++ {AuWbrCreate_TDMFS, "tdmfs:%d"}, ++ {AuWbrCreate_TDMFSV, "tdmfs:%d:%d"}, ++ ++ {AuWbrCreate_MFSRR, "mfsrr:%d"}, ++ {AuWbrCreate_MFSRRV, "mfsrr:%d:%d"}, ++ {AuWbrCreate_PMFS, "pmfs"}, ++ {AuWbrCreate_PMFSV, "pmfs:%d"}, ++ {AuWbrCreate_PMFSRR, "pmfsrr:%d"}, ++ {AuWbrCreate_PMFSRRV, "pmfsrr:%d:%d"}, ++ ++ {-1, NULL} ++}; ++ ++static int au_wbr_mfs_wmark(substring_t *arg, char *str, ++ struct au_opt_wbr_create *create) ++{ ++ int err; ++ unsigned long long ull; ++ ++ err = 0; ++ if (!match_u64(arg, &ull)) ++ create->mfsrr_watermark = ull; ++ else { ++ pr_err("bad integer in %s\n", str); ++ err = -EINVAL; ++ } ++ ++ return err; ++} ++ ++static int au_wbr_mfs_sec(substring_t *arg, char *str, ++ struct au_opt_wbr_create *create) ++{ ++ int n, err; ++ ++ err = 0; ++ if (!match_int(arg, &n) && 0 <= n && n <= AUFS_MFS_MAX_SEC) ++ create->mfs_second = n; ++ else { ++ pr_err("bad integer in %s\n", str); ++ err = -EINVAL; ++ } ++ ++ return err; ++} ++ ++static int noinline_for_stack ++au_wbr_create_val(char *str, struct au_opt_wbr_create *create) ++{ ++ int err, e; ++ substring_t args[MAX_OPT_ARGS]; ++ ++ err = match_token(str, au_wbr_create_policy, args); ++ create->wbr_create = err; ++ switch (err) { ++ case AuWbrCreate_MFSRRV: ++ case AuWbrCreate_TDMFSV: ++ case AuWbrCreate_PMFSRRV: ++ e = au_wbr_mfs_wmark(&args[0], str, create); ++ if (!e) ++ e = au_wbr_mfs_sec(&args[1], str, create); ++ if (unlikely(e)) ++ err = e; ++ break; ++ case AuWbrCreate_MFSRR: ++ case AuWbrCreate_TDMFS: ++ case AuWbrCreate_PMFSRR: ++ e = au_wbr_mfs_wmark(&args[0], str, create); ++ if (unlikely(e)) { ++ err = e; ++ break; ++ } ++ fallthrough; ++ case AuWbrCreate_MFS: ++ case AuWbrCreate_PMFS: ++ create->mfs_second = AUFS_MFS_DEF_SEC; ++ break; ++ case AuWbrCreate_MFSV: ++ case AuWbrCreate_PMFSV: ++ e = au_wbr_mfs_sec(&args[0], str, create); ++ if (unlikely(e)) ++ err = e; ++ break; ++ } ++ ++ return err; ++} ++ ++const char *au_optstr_wbr_create(int wbr_create) ++{ ++ return au_parser_pattern(wbr_create, au_wbr_create_policy); ++} ++ ++static match_table_t au_wbr_copyup_policy = { ++ {AuWbrCopyup_TDP, "tdp"}, ++ {AuWbrCopyup_TDP, "top-down-parent"}, ++ {AuWbrCopyup_BUP, "bup"}, ++ {AuWbrCopyup_BUP, "bottom-up-parent"}, ++ {AuWbrCopyup_BU, "bu"}, ++ {AuWbrCopyup_BU, "bottom-up"}, ++ {-1, NULL} ++}; ++ ++static int noinline_for_stack au_wbr_copyup_val(char *str) ++{ ++ substring_t args[MAX_OPT_ARGS]; ++ ++ return match_token(str, au_wbr_copyup_policy, args); ++} ++ ++const char *au_optstr_wbr_copyup(int wbr_copyup) ++{ ++ return au_parser_pattern(wbr_copyup, au_wbr_copyup_policy); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static const int lkup_dirflags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY; ++ ++static void dump_opts(struct au_opts *opts) ++{ ++#ifdef CONFIG_AUFS_DEBUG ++ /* reduce stack space */ ++ union { ++ struct au_opt_add *add; ++ struct au_opt_del *del; ++ struct au_opt_mod *mod; ++ struct au_opt_xino *xino; ++ struct au_opt_xino_itrunc *xino_itrunc; ++ struct au_opt_wbr_create *create; ++ } u; ++ struct au_opt *opt; ++ ++ opt = opts->opt; ++ while (opt->type != Opt_tail) { ++ switch (opt->type) { ++ case Opt_add: ++ u.add = &opt->add; ++ AuDbg("add {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->pathname, u.add->perm, ++ u.add->path.dentry); ++ break; ++ case Opt_del: ++ case Opt_idel: ++ u.del = &opt->del; ++ AuDbg("del {%s, %p}\n", ++ u.del->pathname, u.del->h_path.dentry); ++ break; ++ case Opt_mod: ++ case Opt_imod: ++ u.mod = &opt->mod; ++ AuDbg("mod {%s, 0x%x, %p}\n", ++ u.mod->path, u.mod->perm, u.mod->h_root); ++ break; ++ case Opt_append: ++ u.add = &opt->add; ++ AuDbg("append {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->pathname, u.add->perm, ++ u.add->path.dentry); ++ break; ++ case Opt_prepend: ++ u.add = &opt->add; ++ AuDbg("prepend {b%d, %s, 0x%x, %p}\n", ++ u.add->bindex, u.add->pathname, u.add->perm, ++ u.add->path.dentry); ++ break; ++ case Opt_dirwh: ++ AuDbg("dirwh %d\n", opt->dirwh); ++ break; ++ case Opt_rdcache: ++ AuDbg("rdcache %d\n", opt->rdcache); ++ break; ++ case Opt_rdblk: ++ AuDbg("rdblk %u\n", opt->rdblk); ++ break; ++ case Opt_rdblk_def: ++ AuDbg("rdblk_def\n"); ++ break; ++ case Opt_rdhash: ++ AuDbg("rdhash %u\n", opt->rdhash); ++ break; ++ case Opt_rdhash_def: ++ AuDbg("rdhash_def\n"); ++ break; ++ case Opt_xino: ++ u.xino = &opt->xino; ++ AuDbg("xino {%s %pD}\n", u.xino->path, u.xino->file); ++ break; ++ case Opt_trunc_xino: ++ AuLabel(trunc_xino); ++ break; ++ case Opt_notrunc_xino: ++ AuLabel(notrunc_xino); ++ break; ++ case Opt_trunc_xino_path: ++ case Opt_itrunc_xino: ++ u.xino_itrunc = &opt->xino_itrunc; ++ AuDbg("trunc_xino %d\n", u.xino_itrunc->bindex); ++ break; ++ case Opt_noxino: ++ AuLabel(noxino); ++ break; ++ case Opt_trunc_xib: ++ AuLabel(trunc_xib); ++ break; ++ case Opt_notrunc_xib: ++ AuLabel(notrunc_xib); ++ break; ++ case Opt_shwh: ++ AuLabel(shwh); ++ break; ++ case Opt_noshwh: ++ AuLabel(noshwh); ++ break; ++ case Opt_dirperm1: ++ AuLabel(dirperm1); ++ break; ++ case Opt_nodirperm1: ++ AuLabel(nodirperm1); ++ break; ++ case Opt_plink: ++ AuLabel(plink); ++ break; ++ case Opt_noplink: ++ AuLabel(noplink); ++ break; ++ case Opt_list_plink: ++ AuLabel(list_plink); ++ break; ++ case Opt_udba: ++ AuDbg("udba %d, %s\n", ++ opt->udba, au_optstr_udba(opt->udba)); ++ break; ++ case Opt_dio: ++ AuLabel(dio); ++ break; ++ case Opt_nodio: ++ AuLabel(nodio); ++ break; ++ case Opt_diropq_a: ++ AuLabel(diropq_a); ++ break; ++ case Opt_diropq_w: ++ AuLabel(diropq_w); ++ break; ++ case Opt_warn_perm: ++ AuLabel(warn_perm); ++ break; ++ case Opt_nowarn_perm: ++ AuLabel(nowarn_perm); ++ break; ++ case Opt_verbose: ++ AuLabel(verbose); ++ break; ++ case Opt_noverbose: ++ AuLabel(noverbose); ++ break; ++ case Opt_sum: ++ AuLabel(sum); ++ break; ++ case Opt_nosum: ++ AuLabel(nosum); ++ break; ++ case Opt_wsum: ++ AuLabel(wsum); ++ break; ++ case Opt_wbr_create: ++ u.create = &opt->wbr_create; ++ AuDbg("create %d, %s\n", u.create->wbr_create, ++ au_optstr_wbr_create(u.create->wbr_create)); ++ switch (u.create->wbr_create) { ++ case AuWbrCreate_MFSV: ++ case AuWbrCreate_PMFSV: ++ AuDbg("%d sec\n", u.create->mfs_second); ++ break; ++ case AuWbrCreate_MFSRR: ++ case AuWbrCreate_TDMFS: ++ AuDbg("%llu watermark\n", ++ u.create->mfsrr_watermark); ++ break; ++ case AuWbrCreate_MFSRRV: ++ case AuWbrCreate_TDMFSV: ++ case AuWbrCreate_PMFSRRV: ++ AuDbg("%llu watermark, %d sec\n", ++ u.create->mfsrr_watermark, ++ u.create->mfs_second); ++ break; ++ } ++ break; ++ case Opt_wbr_copyup: ++ AuDbg("copyup %d, %s\n", opt->wbr_copyup, ++ au_optstr_wbr_copyup(opt->wbr_copyup)); ++ break; ++ case Opt_fhsm_sec: ++ AuDbg("fhsm_sec %u\n", opt->fhsm_second); ++ break; ++ case Opt_dirren: ++ AuLabel(dirren); ++ break; ++ case Opt_nodirren: ++ AuLabel(nodirren); ++ break; ++ case Opt_acl: ++ AuLabel(acl); ++ break; ++ case Opt_noacl: ++ AuLabel(noacl); ++ break; ++ default: ++ BUG(); ++ } ++ opt++; ++ } ++#endif ++} ++ ++void au_opts_free(struct au_opts *opts) ++{ ++ struct au_opt *opt; ++ ++ opt = opts->opt; ++ while (opt->type != Opt_tail) { ++ switch (opt->type) { ++ case Opt_add: ++ case Opt_append: ++ case Opt_prepend: ++ path_put(&opt->add.path); ++ break; ++ case Opt_del: ++ case Opt_idel: ++ path_put(&opt->del.h_path); ++ break; ++ case Opt_mod: ++ case Opt_imod: ++ dput(opt->mod.h_root); ++ break; ++ case Opt_xino: ++ fput(opt->xino.file); ++ break; ++ } ++ opt++; ++ } ++} ++ ++static int opt_add(struct au_opt *opt, char *opt_str, unsigned long sb_flags, ++ aufs_bindex_t bindex) ++{ ++ int err; ++ struct au_opt_add *add = &opt->add; ++ char *p; ++ ++ add->bindex = bindex; ++ add->perm = AuBrPerm_RO; ++ add->pathname = opt_str; ++ p = strchr(opt_str, '='); ++ if (p) { ++ *p++ = 0; ++ if (*p) ++ add->perm = br_perm_val(p); ++ } ++ ++ err = vfsub_kern_path(add->pathname, lkup_dirflags, &add->path); ++ if (!err) { ++ if (!p) { ++ add->perm = AuBrPerm_RO; ++ if (au_test_fs_rr(add->path.dentry->d_sb)) ++ add->perm = AuBrPerm_RR; ++ else if (!bindex && !(sb_flags & SB_RDONLY)) ++ add->perm = AuBrPerm_RW; ++ } ++ opt->type = Opt_add; ++ goto out; ++ } ++ pr_err("lookup failed %s (%d)\n", add->pathname, err); ++ err = -EINVAL; ++ ++out: ++ return err; ++} ++ ++static int au_opts_parse_del(struct au_opt_del *del, substring_t args[]) ++{ ++ int err; ++ ++ del->pathname = args[0].from; ++ AuDbg("del path %s\n", del->pathname); ++ ++ err = vfsub_kern_path(del->pathname, lkup_dirflags, &del->h_path); ++ if (unlikely(err)) ++ pr_err("lookup failed %s (%d)\n", del->pathname, err); ++ ++ return err; ++} ++ ++#if 0 /* reserved for future use */ ++static int au_opts_parse_idel(struct super_block *sb, aufs_bindex_t bindex, ++ struct au_opt_del *del, substring_t args[]) ++{ ++ int err; ++ struct dentry *root; ++ ++ err = -EINVAL; ++ root = sb->s_root; ++ aufs_read_lock(root, AuLock_FLUSH); ++ if (bindex < 0 || au_sbbot(sb) < bindex) { ++ pr_err("out of bounds, %d\n", bindex); ++ goto out; ++ } ++ ++ err = 0; ++ del->h_path.dentry = dget(au_h_dptr(root, bindex)); ++ del->h_path.mnt = mntget(au_sbr_mnt(sb, bindex)); ++ ++out: ++ aufs_read_unlock(root, !AuLock_IR); ++ return err; ++} ++#endif ++ ++static int noinline_for_stack ++au_opts_parse_mod(struct au_opt_mod *mod, substring_t args[]) ++{ ++ int err; ++ struct path path; ++ char *p; ++ ++ err = -EINVAL; ++ mod->path = args[0].from; ++ p = strchr(mod->path, '='); ++ if (unlikely(!p)) { ++ pr_err("no permission %s\n", args[0].from); ++ goto out; ++ } ++ ++ *p++ = 0; ++ err = vfsub_kern_path(mod->path, lkup_dirflags, &path); ++ if (unlikely(err)) { ++ pr_err("lookup failed %s (%d)\n", mod->path, err); ++ goto out; ++ } ++ ++ mod->perm = br_perm_val(p); ++ AuDbg("mod path %s, perm 0x%x, %s\n", mod->path, mod->perm, p); ++ mod->h_root = dget(path.dentry); ++ path_put(&path); ++ ++out: ++ return err; ++} ++ ++#if 0 /* reserved for future use */ ++static int au_opts_parse_imod(struct super_block *sb, aufs_bindex_t bindex, ++ struct au_opt_mod *mod, substring_t args[]) ++{ ++ int err; ++ struct dentry *root; ++ ++ err = -EINVAL; ++ root = sb->s_root; ++ aufs_read_lock(root, AuLock_FLUSH); ++ if (bindex < 0 || au_sbbot(sb) < bindex) { ++ pr_err("out of bounds, %d\n", bindex); ++ goto out; ++ } ++ ++ err = 0; ++ mod->perm = br_perm_val(args[1].from); ++ AuDbg("mod path %s, perm 0x%x, %s\n", ++ mod->path, mod->perm, args[1].from); ++ mod->h_root = dget(au_h_dptr(root, bindex)); ++ ++out: ++ aufs_read_unlock(root, !AuLock_IR); ++ return err; ++} ++#endif ++ ++static int au_opts_parse_xino(struct super_block *sb, struct au_opt_xino *xino, ++ substring_t args[]) ++{ ++ int err; ++ struct file *file; ++ ++ file = au_xino_create(sb, args[0].from, /*silent*/0, /*wbrtop*/0); ++ err = PTR_ERR(file); ++ if (IS_ERR(file)) ++ goto out; ++ ++ err = -EINVAL; ++ if (unlikely(file->f_path.dentry->d_sb == sb)) { ++ fput(file); ++ pr_err("%s must be outside\n", args[0].from); ++ goto out; ++ } ++ ++ err = 0; ++ xino->file = file; ++ xino->path = args[0].from; ++ ++out: ++ return err; ++} ++ ++static int noinline_for_stack ++au_opts_parse_xino_itrunc_path(struct super_block *sb, ++ struct au_opt_xino_itrunc *xino_itrunc, ++ substring_t args[]) ++{ ++ int err; ++ aufs_bindex_t bbot, bindex; ++ struct path path; ++ struct dentry *root; ++ ++ err = vfsub_kern_path(args[0].from, lkup_dirflags, &path); ++ if (unlikely(err)) { ++ pr_err("lookup failed %s (%d)\n", args[0].from, err); ++ goto out; ++ } ++ ++ xino_itrunc->bindex = -1; ++ root = sb->s_root; ++ aufs_read_lock(root, AuLock_FLUSH); ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ if (au_h_dptr(root, bindex) == path.dentry) { ++ xino_itrunc->bindex = bindex; ++ break; ++ } ++ } ++ aufs_read_unlock(root, !AuLock_IR); ++ path_put(&path); ++ ++ if (unlikely(xino_itrunc->bindex < 0)) { ++ pr_err("no such branch %s\n", args[0].from); ++ err = -EINVAL; ++ } ++ ++out: ++ return err; ++} ++ ++/* called without aufs lock */ ++int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts) ++{ ++ int err, n, token; ++ aufs_bindex_t bindex; ++ unsigned char skipped; ++ struct dentry *root; ++ struct au_opt *opt, *opt_tail; ++ char *opt_str; ++ /* reduce the stack space */ ++ union { ++ struct au_opt_xino_itrunc *xino_itrunc; ++ struct au_opt_wbr_create *create; ++ } u; ++ struct { ++ substring_t args[MAX_OPT_ARGS]; ++ } *a; ++ ++ err = -ENOMEM; ++ a = kmalloc(sizeof(*a), GFP_NOFS); ++ if (unlikely(!a)) ++ goto out; ++ ++ root = sb->s_root; ++ err = 0; ++ bindex = 0; ++ opt = opts->opt; ++ opt_tail = opt + opts->max_opt - 1; ++ opt->type = Opt_tail; ++ while (!err && (opt_str = strsep(&str, ",")) && *opt_str) { ++ err = -EINVAL; ++ skipped = 0; ++ token = match_token(opt_str, options, a->args); ++ switch (token) { ++ case Opt_br: ++ err = 0; ++ while (!err && (opt_str = strsep(&a->args[0].from, ":")) ++ && *opt_str) { ++ err = opt_add(opt, opt_str, opts->sb_flags, ++ bindex++); ++ if (unlikely(!err && ++opt > opt_tail)) { ++ err = -E2BIG; ++ break; ++ } ++ opt->type = Opt_tail; ++ skipped = 1; ++ } ++ break; ++ case Opt_add: ++ if (unlikely(match_int(&a->args[0], &n))) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ bindex = n; ++ err = opt_add(opt, a->args[1].from, opts->sb_flags, ++ bindex); ++ if (!err) ++ opt->type = token; ++ break; ++ case Opt_append: ++ err = opt_add(opt, a->args[0].from, opts->sb_flags, ++ /*dummy bindex*/1); ++ if (!err) ++ opt->type = token; ++ break; ++ case Opt_prepend: ++ err = opt_add(opt, a->args[0].from, opts->sb_flags, ++ /*bindex*/0); ++ if (!err) ++ opt->type = token; ++ break; ++ case Opt_del: ++ err = au_opts_parse_del(&opt->del, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++#if 0 /* reserved for future use */ ++ case Opt_idel: ++ del->pathname = "(indexed)"; ++ if (unlikely(match_int(&args[0], &n))) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ err = au_opts_parse_idel(sb, n, &opt->del, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++#endif ++ case Opt_mod: ++ err = au_opts_parse_mod(&opt->mod, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++#ifdef IMOD /* reserved for future use */ ++ case Opt_imod: ++ u.mod->path = "(indexed)"; ++ if (unlikely(match_int(&a->args[0], &n))) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ err = au_opts_parse_imod(sb, n, &opt->mod, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++#endif ++ case Opt_xino: ++ err = au_opts_parse_xino(sb, &opt->xino, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++ ++ case Opt_trunc_xino_path: ++ err = au_opts_parse_xino_itrunc_path ++ (sb, &opt->xino_itrunc, a->args); ++ if (!err) ++ opt->type = token; ++ break; ++ ++ case Opt_itrunc_xino: ++ u.xino_itrunc = &opt->xino_itrunc; ++ if (unlikely(match_int(&a->args[0], &n))) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ u.xino_itrunc->bindex = n; ++ aufs_read_lock(root, AuLock_FLUSH); ++ if (n < 0 || au_sbbot(sb) < n) { ++ pr_err("out of bounds, %d\n", n); ++ aufs_read_unlock(root, !AuLock_IR); ++ break; ++ } ++ aufs_read_unlock(root, !AuLock_IR); ++ err = 0; ++ opt->type = token; ++ break; ++ ++ case Opt_dirwh: ++ if (unlikely(match_int(&a->args[0], &opt->dirwh))) ++ break; ++ err = 0; ++ opt->type = token; ++ break; ++ ++ case Opt_rdcache: ++ if (unlikely(match_int(&a->args[0], &n))) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ if (unlikely(n > AUFS_RDCACHE_MAX)) { ++ pr_err("rdcache must be smaller than %d\n", ++ AUFS_RDCACHE_MAX); ++ break; ++ } ++ opt->rdcache = n; ++ err = 0; ++ opt->type = token; ++ break; ++ case Opt_rdblk: ++ if (unlikely(match_int(&a->args[0], &n) ++ || n < 0 ++ || n > KMALLOC_MAX_SIZE)) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ if (unlikely(n && n < NAME_MAX)) { ++ pr_err("rdblk must be larger than %d\n", ++ NAME_MAX); ++ break; ++ } ++ opt->rdblk = n; ++ err = 0; ++ opt->type = token; ++ break; ++ case Opt_rdhash: ++ if (unlikely(match_int(&a->args[0], &n) ++ || n < 0 ++ || n * sizeof(struct hlist_head) ++ > KMALLOC_MAX_SIZE)) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ opt->rdhash = n; ++ err = 0; ++ opt->type = token; ++ break; ++ ++ case Opt_trunc_xino: ++ case Opt_notrunc_xino: ++ case Opt_noxino: ++ case Opt_trunc_xib: ++ case Opt_notrunc_xib: ++ case Opt_shwh: ++ case Opt_noshwh: ++ case Opt_dirperm1: ++ case Opt_nodirperm1: ++ case Opt_plink: ++ case Opt_noplink: ++ case Opt_list_plink: ++ case Opt_dio: ++ case Opt_nodio: ++ case Opt_diropq_a: ++ case Opt_diropq_w: ++ case Opt_warn_perm: ++ case Opt_nowarn_perm: ++ case Opt_verbose: ++ case Opt_noverbose: ++ case Opt_sum: ++ case Opt_nosum: ++ case Opt_wsum: ++ case Opt_rdblk_def: ++ case Opt_rdhash_def: ++ case Opt_dirren: ++ case Opt_nodirren: ++ case Opt_acl: ++ case Opt_noacl: ++ err = 0; ++ opt->type = token; ++ break; ++ ++ case Opt_udba: ++ opt->udba = udba_val(a->args[0].from); ++ if (opt->udba >= 0) { ++ err = 0; ++ opt->type = token; ++ } else ++ pr_err("wrong value, %s\n", opt_str); ++ break; ++ ++ case Opt_wbr_create: ++ u.create = &opt->wbr_create; ++ u.create->wbr_create ++ = au_wbr_create_val(a->args[0].from, u.create); ++ if (u.create->wbr_create >= 0) { ++ err = 0; ++ opt->type = token; ++ } else ++ pr_err("wrong value, %s\n", opt_str); ++ break; ++ case Opt_wbr_copyup: ++ opt->wbr_copyup = au_wbr_copyup_val(a->args[0].from); ++ if (opt->wbr_copyup >= 0) { ++ err = 0; ++ opt->type = token; ++ } else ++ pr_err("wrong value, %s\n", opt_str); ++ break; ++ ++ case Opt_fhsm_sec: ++ if (unlikely(match_int(&a->args[0], &n) ++ || n < 0)) { ++ pr_err("bad integer in %s\n", opt_str); ++ break; ++ } ++ if (sysaufs_brs) { ++ opt->fhsm_second = n; ++ opt->type = token; ++ } else ++ pr_warn("ignored %s\n", opt_str); ++ err = 0; ++ break; ++ ++ case Opt_ignore: ++ pr_warn("ignored %s\n", opt_str); ++ fallthrough; ++ case Opt_ignore_silent: ++ skipped = 1; ++ err = 0; ++ break; ++ case Opt_err: ++ pr_err("unknown option %s\n", opt_str); ++ break; ++ } ++ ++ if (!err && !skipped) { ++ if (unlikely(++opt > opt_tail)) { ++ err = -E2BIG; ++ opt--; ++ opt->type = Opt_tail; ++ break; ++ } ++ opt->type = Opt_tail; ++ } ++ } ++ ++ au_kfree_rcu(a); ++ dump_opts(opts); ++ if (unlikely(err)) ++ au_opts_free(opts); ++ ++out: ++ return err; ++} ++ ++static int au_opt_wbr_create(struct super_block *sb, ++ struct au_opt_wbr_create *create) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ err = 1; /* handled */ ++ sbinfo = au_sbi(sb); ++ if (sbinfo->si_wbr_create_ops->fin) { ++ err = sbinfo->si_wbr_create_ops->fin(sb); ++ if (!err) ++ err = 1; ++ } ++ ++ sbinfo->si_wbr_create = create->wbr_create; ++ sbinfo->si_wbr_create_ops = au_wbr_create_ops + create->wbr_create; ++ switch (create->wbr_create) { ++ case AuWbrCreate_MFSRRV: ++ case AuWbrCreate_MFSRR: ++ case AuWbrCreate_TDMFS: ++ case AuWbrCreate_TDMFSV: ++ case AuWbrCreate_PMFSRR: ++ case AuWbrCreate_PMFSRRV: ++ sbinfo->si_wbr_mfs.mfsrr_watermark = create->mfsrr_watermark; ++ fallthrough; ++ case AuWbrCreate_MFS: ++ case AuWbrCreate_MFSV: ++ case AuWbrCreate_PMFS: ++ case AuWbrCreate_PMFSV: ++ sbinfo->si_wbr_mfs.mfs_expire ++ = msecs_to_jiffies(create->mfs_second * MSEC_PER_SEC); ++ break; ++ } ++ ++ if (sbinfo->si_wbr_create_ops->init) ++ sbinfo->si_wbr_create_ops->init(sb); /* ignore */ ++ ++ return err; ++} ++ ++/* ++ * returns, ++ * plus: processed without an error ++ * zero: unprocessed ++ */ ++static int au_opt_simple(struct super_block *sb, struct au_opt *opt, ++ struct au_opts *opts) ++{ ++ int err; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ err = 1; /* handled */ ++ sbinfo = au_sbi(sb); ++ switch (opt->type) { ++ case Opt_udba: ++ sbinfo->si_mntflags &= ~AuOptMask_UDBA; ++ sbinfo->si_mntflags |= opt->udba; ++ opts->given_udba |= opt->udba; ++ break; ++ ++ case Opt_plink: ++ au_opt_set(sbinfo->si_mntflags, PLINK); ++ break; ++ case Opt_noplink: ++ if (au_opt_test(sbinfo->si_mntflags, PLINK)) ++ au_plink_put(sb, /*verbose*/1); ++ au_opt_clr(sbinfo->si_mntflags, PLINK); ++ break; ++ case Opt_list_plink: ++ if (au_opt_test(sbinfo->si_mntflags, PLINK)) ++ au_plink_list(sb); ++ break; ++ ++ case Opt_dio: ++ au_opt_set(sbinfo->si_mntflags, DIO); ++ au_fset_opts(opts->flags, REFRESH_DYAOP); ++ break; ++ case Opt_nodio: ++ au_opt_clr(sbinfo->si_mntflags, DIO); ++ au_fset_opts(opts->flags, REFRESH_DYAOP); ++ break; ++ ++ case Opt_fhsm_sec: ++ au_fhsm_set(sbinfo, opt->fhsm_second); ++ break; ++ ++ case Opt_diropq_a: ++ au_opt_set(sbinfo->si_mntflags, ALWAYS_DIROPQ); ++ break; ++ case Opt_diropq_w: ++ au_opt_clr(sbinfo->si_mntflags, ALWAYS_DIROPQ); ++ break; ++ ++ case Opt_warn_perm: ++ au_opt_set(sbinfo->si_mntflags, WARN_PERM); ++ break; ++ case Opt_nowarn_perm: ++ au_opt_clr(sbinfo->si_mntflags, WARN_PERM); ++ break; ++ ++ case Opt_verbose: ++ au_opt_set(sbinfo->si_mntflags, VERBOSE); ++ break; ++ case Opt_noverbose: ++ au_opt_clr(sbinfo->si_mntflags, VERBOSE); ++ break; ++ ++ case Opt_sum: ++ au_opt_set(sbinfo->si_mntflags, SUM); ++ break; ++ case Opt_wsum: ++ au_opt_clr(sbinfo->si_mntflags, SUM); ++ au_opt_set(sbinfo->si_mntflags, SUM_W); ++ break; ++ case Opt_nosum: ++ au_opt_clr(sbinfo->si_mntflags, SUM); ++ au_opt_clr(sbinfo->si_mntflags, SUM_W); ++ break; ++ ++ case Opt_wbr_create: ++ err = au_opt_wbr_create(sb, &opt->wbr_create); ++ break; ++ case Opt_wbr_copyup: ++ sbinfo->si_wbr_copyup = opt->wbr_copyup; ++ sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + opt->wbr_copyup; ++ break; ++ ++ case Opt_dirwh: ++ sbinfo->si_dirwh = opt->dirwh; ++ break; ++ ++ case Opt_rdcache: ++ sbinfo->si_rdcache ++ = msecs_to_jiffies(opt->rdcache * MSEC_PER_SEC); ++ break; ++ case Opt_rdblk: ++ sbinfo->si_rdblk = opt->rdblk; ++ break; ++ case Opt_rdblk_def: ++ sbinfo->si_rdblk = AUFS_RDBLK_DEF; ++ break; ++ case Opt_rdhash: ++ sbinfo->si_rdhash = opt->rdhash; ++ break; ++ case Opt_rdhash_def: ++ sbinfo->si_rdhash = AUFS_RDHASH_DEF; ++ break; ++ ++ case Opt_shwh: ++ au_opt_set(sbinfo->si_mntflags, SHWH); ++ break; ++ case Opt_noshwh: ++ au_opt_clr(sbinfo->si_mntflags, SHWH); ++ break; ++ ++ case Opt_dirperm1: ++ au_opt_set(sbinfo->si_mntflags, DIRPERM1); ++ break; ++ case Opt_nodirperm1: ++ au_opt_clr(sbinfo->si_mntflags, DIRPERM1); ++ break; ++ ++ case Opt_trunc_xino: ++ au_opt_set(sbinfo->si_mntflags, TRUNC_XINO); ++ break; ++ case Opt_notrunc_xino: ++ au_opt_clr(sbinfo->si_mntflags, TRUNC_XINO); ++ break; ++ ++ case Opt_trunc_xino_path: ++ case Opt_itrunc_xino: ++ err = au_xino_trunc(sb, opt->xino_itrunc.bindex, ++ /*idx_begin*/0); ++ if (!err) ++ err = 1; ++ break; ++ ++ case Opt_trunc_xib: ++ au_fset_opts(opts->flags, TRUNC_XIB); ++ break; ++ case Opt_notrunc_xib: ++ au_fclr_opts(opts->flags, TRUNC_XIB); ++ break; ++ ++ case Opt_dirren: ++ err = 1; ++ if (!au_opt_test(sbinfo->si_mntflags, DIRREN)) { ++ err = au_dr_opt_set(sb); ++ if (!err) ++ err = 1; ++ } ++ if (err == 1) ++ au_opt_set(sbinfo->si_mntflags, DIRREN); ++ break; ++ case Opt_nodirren: ++ err = 1; ++ if (au_opt_test(sbinfo->si_mntflags, DIRREN)) { ++ err = au_dr_opt_clr(sb, au_ftest_opts(opts->flags, ++ DR_FLUSHED)); ++ if (!err) ++ err = 1; ++ } ++ if (err == 1) ++ au_opt_clr(sbinfo->si_mntflags, DIRREN); ++ break; ++ ++ case Opt_acl: ++ sb->s_flags |= SB_POSIXACL; ++ break; ++ case Opt_noacl: ++ sb->s_flags &= ~SB_POSIXACL; ++ break; ++ ++ default: ++ err = 0; ++ break; ++ } ++ ++ return err; ++} ++ ++/* ++ * returns tri-state. ++ * plus: processed without an error ++ * zero: unprocessed ++ * minus: error ++ */ ++static int au_opt_br(struct super_block *sb, struct au_opt *opt, ++ struct au_opts *opts) ++{ ++ int err, do_refresh; ++ ++ err = 0; ++ switch (opt->type) { ++ case Opt_append: ++ opt->add.bindex = au_sbbot(sb) + 1; ++ if (opt->add.bindex < 0) ++ opt->add.bindex = 0; ++ goto add; ++ /* Always goto add, not fallthrough */ ++ case Opt_prepend: ++ opt->add.bindex = 0; ++ fallthrough; ++ add: /* indented label */ ++ case Opt_add: ++ err = au_br_add(sb, &opt->add, ++ au_ftest_opts(opts->flags, REMOUNT)); ++ if (!err) { ++ err = 1; ++ au_fset_opts(opts->flags, REFRESH); ++ } ++ break; ++ ++ case Opt_del: ++ case Opt_idel: ++ err = au_br_del(sb, &opt->del, ++ au_ftest_opts(opts->flags, REMOUNT)); ++ if (!err) { ++ err = 1; ++ au_fset_opts(opts->flags, TRUNC_XIB); ++ au_fset_opts(opts->flags, REFRESH); ++ } ++ break; ++ ++ case Opt_mod: ++ case Opt_imod: ++ err = au_br_mod(sb, &opt->mod, ++ au_ftest_opts(opts->flags, REMOUNT), ++ &do_refresh); ++ if (!err) { ++ err = 1; ++ if (do_refresh) ++ au_fset_opts(opts->flags, REFRESH); ++ } ++ break; ++ } ++ return err; ++} ++ ++static int au_opt_xino(struct super_block *sb, struct au_opt *opt, ++ struct au_opt_xino **opt_xino, ++ struct au_opts *opts) ++{ ++ int err; ++ ++ err = 0; ++ switch (opt->type) { ++ case Opt_xino: ++ err = au_xino_set(sb, &opt->xino, ++ !!au_ftest_opts(opts->flags, REMOUNT)); ++ if (unlikely(err)) ++ break; ++ ++ *opt_xino = &opt->xino; ++ break; ++ ++ case Opt_noxino: ++ au_xino_clr(sb); ++ *opt_xino = (void *)-1; ++ break; ++ } ++ ++ return err; ++} ++ ++int au_opts_verify(struct super_block *sb, unsigned long sb_flags, ++ unsigned int pending) ++{ ++ int err, fhsm; ++ aufs_bindex_t bindex, bbot; ++ unsigned char do_plink, skip, do_free, can_no_dreval; ++ struct au_branch *br; ++ struct au_wbr *wbr; ++ struct dentry *root, *dentry; ++ struct inode *dir, *h_dir; ++ struct au_sbinfo *sbinfo; ++ struct au_hinode *hdir; ++ ++ SiMustAnyLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ AuDebugOn(!(sbinfo->si_mntflags & AuOptMask_UDBA)); ++ ++ if (!(sb_flags & SB_RDONLY)) { ++ if (unlikely(!au_br_writable(au_sbr_perm(sb, 0)))) ++ pr_warn("first branch should be rw\n"); ++ if (unlikely(au_opt_test(sbinfo->si_mntflags, SHWH))) ++ pr_warn_once("shwh should be used with ro\n"); ++ } ++ ++ if (au_opt_test((sbinfo->si_mntflags | pending), UDBA_HNOTIFY) ++ && !au_opt_test(sbinfo->si_mntflags, XINO)) ++ pr_warn_once("udba=*notify requires xino\n"); ++ ++ if (au_opt_test(sbinfo->si_mntflags, DIRPERM1)) ++ pr_warn_once("dirperm1 breaks the protection" ++ " by the permission bits on the lower branch\n"); ++ ++ err = 0; ++ fhsm = 0; ++ root = sb->s_root; ++ dir = d_inode(root); ++ do_plink = !!au_opt_test(sbinfo->si_mntflags, PLINK); ++ can_no_dreval = !!au_opt_test((sbinfo->si_mntflags | pending), ++ UDBA_NONE); ++ bbot = au_sbbot(sb); ++ for (bindex = 0; !err && bindex <= bbot; bindex++) { ++ skip = 0; ++ h_dir = au_h_iptr(dir, bindex); ++ br = au_sbr(sb, bindex); ++ ++ if ((br->br_perm & AuBrAttr_ICEX) ++ && !h_dir->i_op->listxattr) ++ br->br_perm &= ~AuBrAttr_ICEX; ++#if 0 /* untested */ ++ if ((br->br_perm & AuBrAttr_ICEX_SEC) ++ && (au_br_sb(br)->s_flags & SB_NOSEC)) ++ br->br_perm &= ~AuBrAttr_ICEX_SEC; ++#endif ++ ++ do_free = 0; ++ wbr = br->br_wbr; ++ if (wbr) ++ wbr_wh_read_lock(wbr); ++ ++ if (!au_br_writable(br->br_perm)) { ++ do_free = !!wbr; ++ skip = (!wbr ++ || (!wbr->wbr_whbase ++ && !wbr->wbr_plink ++ && !wbr->wbr_orph)); ++ } else if (!au_br_wh_linkable(br->br_perm)) { ++ /* skip = (!br->br_whbase && !br->br_orph); */ ++ skip = (!wbr || !wbr->wbr_whbase); ++ if (skip && wbr) { ++ if (do_plink) ++ skip = !!wbr->wbr_plink; ++ else ++ skip = !wbr->wbr_plink; ++ } ++ } else { ++ /* skip = (br->br_whbase && br->br_ohph); */ ++ skip = (wbr && wbr->wbr_whbase); ++ if (skip) { ++ if (do_plink) ++ skip = !!wbr->wbr_plink; ++ else ++ skip = !wbr->wbr_plink; ++ } ++ } ++ if (wbr) ++ wbr_wh_read_unlock(wbr); ++ ++ if (can_no_dreval) { ++ dentry = br->br_path.dentry; ++ spin_lock(&dentry->d_lock); ++ if (dentry->d_flags & ++ (DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE)) ++ can_no_dreval = 0; ++ spin_unlock(&dentry->d_lock); ++ } ++ ++ if (au_br_fhsm(br->br_perm)) { ++ fhsm++; ++ AuDebugOn(!br->br_fhsm); ++ } ++ ++ if (skip) ++ continue; ++ ++ hdir = au_hi(dir, bindex); ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ if (wbr) ++ wbr_wh_write_lock(wbr); ++ err = au_wh_init(br, sb); ++ if (wbr) ++ wbr_wh_write_unlock(wbr); ++ au_hn_inode_unlock(hdir); ++ ++ if (!err && do_free) { ++ au_kfree_rcu(wbr); ++ br->br_wbr = NULL; ++ } ++ } ++ ++ if (can_no_dreval) ++ au_fset_si(sbinfo, NO_DREVAL); ++ else ++ au_fclr_si(sbinfo, NO_DREVAL); ++ ++ if (fhsm >= 2) { ++ au_fset_si(sbinfo, FHSM); ++ for (bindex = bbot; bindex >= 0; bindex--) { ++ br = au_sbr(sb, bindex); ++ if (au_br_fhsm(br->br_perm)) { ++ au_fhsm_set_bottom(sb, bindex); ++ break; ++ } ++ } ++ } else { ++ au_fclr_si(sbinfo, FHSM); ++ au_fhsm_set_bottom(sb, -1); ++ } ++ ++ return err; ++} ++ ++int au_opts_mount(struct super_block *sb, struct au_opts *opts) ++{ ++ int err; ++ unsigned int tmp; ++ aufs_bindex_t bindex, bbot; ++ struct au_opt *opt; ++ struct au_opt_xino *opt_xino, xino; ++ struct au_sbinfo *sbinfo; ++ struct au_branch *br; ++ struct inode *dir; ++ ++ SiMustWriteLock(sb); ++ ++ err = 0; ++ opt_xino = NULL; ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) ++ err = au_opt_simple(sb, opt++, opts); ++ if (err > 0) ++ err = 0; ++ else if (unlikely(err < 0)) ++ goto out; ++ ++ /* disable xino and udba temporary */ ++ sbinfo = au_sbi(sb); ++ tmp = sbinfo->si_mntflags; ++ au_opt_clr(sbinfo->si_mntflags, XINO); ++ au_opt_set_udba(sbinfo->si_mntflags, UDBA_REVAL); ++ ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) ++ err = au_opt_br(sb, opt++, opts); ++ if (err > 0) ++ err = 0; ++ else if (unlikely(err < 0)) ++ goto out; ++ ++ bbot = au_sbbot(sb); ++ if (unlikely(bbot < 0)) { ++ err = -EINVAL; ++ pr_err("no branches\n"); ++ goto out; ++ } ++ ++ if (au_opt_test(tmp, XINO)) ++ au_opt_set(sbinfo->si_mntflags, XINO); ++ opt = opts->opt; ++ while (!err && opt->type != Opt_tail) ++ err = au_opt_xino(sb, opt++, &opt_xino, opts); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_opts_verify(sb, sb->s_flags, tmp); ++ if (unlikely(err)) ++ goto out; ++ ++ /* restore xino */ ++ if (au_opt_test(tmp, XINO) && !opt_xino) { ++ xino.file = au_xino_def(sb); ++ err = PTR_ERR(xino.file); ++ if (IS_ERR(xino.file)) ++ goto out; ++ ++ err = au_xino_set(sb, &xino, /*remount*/0); ++ fput(xino.file); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ /* restore udba */ ++ tmp &= AuOptMask_UDBA; ++ sbinfo->si_mntflags &= ~AuOptMask_UDBA; ++ sbinfo->si_mntflags |= tmp; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ err = au_hnotify_reset_br(tmp, br, br->br_perm); ++ if (unlikely(err)) ++ AuIOErr("hnotify failed on br %d, %d, ignored\n", ++ bindex, err); ++ /* go on even if err */ ++ } ++ if (au_opt_test(tmp, UDBA_HNOTIFY)) { ++ dir = d_inode(sb->s_root); ++ au_hn_reset(dir, au_hi_flags(dir, /*isdir*/1) & ~AuHi_XINO); ++ } ++ ++out: ++ return err; ++} ++ ++int au_opts_remount(struct super_block *sb, struct au_opts *opts) ++{ ++ int err, rerr; ++ unsigned char no_dreval; ++ struct inode *dir; ++ struct au_opt_xino *opt_xino; ++ struct au_opt *opt; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ err = au_dr_opt_flush(sb); ++ if (unlikely(err)) ++ goto out; ++ au_fset_opts(opts->flags, DR_FLUSHED); ++ ++ dir = d_inode(sb->s_root); ++ sbinfo = au_sbi(sb); ++ opt_xino = NULL; ++ opt = opts->opt; ++ while (err >= 0 && opt->type != Opt_tail) { ++ err = au_opt_simple(sb, opt, opts); ++ if (!err) ++ err = au_opt_br(sb, opt, opts); ++ if (!err) ++ err = au_opt_xino(sb, opt, &opt_xino, opts); ++ opt++; ++ } ++ if (err > 0) ++ err = 0; ++ AuTraceErr(err); ++ /* go on even err */ ++ ++ no_dreval = !!au_ftest_si(sbinfo, NO_DREVAL); ++ rerr = au_opts_verify(sb, opts->sb_flags, /*pending*/0); ++ if (unlikely(rerr && !err)) ++ err = rerr; ++ ++ if (no_dreval != !!au_ftest_si(sbinfo, NO_DREVAL)) ++ au_fset_opts(opts->flags, REFRESH_IDOP); ++ ++ if (au_ftest_opts(opts->flags, TRUNC_XIB)) { ++ rerr = au_xib_trunc(sb); ++ if (unlikely(rerr && !err)) ++ err = rerr; ++ } ++ ++ /* will be handled by the caller */ ++ if (!au_ftest_opts(opts->flags, REFRESH) ++ && (opts->given_udba ++ || au_opt_test(sbinfo->si_mntflags, XINO) ++ || au_ftest_opts(opts->flags, REFRESH_IDOP) ++ )) ++ au_fset_opts(opts->flags, REFRESH); ++ ++ AuDbg("status 0x%x\n", opts->flags); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++unsigned int au_opt_udba(struct super_block *sb) ++{ ++ return au_mntflags(sb) & AuOptMask_UDBA; ++} +diff --git a/fs/aufs/opts.h b/fs/aufs/opts.h +new file mode 100644 +index 000000000000..5e00aeac6d21 +--- /dev/null ++++ b/fs/aufs/opts.h +@@ -0,0 +1,212 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * mount options/flags ++ */ ++ ++#ifndef __AUFS_OPTS_H__ ++#define __AUFS_OPTS_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++struct file; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* mount flags */ ++#define AuOpt_XINO 1 /* external inode number bitmap ++ and translation table */ ++#define AuOpt_TRUNC_XINO (1 << 1) /* truncate xino files */ ++#define AuOpt_UDBA_NONE (1 << 2) /* users direct branch access */ ++#define AuOpt_UDBA_REVAL (1 << 3) ++#define AuOpt_UDBA_HNOTIFY (1 << 4) ++#define AuOpt_SHWH (1 << 5) /* show whiteout */ ++#define AuOpt_PLINK (1 << 6) /* pseudo-link */ ++#define AuOpt_DIRPERM1 (1 << 7) /* ignore the lower dir's perm ++ bits */ ++#define AuOpt_ALWAYS_DIROPQ (1 << 9) /* policy to creating diropq */ ++#define AuOpt_SUM (1 << 10) /* summation for statfs(2) */ ++#define AuOpt_SUM_W (1 << 11) /* unimplemented */ ++#define AuOpt_WARN_PERM (1 << 12) /* warn when add-branch */ ++#define AuOpt_VERBOSE (1 << 13) /* print the cause of error */ ++#define AuOpt_DIO (1 << 14) /* direct io */ ++#define AuOpt_DIRREN (1 << 15) /* directory rename */ ++ ++#ifndef CONFIG_AUFS_HNOTIFY ++#undef AuOpt_UDBA_HNOTIFY ++#define AuOpt_UDBA_HNOTIFY 0 ++#endif ++#ifndef CONFIG_AUFS_DIRREN ++#undef AuOpt_DIRREN ++#define AuOpt_DIRREN 0 ++#endif ++#ifndef CONFIG_AUFS_SHWH ++#undef AuOpt_SHWH ++#define AuOpt_SHWH 0 ++#endif ++ ++#define AuOpt_Def (AuOpt_XINO \ ++ | AuOpt_UDBA_REVAL \ ++ | AuOpt_PLINK \ ++ /* | AuOpt_DIRPERM1 */ \ ++ | AuOpt_WARN_PERM) ++#define AuOptMask_UDBA (AuOpt_UDBA_NONE \ ++ | AuOpt_UDBA_REVAL \ ++ | AuOpt_UDBA_HNOTIFY) ++ ++#define au_opt_test(flags, name) (flags & AuOpt_##name) ++#define au_opt_set(flags, name) do { \ ++ BUILD_BUG_ON(AuOpt_##name & AuOptMask_UDBA); \ ++ ((flags) |= AuOpt_##name); \ ++} while (0) ++#define au_opt_set_udba(flags, name) do { \ ++ (flags) &= ~AuOptMask_UDBA; \ ++ ((flags) |= AuOpt_##name); \ ++} while (0) ++#define au_opt_clr(flags, name) do { \ ++ ((flags) &= ~AuOpt_##name); \ ++} while (0) ++ ++static inline unsigned int au_opts_plink(unsigned int mntflags) ++{ ++#ifdef CONFIG_PROC_FS ++ return mntflags; ++#else ++ return mntflags & ~AuOpt_PLINK; ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policies to select one among multiple writable branches */ ++enum { ++ AuWbrCreate_TDP, /* top down parent */ ++ AuWbrCreate_RR, /* round robin */ ++ AuWbrCreate_MFS, /* most free space */ ++ AuWbrCreate_MFSV, /* mfs with seconds */ ++ AuWbrCreate_MFSRR, /* mfs then rr */ ++ AuWbrCreate_MFSRRV, /* mfs then rr with seconds */ ++ AuWbrCreate_TDMFS, /* top down regardless parent and mfs */ ++ AuWbrCreate_TDMFSV, /* top down regardless parent and mfs */ ++ AuWbrCreate_PMFS, /* parent and mfs */ ++ AuWbrCreate_PMFSV, /* parent and mfs with seconds */ ++ AuWbrCreate_PMFSRR, /* parent, mfs and round-robin */ ++ AuWbrCreate_PMFSRRV, /* plus seconds */ ++ ++ AuWbrCreate_Def = AuWbrCreate_TDP ++}; ++ ++enum { ++ AuWbrCopyup_TDP, /* top down parent */ ++ AuWbrCopyup_BUP, /* bottom up parent */ ++ AuWbrCopyup_BU, /* bottom up */ ++ ++ AuWbrCopyup_Def = AuWbrCopyup_TDP ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_opt_add { ++ aufs_bindex_t bindex; ++ char *pathname; ++ int perm; ++ struct path path; ++}; ++ ++struct au_opt_del { ++ char *pathname; ++ struct path h_path; ++}; ++ ++struct au_opt_mod { ++ char *path; ++ int perm; ++ struct dentry *h_root; ++}; ++ ++struct au_opt_xino { ++ char *path; ++ struct file *file; ++}; ++ ++struct au_opt_xino_itrunc { ++ aufs_bindex_t bindex; ++}; ++ ++struct au_opt_wbr_create { ++ int wbr_create; ++ int mfs_second; ++ unsigned long long mfsrr_watermark; ++}; ++ ++struct au_opt { ++ int type; ++ union { ++ struct au_opt_xino xino; ++ struct au_opt_xino_itrunc xino_itrunc; ++ struct au_opt_add add; ++ struct au_opt_del del; ++ struct au_opt_mod mod; ++ int dirwh; ++ int rdcache; ++ unsigned int rdblk; ++ unsigned int rdhash; ++ int udba; ++ struct au_opt_wbr_create wbr_create; ++ int wbr_copyup; ++ unsigned int fhsm_second; ++ }; ++}; ++ ++/* opts flags */ ++#define AuOpts_REMOUNT 1 ++#define AuOpts_REFRESH (1 << 1) ++#define AuOpts_TRUNC_XIB (1 << 2) ++#define AuOpts_REFRESH_DYAOP (1 << 3) ++#define AuOpts_REFRESH_IDOP (1 << 4) ++#define AuOpts_DR_FLUSHED (1 << 5) ++#define au_ftest_opts(flags, name) ((flags) & AuOpts_##name) ++#define au_fset_opts(flags, name) \ ++ do { (flags) |= AuOpts_##name; } while (0) ++#define au_fclr_opts(flags, name) \ ++ do { (flags) &= ~AuOpts_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_DIRREN ++#undef AuOpts_DR_FLUSHED ++#define AuOpts_DR_FLUSHED 0 ++#endif ++ ++struct au_opts { ++ struct au_opt *opt; ++ int max_opt; ++ ++ unsigned int given_udba; ++ unsigned int flags; ++ unsigned long sb_flags; ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* opts.c */ ++void au_optstr_br_perm(au_br_perm_str_t *str, int perm); ++const char *au_optstr_udba(int udba); ++const char *au_optstr_wbr_copyup(int wbr_copyup); ++const char *au_optstr_wbr_create(int wbr_create); ++ ++void au_opts_free(struct au_opts *opts); ++struct super_block; ++int au_opts_parse(struct super_block *sb, char *str, struct au_opts *opts); ++int au_opts_verify(struct super_block *sb, unsigned long sb_flags, ++ unsigned int pending); ++int au_opts_mount(struct super_block *sb, struct au_opts *opts); ++int au_opts_remount(struct super_block *sb, struct au_opts *opts); ++ ++unsigned int au_opt_udba(struct super_block *sb); ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_OPTS_H__ */ +diff --git a/fs/aufs/plink.c b/fs/aufs/plink.c +new file mode 100644 +index 000000000000..1c67183bebfb +--- /dev/null ++++ b/fs/aufs/plink.c +@@ -0,0 +1,503 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 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..ff7697c334b4 +--- /dev/null ++++ b/fs/aufs/poll.c +@@ -0,0 +1,38 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 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..946c2247e78d +--- /dev/null ++++ b/fs/aufs/posix_acl.c +@@ -0,0 +1,92 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2014-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * posix acl operations ++ */ ++ ++#include ++#include "aufs.h" ++ ++struct posix_acl *aufs_get_acl(struct inode *inode, int type) ++{ ++ struct posix_acl *acl; ++ int err; ++ aufs_bindex_t bindex; ++ struct inode *h_inode; ++ struct super_block *sb; ++ ++ acl = NULL; ++ sb = inode->i_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ ii_read_lock_child(inode); ++ if (!(sb->s_flags & SB_POSIXACL)) ++ goto out; ++ ++ bindex = au_ibtop(inode); ++ h_inode = au_h_iptr(inode, bindex); ++ if (unlikely(!h_inode ++ || ((h_inode->i_mode & S_IFMT) ++ != (inode->i_mode & S_IFMT)))) { ++ err = au_busy_or_stale(); ++ acl = ERR_PTR(err); ++ goto out; ++ } ++ ++ /* always topmost only */ ++ acl = get_acl(h_inode, type); ++ if (IS_ERR(acl)) ++ forget_cached_acl(inode, type); ++ else ++ set_cached_acl(inode, type, acl); ++ ++out: ++ ii_read_unlock(inode); ++ si_read_unlock(sb); ++ ++ AuTraceErrPtr(acl); ++ return acl; ++} ++ ++int aufs_set_acl(struct inode *inode, struct posix_acl *acl, int type) ++{ ++ int err; ++ ssize_t ssz; ++ struct dentry *dentry; ++ struct au_sxattr arg = { ++ .type = AU_ACL_SET, ++ .u.acl_set = { ++ .acl = acl, ++ .type = type ++ }, ++ }; ++ ++ IMustLock(inode); ++ ++ if (inode->i_ino == AUFS_ROOT_INO) ++ dentry = dget(inode->i_sb->s_root); ++ else { ++ dentry = d_find_alias(inode); ++ if (!dentry) ++ dentry = d_find_any_alias(inode); ++ if (!dentry) { ++ pr_warn("cannot handle this inode, " ++ "please report to aufs-users ML\n"); ++ err = -ENOENT; ++ goto out; ++ } ++ } ++ ++ ssz = au_sxattr(dentry, inode, &arg); ++ /* forget even it if succeeds since the branch might set differently */ ++ forget_cached_acl(inode, type); ++ dput(dentry); ++ err = ssz; ++ if (ssz >= 0) ++ err = 0; ++ ++out: ++ return err; ++} +diff --git a/fs/aufs/procfs.c b/fs/aufs/procfs.c +new file mode 100644 +index 000000000000..055e9bcc9af4 +--- /dev/null ++++ b/fs/aufs/procfs.c +@@ -0,0 +1,157 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2010-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * procfs interfaces ++ */ ++ ++#include ++#include "aufs.h" ++ ++static int au_procfs_plm_release(struct inode *inode, struct file *file) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ sbinfo = file->private_data; ++ if (sbinfo) { ++ au_plink_maint_leave(sbinfo); ++ kobject_put(&sbinfo->si_kobj); ++ } ++ ++ return 0; ++} ++ ++static void au_procfs_plm_write_clean(struct file *file) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ sbinfo = file->private_data; ++ if (sbinfo) ++ au_plink_clean(sbinfo->si_sb, /*verbose*/0); ++} ++ ++static int au_procfs_plm_write_si(struct file *file, unsigned long id) ++{ ++ int err; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ struct hlist_bl_node *pos; ++ ++ err = -EBUSY; ++ if (unlikely(file->private_data)) ++ goto out; ++ ++ sb = NULL; ++ /* don't use au_sbilist_lock() here */ ++ hlist_bl_lock(&au_sbilist); ++ hlist_bl_for_each_entry(sbinfo, pos, &au_sbilist, si_list) ++ if (id == sysaufs_si_id(sbinfo)) { ++ if (kobject_get_unless_zero(&sbinfo->si_kobj)) ++ sb = sbinfo->si_sb; ++ break; ++ } ++ hlist_bl_unlock(&au_sbilist); ++ ++ err = -EINVAL; ++ if (unlikely(!sb)) ++ goto out; ++ ++ err = au_plink_maint_enter(sb); ++ if (!err) ++ /* keep kobject_get() */ ++ file->private_data = sbinfo; ++ else ++ kobject_put(&sbinfo->si_kobj); ++out: ++ return err; ++} ++ ++/* ++ * Accept a valid "si=xxxx" only. ++ * Once it is accepted successfully, accept "clean" too. ++ */ ++static ssize_t au_procfs_plm_write(struct file *file, const char __user *ubuf, ++ size_t count, loff_t *ppos) ++{ ++ ssize_t err; ++ unsigned long id; ++ /* last newline is allowed */ ++ char buf[3 + sizeof(unsigned long) * 2 + 1]; ++ ++ err = -EACCES; ++ if (unlikely(!capable(CAP_SYS_ADMIN))) ++ goto out; ++ ++ err = -EINVAL; ++ if (unlikely(count > sizeof(buf))) ++ goto out; ++ ++ err = copy_from_user(buf, ubuf, count); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ goto out; ++ } ++ buf[count] = 0; ++ ++ err = -EINVAL; ++ if (!strcmp("clean", buf)) { ++ au_procfs_plm_write_clean(file); ++ goto out_success; ++ } else if (unlikely(strncmp("si=", buf, 3))) ++ goto out; ++ ++ err = kstrtoul(buf + 3, 16, &id); ++ if (unlikely(err)) ++ goto out; ++ ++ err = au_procfs_plm_write_si(file, id); ++ if (unlikely(err)) ++ goto out; ++ ++out_success: ++ err = count; /* success */ ++out: ++ return err; ++} ++ ++static const struct proc_ops au_procfs_plm_op = { ++ .proc_write = au_procfs_plm_write, ++ .proc_release = au_procfs_plm_release ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++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_op); ++ 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..bef4607f057e +--- /dev/null ++++ b/fs/aufs/rdu.c +@@ -0,0 +1,371 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * readdir in userspace. ++ */ ++ ++#include ++#include ++#include ++#include "aufs.h" ++ ++/* bits for struct aufs_rdu.flags */ ++#define AuRdu_CALLED 1 ++#define AuRdu_CONT (1 << 1) ++#define AuRdu_FULL (1 << 2) ++#define au_ftest_rdu(flags, name) ((flags) & AuRdu_##name) ++#define au_fset_rdu(flags, name) \ ++ do { (flags) |= AuRdu_##name; } while (0) ++#define au_fclr_rdu(flags, name) \ ++ do { (flags) &= ~AuRdu_##name; } while (0) ++ ++struct au_rdu_arg { ++ struct dir_context ctx; ++ struct aufs_rdu *rdu; ++ union au_rdu_ent_ul ent; ++ unsigned long end; ++ ++ struct super_block *sb; ++ int err; ++}; ++ ++static int au_rdu_fill(struct dir_context *ctx, const char *name, int nlen, ++ loff_t offset, u64 h_ino, unsigned int d_type) ++{ ++ int err, len; ++ struct au_rdu_arg *arg = container_of(ctx, struct au_rdu_arg, ctx); ++ struct aufs_rdu *rdu = arg->rdu; ++ struct au_rdu_ent ent; ++ ++ err = 0; ++ arg->err = 0; ++ au_fset_rdu(rdu->cookie.flags, CALLED); ++ len = au_rdu_len(nlen); ++ if (arg->ent.ul + len < arg->end) { ++ ent.ino = h_ino; ++ ent.bindex = rdu->cookie.bindex; ++ ent.type = d_type; ++ ent.nlen = nlen; ++ if (unlikely(nlen > AUFS_MAX_NAMELEN)) ++ ent.type = DT_UNKNOWN; ++ ++ /* unnecessary to support mmap_sem since this is a dir */ ++ err = -EFAULT; ++ if (copy_to_user(arg->ent.e, &ent, sizeof(ent))) ++ goto out; ++ if (copy_to_user(arg->ent.e->name, name, nlen)) ++ goto out; ++ /* the terminating NULL */ ++ if (__put_user(0, arg->ent.e->name + nlen)) ++ goto out; ++ err = 0; ++ /* AuDbg("%p, %.*s\n", arg->ent.p, nlen, name); */ ++ arg->ent.ul += len; ++ rdu->rent++; ++ } else { ++ err = -EFAULT; ++ au_fset_rdu(rdu->cookie.flags, FULL); ++ rdu->full = 1; ++ rdu->tail = arg->ent; ++ } ++ ++out: ++ /* AuTraceErr(err); */ ++ return err; ++} ++ ++static int au_rdu_do(struct file *h_file, struct au_rdu_arg *arg) ++{ ++ int err; ++ loff_t offset; ++ struct au_rdu_cookie *cookie = &arg->rdu->cookie; ++ ++ /* we don't have to care (FMODE_32BITHASH | FMODE_64BITHASH) for ext4 */ ++ offset = vfsub_llseek(h_file, cookie->h_pos, SEEK_SET); ++ err = offset; ++ if (unlikely(offset != cookie->h_pos)) ++ goto out; ++ ++ err = 0; ++ do { ++ arg->err = 0; ++ au_fclr_rdu(cookie->flags, CALLED); ++ /* smp_mb(); */ ++ err = vfsub_iterate_dir(h_file, &arg->ctx); ++ if (err >= 0) ++ err = arg->err; ++ } while (!err ++ && au_ftest_rdu(cookie->flags, CALLED) ++ && !au_ftest_rdu(cookie->flags, FULL)); ++ cookie->h_pos = h_file->f_pos; ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_rdu(struct file *file, struct aufs_rdu *rdu) ++{ ++ int err; ++ aufs_bindex_t bbot; ++ struct au_rdu_arg arg = { ++ .ctx = { ++ .actor = au_rdu_fill ++ } ++ }; ++ struct dentry *dentry; ++ struct inode *inode; ++ struct file *h_file; ++ struct au_rdu_cookie *cookie = &rdu->cookie; ++ ++ /* VERIFY_WRITE */ ++ err = !access_ok(rdu->ent.e, rdu->sz); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ rdu->rent = 0; ++ rdu->tail = rdu->ent; ++ rdu->full = 0; ++ arg.rdu = rdu; ++ arg.ent = rdu->ent; ++ arg.end = arg.ent.ul; ++ arg.end += rdu->sz; ++ ++ err = -ENOTDIR; ++ if (unlikely(!file->f_op->iterate && !file->f_op->iterate_shared)) ++ goto out; ++ ++ err = security_file_permission(file, MAY_READ); ++ AuTraceErr(err); ++ if (unlikely(err)) ++ goto out; ++ ++ dentry = file->f_path.dentry; ++ inode = d_inode(dentry); ++ inode_lock_shared(inode); ++ ++ arg.sb = inode->i_sb; ++ err = si_read_lock(arg.sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out_mtx; ++ err = au_alive_dir(dentry); ++ if (unlikely(err)) ++ goto out_si; ++ /* todo: reval? */ ++ fi_read_lock(file); ++ ++ err = -EAGAIN; ++ if (unlikely(au_ftest_rdu(cookie->flags, CONT) ++ && cookie->generation != au_figen(file))) ++ goto out_unlock; ++ ++ err = 0; ++ if (!rdu->blk) { ++ rdu->blk = au_sbi(arg.sb)->si_rdblk; ++ if (!rdu->blk) ++ rdu->blk = au_dir_size(file, /*dentry*/NULL); ++ } ++ bbot = au_fbtop(file); ++ if (cookie->bindex < bbot) ++ cookie->bindex = bbot; ++ bbot = au_fbbot_dir(file); ++ /* AuDbg("b%d, b%d\n", cookie->bindex, bbot); */ ++ for (; !err && cookie->bindex <= bbot; ++ cookie->bindex++, cookie->h_pos = 0) { ++ h_file = au_hf_dir(file, cookie->bindex); ++ if (!h_file) ++ continue; ++ ++ au_fclr_rdu(cookie->flags, FULL); ++ err = au_rdu_do(h_file, &arg); ++ AuTraceErr(err); ++ if (unlikely(au_ftest_rdu(cookie->flags, FULL) || err)) ++ break; ++ } ++ AuDbg("rent %llu\n", rdu->rent); ++ ++ if (!err && !au_ftest_rdu(cookie->flags, CONT)) { ++ rdu->shwh = !!au_opt_test(au_sbi(arg.sb)->si_mntflags, SHWH); ++ au_fset_rdu(cookie->flags, CONT); ++ cookie->generation = au_figen(file); ++ } ++ ++ ii_read_lock_child(inode); ++ fsstack_copy_attr_atime(inode, au_h_iptr(inode, au_ibtop(inode))); ++ ii_read_unlock(inode); ++ ++out_unlock: ++ fi_read_unlock(file); ++out_si: ++ si_read_unlock(arg.sb); ++out_mtx: ++ inode_unlock_shared(inode); ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_rdu_ino(struct file *file, struct aufs_rdu *rdu) ++{ ++ int err; ++ ino_t ino; ++ unsigned long long nent; ++ union au_rdu_ent_ul *u; ++ struct au_rdu_ent ent; ++ struct super_block *sb; ++ ++ err = 0; ++ nent = rdu->nent; ++ u = &rdu->ent; ++ sb = file->f_path.dentry->d_sb; ++ si_read_lock(sb, AuLock_FLUSH); ++ while (nent-- > 0) { ++ /* unnecessary to support mmap_sem since this is a dir */ ++ err = copy_from_user(&ent, u->e, sizeof(ent)); ++ if (!err) ++ /* VERIFY_WRITE */ ++ err = !access_ok(&u->e->ino, sizeof(ino)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ break; ++ } ++ ++ /* AuDbg("b%d, i%llu\n", ent.bindex, ent.ino); */ ++ if (!ent.wh) ++ err = au_ino(sb, ent.bindex, ent.ino, ent.type, &ino); ++ else ++ err = au_wh_ino(sb, ent.bindex, ent.ino, ent.type, ++ &ino); ++ if (unlikely(err)) { ++ AuTraceErr(err); ++ break; ++ } ++ ++ err = __put_user(ino, &u->e->ino); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ break; ++ } ++ u->ul += au_rdu_len(ent.nlen); ++ } ++ si_read_unlock(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_rdu_verify(struct aufs_rdu *rdu) ++{ ++ AuDbg("rdu{%llu, %p, %u | %u | %llu, %u, %u | " ++ "%llu, b%d, 0x%x, g%u}\n", ++ rdu->sz, rdu->ent.e, rdu->verify[AufsCtlRduV_SZ], ++ rdu->blk, ++ rdu->rent, rdu->shwh, rdu->full, ++ rdu->cookie.h_pos, rdu->cookie.bindex, rdu->cookie.flags, ++ rdu->cookie.generation); ++ ++ if (rdu->verify[AufsCtlRduV_SZ] == sizeof(*rdu)) ++ return 0; ++ ++ AuDbg("%u:%u\n", ++ rdu->verify[AufsCtlRduV_SZ], (unsigned int)sizeof(*rdu)); ++ return -EINVAL; ++} ++ ++long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long err, e; ++ struct aufs_rdu rdu; ++ void __user *p = (void __user *)arg; ++ ++ err = copy_from_user(&rdu, p, sizeof(rdu)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ err = au_rdu_verify(&rdu); ++ if (unlikely(err)) ++ goto out; ++ ++ switch (cmd) { ++ case AUFS_CTL_RDU: ++ err = au_rdu(file, &rdu); ++ if (unlikely(err)) ++ break; ++ ++ e = copy_to_user(p, &rdu, sizeof(rdu)); ++ if (unlikely(e)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ } ++ break; ++ case AUFS_CTL_RDU_INO: ++ err = au_rdu_ino(file, &rdu); ++ break; ++ ++ default: ++ /* err = -ENOTTY; */ ++ err = -EINVAL; ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++#ifdef CONFIG_COMPAT ++long au_rdu_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ long err, e; ++ struct aufs_rdu rdu; ++ void __user *p = compat_ptr(arg); ++ ++ /* todo: get_user()? */ ++ err = copy_from_user(&rdu, p, sizeof(rdu)); ++ if (unlikely(err)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ goto out; ++ } ++ rdu.ent.e = compat_ptr(rdu.ent.ul); ++ err = au_rdu_verify(&rdu); ++ if (unlikely(err)) ++ goto out; ++ ++ switch (cmd) { ++ case AUFS_CTL_RDU: ++ err = au_rdu(file, &rdu); ++ if (unlikely(err)) ++ break; ++ ++ rdu.ent.ul = ptr_to_compat(rdu.ent.e); ++ rdu.tail.ul = ptr_to_compat(rdu.tail.e); ++ e = copy_to_user(p, &rdu, sizeof(rdu)); ++ if (unlikely(e)) { ++ err = -EFAULT; ++ AuTraceErr(err); ++ } ++ break; ++ case AUFS_CTL_RDU_INO: ++ err = au_rdu_ino(file, &rdu); ++ break; ++ ++ default: ++ /* err = -ENOTTY; */ ++ err = -EINVAL; ++ } ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++#endif +diff --git a/fs/aufs/rwsem.h b/fs/aufs/rwsem.h +new file mode 100644 +index 000000000000..ab5af8236699 +--- /dev/null ++++ b/fs/aufs/rwsem.h +@@ -0,0 +1,60 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2020 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..26c6afab5df6 +--- /dev/null ++++ b/fs/aufs/sbinfo.c +@@ -0,0 +1,301 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * superblock private data ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* ++ * they are necessary regardless sysfs is disabled. ++ */ ++void au_si_free(struct kobject *kobj) ++{ ++ int i; ++ struct au_sbinfo *sbinfo; ++ char *locked __maybe_unused; /* debug only */ ++ ++ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); ++ for (i = 0; i < AuPlink_NHASH; i++) ++ AuDebugOn(!hlist_bl_empty(sbinfo->si_plink + i)); ++ AuDebugOn(atomic_read(&sbinfo->si_nowait.nw_len)); ++ ++ AuLCntZero(au_lcnt_read(&sbinfo->si_ninodes, /*do_rev*/0)); ++ au_lcnt_fin(&sbinfo->si_ninodes, /*do_sync*/0); ++ AuLCntZero(au_lcnt_read(&sbinfo->si_nfiles, /*do_rev*/0)); ++ au_lcnt_fin(&sbinfo->si_nfiles, /*do_sync*/0); ++ ++ dbgaufs_si_fin(sbinfo); ++ au_rw_write_lock(&sbinfo->si_rwsem); ++ au_br_free(sbinfo); ++ au_rw_write_unlock(&sbinfo->si_rwsem); ++ ++ au_kfree_try_rcu(sbinfo->si_branch); ++ mutex_destroy(&sbinfo->si_xib_mtx); ++ AuRwDestroy(&sbinfo->si_rwsem); ++ ++ au_lcnt_wait_for_fin(&sbinfo->si_ninodes); ++ /* si_nfiles is waited too */ ++ au_kfree_rcu(sbinfo); ++} ++ ++int au_si_alloc(struct super_block *sb) ++{ ++ int err, i; ++ struct au_sbinfo *sbinfo; ++ ++ err = -ENOMEM; ++ sbinfo = kzalloc(sizeof(*sbinfo), GFP_NOFS); ++ if (unlikely(!sbinfo)) ++ goto out; ++ ++ /* will be reallocated separately */ ++ sbinfo->si_branch = kzalloc(sizeof(*sbinfo->si_branch), GFP_NOFS); ++ if (unlikely(!sbinfo->si_branch)) ++ goto out_sbinfo; ++ ++ err = sysaufs_si_init(sbinfo); ++ if (!err) { ++ dbgaufs_si_null(sbinfo); ++ err = dbgaufs_si_init(sbinfo); ++ if (unlikely(err)) ++ kobject_put(&sbinfo->si_kobj); ++ } ++ if (unlikely(err)) ++ goto out_br; ++ ++ au_nwt_init(&sbinfo->si_nowait); ++ au_rw_init_wlock(&sbinfo->si_rwsem); ++ ++ au_lcnt_init(&sbinfo->si_ninodes, /*release*/NULL); ++ au_lcnt_init(&sbinfo->si_nfiles, /*release*/NULL); ++ ++ sbinfo->si_bbot = -1; ++ sbinfo->si_last_br_id = AUFS_BRANCH_MAX / 2; ++ ++ sbinfo->si_wbr_copyup = AuWbrCopyup_Def; ++ sbinfo->si_wbr_create = AuWbrCreate_Def; ++ sbinfo->si_wbr_copyup_ops = au_wbr_copyup_ops + sbinfo->si_wbr_copyup; ++ sbinfo->si_wbr_create_ops = au_wbr_create_ops + sbinfo->si_wbr_create; ++ ++ au_fhsm_init(sbinfo); ++ ++ sbinfo->si_mntflags = au_opts_plink(AuOpt_Def); ++ ++ sbinfo->si_xino_jiffy = jiffies; ++ sbinfo->si_xino_expire ++ = msecs_to_jiffies(AUFS_XINO_DEF_SEC * MSEC_PER_SEC); ++ mutex_init(&sbinfo->si_xib_mtx); ++ /* leave si_xib_last_pindex and si_xib_next_bit */ ++ ++ INIT_HLIST_BL_HEAD(&sbinfo->si_aopen); ++ ++ sbinfo->si_rdcache = msecs_to_jiffies(AUFS_RDCACHE_DEF * MSEC_PER_SEC); ++ sbinfo->si_rdblk = AUFS_RDBLK_DEF; ++ sbinfo->si_rdhash = AUFS_RDHASH_DEF; ++ sbinfo->si_dirwh = AUFS_DIRWH_DEF; ++ ++ for (i = 0; i < AuPlink_NHASH; i++) ++ INIT_HLIST_BL_HEAD(sbinfo->si_plink + i); ++ init_waitqueue_head(&sbinfo->si_plink_wq); ++ spin_lock_init(&sbinfo->si_plink_maint_lock); ++ ++ INIT_HLIST_BL_HEAD(&sbinfo->si_files); ++ ++ /* with getattr by default */ ++ sbinfo->si_iop_array = aufs_iop; ++ ++ /* leave other members for sysaufs and si_mnt. */ ++ sbinfo->si_sb = sb; ++ sb->s_fs_info = sbinfo; ++ si_pid_set(sb); ++ return 0; /* success */ ++ ++out_br: ++ au_kfree_try_rcu(sbinfo->si_branch); ++out_sbinfo: ++ au_kfree_rcu(sbinfo); ++out: ++ return err; ++} ++ ++int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr, int may_shrink) ++{ ++ int err, sz; ++ struct au_branch **brp; ++ ++ AuRwMustWriteLock(&sbinfo->si_rwsem); ++ ++ err = -ENOMEM; ++ sz = sizeof(*brp) * (sbinfo->si_bbot + 1); ++ if (unlikely(!sz)) ++ sz = sizeof(*brp); ++ brp = au_kzrealloc(sbinfo->si_branch, sz, sizeof(*brp) * nbr, GFP_NOFS, ++ may_shrink); ++ if (brp) { ++ sbinfo->si_branch = brp; ++ err = 0; ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++unsigned int au_sigen_inc(struct super_block *sb) ++{ ++ unsigned int gen; ++ struct inode *inode; ++ ++ SiMustWriteLock(sb); ++ ++ gen = ++au_sbi(sb)->si_generation; ++ au_update_digen(sb->s_root); ++ inode = d_inode(sb->s_root); ++ au_update_iigen(inode, /*half*/0); ++ inode_inc_iversion(inode); ++ return gen; ++} ++ ++aufs_bindex_t au_new_br_id(struct super_block *sb) ++{ ++ aufs_bindex_t br_id; ++ int i; ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ for (i = 0; i <= AUFS_BRANCH_MAX; i++) { ++ br_id = ++sbinfo->si_last_br_id; ++ AuDebugOn(br_id < 0); ++ if (br_id && au_br_index(sb, br_id) < 0) ++ return br_id; ++ } ++ ++ return -1; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* it is ok that new 'nwt' tasks are appended while we are sleeping */ ++int si_read_lock(struct super_block *sb, int flags) ++{ ++ int err; ++ ++ err = 0; ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ ++ si_noflush_read_lock(sb); ++ err = au_plink_maint(sb, flags); ++ if (unlikely(err)) ++ si_read_unlock(sb); ++ ++ return err; ++} ++ ++int si_write_lock(struct super_block *sb, int flags) ++{ ++ int err; ++ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ ++ si_noflush_write_lock(sb); ++ err = au_plink_maint(sb, flags); ++ if (unlikely(err)) ++ si_write_unlock(sb); ++ ++ return err; ++} ++ ++/* dentry and super_block lock. call at entry point */ ++int aufs_read_lock(struct dentry *dentry, int flags) ++{ ++ int err; ++ struct super_block *sb; ++ ++ sb = dentry->d_sb; ++ err = si_read_lock(sb, flags); ++ if (unlikely(err)) ++ goto out; ++ ++ if (au_ftest_lock(flags, DW)) ++ di_write_lock_child(dentry); ++ else ++ di_read_lock_child(dentry, flags); ++ ++ if (au_ftest_lock(flags, GEN)) { ++ err = au_digen_test(dentry, au_sigen(sb)); ++ if (!au_opt_test(au_mntflags(sb), UDBA_NONE)) ++ AuDebugOn(!err && au_dbrange_test(dentry)); ++ else if (!err) ++ err = au_dbrange_test(dentry); ++ if (unlikely(err)) ++ aufs_read_unlock(dentry, flags); ++ } ++ ++out: ++ return err; ++} ++ ++void aufs_read_unlock(struct dentry *dentry, int flags) ++{ ++ if (au_ftest_lock(flags, DW)) ++ di_write_unlock(dentry); ++ else ++ di_read_unlock(dentry, flags); ++ si_read_unlock(dentry->d_sb); ++} ++ ++void aufs_write_lock(struct dentry *dentry) ++{ ++ si_write_lock(dentry->d_sb, AuLock_FLUSH | AuLock_NOPLMW); ++ di_write_lock_child(dentry); ++} ++ ++void aufs_write_unlock(struct dentry *dentry) ++{ ++ di_write_unlock(dentry); ++ si_write_unlock(dentry->d_sb); ++} ++ ++int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags) ++{ ++ int err; ++ unsigned int sigen; ++ struct super_block *sb; ++ ++ sb = d1->d_sb; ++ err = si_read_lock(sb, flags); ++ if (unlikely(err)) ++ goto out; ++ ++ di_write_lock2_child(d1, d2, au_ftest_lock(flags, DIRS)); ++ ++ if (au_ftest_lock(flags, GEN)) { ++ sigen = au_sigen(sb); ++ err = au_digen_test(d1, sigen); ++ AuDebugOn(!err && au_dbrange_test(d1)); ++ if (!err) { ++ err = au_digen_test(d2, sigen); ++ AuDebugOn(!err && au_dbrange_test(d2)); ++ } ++ if (unlikely(err)) ++ aufs_read_and_write_unlock2(d1, d2); ++ } ++ ++out: ++ return err; ++} ++ ++void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2) ++{ ++ di_write_unlock2(d1, d2); ++ si_read_unlock(d1->d_sb); ++} +diff --git a/fs/aufs/super.c b/fs/aufs/super.c +new file mode 100644 +index 000000000000..589dd0122020 +--- /dev/null ++++ b/fs/aufs/super.c +@@ -0,0 +1,1034 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * mount and super_block operations ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "aufs.h" ++ ++/* ++ * super_operations ++ */ ++static struct inode *aufs_alloc_inode(struct super_block *sb __maybe_unused) ++{ ++ struct au_icntnr *c; ++ ++ c = au_cache_alloc_icntnr(); ++ if (c) { ++ au_icntnr_init(c); ++ inode_set_iversion(&c->vfs_inode, 1); /* sigen(sb); */ ++ c->iinfo.ii_hinode = NULL; ++ return &c->vfs_inode; ++ } ++ return NULL; ++} ++ ++static void aufs_destroy_inode(struct inode *inode) ++{ ++ if (!au_is_bad_inode(inode)) ++ au_iinfo_fin(inode); ++} ++ ++static void aufs_free_inode(struct inode *inode) ++{ ++ au_cache_free_icntnr(container_of(inode, struct au_icntnr, vfs_inode)); ++} ++ ++struct inode *au_iget_locked(struct super_block *sb, ino_t ino) ++{ ++ struct inode *inode; ++ int err; ++ ++ inode = iget_locked(sb, ino); ++ if (unlikely(!inode)) { ++ inode = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ if (!(inode->i_state & I_NEW)) ++ goto out; ++ ++ err = au_xigen_new(inode); ++ if (!err) ++ err = au_iinfo_init(inode); ++ if (!err) ++ inode_inc_iversion(inode); ++ else { ++ iget_failed(inode); ++ inode = ERR_PTR(err); ++ } ++ ++out: ++ /* never return NULL */ ++ AuDebugOn(!inode); ++ AuTraceErrPtr(inode); ++ return inode; ++} ++ ++/* lock free root dinfo */ ++static int au_show_brs(struct seq_file *seq, struct super_block *sb) ++{ ++ int err; ++ aufs_bindex_t bindex, bbot; ++ struct path path; ++ struct au_hdentry *hdp; ++ struct au_branch *br; ++ au_br_perm_str_t perm; ++ ++ err = 0; ++ bbot = au_sbbot(sb); ++ bindex = 0; ++ hdp = au_hdentry(au_di(sb->s_root), bindex); ++ for (; !err && bindex <= bbot; bindex++, hdp++) { ++ br = au_sbr(sb, bindex); ++ path.mnt = au_br_mnt(br); ++ path.dentry = hdp->hd_dentry; ++ err = au_seq_path(seq, &path); ++ if (!err) { ++ au_optstr_br_perm(&perm, br->br_perm); ++ seq_printf(seq, "=%s", perm.a); ++ if (bindex != bbot) ++ seq_putc(seq, ':'); ++ } ++ } ++ if (unlikely(err || seq_has_overflowed(seq))) ++ err = -E2BIG; ++ ++ return err; ++} ++ ++static void au_gen_fmt(char *fmt, int len __maybe_unused, const char *pat, ++ const char *append) ++{ ++ char *p; ++ ++ p = fmt; ++ while (*pat != ':') ++ *p++ = *pat++; ++ *p++ = *pat++; ++ strcpy(p, append); ++ AuDebugOn(strlen(fmt) >= len); ++} ++ ++static void au_show_wbr_create(struct seq_file *m, int v, ++ struct au_sbinfo *sbinfo) ++{ ++ const char *pat; ++ char fmt[32]; ++ struct au_wbr_mfs *mfs; ++ ++ AuRwMustAnyLock(&sbinfo->si_rwsem); ++ ++ seq_puts(m, ",create="); ++ pat = au_optstr_wbr_create(v); ++ mfs = &sbinfo->si_wbr_mfs; ++ switch (v) { ++ case AuWbrCreate_TDP: ++ case AuWbrCreate_RR: ++ case AuWbrCreate_MFS: ++ case AuWbrCreate_PMFS: ++ seq_puts(m, pat); ++ break; ++ case AuWbrCreate_MFSRR: ++ case AuWbrCreate_TDMFS: ++ case AuWbrCreate_PMFSRR: ++ au_gen_fmt(fmt, sizeof(fmt), pat, "%llu"); ++ seq_printf(m, fmt, mfs->mfsrr_watermark); ++ break; ++ case AuWbrCreate_MFSV: ++ case AuWbrCreate_PMFSV: ++ au_gen_fmt(fmt, sizeof(fmt), pat, "%lu"); ++ seq_printf(m, fmt, ++ jiffies_to_msecs(mfs->mfs_expire) ++ / MSEC_PER_SEC); ++ break; ++ case AuWbrCreate_MFSRRV: ++ case AuWbrCreate_TDMFSV: ++ case AuWbrCreate_PMFSRRV: ++ au_gen_fmt(fmt, sizeof(fmt), pat, "%llu:%lu"); ++ seq_printf(m, fmt, mfs->mfsrr_watermark, ++ jiffies_to_msecs(mfs->mfs_expire) / MSEC_PER_SEC); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++static int au_show_xino(struct seq_file *seq, struct super_block *sb) ++{ ++#ifdef CONFIG_SYSFS ++ return 0; ++#else ++ int err; ++ const int len = sizeof(AUFS_XINO_FNAME) - 1; ++ aufs_bindex_t bindex, brid; ++ struct qstr *name; ++ struct file *f; ++ struct dentry *d, *h_root; ++ struct au_branch *br; ++ ++ AuRwMustAnyLock(&sbinfo->si_rwsem); ++ ++ err = 0; ++ f = au_sbi(sb)->si_xib; ++ if (!f) ++ goto out; ++ ++ /* stop printing the default xino path on the first writable branch */ ++ h_root = NULL; ++ bindex = au_xi_root(sb, f->f_path.dentry); ++ if (bindex >= 0) { ++ br = au_sbr_sb(sb, bindex); ++ h_root = au_br_dentry(br); ++ } ++ ++ d = f->f_path.dentry; ++ name = &d->d_name; ++ /* safe ->d_parent because the file is unlinked */ ++ if (d->d_parent == h_root ++ && name->len == len ++ && !memcmp(name->name, AUFS_XINO_FNAME, len)) ++ goto out; ++ ++ seq_puts(seq, ",xino="); ++ err = au_xino_path(seq, f); ++ ++out: ++ return err; ++#endif ++} ++ ++/* seq_file will re-call me in case of too long string */ ++static int aufs_show_options(struct seq_file *m, struct dentry *dentry) ++{ ++ int err; ++ unsigned int mnt_flags, v; ++ struct super_block *sb; ++ struct au_sbinfo *sbinfo; ++ ++#define AuBool(name, str) do { \ ++ v = au_opt_test(mnt_flags, name); \ ++ if (v != au_opt_test(AuOpt_Def, name)) \ ++ seq_printf(m, ",%s" #str, v ? "" : "no"); \ ++} while (0) ++ ++#define AuStr(name, str) do { \ ++ v = mnt_flags & AuOptMask_##name; \ ++ if (v != (AuOpt_Def & AuOptMask_##name)) \ ++ seq_printf(m, "," #str "=%s", au_optstr_##str(v)); \ ++} while (0) ++ ++#define AuUInt(name, str, val) do { \ ++ if (val != AUFS_##name##_DEF) \ ++ seq_printf(m, "," #str "=%u", val); \ ++} while (0) ++ ++ sb = dentry->d_sb; ++ if (sb->s_flags & SB_POSIXACL) ++ seq_puts(m, ",acl"); ++#if 0 /* reserved for future use */ ++ if (sb->s_flags & SB_I_VERSION) ++ seq_puts(m, ",i_version"); ++#endif ++ ++ /* lock free root dinfo */ ++ si_noflush_read_lock(sb); ++ sbinfo = au_sbi(sb); ++ seq_printf(m, ",si=%lx", sysaufs_si_id(sbinfo)); ++ ++ mnt_flags = au_mntflags(sb); ++ if (au_opt_test(mnt_flags, XINO)) { ++ err = au_show_xino(m, sb); ++ if (unlikely(err)) ++ goto out; ++ } else ++ seq_puts(m, ",noxino"); ++ ++ AuBool(TRUNC_XINO, trunc_xino); ++ AuStr(UDBA, udba); ++ AuBool(SHWH, shwh); ++ AuBool(PLINK, plink); ++ AuBool(DIO, dio); ++ AuBool(DIRPERM1, dirperm1); ++ ++ v = sbinfo->si_wbr_create; ++ if (v != AuWbrCreate_Def) ++ au_show_wbr_create(m, v, sbinfo); ++ ++ v = sbinfo->si_wbr_copyup; ++ if (v != AuWbrCopyup_Def) ++ seq_printf(m, ",cpup=%s", au_optstr_wbr_copyup(v)); ++ ++ v = au_opt_test(mnt_flags, ALWAYS_DIROPQ); ++ if (v != au_opt_test(AuOpt_Def, ALWAYS_DIROPQ)) ++ seq_printf(m, ",diropq=%c", v ? 'a' : 'w'); ++ ++ AuUInt(DIRWH, dirwh, sbinfo->si_dirwh); ++ ++ v = jiffies_to_msecs(sbinfo->si_rdcache) / MSEC_PER_SEC; ++ AuUInt(RDCACHE, rdcache, v); ++ ++ AuUInt(RDBLK, rdblk, sbinfo->si_rdblk); ++ AuUInt(RDHASH, rdhash, sbinfo->si_rdhash); ++ ++ au_fhsm_show(m, sbinfo); ++ ++ AuBool(DIRREN, dirren); ++ AuBool(SUM, sum); ++ /* AuBool(SUM_W, wsum); */ ++ AuBool(WARN_PERM, warn_perm); ++ AuBool(VERBOSE, verbose); ++ ++out: ++ /* be sure to print "br:" last */ ++ if (!sysaufs_brs) { ++ seq_puts(m, ",br:"); ++ au_show_brs(m, sb); ++ } ++ si_read_unlock(sb); ++ return 0; ++ ++#undef AuBool ++#undef AuStr ++#undef AuUInt ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* sum mode which returns the summation for statfs(2) */ ++ ++static u64 au_add_till_max(u64 a, u64 b) ++{ ++ u64 old; ++ ++ old = a; ++ a += b; ++ if (old <= a) ++ return a; ++ return ULLONG_MAX; ++} ++ ++static u64 au_mul_till_max(u64 a, long mul) ++{ ++ u64 old; ++ ++ old = a; ++ a *= mul; ++ if (old <= a) ++ return a; ++ return ULLONG_MAX; ++} ++ ++static int au_statfs_sum(struct super_block *sb, struct kstatfs *buf) ++{ ++ int err; ++ long bsize, factor; ++ u64 blocks, bfree, bavail, files, ffree; ++ aufs_bindex_t bbot, bindex, i; ++ unsigned char shared; ++ struct path h_path; ++ struct super_block *h_sb; ++ ++ err = 0; ++ bsize = LONG_MAX; ++ files = 0; ++ ffree = 0; ++ blocks = 0; ++ bfree = 0; ++ bavail = 0; ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ h_path.mnt = au_sbr_mnt(sb, bindex); ++ h_sb = h_path.mnt->mnt_sb; ++ shared = 0; ++ for (i = 0; !shared && i < bindex; i++) ++ shared = (au_sbr_sb(sb, i) == h_sb); ++ if (shared) ++ continue; ++ ++ /* sb->s_root for NFS is unreliable */ ++ h_path.dentry = h_path.mnt->mnt_root; ++ err = vfs_statfs(&h_path, buf); ++ if (unlikely(err)) ++ goto out; ++ ++ if (bsize > buf->f_bsize) { ++ /* ++ * we will reduce bsize, so we have to expand blocks ++ * etc. to match them again ++ */ ++ factor = (bsize / buf->f_bsize); ++ blocks = au_mul_till_max(blocks, factor); ++ bfree = au_mul_till_max(bfree, factor); ++ bavail = au_mul_till_max(bavail, factor); ++ bsize = buf->f_bsize; ++ } ++ ++ factor = (buf->f_bsize / bsize); ++ blocks = au_add_till_max(blocks, ++ au_mul_till_max(buf->f_blocks, factor)); ++ bfree = au_add_till_max(bfree, ++ au_mul_till_max(buf->f_bfree, factor)); ++ bavail = au_add_till_max(bavail, ++ au_mul_till_max(buf->f_bavail, factor)); ++ files = au_add_till_max(files, buf->f_files); ++ ffree = au_add_till_max(ffree, buf->f_ffree); ++ } ++ ++ buf->f_bsize = bsize; ++ buf->f_blocks = blocks; ++ buf->f_bfree = bfree; ++ buf->f_bavail = bavail; ++ buf->f_files = files; ++ buf->f_ffree = ffree; ++ buf->f_frsize = 0; ++ ++out: ++ return err; ++} ++ ++static int aufs_statfs(struct dentry *dentry, struct kstatfs *buf) ++{ ++ int err; ++ struct path h_path; ++ struct super_block *sb; ++ ++ /* lock free root dinfo */ ++ sb = dentry->d_sb; ++ si_noflush_read_lock(sb); ++ if (!au_opt_test(au_mntflags(sb), SUM)) { ++ /* sb->s_root for NFS is unreliable */ ++ h_path.mnt = au_sbr_mnt(sb, 0); ++ h_path.dentry = h_path.mnt->mnt_root; ++ err = vfs_statfs(&h_path, buf); ++ } else ++ err = au_statfs_sum(sb, buf); ++ si_read_unlock(sb); ++ ++ if (!err) { ++ buf->f_type = AUFS_SUPER_MAGIC; ++ buf->f_namelen = AUFS_MAX_NAMELEN; ++ memset(&buf->f_fsid, 0, sizeof(buf->f_fsid)); ++ } ++ /* buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1; */ ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int aufs_sync_fs(struct super_block *sb, int wait) ++{ ++ int err, e; ++ aufs_bindex_t bbot, bindex; ++ struct au_branch *br; ++ struct super_block *h_sb; ++ ++ err = 0; ++ si_noflush_read_lock(sb); ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (!au_br_writable(br->br_perm)) ++ continue; ++ ++ h_sb = au_sbr_sb(sb, bindex); ++ e = vfsub_sync_filesystem(h_sb, wait); ++ if (unlikely(e && !err)) ++ err = e; ++ /* go on even if an error happens */ ++ } ++ si_read_unlock(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* final actions when unmounting a file system */ ++static void aufs_put_super(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ sbinfo = au_sbi(sb); ++ if (sbinfo) ++ kobject_put(&sbinfo->si_kobj); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, ++ struct super_block *sb, void *arg) ++{ ++ void *array; ++ unsigned long long n, sz; ++ ++ array = NULL; ++ n = 0; ++ if (!*hint) ++ goto out; ++ ++ if (*hint > ULLONG_MAX / sizeof(array)) { ++ array = ERR_PTR(-EMFILE); ++ pr_err("hint %llu\n", *hint); ++ goto out; ++ } ++ ++ sz = sizeof(array) * *hint; ++ array = kzalloc(sz, GFP_NOFS); ++ if (unlikely(!array)) ++ array = vzalloc(sz); ++ if (unlikely(!array)) { ++ array = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ ++ n = cb(sb, array, *hint, arg); ++ AuDebugOn(n > *hint); ++ ++out: ++ *hint = n; ++ return array; ++} ++ ++static unsigned long long au_iarray_cb(struct super_block *sb, void *a, ++ unsigned long long max __maybe_unused, ++ void *arg) ++{ ++ unsigned long long n; ++ struct inode **p, *inode; ++ struct list_head *head; ++ ++ n = 0; ++ p = a; ++ head = arg; ++ spin_lock(&sb->s_inode_list_lock); ++ list_for_each_entry(inode, head, i_sb_list) { ++ if (!au_is_bad_inode(inode) ++ && au_ii(inode)->ii_btop >= 0) { ++ spin_lock(&inode->i_lock); ++ if (atomic_read(&inode->i_count)) { ++ au_igrab(inode); ++ *p++ = inode; ++ n++; ++ AuDebugOn(n > max); ++ } ++ spin_unlock(&inode->i_lock); ++ } ++ } ++ spin_unlock(&sb->s_inode_list_lock); ++ ++ return n; ++} ++ ++struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max) ++{ ++ struct au_sbinfo *sbi; ++ ++ sbi = au_sbi(sb); ++ *max = au_lcnt_read(&sbi->si_ninodes, /*do_rev*/1); ++ return au_array_alloc(max, au_iarray_cb, sb, &sb->s_inodes); ++} ++ ++void au_iarray_free(struct inode **a, unsigned long long max) ++{ ++ unsigned long long ull; ++ ++ for (ull = 0; ull < max; ull++) ++ iput(a[ull]); ++ kvfree(a); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * refresh dentry and inode at remount time. ++ */ ++/* todo: consolidate with simple_reval_dpath() and au_reval_for_attr() */ ++static int au_do_refresh(struct dentry *dentry, unsigned int dir_flags, ++ struct dentry *parent) ++{ ++ int err; ++ ++ di_write_lock_child(dentry); ++ di_read_lock_parent(parent, AuLock_IR); ++ err = au_refresh_dentry(dentry, parent); ++ if (!err && dir_flags) ++ au_hn_reset(d_inode(dentry), dir_flags); ++ di_read_unlock(parent, AuLock_IR); ++ di_write_unlock(dentry); ++ ++ return err; ++} ++ ++static int au_do_refresh_d(struct dentry *dentry, unsigned int sigen, ++ struct au_sbinfo *sbinfo, ++ const unsigned int dir_flags, unsigned int do_idop) ++{ ++ int err; ++ struct dentry *parent; ++ ++ err = 0; ++ parent = dget_parent(dentry); ++ if (!au_digen_test(parent, sigen) && au_digen_test(dentry, sigen)) { ++ if (d_really_is_positive(dentry)) { ++ if (!d_is_dir(dentry)) ++ err = au_do_refresh(dentry, /*dir_flags*/0, ++ parent); ++ else { ++ err = au_do_refresh(dentry, dir_flags, parent); ++ if (unlikely(err)) ++ au_fset_si(sbinfo, FAILED_REFRESH_DIR); ++ } ++ } else ++ err = au_do_refresh(dentry, /*dir_flags*/0, parent); ++ AuDbgDentry(dentry); ++ } ++ dput(parent); ++ ++ if (!err) { ++ if (do_idop) ++ au_refresh_dop(dentry, /*force_reval*/0); ++ } else ++ au_refresh_dop(dentry, /*force_reval*/1); ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++static int au_refresh_d(struct super_block *sb, unsigned int do_idop) ++{ ++ int err, i, j, ndentry, e; ++ unsigned int sigen; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries, *d; ++ struct au_sbinfo *sbinfo; ++ struct dentry *root = sb->s_root; ++ const unsigned int dir_flags = au_hi_flags(d_inode(root), /*isdir*/1); ++ ++ if (do_idop) ++ au_refresh_dop(root, /*force_reval*/0); ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_dcsub_pages(&dpages, root, NULL, NULL); ++ if (unlikely(err)) ++ goto out_dpages; ++ ++ sigen = au_sigen(sb); ++ sbinfo = au_sbi(sb); ++ for (i = 0; i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ ndentry = dpage->ndentry; ++ for (j = 0; j < ndentry; j++) { ++ d = dentries[j]; ++ e = au_do_refresh_d(d, sigen, sbinfo, dir_flags, ++ do_idop); ++ if (unlikely(e && !err)) ++ err = e; ++ /* go on even err */ ++ } ++ } ++ ++out_dpages: ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++static int au_refresh_i(struct super_block *sb, unsigned int do_idop) ++{ ++ int err, e; ++ unsigned int sigen; ++ unsigned long long max, ull; ++ struct inode *inode, **array; ++ ++ array = au_iarray_alloc(sb, &max); ++ err = PTR_ERR(array); ++ if (IS_ERR(array)) ++ goto out; ++ ++ err = 0; ++ sigen = au_sigen(sb); ++ for (ull = 0; ull < max; ull++) { ++ inode = array[ull]; ++ if (unlikely(!inode)) ++ break; ++ ++ e = 0; ++ ii_write_lock_child(inode); ++ if (au_iigen(inode, NULL) != sigen) { ++ e = au_refresh_hinode_self(inode); ++ if (unlikely(e)) { ++ au_refresh_iop(inode, /*force_getattr*/1); ++ pr_err("error %d, i%lu\n", e, inode->i_ino); ++ if (!err) ++ err = e; ++ /* go on even if err */ ++ } ++ } ++ if (!e && do_idop) ++ au_refresh_iop(inode, /*force_getattr*/0); ++ ii_write_unlock(inode); ++ } ++ ++ au_iarray_free(array, max); ++ ++out: ++ return err; ++} ++ ++static void au_remount_refresh(struct super_block *sb, unsigned int do_idop) ++{ ++ int err, e; ++ unsigned int udba; ++ aufs_bindex_t bindex, bbot; ++ struct dentry *root; ++ struct inode *inode; ++ struct au_branch *br; ++ struct au_sbinfo *sbi; ++ ++ au_sigen_inc(sb); ++ sbi = au_sbi(sb); ++ au_fclr_si(sbi, FAILED_REFRESH_DIR); ++ ++ root = sb->s_root; ++ DiMustNoWaiters(root); ++ inode = d_inode(root); ++ IiMustNoWaiters(inode); ++ ++ udba = au_opt_udba(sb); ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ err = au_hnotify_reset_br(udba, br, br->br_perm); ++ if (unlikely(err)) ++ AuIOErr("hnotify failed on br %d, %d, ignored\n", ++ bindex, err); ++ /* go on even if err */ ++ } ++ au_hn_reset(inode, au_hi_flags(inode, /*isdir*/1)); ++ ++ if (do_idop) { ++ if (au_ftest_si(sbi, NO_DREVAL)) { ++ AuDebugOn(sb->s_d_op == &aufs_dop_noreval); ++ sb->s_d_op = &aufs_dop_noreval; ++ AuDebugOn(sbi->si_iop_array == aufs_iop_nogetattr); ++ sbi->si_iop_array = aufs_iop_nogetattr; ++ } else { ++ AuDebugOn(sb->s_d_op == &aufs_dop); ++ sb->s_d_op = &aufs_dop; ++ AuDebugOn(sbi->si_iop_array == aufs_iop); ++ sbi->si_iop_array = aufs_iop; ++ } ++ pr_info("reset to %ps and %ps\n", ++ sb->s_d_op, sbi->si_iop_array); ++ } ++ ++ di_write_unlock(root); ++ err = au_refresh_d(sb, do_idop); ++ e = au_refresh_i(sb, do_idop); ++ if (unlikely(e && !err)) ++ err = e; ++ /* aufs_write_lock() calls ..._child() */ ++ di_write_lock_child(root); ++ ++ au_cpup_attr_all(inode, /*force*/1); ++ ++ if (unlikely(err)) ++ AuIOErr("refresh failed, ignored, %d\n", err); ++} ++ ++/* stop extra interpretation of errno in mount(8), and strange error messages */ ++static int cvt_err(int err) ++{ ++ AuTraceErr(err); ++ ++ switch (err) { ++ case -ENOENT: ++ case -ENOTDIR: ++ case -EEXIST: ++ case -EIO: ++ err = -EINVAL; ++ } ++ return err; ++} ++ ++static int aufs_remount_fs(struct super_block *sb, int *flags, char *data) ++{ ++ int err, do_dx; ++ unsigned int mntflags; ++ struct au_opts opts = { ++ .opt = NULL ++ }; ++ struct dentry *root; ++ struct inode *inode; ++ struct au_sbinfo *sbinfo; ++ ++ err = 0; ++ root = sb->s_root; ++ if (!data || !*data) { ++ err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (!err) { ++ di_write_lock_child(root); ++ err = au_opts_verify(sb, *flags, /*pending*/0); ++ aufs_write_unlock(root); ++ } ++ goto out; ++ } ++ ++ err = -ENOMEM; ++ opts.opt = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!opts.opt)) ++ goto out; ++ opts.max_opt = PAGE_SIZE / sizeof(*opts.opt); ++ opts.flags = AuOpts_REMOUNT; ++ opts.sb_flags = *flags; ++ ++ /* parse it before aufs lock */ ++ err = au_opts_parse(sb, data, &opts); ++ if (unlikely(err)) ++ goto out_opts; ++ ++ sbinfo = au_sbi(sb); ++ inode = d_inode(root); ++ inode_lock(inode); ++ err = si_write_lock(sb, AuLock_FLUSH | AuLock_NOPLM); ++ if (unlikely(err)) ++ goto out_mtx; ++ di_write_lock_child(root); ++ ++ /* au_opts_remount() may return an error */ ++ err = au_opts_remount(sb, &opts); ++ au_opts_free(&opts); ++ ++ if (au_ftest_opts(opts.flags, REFRESH)) ++ au_remount_refresh(sb, au_ftest_opts(opts.flags, REFRESH_IDOP)); ++ ++ if (au_ftest_opts(opts.flags, REFRESH_DYAOP)) { ++ mntflags = au_mntflags(sb); ++ do_dx = !!au_opt_test(mntflags, DIO); ++ au_dy_arefresh(do_dx); ++ } ++ ++ au_fhsm_wrote_all(sb, /*force*/1); /* ?? */ ++ aufs_write_unlock(root); ++ ++out_mtx: ++ inode_unlock(inode); ++out_opts: ++ free_page((unsigned long)opts.opt); ++out: ++ err = cvt_err(err); ++ AuTraceErr(err); ++ return err; ++} ++ ++static const struct super_operations aufs_sop = { ++ .alloc_inode = aufs_alloc_inode, ++ .destroy_inode = aufs_destroy_inode, ++ .free_inode = aufs_free_inode, ++ /* always deleting, no clearing */ ++ .drop_inode = generic_delete_inode, ++ .show_options = aufs_show_options, ++ .statfs = aufs_statfs, ++ .put_super = aufs_put_super, ++ .sync_fs = aufs_sync_fs, ++ .remount_fs = aufs_remount_fs ++}; ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int alloc_root(struct super_block *sb) ++{ ++ int err; ++ struct inode *inode; ++ struct dentry *root; ++ ++ err = -ENOMEM; ++ inode = au_iget_locked(sb, AUFS_ROOT_INO); ++ err = PTR_ERR(inode); ++ if (IS_ERR(inode)) ++ goto out; ++ ++ inode->i_op = aufs_iop + AuIop_DIR; /* with getattr by default */ ++ inode->i_fop = &aufs_dir_fop; ++ inode->i_mode = S_IFDIR; ++ set_nlink(inode, 2); ++ unlock_new_inode(inode); ++ ++ root = d_make_root(inode); ++ if (unlikely(!root)) ++ goto out; ++ err = PTR_ERR(root); ++ if (IS_ERR(root)) ++ goto out; ++ ++ err = au_di_init(root); ++ if (!err) { ++ sb->s_root = root; ++ return 0; /* success */ ++ } ++ dput(root); ++ ++out: ++ return err; ++} ++ ++static int aufs_fill_super(struct super_block *sb, void *raw_data, ++ int silent __maybe_unused) ++{ ++ int err; ++ struct au_opts opts = { ++ .opt = NULL ++ }; ++ struct au_sbinfo *sbinfo; ++ struct dentry *root; ++ struct inode *inode; ++ char *arg = raw_data; ++ ++ if (unlikely(!arg || !*arg)) { ++ err = -EINVAL; ++ pr_err("no arg\n"); ++ goto out; ++ } ++ ++ err = -ENOMEM; ++ opts.opt = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!opts.opt)) ++ goto out; ++ opts.max_opt = PAGE_SIZE / sizeof(*opts.opt); ++ opts.sb_flags = sb->s_flags; ++ ++ err = au_si_alloc(sb); ++ if (unlikely(err)) ++ goto out_opts; ++ sbinfo = au_sbi(sb); ++ ++ /* all timestamps always follow the ones on the branch */ ++ sb->s_flags |= SB_NOATIME | SB_NODIRATIME; ++ sb->s_flags |= SB_I_VERSION; /* do we really need this? */ ++ sb->s_op = &aufs_sop; ++ sb->s_d_op = &aufs_dop; ++ sb->s_magic = AUFS_SUPER_MAGIC; ++ sb->s_maxbytes = 0; ++ sb->s_stack_depth = 1; ++ au_export_init(sb); ++ au_xattr_init(sb); ++ ++ err = alloc_root(sb); ++ if (unlikely(err)) { ++ si_write_unlock(sb); ++ goto out_info; ++ } ++ root = sb->s_root; ++ inode = d_inode(root); ++ ++ /* ++ * actually we can parse options regardless aufs lock here. ++ * but at remount time, parsing must be done before aufs lock. ++ * so we follow the same rule. ++ */ ++ ii_write_lock_parent(inode); ++ aufs_write_unlock(root); ++ err = au_opts_parse(sb, arg, &opts); ++ if (unlikely(err)) ++ goto out_root; ++ ++ /* lock vfs_inode first, then aufs. */ ++ inode_lock(inode); ++ aufs_write_lock(root); ++ err = au_opts_mount(sb, &opts); ++ au_opts_free(&opts); ++ if (!err && au_ftest_si(sbinfo, NO_DREVAL)) { ++ sb->s_d_op = &aufs_dop_noreval; ++ pr_info("%ps\n", sb->s_d_op); ++ au_refresh_dop(root, /*force_reval*/0); ++ sbinfo->si_iop_array = aufs_iop_nogetattr; ++ au_refresh_iop(inode, /*force_getattr*/0); ++ } ++ aufs_write_unlock(root); ++ inode_unlock(inode); ++ if (!err) ++ goto out_opts; /* success */ ++ ++out_root: ++ dput(root); ++ sb->s_root = NULL; ++out_info: ++ kobject_put(&sbinfo->si_kobj); ++ sb->s_fs_info = NULL; ++out_opts: ++ free_page((unsigned long)opts.opt); ++out: ++ AuTraceErr(err); ++ err = cvt_err(err); ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct dentry *aufs_mount(struct file_system_type *fs_type, int flags, ++ const char *dev_name __maybe_unused, ++ void *raw_data) ++{ ++ struct dentry *root; ++ ++ /* all timestamps always follow the ones on the branch */ ++ /* mnt->mnt_flags |= MNT_NOATIME | MNT_NODIRATIME; */ ++ root = mount_nodev(fs_type, flags, raw_data, aufs_fill_super); ++ if (IS_ERR(root)) ++ goto out; ++ ++ au_sbilist_add(root->d_sb); ++ ++out: ++ return root; ++} ++ ++static void aufs_kill_sb(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ sbinfo = au_sbi(sb); ++ if (sbinfo) { ++ au_sbilist_del(sb); ++ aufs_write_lock(sb->s_root); ++ au_fhsm_fin(sb); ++ if (sbinfo->si_wbr_create_ops->fin) ++ sbinfo->si_wbr_create_ops->fin(sb); ++ if (au_opt_test(sbinfo->si_mntflags, UDBA_HNOTIFY)) { ++ au_opt_set_udba(sbinfo->si_mntflags, UDBA_NONE); ++ au_remount_refresh(sb, /*do_idop*/0); ++ } ++ if (au_opt_test(sbinfo->si_mntflags, PLINK)) ++ au_plink_put(sb, /*verbose*/1); ++ au_xino_clr(sb); ++ au_dr_opt_flush(sb); ++ sbinfo->si_sb = NULL; ++ aufs_write_unlock(sb->s_root); ++ au_nwt_flush(&sbinfo->si_nowait); ++ } ++ kill_anon_super(sb); ++} ++ ++struct file_system_type aufs_fs_type = { ++ .name = AUFS_FSTYPE, ++ /* a race between rename and others */ ++ .fs_flags = FS_RENAME_DOES_D_MOVE, ++ .mount = aufs_mount, ++ .kill_sb = aufs_kill_sb, ++ /* no need to __module_get() and module_put(). */ ++ .owner = THIS_MODULE, ++}; +diff --git a/fs/aufs/super.h b/fs/aufs/super.h +new file mode 100644 +index 000000000000..f840eedbd572 +--- /dev/null ++++ b/fs/aufs/super.h +@@ -0,0 +1,574 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2020 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) */ ++ 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 */ ++ const struct inode_operations *si_iop_array; ++ ++ /* ++ * sysfs and lifetime management. ++ * this is not a small structure and it may be a waste of memory in case ++ * of sysfs is disabled, particularly when many aufs-es are mounted. ++ * but using sysfs is majority. ++ */ ++ struct kobject si_kobj; ++#ifdef CONFIG_DEBUG_FS ++ struct dentry *si_dbgaufs; ++ struct dentry *si_dbgaufs_plink; ++ struct dentry *si_dbgaufs_xib; ++#ifdef CONFIG_AUFS_EXPORT ++ struct dentry *si_dbgaufs_xigen; ++#endif ++#endif ++ ++#ifdef CONFIG_AUFS_SBILIST ++ struct hlist_bl_node si_list; ++#endif ++ ++ /* dirty, necessary for unmounting, sysfs and sysrq */ ++ struct super_block *si_sb; ++}; ++ ++/* sbinfo status flags */ ++/* ++ * set true when refresh_dirs() failed at remount time. ++ * then try refreshing dirs at access time again. ++ * if it is false, refreshing dirs at access time is unnecessary ++ */ ++#define AuSi_FAILED_REFRESH_DIR 1 ++#define AuSi_FHSM (1 << 1) /* fhsm is active now */ ++#define AuSi_NO_DREVAL (1 << 2) /* disable all d_revalidate */ ++ ++#ifndef CONFIG_AUFS_FHSM ++#undef AuSi_FHSM ++#define AuSi_FHSM 0 ++#endif ++ ++static inline unsigned char au_do_ftest_si(struct au_sbinfo *sbi, ++ unsigned int flag) ++{ ++ AuRwMustAnyLock(&sbi->si_rwsem); ++ return sbi->au_si_status & flag; ++} ++#define au_ftest_si(sbinfo, name) au_do_ftest_si(sbinfo, AuSi_##name) ++#define au_fset_si(sbinfo, name) do { \ ++ AuRwMustWriteLock(&(sbinfo)->si_rwsem); \ ++ (sbinfo)->au_si_status |= AuSi_##name; \ ++} while (0) ++#define au_fclr_si(sbinfo, name) do { \ ++ AuRwMustWriteLock(&(sbinfo)->si_rwsem); \ ++ (sbinfo)->au_si_status &= ~AuSi_##name; \ ++} while (0) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policy to select one among writable branches */ ++#define AuWbrCopyup(sbinfo, ...) \ ++ ((sbinfo)->si_wbr_copyup_ops->copyup(__VA_ARGS__)) ++#define AuWbrCreate(sbinfo, ...) \ ++ ((sbinfo)->si_wbr_create_ops->create(__VA_ARGS__)) ++ ++/* flags for si_read_lock()/aufs_read_lock()/di_read_lock() */ ++#define AuLock_DW 1 /* write-lock dentry */ ++#define AuLock_IR (1 << 1) /* read-lock inode */ ++#define AuLock_IW (1 << 2) /* write-lock inode */ ++#define AuLock_FLUSH (1 << 3) /* wait for 'nowait' tasks */ ++#define AuLock_DIRS (1 << 4) /* target is a pair of dirs */ ++ /* except RENAME_EXCHANGE */ ++#define AuLock_NOPLM (1 << 5) /* return err in plm mode */ ++#define AuLock_NOPLMW (1 << 6) /* wait for plm mode ends */ ++#define AuLock_GEN (1 << 7) /* test digen/iigen */ ++#define au_ftest_lock(flags, name) ((flags) & AuLock_##name) ++#define au_fset_lock(flags, name) \ ++ do { (flags) |= AuLock_##name; } while (0) ++#define au_fclr_lock(flags, name) \ ++ do { (flags) &= ~AuLock_##name; } while (0) ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* super.c */ ++extern struct file_system_type aufs_fs_type; ++struct inode *au_iget_locked(struct super_block *sb, ino_t ino); ++typedef unsigned long long (*au_arraycb_t)(struct super_block *sb, void *array, ++ unsigned long long max, void *arg); ++void *au_array_alloc(unsigned long long *hint, au_arraycb_t cb, ++ struct super_block *sb, void *arg); ++struct inode **au_iarray_alloc(struct super_block *sb, unsigned long long *max); ++void au_iarray_free(struct inode **a, unsigned long long max); ++ ++/* sbinfo.c */ ++void au_si_free(struct kobject *kobj); ++int au_si_alloc(struct super_block *sb); ++int au_sbr_realloc(struct au_sbinfo *sbinfo, int nbr, int may_shrink); ++ ++unsigned int au_sigen_inc(struct super_block *sb); ++aufs_bindex_t au_new_br_id(struct super_block *sb); ++ ++int si_read_lock(struct super_block *sb, int flags); ++int si_write_lock(struct super_block *sb, int flags); ++int aufs_read_lock(struct dentry *dentry, int flags); ++void aufs_read_unlock(struct dentry *dentry, int flags); ++void aufs_write_lock(struct dentry *dentry); ++void aufs_write_unlock(struct dentry *dentry); ++int aufs_read_and_write_lock2(struct dentry *d1, struct dentry *d2, int flags); ++void aufs_read_and_write_unlock2(struct dentry *d1, struct dentry *d2); ++ ++/* wbr_policy.c */ ++extern struct au_wbr_copyup_operations au_wbr_copyup_ops[]; ++extern struct au_wbr_create_operations au_wbr_create_ops[]; ++int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst); ++int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex); ++int au_wbr_do_copyup_bu(struct dentry *dentry, aufs_bindex_t btop); ++ ++/* mvdown.c */ ++int au_mvdown(struct dentry *dentry, struct aufs_mvdown __user *arg); ++ ++#ifdef CONFIG_AUFS_FHSM ++/* fhsm.c */ ++ ++static inline pid_t au_fhsm_pid(struct au_fhsm *fhsm) ++{ ++ pid_t pid; ++ ++ spin_lock(&fhsm->fhsm_spin); ++ pid = fhsm->fhsm_pid; ++ spin_unlock(&fhsm->fhsm_spin); ++ ++ return pid; ++} ++ ++void au_fhsm_wrote(struct super_block *sb, aufs_bindex_t bindex, int force); ++void au_fhsm_wrote_all(struct super_block *sb, int force); ++int au_fhsm_fd(struct super_block *sb, int oflags); ++int au_fhsm_br_alloc(struct au_branch *br); ++void au_fhsm_set_bottom(struct super_block *sb, aufs_bindex_t bindex); ++void au_fhsm_fin(struct super_block *sb); ++void au_fhsm_init(struct au_sbinfo *sbinfo); ++void au_fhsm_set(struct au_sbinfo *sbinfo, unsigned int sec); ++void au_fhsm_show(struct seq_file *seq, struct au_sbinfo *sbinfo); ++#else ++AuStubVoid(au_fhsm_wrote, struct super_block *sb, aufs_bindex_t bindex, ++ int force) ++AuStubVoid(au_fhsm_wrote_all, struct super_block *sb, int force) ++AuStub(int, au_fhsm_fd, return -EOPNOTSUPP, struct super_block *sb, int oflags) ++AuStub(pid_t, au_fhsm_pid, return 0, struct au_fhsm *fhsm) ++AuStubInt0(au_fhsm_br_alloc, struct au_branch *br) ++AuStubVoid(au_fhsm_set_bottom, struct super_block *sb, aufs_bindex_t bindex) ++AuStubVoid(au_fhsm_fin, struct super_block *sb) ++AuStubVoid(au_fhsm_init, struct au_sbinfo *sbinfo) ++AuStubVoid(au_fhsm_set, struct au_sbinfo *sbinfo, unsigned int sec) ++AuStubVoid(au_fhsm_show, struct seq_file *seq, struct au_sbinfo *sbinfo) ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline struct au_sbinfo *au_sbi(struct super_block *sb) ++{ ++ return sb->s_fs_info; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_EXPORT ++int au_test_nfsd(void); ++void au_export_init(struct super_block *sb); ++void au_xigen_inc(struct inode *inode); ++int au_xigen_new(struct inode *inode); ++int au_xigen_set(struct super_block *sb, struct path *path); ++void au_xigen_clr(struct super_block *sb); ++ ++static inline int au_busy_or_stale(void) ++{ ++ if (!au_test_nfsd()) ++ return -EBUSY; ++ return -ESTALE; ++} ++#else ++AuStubInt0(au_test_nfsd, void) ++AuStubVoid(au_export_init, struct super_block *sb) ++AuStubVoid(au_xigen_inc, struct inode *inode) ++AuStubInt0(au_xigen_new, struct inode *inode) ++AuStubInt0(au_xigen_set, struct super_block *sb, struct path *path) ++AuStubVoid(au_xigen_clr, struct super_block *sb) ++AuStub(int, au_busy_or_stale, return -EBUSY, void) ++#endif /* CONFIG_AUFS_EXPORT */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef CONFIG_AUFS_SBILIST ++/* module.c */ ++extern struct hlist_bl_head au_sbilist; ++ ++static inline void au_sbilist_init(void) ++{ ++ INIT_HLIST_BL_HEAD(&au_sbilist); ++} ++ ++static inline void au_sbilist_add(struct super_block *sb) ++{ ++ au_hbl_add(&au_sbi(sb)->si_list, &au_sbilist); ++} ++ ++static inline void au_sbilist_del(struct super_block *sb) ++{ ++ au_hbl_del(&au_sbi(sb)->si_list, &au_sbilist); ++} ++ ++#ifdef CONFIG_AUFS_MAGIC_SYSRQ ++static inline void au_sbilist_lock(void) ++{ ++ hlist_bl_lock(&au_sbilist); ++} ++ ++static inline void au_sbilist_unlock(void) ++{ ++ hlist_bl_unlock(&au_sbilist); ++} ++#define AuGFP_SBILIST GFP_ATOMIC ++#else ++AuStubVoid(au_sbilist_lock, void) ++AuStubVoid(au_sbilist_unlock, void) ++#define AuGFP_SBILIST GFP_NOFS ++#endif /* CONFIG_AUFS_MAGIC_SYSRQ */ ++#else ++AuStubVoid(au_sbilist_init, void) ++AuStubVoid(au_sbilist_add, struct super_block *sb) ++AuStubVoid(au_sbilist_del, struct super_block *sb) ++AuStubVoid(au_sbilist_lock, void) ++AuStubVoid(au_sbilist_unlock, void) ++#define AuGFP_SBILIST GFP_NOFS ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline void dbgaufs_si_null(struct au_sbinfo *sbinfo) ++{ ++ /* ++ * This function is a dynamic '__init' function actually, ++ * so the tiny check for si_rwsem is unnecessary. ++ */ ++ /* AuRwMustWriteLock(&sbinfo->si_rwsem); */ ++#ifdef CONFIG_DEBUG_FS ++ sbinfo->si_dbgaufs = NULL; ++ sbinfo->si_dbgaufs_plink = NULL; ++ sbinfo->si_dbgaufs_xib = NULL; ++#ifdef CONFIG_AUFS_EXPORT ++ sbinfo->si_dbgaufs_xigen = NULL; ++#endif ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* current->atomic_flags */ ++/* this value should never corrupt the ones defined in linux/sched.h */ ++#define PFA_AUFS 0x10 ++ ++TASK_PFA_TEST(AUFS, test_aufs) /* task_test_aufs */ ++TASK_PFA_SET(AUFS, aufs) /* task_set_aufs */ ++TASK_PFA_CLEAR(AUFS, aufs) /* task_clear_aufs */ ++ ++static inline int si_pid_test(struct super_block *sb) ++{ ++ return !!task_test_aufs(current); ++} ++ ++static inline void si_pid_clr(struct super_block *sb) ++{ ++ AuDebugOn(!task_test_aufs(current)); ++ task_clear_aufs(current); ++} ++ ++static inline void si_pid_set(struct super_block *sb) ++{ ++ AuDebugOn(task_test_aufs(current)); ++ task_set_aufs(current); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock superblock. mainly for entry point functions */ ++#define __si_read_lock(sb) au_rw_read_lock(&au_sbi(sb)->si_rwsem) ++#define __si_write_lock(sb) au_rw_write_lock(&au_sbi(sb)->si_rwsem) ++#define __si_read_trylock(sb) au_rw_read_trylock(&au_sbi(sb)->si_rwsem) ++#define __si_write_trylock(sb) au_rw_write_trylock(&au_sbi(sb)->si_rwsem) ++/* ++#define __si_read_trylock_nested(sb) \ ++ au_rw_read_trylock_nested(&au_sbi(sb)->si_rwsem) ++#define __si_write_trylock_nested(sb) \ ++ au_rw_write_trylock_nested(&au_sbi(sb)->si_rwsem) ++*/ ++ ++#define __si_read_unlock(sb) au_rw_read_unlock(&au_sbi(sb)->si_rwsem) ++#define __si_write_unlock(sb) au_rw_write_unlock(&au_sbi(sb)->si_rwsem) ++#define __si_downgrade_lock(sb) au_rw_dgrade_lock(&au_sbi(sb)->si_rwsem) ++ ++#define SiMustNoWaiters(sb) AuRwMustNoWaiters(&au_sbi(sb)->si_rwsem) ++#define SiMustAnyLock(sb) AuRwMustAnyLock(&au_sbi(sb)->si_rwsem) ++#define SiMustWriteLock(sb) AuRwMustWriteLock(&au_sbi(sb)->si_rwsem) ++ ++static inline void si_noflush_read_lock(struct super_block *sb) ++{ ++ __si_read_lock(sb); ++ si_pid_set(sb); ++} ++ ++static inline int si_noflush_read_trylock(struct super_block *sb) ++{ ++ int locked; ++ ++ locked = __si_read_trylock(sb); ++ if (locked) ++ si_pid_set(sb); ++ return locked; ++} ++ ++static inline void si_noflush_write_lock(struct super_block *sb) ++{ ++ __si_write_lock(sb); ++ si_pid_set(sb); ++} ++ ++static inline int si_noflush_write_trylock(struct super_block *sb) ++{ ++ int locked; ++ ++ locked = __si_write_trylock(sb); ++ if (locked) ++ si_pid_set(sb); ++ return locked; ++} ++ ++#if 0 /* reserved */ ++static inline int si_read_trylock(struct super_block *sb, int flags) ++{ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ return si_noflush_read_trylock(sb); ++} ++#endif ++ ++static inline void si_read_unlock(struct super_block *sb) ++{ ++ si_pid_clr(sb); ++ __si_read_unlock(sb); ++} ++ ++#if 0 /* reserved */ ++static inline int si_write_trylock(struct super_block *sb, int flags) ++{ ++ if (au_ftest_lock(flags, FLUSH)) ++ au_nwt_flush(&au_sbi(sb)->si_nowait); ++ return si_noflush_write_trylock(sb); ++} ++#endif ++ ++static inline void si_write_unlock(struct super_block *sb) ++{ ++ si_pid_clr(sb); ++ __si_write_unlock(sb); ++} ++ ++#if 0 /* reserved */ ++static inline void si_downgrade_lock(struct super_block *sb) ++{ ++ __si_downgrade_lock(sb); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline aufs_bindex_t au_sbbot(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_bbot; ++} ++ ++static inline unsigned int au_mntflags(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_mntflags; ++} ++ ++static inline unsigned int au_sigen(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_generation; ++} ++ ++static inline struct au_branch *au_sbr(struct super_block *sb, ++ aufs_bindex_t bindex) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_branch[0 + bindex]; ++} ++ ++static inline loff_t au_xi_maxent(struct super_block *sb) ++{ ++ SiMustAnyLock(sb); ++ return au_sbi(sb)->si_ximaxent; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_SUPER_H__ */ +diff --git a/fs/aufs/sysaufs.c b/fs/aufs/sysaufs.c +new file mode 100644 +index 000000000000..88d64b34555e +--- /dev/null ++++ b/fs/aufs/sysaufs.c +@@ -0,0 +1,80 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 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..0d14752482cf +--- /dev/null ++++ b/fs/aufs/sysaufs.h +@@ -0,0 +1,89 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2020 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..955ed071a12a +--- /dev/null ++++ b/fs/aufs/sysfs.c +@@ -0,0 +1,338 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * sysfs interface ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++static struct attribute *au_attr[] = { ++ NULL, /* need to NULL terminate the list of attributes */ ++}; ++ ++static struct attribute_group sysaufs_attr_group_body = { ++ .attrs = au_attr ++}; ++ ++struct attribute_group *sysaufs_attr_group = &sysaufs_attr_group_body; ++ ++/* ---------------------------------------------------------------------- */ ++ ++int sysaufs_si_xi_path(struct seq_file *seq, struct super_block *sb) ++{ ++ int err; ++ ++ SiMustAnyLock(sb); ++ ++ err = 0; ++ if (au_opt_test(au_mntflags(sb), XINO)) { ++ err = au_xino_path(seq, au_sbi(sb)->si_xib); ++ seq_putc(seq, '\n'); ++ } ++ return err; ++} ++ ++/* ++ * the lifetime of branch is independent from the entry under sysfs. ++ * sysfs handles the lifetime of the entry, and never call ->show() after it is ++ * unlinked. ++ */ ++static int sysaufs_si_br(struct seq_file *seq, struct super_block *sb, ++ aufs_bindex_t bindex, int idx) ++{ ++ int err; ++ struct path path; ++ struct dentry *root; ++ struct au_branch *br; ++ au_br_perm_str_t perm; ++ ++ AuDbg("b%d\n", bindex); ++ ++ err = 0; ++ root = sb->s_root; ++ di_read_lock_parent(root, !AuLock_IR); ++ br = au_sbr(sb, bindex); ++ ++ switch (idx) { ++ case AuBrSysfs_BR: ++ path.mnt = au_br_mnt(br); ++ path.dentry = au_h_dptr(root, bindex); ++ err = au_seq_path(seq, &path); ++ if (!err) { ++ au_optstr_br_perm(&perm, br->br_perm); ++ seq_printf(seq, "=%s\n", perm.a); ++ } ++ break; ++ case AuBrSysfs_BRID: ++ seq_printf(seq, "%d\n", br->br_id); ++ break; ++ } ++ di_read_unlock(root, !AuLock_IR); ++ if (unlikely(err || seq_has_overflowed(seq))) ++ err = -E2BIG; ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static struct seq_file *au_seq(char *p, ssize_t len) ++{ ++ struct seq_file *seq; ++ ++ seq = kzalloc(sizeof(*seq), GFP_NOFS); ++ if (seq) { ++ /* mutex_init(&seq.lock); */ ++ seq->buf = p; ++ seq->size = len; ++ return seq; /* success */ ++ } ++ ++ seq = ERR_PTR(-ENOMEM); ++ return seq; ++} ++ ++#define SysaufsBr_PREFIX "br" ++#define SysaufsBrid_PREFIX "brid" ++ ++/* todo: file size may exceed PAGE_SIZE */ ++ssize_t sysaufs_si_show(struct kobject *kobj, struct attribute *attr, ++ char *buf) ++{ ++ ssize_t err; ++ int idx; ++ long l; ++ aufs_bindex_t bbot; ++ struct au_sbinfo *sbinfo; ++ struct super_block *sb; ++ struct seq_file *seq; ++ char *name; ++ struct attribute **cattr; ++ ++ sbinfo = container_of(kobj, struct au_sbinfo, si_kobj); ++ sb = sbinfo->si_sb; ++ ++ /* ++ * prevent a race condition between sysfs and aufs. ++ * for instance, sysfs_file_read() calls sysfs_get_active_two() which ++ * prohibits maintaining the sysfs entries. ++ * hew we acquire read lock after sysfs_get_active_two(). ++ * on the other hand, the remount process may maintain the sysfs/aufs ++ * entries after acquiring write lock. ++ * it can cause a deadlock. ++ * simply we gave up processing read here. ++ */ ++ err = -EBUSY; ++ if (unlikely(!si_noflush_read_trylock(sb))) ++ goto out; ++ ++ seq = au_seq(buf, PAGE_SIZE); ++ err = PTR_ERR(seq); ++ if (IS_ERR(seq)) ++ goto out_unlock; ++ ++ name = (void *)attr->name; ++ cattr = sysaufs_si_attrs; ++ while (*cattr) { ++ if (!strcmp(name, (*cattr)->name)) { ++ err = container_of(*cattr, struct sysaufs_si_attr, attr) ++ ->show(seq, sb); ++ goto out_seq; ++ } ++ cattr++; ++ } ++ ++ if (!strncmp(name, SysaufsBrid_PREFIX, ++ sizeof(SysaufsBrid_PREFIX) - 1)) { ++ idx = AuBrSysfs_BRID; ++ name += sizeof(SysaufsBrid_PREFIX) - 1; ++ } else if (!strncmp(name, SysaufsBr_PREFIX, ++ sizeof(SysaufsBr_PREFIX) - 1)) { ++ idx = AuBrSysfs_BR; ++ name += sizeof(SysaufsBr_PREFIX) - 1; ++ } else ++ BUG(); ++ ++ err = kstrtol(name, 10, &l); ++ if (!err) { ++ bbot = au_sbbot(sb); ++ if (l <= bbot) ++ err = sysaufs_si_br(seq, sb, (aufs_bindex_t)l, idx); ++ else ++ err = -ENOENT; ++ } ++ ++out_seq: ++ if (!err) { ++ err = seq->count; ++ /* sysfs limit */ ++ if (unlikely(err == PAGE_SIZE)) ++ err = -EFBIG; ++ } ++ au_kfree_rcu(seq); ++out_unlock: ++ si_read_unlock(sb); ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_brinfo(struct super_block *sb, union aufs_brinfo __user *arg) ++{ ++ int err; ++ int16_t brid; ++ aufs_bindex_t bindex, bbot; ++ size_t sz; ++ char *buf; ++ struct seq_file *seq; ++ struct au_branch *br; ++ ++ si_read_lock(sb, AuLock_FLUSH); ++ bbot = au_sbbot(sb); ++ err = bbot + 1; ++ if (!arg) ++ goto out; ++ ++ err = -ENOMEM; ++ buf = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!buf)) ++ goto out; ++ ++ seq = au_seq(buf, PAGE_SIZE); ++ err = PTR_ERR(seq); ++ if (IS_ERR(seq)) ++ goto out_buf; ++ ++ sz = sizeof(*arg) - offsetof(union aufs_brinfo, path); ++ for (bindex = 0; bindex <= bbot; bindex++, arg++) { ++ /* VERIFY_WRITE */ ++ err = !access_ok(arg, sizeof(*arg)); ++ if (unlikely(err)) ++ break; ++ ++ br = au_sbr(sb, bindex); ++ brid = br->br_id; ++ BUILD_BUG_ON(sizeof(brid) != sizeof(arg->id)); ++ err = __put_user(brid, &arg->id); ++ if (unlikely(err)) ++ break; ++ ++ BUILD_BUG_ON(sizeof(br->br_perm) != sizeof(arg->perm)); ++ err = __put_user(br->br_perm, &arg->perm); ++ if (unlikely(err)) ++ break; ++ ++ err = au_seq_path(seq, &br->br_path); ++ if (unlikely(err)) ++ break; ++ seq_putc(seq, '\0'); ++ if (!seq_has_overflowed(seq)) { ++ err = copy_to_user(arg->path, seq->buf, seq->count); ++ seq->count = 0; ++ if (unlikely(err)) ++ break; ++ } else { ++ err = -E2BIG; ++ goto out_seq; ++ } ++ } ++ if (unlikely(err)) ++ err = -EFAULT; ++ ++out_seq: ++ au_kfree_rcu(seq); ++out_buf: ++ free_page((unsigned long)buf); ++out: ++ si_read_unlock(sb); ++ return err; ++} ++ ++long au_brinfo_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_brinfo(file->f_path.dentry->d_sb, (void __user *)arg); ++} ++ ++#ifdef CONFIG_COMPAT ++long au_brinfo_compat_ioctl(struct file *file, unsigned long arg) ++{ ++ return au_brinfo(file->f_path.dentry->d_sb, compat_ptr(arg)); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++void sysaufs_br_init(struct au_branch *br) ++{ ++ int i; ++ struct au_brsysfs *br_sysfs; ++ struct attribute *attr; ++ ++ br_sysfs = br->br_sysfs; ++ for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { ++ attr = &br_sysfs->attr; ++ sysfs_attr_init(attr); ++ attr->name = br_sysfs->name; ++ attr->mode = 0444; ++ br_sysfs++; ++ } ++} ++ ++void sysaufs_brs_del(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ struct au_branch *br; ++ struct kobject *kobj; ++ struct au_brsysfs *br_sysfs; ++ int i; ++ aufs_bindex_t bbot; ++ ++ if (!sysaufs_brs) ++ return; ++ ++ kobj = &au_sbi(sb)->si_kobj; ++ bbot = au_sbbot(sb); ++ for (; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ br_sysfs = br->br_sysfs; ++ for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { ++ sysfs_remove_file(kobj, &br_sysfs->attr); ++ br_sysfs++; ++ } ++ } ++} ++ ++void sysaufs_brs_add(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ int err, i; ++ aufs_bindex_t bbot; ++ struct kobject *kobj; ++ struct au_branch *br; ++ struct au_brsysfs *br_sysfs; ++ ++ if (!sysaufs_brs) ++ return; ++ ++ kobj = &au_sbi(sb)->si_kobj; ++ bbot = au_sbbot(sb); ++ for (; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ br_sysfs = br->br_sysfs; ++ snprintf(br_sysfs[AuBrSysfs_BR].name, sizeof(br_sysfs->name), ++ SysaufsBr_PREFIX "%d", bindex); ++ snprintf(br_sysfs[AuBrSysfs_BRID].name, sizeof(br_sysfs->name), ++ SysaufsBrid_PREFIX "%d", bindex); ++ for (i = 0; i < ARRAY_SIZE(br->br_sysfs); i++) { ++ err = sysfs_create_file(kobj, &br_sysfs->attr); ++ if (unlikely(err)) ++ pr_warn("failed %s under sysfs(%d)\n", ++ br_sysfs->name, err); ++ br_sysfs++; ++ } ++ } ++} +diff --git a/fs/aufs/sysrq.c b/fs/aufs/sysrq.c +new file mode 100644 +index 000000000000..d51b95163e24 +--- /dev/null ++++ b/fs/aufs/sysrq.c +@@ -0,0 +1,136 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 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; ++ struct inode *i; ++ ++ 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 /* reserved */ ++ 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 ++ ++ 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 (hlist_empty(&i->i_dentry)) ++ au_dpri_inode(i); ++ spin_unlock(&i->i_lock); ++ } ++ spin_unlock(&sb->s_inode_list_lock); ++ ++ 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..6cc7ecf0b0e1 +--- /dev/null ++++ b/fs/aufs/vdir.c +@@ -0,0 +1,883 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * virtual or vertical directory ++ */ ++ ++#include ++#include "aufs.h" ++ ++static unsigned int calc_size(int nlen) ++{ ++ return ALIGN(sizeof(struct au_vdir_de) + nlen, sizeof(ino_t)); ++} ++ ++static int set_deblk_end(union au_vdir_deblk_p *p, ++ union au_vdir_deblk_p *deblk_end) ++{ ++ if (calc_size(0) <= deblk_end->deblk - p->deblk) { ++ p->de->de_str.len = 0; ++ /* smp_mb(); */ ++ return 0; ++ } ++ return -1; /* error */ ++} ++ ++/* returns true or false */ ++static int is_deblk_end(union au_vdir_deblk_p *p, ++ union au_vdir_deblk_p *deblk_end) ++{ ++ if (calc_size(0) <= deblk_end->deblk - p->deblk) ++ return !p->de->de_str.len; ++ return 1; ++} ++ ++static unsigned char *last_deblk(struct au_vdir *vdir) ++{ ++ return vdir->vd_deblk[vdir->vd_nblk - 1]; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* estimate the appropriate size for name hash table */ ++unsigned int au_rdhash_est(loff_t sz) ++{ ++ unsigned int n; ++ ++ n = UINT_MAX; ++ sz >>= 10; ++ if (sz < n) ++ n = sz; ++ if (sz < AUFS_RDHASH_DEF) ++ n = AUFS_RDHASH_DEF; ++ /* pr_info("n %u\n", n); */ ++ return n; ++} ++ ++/* ++ * the allocated memory has to be freed by ++ * au_nhash_wh_free() or au_nhash_de_free(). ++ */ ++int au_nhash_alloc(struct au_nhash *nhash, unsigned int num_hash, gfp_t gfp) ++{ ++ struct hlist_head *head; ++ unsigned int u; ++ size_t sz; ++ ++ sz = sizeof(*nhash->nh_head) * num_hash; ++ head = kmalloc(sz, gfp); ++ if (head) { ++ nhash->nh_num = num_hash; ++ nhash->nh_head = head; ++ for (u = 0; u < num_hash; u++) ++ INIT_HLIST_HEAD(head++); ++ return 0; /* success */ ++ } ++ ++ return -ENOMEM; ++} ++ ++static void nhash_count(struct hlist_head *head) ++{ ++#if 0 /* debugging */ ++ unsigned long n; ++ struct hlist_node *pos; ++ ++ n = 0; ++ hlist_for_each(pos, head) ++ n++; ++ pr_info("%lu\n", n); ++#endif ++} ++ ++static void au_nhash_wh_do_free(struct hlist_head *head) ++{ ++ struct au_vdir_wh *pos; ++ struct hlist_node *node; ++ ++ hlist_for_each_entry_safe(pos, node, head, wh_hash) ++ au_kfree_rcu(pos); ++} ++ ++static void au_nhash_de_do_free(struct hlist_head *head) ++{ ++ struct au_vdir_dehstr *pos; ++ struct hlist_node *node; ++ ++ hlist_for_each_entry_safe(pos, node, head, hash) ++ au_cache_free_vdir_dehstr(pos); ++} ++ ++static void au_nhash_do_free(struct au_nhash *nhash, ++ void (*free)(struct hlist_head *head)) ++{ ++ unsigned int n; ++ struct hlist_head *head; ++ ++ n = nhash->nh_num; ++ if (!n) ++ return; ++ ++ head = nhash->nh_head; ++ while (n-- > 0) { ++ nhash_count(head); ++ free(head++); ++ } ++ au_kfree_try_rcu(nhash->nh_head); ++} ++ ++void au_nhash_wh_free(struct au_nhash *whlist) ++{ ++ au_nhash_do_free(whlist, au_nhash_wh_do_free); ++} ++ ++static void au_nhash_de_free(struct au_nhash *delist) ++{ ++ au_nhash_do_free(delist, au_nhash_de_do_free); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_nhash_test_longer_wh(struct au_nhash *whlist, aufs_bindex_t btgt, ++ int limit) ++{ ++ int num; ++ unsigned int u, n; ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ ++ num = 0; ++ n = whlist->nh_num; ++ head = whlist->nh_head; ++ for (u = 0; u < n; u++, head++) ++ hlist_for_each_entry(pos, head, wh_hash) ++ if (pos->wh_bindex == btgt && ++num > limit) ++ return 1; ++ return 0; ++} ++ ++static struct hlist_head *au_name_hash(struct au_nhash *nhash, ++ unsigned char *name, ++ unsigned int len) ++{ ++ unsigned int v; ++ /* const unsigned int magic_bit = 12; */ ++ ++ AuDebugOn(!nhash->nh_num || !nhash->nh_head); ++ ++ v = 0; ++ if (len > 8) ++ len = 8; ++ while (len--) ++ v += *name++; ++ /* v = hash_long(v, magic_bit); */ ++ v %= nhash->nh_num; ++ return nhash->nh_head + v; ++} ++ ++static int au_nhash_test_name(struct au_vdir_destr *str, const char *name, ++ int nlen) ++{ ++ return str->len == nlen && !memcmp(str->name, name, nlen); ++} ++ ++/* returns found or not */ ++int au_nhash_test_known_wh(struct au_nhash *whlist, char *name, int nlen) ++{ ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ struct au_vdir_destr *str; ++ ++ head = au_name_hash(whlist, name, nlen); ++ hlist_for_each_entry(pos, head, wh_hash) { ++ str = &pos->wh_str; ++ AuDbg("%.*s\n", str->len, str->name); ++ if (au_nhash_test_name(str, name, nlen)) ++ return 1; ++ } ++ return 0; ++} ++ ++/* returns found(true) or not */ ++static int test_known(struct au_nhash *delist, char *name, int nlen) ++{ ++ struct hlist_head *head; ++ struct au_vdir_dehstr *pos; ++ struct au_vdir_destr *str; ++ ++ head = au_name_hash(delist, name, nlen); ++ hlist_for_each_entry(pos, head, hash) { ++ str = pos->str; ++ AuDbg("%.*s\n", str->len, str->name); ++ if (au_nhash_test_name(str, name, nlen)) ++ return 1; ++ } ++ return 0; ++} ++ ++static void au_shwh_init_wh(struct au_vdir_wh *wh, ino_t ino, ++ unsigned char d_type) ++{ ++#ifdef CONFIG_AUFS_SHWH ++ wh->wh_ino = ino; ++ wh->wh_type = d_type; ++#endif ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int au_nhash_append_wh(struct au_nhash *whlist, char *name, int nlen, ino_t ino, ++ unsigned int d_type, aufs_bindex_t bindex, ++ unsigned char shwh) ++{ ++ int err; ++ struct au_vdir_destr *str; ++ struct au_vdir_wh *wh; ++ ++ AuDbg("%.*s\n", nlen, name); ++ AuDebugOn(!whlist->nh_num || !whlist->nh_head); ++ ++ err = -ENOMEM; ++ wh = kmalloc(sizeof(*wh) + nlen, GFP_NOFS); ++ if (unlikely(!wh)) ++ goto out; ++ ++ err = 0; ++ wh->wh_bindex = bindex; ++ if (shwh) ++ au_shwh_init_wh(wh, ino, d_type); ++ str = &wh->wh_str; ++ str->len = nlen; ++ memcpy(str->name, name, nlen); ++ hlist_add_head(&wh->wh_hash, au_name_hash(whlist, name, nlen)); ++ /* smp_mb(); */ ++ ++out: ++ return err; ++} ++ ++static int append_deblk(struct au_vdir *vdir) ++{ ++ int err; ++ unsigned long ul; ++ const unsigned int deblk_sz = vdir->vd_deblk_sz; ++ union au_vdir_deblk_p p, deblk_end; ++ unsigned char **o; ++ ++ err = -ENOMEM; ++ o = au_krealloc(vdir->vd_deblk, sizeof(*o) * (vdir->vd_nblk + 1), ++ GFP_NOFS, /*may_shrink*/0); ++ if (unlikely(!o)) ++ goto out; ++ ++ vdir->vd_deblk = o; ++ p.deblk = kmalloc(deblk_sz, GFP_NOFS); ++ if (p.deblk) { ++ ul = vdir->vd_nblk++; ++ vdir->vd_deblk[ul] = p.deblk; ++ vdir->vd_last.ul = ul; ++ vdir->vd_last.p.deblk = p.deblk; ++ deblk_end.deblk = p.deblk + deblk_sz; ++ err = set_deblk_end(&p, &deblk_end); ++ } ++ ++out: ++ return err; ++} ++ ++static int append_de(struct au_vdir *vdir, char *name, int nlen, ino_t ino, ++ unsigned int d_type, struct au_nhash *delist) ++{ ++ int err; ++ unsigned int sz; ++ const unsigned int deblk_sz = vdir->vd_deblk_sz; ++ union au_vdir_deblk_p p, *room, deblk_end; ++ struct au_vdir_dehstr *dehstr; ++ ++ p.deblk = last_deblk(vdir); ++ deblk_end.deblk = p.deblk + deblk_sz; ++ room = &vdir->vd_last.p; ++ AuDebugOn(room->deblk < p.deblk || deblk_end.deblk <= room->deblk ++ || !is_deblk_end(room, &deblk_end)); ++ ++ sz = calc_size(nlen); ++ if (unlikely(sz > deblk_end.deblk - room->deblk)) { ++ err = append_deblk(vdir); ++ if (unlikely(err)) ++ goto out; ++ ++ p.deblk = last_deblk(vdir); ++ deblk_end.deblk = p.deblk + deblk_sz; ++ /* smp_mb(); */ ++ AuDebugOn(room->deblk != p.deblk); ++ } ++ ++ err = -ENOMEM; ++ dehstr = au_cache_alloc_vdir_dehstr(); ++ if (unlikely(!dehstr)) ++ goto out; ++ ++ dehstr->str = &room->de->de_str; ++ hlist_add_head(&dehstr->hash, au_name_hash(delist, name, nlen)); ++ room->de->de_ino = ino; ++ room->de->de_type = d_type; ++ room->de->de_str.len = nlen; ++ memcpy(room->de->de_str.name, name, nlen); ++ ++ err = 0; ++ room->deblk += sz; ++ if (unlikely(set_deblk_end(room, &deblk_end))) ++ err = append_deblk(vdir); ++ /* smp_mb(); */ ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++void au_vdir_free(struct au_vdir *vdir) ++{ ++ unsigned char **deblk; ++ ++ deblk = vdir->vd_deblk; ++ while (vdir->vd_nblk--) ++ au_kfree_try_rcu(*deblk++); ++ au_kfree_try_rcu(vdir->vd_deblk); ++ au_cache_free_vdir(vdir); ++} ++ ++static struct au_vdir *alloc_vdir(struct file *file) ++{ ++ struct au_vdir *vdir; ++ struct super_block *sb; ++ int err; ++ ++ sb = file->f_path.dentry->d_sb; ++ SiMustAnyLock(sb); ++ ++ err = -ENOMEM; ++ vdir = au_cache_alloc_vdir(); ++ if (unlikely(!vdir)) ++ goto out; ++ ++ vdir->vd_deblk = kzalloc(sizeof(*vdir->vd_deblk), GFP_NOFS); ++ if (unlikely(!vdir->vd_deblk)) ++ goto out_free; ++ ++ vdir->vd_deblk_sz = au_sbi(sb)->si_rdblk; ++ if (!vdir->vd_deblk_sz) { ++ /* estimate the appropriate size for deblk */ ++ vdir->vd_deblk_sz = au_dir_size(file, /*dentry*/NULL); ++ /* pr_info("vd_deblk_sz %u\n", vdir->vd_deblk_sz); */ ++ } ++ vdir->vd_nblk = 0; ++ vdir->vd_version = 0; ++ vdir->vd_jiffy = 0; ++ err = append_deblk(vdir); ++ if (!err) ++ return vdir; /* success */ ++ ++ au_kfree_try_rcu(vdir->vd_deblk); ++ ++out_free: ++ au_cache_free_vdir(vdir); ++out: ++ vdir = ERR_PTR(err); ++ return vdir; ++} ++ ++static int reinit_vdir(struct au_vdir *vdir) ++{ ++ int err; ++ union au_vdir_deblk_p p, deblk_end; ++ ++ while (vdir->vd_nblk > 1) { ++ au_kfree_try_rcu(vdir->vd_deblk[vdir->vd_nblk - 1]); ++ /* vdir->vd_deblk[vdir->vd_nblk - 1] = NULL; */ ++ vdir->vd_nblk--; ++ } ++ p.deblk = vdir->vd_deblk[0]; ++ deblk_end.deblk = p.deblk + vdir->vd_deblk_sz; ++ err = set_deblk_end(&p, &deblk_end); ++ /* keep vd_dblk_sz */ ++ vdir->vd_last.ul = 0; ++ vdir->vd_last.p.deblk = vdir->vd_deblk[0]; ++ vdir->vd_version = 0; ++ vdir->vd_jiffy = 0; ++ /* smp_mb(); */ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AuFillVdir_CALLED 1 ++#define AuFillVdir_WHABLE (1 << 1) ++#define AuFillVdir_SHWH (1 << 2) ++#define au_ftest_fillvdir(flags, name) ((flags) & AuFillVdir_##name) ++#define au_fset_fillvdir(flags, name) \ ++ do { (flags) |= AuFillVdir_##name; } while (0) ++#define au_fclr_fillvdir(flags, name) \ ++ do { (flags) &= ~AuFillVdir_##name; } while (0) ++ ++#ifndef CONFIG_AUFS_SHWH ++#undef AuFillVdir_SHWH ++#define AuFillVdir_SHWH 0 ++#endif ++ ++struct fillvdir_arg { ++ struct dir_context ctx; ++ struct file *file; ++ struct au_vdir *vdir; ++ struct au_nhash delist; ++ struct au_nhash whlist; ++ aufs_bindex_t bindex; ++ unsigned int flags; ++ int err; ++}; ++ ++static int fillvdir(struct dir_context *ctx, const char *__name, int nlen, ++ loff_t offset __maybe_unused, u64 h_ino, ++ unsigned int d_type) ++{ ++ struct fillvdir_arg *arg = container_of(ctx, struct fillvdir_arg, ctx); ++ char *name = (void *)__name; ++ struct super_block *sb; ++ ino_t ino; ++ const unsigned char shwh = !!au_ftest_fillvdir(arg->flags, SHWH); ++ ++ arg->err = 0; ++ sb = arg->file->f_path.dentry->d_sb; ++ au_fset_fillvdir(arg->flags, CALLED); ++ /* smp_mb(); */ ++ if (nlen <= AUFS_WH_PFX_LEN ++ || memcmp(name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) { ++ if (test_known(&arg->delist, name, nlen) ++ || au_nhash_test_known_wh(&arg->whlist, name, nlen)) ++ goto out; /* already exists or whiteouted */ ++ ++ arg->err = au_ino(sb, arg->bindex, h_ino, d_type, &ino); ++ if (!arg->err) { ++ if (unlikely(nlen > AUFS_MAX_NAMELEN)) ++ d_type = DT_UNKNOWN; ++ arg->err = append_de(arg->vdir, name, nlen, ino, ++ d_type, &arg->delist); ++ } ++ } else if (au_ftest_fillvdir(arg->flags, WHABLE)) { ++ name += AUFS_WH_PFX_LEN; ++ nlen -= AUFS_WH_PFX_LEN; ++ if (au_nhash_test_known_wh(&arg->whlist, name, nlen)) ++ goto out; /* already whiteouted */ ++ ++ ino = 0; /* just to suppress a warning */ ++ if (shwh) ++ arg->err = au_wh_ino(sb, arg->bindex, h_ino, d_type, ++ &ino); ++ if (!arg->err) { ++ if (nlen <= AUFS_MAX_NAMELEN + AUFS_WH_PFX_LEN) ++ d_type = DT_UNKNOWN; ++ arg->err = au_nhash_append_wh ++ (&arg->whlist, name, nlen, ino, d_type, ++ arg->bindex, shwh); ++ } ++ } ++ ++out: ++ if (!arg->err) ++ arg->vdir->vd_jiffy = jiffies; ++ /* smp_mb(); */ ++ AuTraceErr(arg->err); ++ return arg->err; ++} ++ ++static int au_handle_shwh(struct super_block *sb, struct au_vdir *vdir, ++ struct au_nhash *whlist, struct au_nhash *delist) ++{ ++#ifdef CONFIG_AUFS_SHWH ++ int err; ++ unsigned int nh, u; ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ struct hlist_node *n; ++ char *p, *o; ++ struct au_vdir_destr *destr; ++ ++ AuDebugOn(!au_opt_test(au_mntflags(sb), SHWH)); ++ ++ err = -ENOMEM; ++ o = p = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!p)) ++ goto out; ++ ++ err = 0; ++ nh = whlist->nh_num; ++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); ++ p += AUFS_WH_PFX_LEN; ++ for (u = 0; u < nh; u++) { ++ head = whlist->nh_head + u; ++ hlist_for_each_entry_safe(pos, n, head, wh_hash) { ++ destr = &pos->wh_str; ++ memcpy(p, destr->name, destr->len); ++ err = append_de(vdir, o, destr->len + AUFS_WH_PFX_LEN, ++ pos->wh_ino, pos->wh_type, delist); ++ if (unlikely(err)) ++ break; ++ } ++ } ++ ++ free_page((unsigned long)o); ++ ++out: ++ AuTraceErr(err); ++ return err; ++#else ++ return 0; ++#endif ++} ++ ++static int au_do_read_vdir(struct fillvdir_arg *arg) ++{ ++ int err; ++ unsigned int rdhash; ++ loff_t offset; ++ aufs_bindex_t bbot, bindex, btop; ++ unsigned char shwh; ++ struct file *hf, *file; ++ struct super_block *sb; ++ ++ file = arg->file; ++ sb = file->f_path.dentry->d_sb; ++ SiMustAnyLock(sb); ++ ++ rdhash = au_sbi(sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = au_rdhash_est(au_dir_size(file, /*dentry*/NULL)); ++ err = au_nhash_alloc(&arg->delist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ err = au_nhash_alloc(&arg->whlist, rdhash, GFP_NOFS); ++ if (unlikely(err)) ++ goto out_delist; ++ ++ err = 0; ++ arg->flags = 0; ++ shwh = 0; ++ if (au_opt_test(au_mntflags(sb), SHWH)) { ++ shwh = 1; ++ au_fset_fillvdir(arg->flags, SHWH); ++ } ++ btop = au_fbtop(file); ++ bbot = au_fbbot_dir(file); ++ for (bindex = btop; !err && bindex <= bbot; bindex++) { ++ hf = au_hf_dir(file, bindex); ++ if (!hf) ++ continue; ++ ++ offset = vfsub_llseek(hf, 0, SEEK_SET); ++ err = offset; ++ if (unlikely(offset)) ++ break; ++ ++ arg->bindex = bindex; ++ au_fclr_fillvdir(arg->flags, WHABLE); ++ if (shwh ++ || (bindex != bbot ++ && au_br_whable(au_sbr_perm(sb, bindex)))) ++ au_fset_fillvdir(arg->flags, WHABLE); ++ do { ++ arg->err = 0; ++ au_fclr_fillvdir(arg->flags, CALLED); ++ /* smp_mb(); */ ++ err = vfsub_iterate_dir(hf, &arg->ctx); ++ if (err >= 0) ++ err = arg->err; ++ } while (!err && au_ftest_fillvdir(arg->flags, CALLED)); ++ ++ /* ++ * dir_relax() may be good for concurrency, but aufs should not ++ * use it since it will cause a lockdep problem. ++ */ ++ } ++ ++ if (!err && shwh) ++ err = au_handle_shwh(sb, arg->vdir, &arg->whlist, &arg->delist); ++ ++ au_nhash_wh_free(&arg->whlist); ++ ++out_delist: ++ au_nhash_de_free(&arg->delist); ++out: ++ return err; ++} ++ ++static int read_vdir(struct file *file, int may_read) ++{ ++ int err; ++ unsigned long expire; ++ unsigned char do_read; ++ struct fillvdir_arg arg = { ++ .ctx = { ++ .actor = fillvdir ++ } ++ }; ++ struct inode *inode; ++ struct au_vdir *vdir, *allocated; ++ ++ err = 0; ++ inode = file_inode(file); ++ IMustLock(inode); ++ IiMustWriteLock(inode); ++ SiMustAnyLock(inode->i_sb); ++ ++ allocated = NULL; ++ do_read = 0; ++ expire = au_sbi(inode->i_sb)->si_rdcache; ++ vdir = au_ivdir(inode); ++ if (!vdir) { ++ do_read = 1; ++ vdir = alloc_vdir(file); ++ err = PTR_ERR(vdir); ++ if (IS_ERR(vdir)) ++ goto out; ++ err = 0; ++ allocated = vdir; ++ } else if (may_read ++ && (!inode_eq_iversion(inode, vdir->vd_version) ++ || time_after(jiffies, vdir->vd_jiffy + expire))) { ++ do_read = 1; ++ err = reinit_vdir(vdir); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++ if (!do_read) ++ return 0; /* success */ ++ ++ arg.file = file; ++ arg.vdir = vdir; ++ err = au_do_read_vdir(&arg); ++ if (!err) { ++ /* file->f_pos = 0; */ /* todo: ctx->pos? */ ++ vdir->vd_version = inode_query_iversion(inode); ++ vdir->vd_last.ul = 0; ++ vdir->vd_last.p.deblk = vdir->vd_deblk[0]; ++ if (allocated) ++ au_set_ivdir(inode, allocated); ++ } else if (allocated) ++ au_vdir_free(allocated); ++ ++out: ++ return err; ++} ++ ++static int copy_vdir(struct au_vdir *tgt, struct au_vdir *src) ++{ ++ int err, rerr; ++ unsigned long ul, n; ++ const unsigned int deblk_sz = src->vd_deblk_sz; ++ ++ AuDebugOn(tgt->vd_nblk != 1); ++ ++ err = -ENOMEM; ++ if (tgt->vd_nblk < src->vd_nblk) { ++ unsigned char **p; ++ ++ p = au_krealloc(tgt->vd_deblk, sizeof(*p) * src->vd_nblk, ++ GFP_NOFS, /*may_shrink*/0); ++ if (unlikely(!p)) ++ goto out; ++ tgt->vd_deblk = p; ++ } ++ ++ if (tgt->vd_deblk_sz != deblk_sz) { ++ unsigned char *p; ++ ++ tgt->vd_deblk_sz = deblk_sz; ++ p = au_krealloc(tgt->vd_deblk[0], deblk_sz, GFP_NOFS, ++ /*may_shrink*/1); ++ if (unlikely(!p)) ++ goto out; ++ tgt->vd_deblk[0] = p; ++ } ++ memcpy(tgt->vd_deblk[0], src->vd_deblk[0], deblk_sz); ++ tgt->vd_version = src->vd_version; ++ tgt->vd_jiffy = src->vd_jiffy; ++ ++ n = src->vd_nblk; ++ for (ul = 1; ul < n; ul++) { ++ tgt->vd_deblk[ul] = kmemdup(src->vd_deblk[ul], deblk_sz, ++ GFP_NOFS); ++ if (unlikely(!tgt->vd_deblk[ul])) ++ goto out; ++ tgt->vd_nblk++; ++ } ++ tgt->vd_nblk = n; ++ tgt->vd_last.ul = tgt->vd_last.ul; ++ tgt->vd_last.p.deblk = tgt->vd_deblk[tgt->vd_last.ul]; ++ tgt->vd_last.p.deblk += src->vd_last.p.deblk ++ - src->vd_deblk[src->vd_last.ul]; ++ /* smp_mb(); */ ++ return 0; /* success */ ++ ++out: ++ rerr = reinit_vdir(tgt); ++ BUG_ON(rerr); ++ return err; ++} ++ ++int au_vdir_init(struct file *file) ++{ ++ int err; ++ struct inode *inode; ++ struct au_vdir *vdir_cache, *allocated; ++ ++ /* test file->f_pos here instead of ctx->pos */ ++ err = read_vdir(file, !file->f_pos); ++ if (unlikely(err)) ++ goto out; ++ ++ allocated = NULL; ++ vdir_cache = au_fvdir_cache(file); ++ if (!vdir_cache) { ++ vdir_cache = alloc_vdir(file); ++ err = PTR_ERR(vdir_cache); ++ if (IS_ERR(vdir_cache)) ++ goto out; ++ allocated = vdir_cache; ++ } else if (!file->f_pos && vdir_cache->vd_version != file->f_version) { ++ /* test file->f_pos here instead of ctx->pos */ ++ err = reinit_vdir(vdir_cache); ++ if (unlikely(err)) ++ goto out; ++ } else ++ return 0; /* success */ ++ ++ inode = file_inode(file); ++ err = copy_vdir(vdir_cache, au_ivdir(inode)); ++ if (!err) { ++ file->f_version = inode_query_iversion(inode); ++ if (allocated) ++ au_set_fvdir_cache(file, allocated); ++ } else if (allocated) ++ au_vdir_free(allocated); ++ ++out: ++ return err; ++} ++ ++static loff_t calc_offset(struct au_vdir *vdir) ++{ ++ loff_t offset; ++ union au_vdir_deblk_p p; ++ ++ p.deblk = vdir->vd_deblk[vdir->vd_last.ul]; ++ offset = vdir->vd_last.p.deblk - p.deblk; ++ offset += vdir->vd_deblk_sz * vdir->vd_last.ul; ++ return offset; ++} ++ ++/* returns true or false */ ++static int seek_vdir(struct file *file, struct dir_context *ctx) ++{ ++ int valid; ++ unsigned int deblk_sz; ++ unsigned long ul, n; ++ loff_t offset; ++ union au_vdir_deblk_p p, deblk_end; ++ struct au_vdir *vdir_cache; ++ ++ valid = 1; ++ vdir_cache = au_fvdir_cache(file); ++ offset = calc_offset(vdir_cache); ++ AuDbg("offset %lld\n", offset); ++ if (ctx->pos == offset) ++ goto out; ++ ++ vdir_cache->vd_last.ul = 0; ++ vdir_cache->vd_last.p.deblk = vdir_cache->vd_deblk[0]; ++ if (!ctx->pos) ++ goto out; ++ ++ valid = 0; ++ deblk_sz = vdir_cache->vd_deblk_sz; ++ ul = div64_u64(ctx->pos, deblk_sz); ++ AuDbg("ul %lu\n", ul); ++ if (ul >= vdir_cache->vd_nblk) ++ goto out; ++ ++ n = vdir_cache->vd_nblk; ++ for (; ul < n; ul++) { ++ p.deblk = vdir_cache->vd_deblk[ul]; ++ deblk_end.deblk = p.deblk + deblk_sz; ++ offset = ul; ++ offset *= deblk_sz; ++ while (!is_deblk_end(&p, &deblk_end) && offset < ctx->pos) { ++ unsigned int l; ++ ++ l = calc_size(p.de->de_str.len); ++ offset += l; ++ p.deblk += l; ++ } ++ if (!is_deblk_end(&p, &deblk_end)) { ++ valid = 1; ++ vdir_cache->vd_last.ul = ul; ++ vdir_cache->vd_last.p = p; ++ break; ++ } ++ } ++ ++out: ++ /* smp_mb(); */ ++ if (!valid) ++ AuDbg("valid %d\n", !valid); ++ return valid; ++} ++ ++int au_vdir_fill_de(struct file *file, struct dir_context *ctx) ++{ ++ unsigned int l, deblk_sz; ++ union au_vdir_deblk_p deblk_end; ++ struct au_vdir *vdir_cache; ++ struct au_vdir_de *de; ++ ++ if (!seek_vdir(file, ctx)) ++ return 0; ++ ++ vdir_cache = au_fvdir_cache(file); ++ deblk_sz = vdir_cache->vd_deblk_sz; ++ while (1) { ++ deblk_end.deblk = vdir_cache->vd_deblk[vdir_cache->vd_last.ul]; ++ deblk_end.deblk += deblk_sz; ++ while (!is_deblk_end(&vdir_cache->vd_last.p, &deblk_end)) { ++ de = vdir_cache->vd_last.p.de; ++ AuDbg("%.*s, off%lld, i%lu, dt%d\n", ++ de->de_str.len, de->de_str.name, ctx->pos, ++ (unsigned long)de->de_ino, de->de_type); ++ if (unlikely(!dir_emit(ctx, de->de_str.name, ++ de->de_str.len, de->de_ino, ++ de->de_type))) { ++ /* todo: ignore the error caused by udba? */ ++ /* return err; */ ++ return 0; ++ } ++ ++ l = calc_size(de->de_str.len); ++ vdir_cache->vd_last.p.deblk += l; ++ ctx->pos += l; ++ } ++ if (vdir_cache->vd_last.ul < vdir_cache->vd_nblk - 1) { ++ vdir_cache->vd_last.ul++; ++ vdir_cache->vd_last.p.deblk ++ = vdir_cache->vd_deblk[vdir_cache->vd_last.ul]; ++ ctx->pos = deblk_sz * vdir_cache->vd_last.ul; ++ continue; ++ } ++ break; ++ } ++ ++ /* smp_mb(); */ ++ return 0; ++} +diff --git a/fs/aufs/vfsub.c b/fs/aufs/vfsub.c +new file mode 100644 +index 000000000000..fa29c543cc28 +--- /dev/null ++++ b/fs/aufs/vfsub.c +@@ -0,0 +1,872 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 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) ++{ ++ return dentry_open(path, flags /* | __FMODE_NONOTIFY */, ++ current_cred()); ++} ++ ++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; ++} ++ ++ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, ++ loff_t *ppos) ++{ ++ ssize_t err; ++ ++ lockdep_off(); ++ err = kernel_read(file, kbuf, count, ppos); ++ lockdep_on(); ++ AuTraceErr(err); ++ if (err >= 0) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ 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; ++ ++ lockdep_off(); ++ err = kernel_write(file, kbuf, count, ppos); ++ lockdep_on(); ++ if (err >= 0) ++ vfsub_update_h_iattr(&file->f_path, /*did*/NULL); /*ignore*/ ++ 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..7d8993052cd5 +--- /dev/null ++++ b/fs/aufs/vfsub.h +@@ -0,0 +1,341 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * sub-routines for VFS ++ */ ++ ++#ifndef __AUFS_VFSUB_H__ ++#define __AUFS_VFSUB_H__ ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++#include ++#include ++#include "debug.h" ++ ++/* copied from linux/fs/internal.h */ ++/* todo: BAD approach!! */ ++extern void __mnt_drop_write(struct vfsmount *); ++extern struct file *alloc_empty_file(int, const struct cred *); ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* lock subclass for lower inode */ ++/* default MAX_LOCKDEP_SUBCLASSES(8) is not enough */ ++/* reduce? gave up. */ ++enum { ++ AuLsc_I_Begin = I_MUTEX_PARENT2, /* 5 */ ++ AuLsc_I_PARENT, /* lower inode, parent first */ ++ AuLsc_I_PARENT2, /* copyup dirs */ ++ AuLsc_I_PARENT3, /* copyup wh */ ++ AuLsc_I_CHILD, ++ AuLsc_I_CHILD2, ++ AuLsc_I_End ++}; ++ ++/* to debug easier, do not make them inlined functions */ ++#define MtxMustLock(mtx) AuDebugOn(!mutex_is_locked(mtx)) ++#define IMustLock(i) AuDebugOn(!inode_is_locked(i)) ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline void vfsub_drop_nlink(struct inode *inode) ++{ ++ AuDebugOn(!inode->i_nlink); ++ drop_nlink(inode); ++} ++ ++static inline void vfsub_dead_dir(struct inode *inode) ++{ ++ AuDebugOn(!S_ISDIR(inode->i_mode)); ++ inode->i_flags |= S_DEAD; ++ clear_nlink(inode); ++} ++ ++static inline int vfsub_native_ro(struct inode *inode) ++{ ++ return sb_rdonly(inode->i_sb) ++ || IS_RDONLY(inode) ++ /* || IS_APPEND(inode) */ ++ || IS_IMMUTABLE(inode); ++} ++ ++#ifdef CONFIG_AUFS_BR_FUSE ++int vfsub_test_mntns(struct vfsmount *mnt, struct super_block *h_sb); ++#else ++AuStubInt0(vfsub_test_mntns, struct vfsmount *mnt, struct super_block *h_sb); ++#endif ++ ++int vfsub_sync_filesystem(struct super_block *h_sb, int wait); ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_update_h_iattr(struct path *h_path, int *did); ++struct file *vfsub_dentry_open(struct path *path, int flags); ++struct file *vfsub_filp_open(const char *path, int oflags, int mode); ++struct au_branch; ++struct vfsub_aopen_args { ++ struct file *file; ++ unsigned int open_flag; ++ umode_t create_mode; ++ struct au_branch *br; ++}; ++int vfsub_atomic_open(struct inode *dir, struct dentry *dentry, ++ struct vfsub_aopen_args *args); ++int vfsub_kern_path(const char *name, unsigned int flags, struct path *path); ++ ++struct dentry *vfsub_lookup_one_len_unlocked(const char *name, ++ struct dentry *parent, int len); ++struct dentry *vfsub_lookup_one_len(const char *name, struct dentry *parent, ++ int len); ++ ++struct vfsub_lkup_one_args { ++ struct dentry **errp; ++ struct qstr *name; ++ struct dentry *parent; ++}; ++ ++static inline struct dentry *vfsub_lkup_one(struct qstr *name, ++ struct dentry *parent) ++{ ++ return vfsub_lookup_one_len(name->name, parent, name->len); ++} ++ ++void vfsub_call_lkup_one(void *args); ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int vfsub_mnt_want_write(struct vfsmount *mnt) ++{ ++ int err; ++ ++ lockdep_off(); ++ err = mnt_want_write(mnt); ++ lockdep_on(); ++ return err; ++} ++ ++static inline void vfsub_mnt_drop_write(struct vfsmount *mnt) ++{ ++ lockdep_off(); ++ mnt_drop_write(mnt); ++ lockdep_on(); ++} ++ ++#if 0 /* reserved */ ++static inline void vfsub_mnt_drop_write_file(struct file *file) ++{ ++ lockdep_off(); ++ mnt_drop_write_file(file); ++ lockdep_on(); ++} ++#endif ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_hinode; ++struct dentry *vfsub_lock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2); ++void vfsub_unlock_rename(struct dentry *d1, struct au_hinode *hdir1, ++ struct dentry *d2, struct au_hinode *hdir2); ++ ++int vfsub_create(struct inode *dir, struct path *path, int mode, ++ bool want_excl); ++int vfsub_symlink(struct inode *dir, struct path *path, ++ const char *symname); ++int vfsub_mknod(struct inode *dir, struct path *path, int mode, dev_t dev); ++int vfsub_link(struct dentry *src_dentry, struct inode *dir, ++ struct path *path, struct inode **delegated_inode); ++int vfsub_rename(struct inode *src_hdir, struct dentry *src_dentry, ++ struct inode *hdir, struct path *path, ++ struct inode **delegated_inode, unsigned int flags); ++int vfsub_mkdir(struct inode *dir, struct path *path, int mode); ++int vfsub_rmdir(struct inode *dir, struct path *path); ++ ++/* ---------------------------------------------------------------------- */ ++ ++ssize_t vfsub_read_u(struct file *file, char __user *ubuf, size_t count, ++ loff_t *ppos); ++ssize_t vfsub_read_k(struct file *file, void *kbuf, size_t count, ++ loff_t *ppos); ++ssize_t vfsub_write_u(struct file *file, const char __user *ubuf, size_t count, ++ loff_t *ppos); ++ssize_t vfsub_write_k(struct file *file, void *kbuf, size_t count, ++ loff_t *ppos); ++int vfsub_flush(struct file *file, fl_owner_t id); ++int vfsub_iterate_dir(struct file *file, struct dir_context *ctx); ++ ++static inline loff_t vfsub_f_size_read(struct file *file) ++{ ++ return i_size_read(file_inode(file)); ++} ++ ++static inline unsigned int vfsub_file_flags(struct file *file) ++{ ++ unsigned int flags; ++ ++ spin_lock(&file->f_lock); ++ flags = file->f_flags; ++ spin_unlock(&file->f_lock); ++ ++ return flags; ++} ++ ++static inline int vfsub_file_execed(struct file *file) ++{ ++ /* todo: direct access f_flags */ ++ return !!(vfsub_file_flags(file) & __FMODE_EXEC); ++} ++ ++#if 0 /* reserved */ ++static inline void vfsub_file_accessed(struct file *h_file) ++{ ++ file_accessed(h_file); ++ vfsub_update_h_iattr(&h_file->f_path, /*did*/NULL); /*ignore*/ ++} ++#endif ++ ++#if 0 /* reserved */ ++static inline void vfsub_touch_atime(struct vfsmount *h_mnt, ++ struct dentry *h_dentry) ++{ ++ struct path h_path = { ++ .dentry = h_dentry, ++ .mnt = h_mnt ++ }; ++ touch_atime(&h_path); ++ vfsub_update_h_iattr(&h_path, /*did*/NULL); /*ignore*/ ++} ++#endif ++ ++static inline int vfsub_update_time(struct inode *h_inode, ++ struct timespec64 *ts, int flags) ++{ ++ return update_time(h_inode, ts, flags); ++ /* no vfsub_update_h_iattr() since we don't have struct path */ ++} ++ ++#ifdef CONFIG_FS_POSIX_ACL ++static inline int vfsub_acl_chmod(struct inode *h_inode, umode_t h_mode) ++{ ++ int err; ++ ++ err = posix_acl_chmod(h_inode, h_mode); ++ if (err == -EOPNOTSUPP) ++ err = 0; ++ return err; ++} ++#else ++AuStubInt0(vfsub_acl_chmod, struct inode *h_inode, umode_t h_mode); ++#endif ++ ++long vfsub_splice_to(struct file *in, loff_t *ppos, ++ struct pipe_inode_info *pipe, size_t len, ++ unsigned int flags); ++long vfsub_splice_from(struct pipe_inode_info *pipe, struct file *out, ++ loff_t *ppos, size_t len, unsigned int flags); ++ ++static inline long vfsub_truncate(struct path *path, loff_t length) ++{ ++ long err; ++ ++ lockdep_off(); ++ err = vfs_truncate(path, length); ++ lockdep_on(); ++ return err; ++} ++ ++int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr, ++ struct file *h_file); ++int vfsub_fsync(struct file *file, struct path *path, int datasync); ++ ++/* ++ * re-use branch fs's ioctl(FICLONE) while aufs itself doesn't support such ++ * ioctl. ++ */ ++static inline loff_t vfsub_clone_file_range(struct file *src, struct file *dst, ++ loff_t len) ++{ ++ loff_t err; ++ ++ lockdep_off(); ++ err = vfs_clone_file_range(src, 0, dst, 0, len, /*remap_flags*/0); ++ lockdep_on(); ++ ++ return err; ++} ++ ++/* copy_file_range(2) is a systemcall */ ++static inline ssize_t vfsub_copy_file_range(struct file *src, loff_t src_pos, ++ struct file *dst, loff_t dst_pos, ++ size_t len, unsigned int flags) ++{ ++ ssize_t ssz; ++ ++ lockdep_off(); ++ ssz = vfs_copy_file_range(src, src_pos, dst, dst_pos, len, flags); ++ lockdep_on(); ++ ++ return ssz; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline loff_t vfsub_llseek(struct file *file, loff_t offset, int origin) ++{ ++ loff_t err; ++ ++ lockdep_off(); ++ err = vfs_llseek(file, offset, origin); ++ lockdep_on(); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++int vfsub_sio_mkdir(struct inode *dir, struct path *path, int mode); ++int vfsub_sio_rmdir(struct inode *dir, struct path *path); ++int vfsub_sio_notify_change(struct path *path, struct iattr *ia, ++ struct inode **delegated_inode); ++int vfsub_notify_change(struct path *path, struct iattr *ia, ++ struct inode **delegated_inode); ++int vfsub_unlink(struct inode *dir, struct path *path, ++ struct inode **delegated_inode, int force); ++ ++static inline int vfsub_getattr(const struct path *path, struct kstat *st) ++{ ++ return vfs_getattr(path, st, STATX_BASIC_STATS, AT_STATX_SYNC_AS_STAT); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static inline int vfsub_setxattr(struct dentry *dentry, const char *name, ++ const void *value, size_t size, int flags) ++{ ++ int err; ++ ++ lockdep_off(); ++ err = vfs_setxattr(dentry, name, value, size, flags); ++ lockdep_on(); ++ ++ return err; ++} ++ ++static inline int vfsub_removexattr(struct dentry *dentry, const char *name) ++{ ++ int err; ++ ++ lockdep_off(); ++ err = vfs_removexattr(dentry, name); ++ lockdep_on(); ++ ++ return err; ++} ++ ++#endif /* __KERNEL__ */ ++#endif /* __AUFS_VFSUB_H__ */ +diff --git a/fs/aufs/wbr_policy.c b/fs/aufs/wbr_policy.c +new file mode 100644 +index 000000000000..a18045b12573 +--- /dev/null ++++ b/fs/aufs/wbr_policy.c +@@ -0,0 +1,817 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * policies for selecting one among multiple writable branches ++ */ ++ ++#include ++#include "aufs.h" ++ ++/* subset of cpup_attr() */ ++static noinline_for_stack ++int au_cpdown_attr(struct path *h_path, struct dentry *h_src) ++{ ++ int err, sbits; ++ struct iattr ia; ++ struct inode *h_isrc; ++ ++ h_isrc = d_inode(h_src); ++ ia.ia_valid = ATTR_FORCE | ATTR_MODE | ATTR_UID | ATTR_GID; ++ ia.ia_mode = h_isrc->i_mode; ++ ia.ia_uid = h_isrc->i_uid; ++ ia.ia_gid = h_isrc->i_gid; ++ sbits = !!(ia.ia_mode & (S_ISUID | S_ISGID)); ++ au_cpup_attr_flags(d_inode(h_path->dentry), h_isrc->i_flags); ++ /* no delegation since it is just created */ ++ err = vfsub_sio_notify_change(h_path, &ia, /*delegated*/NULL); ++ ++ /* is this nfs only? */ ++ if (!err && sbits && au_test_nfs(h_path->dentry->d_sb)) { ++ ia.ia_valid = ATTR_FORCE | ATTR_MODE; ++ ia.ia_mode = h_isrc->i_mode; ++ err = vfsub_sio_notify_change(h_path, &ia, /*delegated*/NULL); ++ } ++ ++ return err; ++} ++ ++#define AuCpdown_PARENT_OPQ 1 ++#define AuCpdown_WHED (1 << 1) ++#define AuCpdown_MADE_DIR (1 << 2) ++#define AuCpdown_DIROPQ (1 << 3) ++#define au_ftest_cpdown(flags, name) ((flags) & AuCpdown_##name) ++#define au_fset_cpdown(flags, name) \ ++ do { (flags) |= AuCpdown_##name; } while (0) ++#define au_fclr_cpdown(flags, name) \ ++ do { (flags) &= ~AuCpdown_##name; } while (0) ++ ++static int au_cpdown_dir_opq(struct dentry *dentry, aufs_bindex_t bdst, ++ unsigned int *flags) ++{ ++ int err; ++ struct dentry *opq_dentry; ++ ++ opq_dentry = au_diropq_create(dentry, bdst); ++ err = PTR_ERR(opq_dentry); ++ if (IS_ERR(opq_dentry)) ++ goto out; ++ dput(opq_dentry); ++ au_fset_cpdown(*flags, DIROPQ); ++ ++out: ++ return err; ++} ++ ++static int au_cpdown_dir_wh(struct dentry *dentry, struct dentry *h_parent, ++ struct inode *dir, aufs_bindex_t bdst) ++{ ++ int err; ++ struct path h_path; ++ struct au_branch *br; ++ ++ br = au_sbr(dentry->d_sb, bdst); ++ h_path.dentry = au_wh_lkup(h_parent, &dentry->d_name, br); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) ++ goto out; ++ ++ err = 0; ++ if (d_is_positive(h_path.dentry)) { ++ h_path.mnt = au_br_mnt(br); ++ err = au_wh_unlink_dentry(au_h_iptr(dir, bdst), &h_path, ++ dentry); ++ } ++ dput(h_path.dentry); ++ ++out: ++ return err; ++} ++ ++static int au_cpdown_dir(struct dentry *dentry, aufs_bindex_t bdst, ++ struct au_pin *pin, ++ struct dentry *h_parent, void *arg) ++{ ++ int err, rerr; ++ aufs_bindex_t bopq, btop; ++ struct path h_path; ++ struct dentry *parent; ++ struct inode *h_dir, *h_inode, *inode, *dir; ++ unsigned int *flags = arg; ++ ++ btop = au_dbtop(dentry); ++ /* dentry is di-locked */ ++ parent = dget_parent(dentry); ++ dir = d_inode(parent); ++ h_dir = d_inode(h_parent); ++ AuDebugOn(h_dir != au_h_iptr(dir, bdst)); ++ IMustLock(h_dir); ++ ++ err = au_lkup_neg(dentry, bdst, /*wh*/0); ++ if (unlikely(err < 0)) ++ goto out; ++ h_path.dentry = au_h_dptr(dentry, bdst); ++ h_path.mnt = au_sbr_mnt(dentry->d_sb, bdst); ++ err = vfsub_sio_mkdir(au_h_iptr(dir, bdst), &h_path, 0755); ++ if (unlikely(err)) ++ goto out_put; ++ au_fset_cpdown(*flags, MADE_DIR); ++ ++ bopq = au_dbdiropq(dentry); ++ au_fclr_cpdown(*flags, WHED); ++ au_fclr_cpdown(*flags, DIROPQ); ++ if (au_dbwh(dentry) == bdst) ++ au_fset_cpdown(*flags, WHED); ++ if (!au_ftest_cpdown(*flags, PARENT_OPQ) && bopq <= bdst) ++ au_fset_cpdown(*flags, PARENT_OPQ); ++ h_inode = d_inode(h_path.dentry); ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ if (au_ftest_cpdown(*flags, WHED)) { ++ err = au_cpdown_dir_opq(dentry, bdst, flags); ++ if (unlikely(err)) { ++ inode_unlock(h_inode); ++ goto out_dir; ++ } ++ } ++ ++ err = au_cpdown_attr(&h_path, au_h_dptr(dentry, btop)); ++ inode_unlock(h_inode); ++ if (unlikely(err)) ++ goto out_opq; ++ ++ if (au_ftest_cpdown(*flags, WHED)) { ++ err = au_cpdown_dir_wh(dentry, h_parent, dir, bdst); ++ if (unlikely(err)) ++ goto out_opq; ++ } ++ ++ inode = d_inode(dentry); ++ if (au_ibbot(inode) < bdst) ++ au_set_ibbot(inode, bdst); ++ au_set_h_iptr(inode, bdst, au_igrab(h_inode), ++ au_hi_flags(inode, /*isdir*/1)); ++ au_fhsm_wrote(dentry->d_sb, bdst, /*force*/0); ++ goto out; /* success */ ++ ++ /* revert */ ++out_opq: ++ if (au_ftest_cpdown(*flags, DIROPQ)) { ++ inode_lock_nested(h_inode, AuLsc_I_CHILD); ++ rerr = au_diropq_remove(dentry, bdst); ++ inode_unlock(h_inode); ++ if (unlikely(rerr)) { ++ AuIOErr("failed removing diropq for %pd b%d (%d)\n", ++ dentry, bdst, rerr); ++ err = -EIO; ++ goto out; ++ } ++ } ++out_dir: ++ if (au_ftest_cpdown(*flags, MADE_DIR)) { ++ rerr = vfsub_sio_rmdir(au_h_iptr(dir, bdst), &h_path); ++ if (unlikely(rerr)) { ++ AuIOErr("failed removing %pd b%d (%d)\n", ++ dentry, bdst, rerr); ++ err = -EIO; ++ } ++ } ++out_put: ++ au_set_h_dptr(dentry, bdst, NULL); ++ if (au_dbbot(dentry) == bdst) ++ au_update_dbbot(dentry); ++out: ++ dput(parent); ++ return err; ++} ++ ++int au_cpdown_dirs(struct dentry *dentry, aufs_bindex_t bdst) ++{ ++ int err; ++ unsigned int flags; ++ ++ flags = 0; ++ err = au_cp_dirs(dentry, bdst, au_cpdown_dir, &flags); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policies for create */ ++ ++int au_wbr_nonopq(struct dentry *dentry, aufs_bindex_t bindex) ++{ ++ int err, i, j, ndentry; ++ aufs_bindex_t bopq; ++ struct au_dcsub_pages dpages; ++ struct au_dpage *dpage; ++ struct dentry **dentries, *parent, *d; ++ ++ err = au_dpages_init(&dpages, GFP_NOFS); ++ if (unlikely(err)) ++ goto out; ++ parent = dget_parent(dentry); ++ err = au_dcsub_pages_rev_aufs(&dpages, parent, /*do_include*/0); ++ if (unlikely(err)) ++ goto out_free; ++ ++ err = bindex; ++ for (i = 0; i < dpages.ndpage; i++) { ++ dpage = dpages.dpages + i; ++ dentries = dpage->dentries; ++ ndentry = dpage->ndentry; ++ for (j = 0; j < ndentry; j++) { ++ d = dentries[j]; ++ di_read_lock_parent2(d, !AuLock_IR); ++ bopq = au_dbdiropq(d); ++ di_read_unlock(d, !AuLock_IR); ++ if (bopq >= 0 && bopq < err) ++ err = bopq; ++ } ++ } ++ ++out_free: ++ dput(parent); ++ au_dpages_free(&dpages); ++out: ++ return err; ++} ++ ++static int au_wbr_bu(struct super_block *sb, aufs_bindex_t bindex) ++{ ++ for (; bindex >= 0; bindex--) ++ if (!au_br_rdonly(au_sbr(sb, bindex))) ++ return bindex; ++ return -EROFS; ++} ++ ++/* top down parent */ ++static int au_wbr_create_tdp(struct dentry *dentry, ++ unsigned int flags __maybe_unused) ++{ ++ int err; ++ aufs_bindex_t btop, bindex; ++ struct super_block *sb; ++ struct dentry *parent, *h_parent; ++ ++ sb = dentry->d_sb; ++ btop = au_dbtop(dentry); ++ err = btop; ++ if (!au_br_rdonly(au_sbr(sb, btop))) ++ goto out; ++ ++ err = -EROFS; ++ parent = dget_parent(dentry); ++ for (bindex = au_dbtop(parent); bindex < btop; bindex++) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || d_is_negative(h_parent)) ++ continue; ++ ++ if (!au_br_rdonly(au_sbr(sb, bindex))) { ++ err = bindex; ++ break; ++ } ++ } ++ dput(parent); ++ ++ /* bottom up here */ ++ if (unlikely(err < 0)) { ++ err = au_wbr_bu(sb, btop - 1); ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ } ++ ++out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* an exception for the policy other than tdp */ ++static int au_wbr_create_exp(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bwh, bdiropq; ++ struct dentry *parent; ++ ++ err = -1; ++ bwh = au_dbwh(dentry); ++ parent = dget_parent(dentry); ++ bdiropq = au_dbdiropq(parent); ++ if (bwh >= 0) { ++ if (bdiropq >= 0) ++ err = min(bdiropq, bwh); ++ else ++ err = bwh; ++ AuDbg("%d\n", err); ++ } else if (bdiropq >= 0) { ++ err = bdiropq; ++ AuDbg("%d\n", err); ++ } ++ dput(parent); ++ ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ ++ if (err >= 0 && au_br_rdonly(au_sbr(dentry->d_sb, err))) ++ err = -1; ++ ++ AuDbg("%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* round robin */ ++static int au_wbr_create_init_rr(struct super_block *sb) ++{ ++ int err; ++ ++ err = au_wbr_bu(sb, au_sbbot(sb)); ++ atomic_set(&au_sbi(sb)->si_wbr_rr_next, -err); /* less important */ ++ /* smp_mb(); */ ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_create_rr(struct dentry *dentry, unsigned int flags) ++{ ++ int err, nbr; ++ unsigned int u; ++ aufs_bindex_t bindex, bbot; ++ struct super_block *sb; ++ atomic_t *next; ++ ++ err = au_wbr_create_exp(dentry); ++ if (err >= 0) ++ goto out; ++ ++ sb = dentry->d_sb; ++ next = &au_sbi(sb)->si_wbr_rr_next; ++ bbot = au_sbbot(sb); ++ nbr = bbot + 1; ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ if (!au_ftest_wbr(flags, DIR)) { ++ err = atomic_dec_return(next) + 1; ++ /* modulo for 0 is meaningless */ ++ if (unlikely(!err)) ++ err = atomic_dec_return(next) + 1; ++ } else ++ err = atomic_read(next); ++ AuDbg("%d\n", err); ++ u = err; ++ err = u % nbr; ++ AuDbg("%d\n", err); ++ if (!au_br_rdonly(au_sbr(sb, err))) ++ break; ++ err = -EROFS; ++ } ++ ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ ++out: ++ AuDbg("%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* most free space */ ++static void au_mfs(struct dentry *dentry, struct dentry *parent) ++{ ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_wbr_mfs *mfs; ++ struct dentry *h_parent; ++ aufs_bindex_t bindex, bbot; ++ int err; ++ unsigned long long b, bavail; ++ struct path h_path; ++ /* reduce the stack usage */ ++ struct kstatfs *st; ++ ++ st = kmalloc(sizeof(*st), GFP_NOFS); ++ if (unlikely(!st)) { ++ AuWarn1("failed updating mfs(%d), ignored\n", -ENOMEM); ++ return; ++ } ++ ++ bavail = 0; ++ sb = dentry->d_sb; ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ MtxMustLock(&mfs->mfs_lock); ++ mfs->mfs_bindex = -EROFS; ++ mfs->mfsrr_bytes = 0; ++ if (!parent) { ++ bindex = 0; ++ bbot = au_sbbot(sb); ++ } else { ++ bindex = au_dbtop(parent); ++ bbot = au_dbtaildir(parent); ++ } ++ ++ for (; bindex <= bbot; bindex++) { ++ if (parent) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || d_is_negative(h_parent)) ++ continue; ++ } ++ br = au_sbr(sb, bindex); ++ if (au_br_rdonly(br)) ++ continue; ++ ++ /* sb->s_root for NFS is unreliable */ ++ h_path.mnt = au_br_mnt(br); ++ h_path.dentry = h_path.mnt->mnt_root; ++ err = vfs_statfs(&h_path, st); ++ if (unlikely(err)) { ++ AuWarn1("failed statfs, b%d, %d\n", bindex, err); ++ continue; ++ } ++ ++ /* when the available size is equal, select the lower one */ ++ BUILD_BUG_ON(sizeof(b) < sizeof(st->f_bavail) ++ || sizeof(b) < sizeof(st->f_bsize)); ++ b = st->f_bavail * st->f_bsize; ++ br->br_wbr->wbr_bytes = b; ++ if (b >= bavail) { ++ bavail = b; ++ mfs->mfs_bindex = bindex; ++ mfs->mfs_jiffy = jiffies; ++ } ++ } ++ ++ mfs->mfsrr_bytes = bavail; ++ AuDbg("b%d\n", mfs->mfs_bindex); ++ au_kfree_rcu(st); ++} ++ ++static int au_wbr_create_mfs(struct dentry *dentry, unsigned int flags) ++{ ++ int err; ++ struct dentry *parent; ++ struct super_block *sb; ++ struct au_wbr_mfs *mfs; ++ ++ err = au_wbr_create_exp(dentry); ++ if (err >= 0) ++ goto out; ++ ++ sb = dentry->d_sb; ++ parent = NULL; ++ if (au_ftest_wbr(flags, PARENT)) ++ parent = dget_parent(dentry); ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ mutex_lock(&mfs->mfs_lock); ++ if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire) ++ || mfs->mfs_bindex < 0 ++ || au_br_rdonly(au_sbr(sb, mfs->mfs_bindex))) ++ au_mfs(dentry, parent); ++ mutex_unlock(&mfs->mfs_lock); ++ err = mfs->mfs_bindex; ++ dput(parent); ++ ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ ++out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_create_init_mfs(struct super_block *sb) ++{ ++ struct au_wbr_mfs *mfs; ++ ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ mutex_init(&mfs->mfs_lock); ++ mfs->mfs_jiffy = 0; ++ mfs->mfs_bindex = -EROFS; ++ ++ return 0; ++} ++ ++static int au_wbr_create_fin_mfs(struct super_block *sb __maybe_unused) ++{ ++ mutex_destroy(&au_sbi(sb)->si_wbr_mfs.mfs_lock); ++ return 0; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* top down regardless parent, and then mfs */ ++static int au_wbr_create_tdmfs(struct dentry *dentry, ++ unsigned int flags __maybe_unused) ++{ ++ int err; ++ aufs_bindex_t bwh, btail, bindex, bfound, bmfs; ++ unsigned long long watermark; ++ struct super_block *sb; ++ struct au_wbr_mfs *mfs; ++ struct au_branch *br; ++ struct dentry *parent; ++ ++ sb = dentry->d_sb; ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ mutex_lock(&mfs->mfs_lock); ++ if (time_after(jiffies, mfs->mfs_jiffy + mfs->mfs_expire) ++ || mfs->mfs_bindex < 0) ++ au_mfs(dentry, /*parent*/NULL); ++ watermark = mfs->mfsrr_watermark; ++ bmfs = mfs->mfs_bindex; ++ mutex_unlock(&mfs->mfs_lock); ++ ++ /* another style of au_wbr_create_exp() */ ++ bwh = au_dbwh(dentry); ++ parent = dget_parent(dentry); ++ btail = au_dbtaildir(parent); ++ if (bwh >= 0 && bwh < btail) ++ btail = bwh; ++ ++ err = au_wbr_nonopq(dentry, btail); ++ if (unlikely(err < 0)) ++ goto out; ++ btail = err; ++ bfound = -1; ++ for (bindex = 0; bindex <= btail; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_rdonly(br)) ++ continue; ++ if (br->br_wbr->wbr_bytes > watermark) { ++ bfound = bindex; ++ break; ++ } ++ } ++ err = bfound; ++ if (err < 0) ++ err = bmfs; ++ ++out: ++ dput(parent); ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* most free space and then round robin */ ++static int au_wbr_create_mfsrr(struct dentry *dentry, unsigned int flags) ++{ ++ int err; ++ struct au_wbr_mfs *mfs; ++ ++ err = au_wbr_create_mfs(dentry, flags); ++ if (err >= 0) { ++ mfs = &au_sbi(dentry->d_sb)->si_wbr_mfs; ++ mutex_lock(&mfs->mfs_lock); ++ if (mfs->mfsrr_bytes < mfs->mfsrr_watermark) ++ err = au_wbr_create_rr(dentry, flags); ++ mutex_unlock(&mfs->mfs_lock); ++ } ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_create_init_mfsrr(struct super_block *sb) ++{ ++ int err; ++ ++ au_wbr_create_init_mfs(sb); /* ignore */ ++ err = au_wbr_create_init_rr(sb); ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* top down parent and most free space */ ++static int au_wbr_create_pmfs(struct dentry *dentry, unsigned int flags) ++{ ++ int err, e2; ++ unsigned long long b; ++ aufs_bindex_t bindex, btop, bbot; ++ struct super_block *sb; ++ struct dentry *parent, *h_parent; ++ struct au_branch *br; ++ ++ err = au_wbr_create_tdp(dentry, flags); ++ if (unlikely(err < 0)) ++ goto out; ++ parent = dget_parent(dentry); ++ btop = au_dbtop(parent); ++ bbot = au_dbtaildir(parent); ++ if (btop == bbot) ++ goto out_parent; /* success */ ++ ++ e2 = au_wbr_create_mfs(dentry, flags); ++ if (e2 < 0) ++ goto out_parent; /* success */ ++ ++ /* when the available size is equal, select upper one */ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, err); ++ b = br->br_wbr->wbr_bytes; ++ AuDbg("b%d, %llu\n", err, b); ++ ++ for (bindex = btop; bindex <= bbot; bindex++) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || d_is_negative(h_parent)) ++ continue; ++ ++ br = au_sbr(sb, bindex); ++ if (!au_br_rdonly(br) && br->br_wbr->wbr_bytes > b) { ++ b = br->br_wbr->wbr_bytes; ++ err = bindex; ++ AuDbg("b%d, %llu\n", err, b); ++ } ++ } ++ ++ if (err >= 0) ++ err = au_wbr_nonopq(dentry, err); ++ ++out_parent: ++ dput(parent); ++out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * - top down parent ++ * - most free space with parent ++ * - most free space round-robin regardless parent ++ */ ++static int au_wbr_create_pmfsrr(struct dentry *dentry, unsigned int flags) ++{ ++ int err; ++ unsigned long long watermark; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_wbr_mfs *mfs; ++ ++ err = au_wbr_create_pmfs(dentry, flags | AuWbr_PARENT); ++ if (unlikely(err < 0)) ++ goto out; ++ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, err); ++ mfs = &au_sbi(sb)->si_wbr_mfs; ++ mutex_lock(&mfs->mfs_lock); ++ watermark = mfs->mfsrr_watermark; ++ mutex_unlock(&mfs->mfs_lock); ++ if (br->br_wbr->wbr_bytes < watermark) ++ /* regardless the parent dir */ ++ err = au_wbr_create_mfsrr(dentry, flags); ++ ++out: ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* policies for copyup */ ++ ++/* top down parent */ ++static int au_wbr_copyup_tdp(struct dentry *dentry) ++{ ++ return au_wbr_create_tdp(dentry, /*flags, anything is ok*/0); ++} ++ ++/* bottom up parent */ ++static int au_wbr_copyup_bup(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t bindex, btop; ++ struct dentry *parent, *h_parent; ++ struct super_block *sb; ++ ++ err = -EROFS; ++ sb = dentry->d_sb; ++ parent = dget_parent(dentry); ++ btop = au_dbtop(parent); ++ for (bindex = au_dbtop(dentry); bindex >= btop; bindex--) { ++ h_parent = au_h_dptr(parent, bindex); ++ if (!h_parent || d_is_negative(h_parent)) ++ continue; ++ ++ if (!au_br_rdonly(au_sbr(sb, bindex))) { ++ err = bindex; ++ break; ++ } ++ } ++ dput(parent); ++ ++ /* bottom up here */ ++ if (unlikely(err < 0)) ++ err = au_wbr_bu(sb, btop - 1); ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++/* bottom up */ ++int au_wbr_do_copyup_bu(struct dentry *dentry, aufs_bindex_t btop) ++{ ++ int err; ++ ++ err = au_wbr_bu(dentry->d_sb, btop); ++ AuDbg("b%d\n", err); ++ if (err > btop) ++ err = au_wbr_nonopq(dentry, err); ++ ++ AuDbg("b%d\n", err); ++ return err; ++} ++ ++static int au_wbr_copyup_bu(struct dentry *dentry) ++{ ++ int err; ++ aufs_bindex_t btop; ++ ++ btop = au_dbtop(dentry); ++ err = au_wbr_do_copyup_bu(dentry, btop); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_wbr_copyup_operations au_wbr_copyup_ops[] = { ++ [AuWbrCopyup_TDP] = { ++ .copyup = au_wbr_copyup_tdp ++ }, ++ [AuWbrCopyup_BUP] = { ++ .copyup = au_wbr_copyup_bup ++ }, ++ [AuWbrCopyup_BU] = { ++ .copyup = au_wbr_copyup_bu ++ } ++}; ++ ++struct au_wbr_create_operations au_wbr_create_ops[] = { ++ [AuWbrCreate_TDP] = { ++ .create = au_wbr_create_tdp ++ }, ++ [AuWbrCreate_RR] = { ++ .create = au_wbr_create_rr, ++ .init = au_wbr_create_init_rr ++ }, ++ [AuWbrCreate_MFS] = { ++ .create = au_wbr_create_mfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_MFSV] = { ++ .create = au_wbr_create_mfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_MFSRR] = { ++ .create = au_wbr_create_mfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_MFSRRV] = { ++ .create = au_wbr_create_mfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_TDMFS] = { ++ .create = au_wbr_create_tdmfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_TDMFSV] = { ++ .create = au_wbr_create_tdmfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFS] = { ++ .create = au_wbr_create_pmfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFSV] = { ++ .create = au_wbr_create_pmfs, ++ .init = au_wbr_create_init_mfs, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFSRR] = { ++ .create = au_wbr_create_pmfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ }, ++ [AuWbrCreate_PMFSRRV] = { ++ .create = au_wbr_create_pmfsrr, ++ .init = au_wbr_create_init_mfsrr, ++ .fin = au_wbr_create_fin_mfs ++ } ++}; +diff --git a/fs/aufs/whout.c b/fs/aufs/whout.c +new file mode 100644 +index 000000000000..9363954c4b06 +--- /dev/null ++++ b/fs/aufs/whout.c +@@ -0,0 +1,1049 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * whiteout for logical deletion and opaque directory ++ */ ++ ++#include "aufs.h" ++ ++#define WH_MASK 0444 ++ ++/* ++ * If a directory contains this file, then it is opaque. We start with the ++ * .wh. flag so that it is blocked by lookup. ++ */ ++static struct qstr diropq_name = QSTR_INIT(AUFS_WH_DIROPQ, ++ sizeof(AUFS_WH_DIROPQ) - 1); ++ ++/* ++ * generate whiteout name, which is NOT terminated by NULL. ++ * @name: original d_name.name ++ * @len: original d_name.len ++ * @wh: whiteout qstr ++ * returns zero when succeeds, otherwise error. ++ * succeeded value as wh->name should be freed by kfree(). ++ */ ++int au_wh_name_alloc(struct qstr *wh, const struct qstr *name) ++{ ++ char *p; ++ ++ if (unlikely(name->len > PATH_MAX - AUFS_WH_PFX_LEN)) ++ return -ENAMETOOLONG; ++ ++ wh->len = name->len + AUFS_WH_PFX_LEN; ++ p = kmalloc(wh->len, GFP_NOFS); ++ wh->name = p; ++ if (p) { ++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); ++ memcpy(p + AUFS_WH_PFX_LEN, name->name, name->len); ++ /* smp_mb(); */ ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * test if the @wh_name exists under @h_parent. ++ * @try_sio specifies the necessary of super-io. ++ */ ++int au_wh_test(struct dentry *h_parent, struct qstr *wh_name, int try_sio) ++{ ++ int err; ++ struct dentry *wh_dentry; ++ ++ if (!try_sio) ++ wh_dentry = vfsub_lkup_one(wh_name, h_parent); ++ else ++ wh_dentry = au_sio_lkup_one(wh_name, h_parent); ++ err = PTR_ERR(wh_dentry); ++ if (IS_ERR(wh_dentry)) { ++ if (err == -ENAMETOOLONG) ++ err = 0; ++ goto out; ++ } ++ ++ err = 0; ++ if (d_is_negative(wh_dentry)) ++ goto out_wh; /* success */ ++ ++ err = 1; ++ if (d_is_reg(wh_dentry)) ++ goto out_wh; /* success */ ++ ++ err = -EIO; ++ AuIOErr("%pd Invalid whiteout entry type 0%o.\n", ++ wh_dentry, d_inode(wh_dentry)->i_mode); ++ ++out_wh: ++ dput(wh_dentry); ++out: ++ return err; ++} ++ ++/* ++ * test if the @h_dentry sets opaque or not. ++ */ ++int au_diropq_test(struct dentry *h_dentry) ++{ ++ int err; ++ struct inode *h_dir; ++ ++ h_dir = d_inode(h_dentry); ++ err = au_wh_test(h_dentry, &diropq_name, ++ au_test_h_perm_sio(h_dir, MAY_EXEC)); ++ return err; ++} ++ ++/* ++ * returns a negative dentry whose name is unique and temporary. ++ */ ++struct dentry *au_whtmp_lkup(struct dentry *h_parent, struct au_branch *br, ++ struct qstr *prefix) ++{ ++ struct dentry *dentry; ++ int i; ++ char defname[NAME_MAX - AUFS_MAX_NAMELEN + DNAME_INLINE_LEN + 1], ++ *name, *p; ++ /* strict atomic_t is unnecessary here */ ++ static unsigned short cnt; ++ struct qstr qs; ++ ++ BUILD_BUG_ON(sizeof(cnt) * 2 > AUFS_WH_TMP_LEN); ++ ++ name = defname; ++ qs.len = sizeof(defname) - DNAME_INLINE_LEN + prefix->len - 1; ++ if (unlikely(prefix->len > DNAME_INLINE_LEN)) { ++ dentry = ERR_PTR(-ENAMETOOLONG); ++ if (unlikely(qs.len > NAME_MAX)) ++ goto out; ++ dentry = ERR_PTR(-ENOMEM); ++ name = kmalloc(qs.len + 1, GFP_NOFS); ++ if (unlikely(!name)) ++ goto out; ++ } ++ ++ /* doubly whiteout-ed */ ++ memcpy(name, AUFS_WH_PFX AUFS_WH_PFX, AUFS_WH_PFX_LEN * 2); ++ p = name + AUFS_WH_PFX_LEN * 2; ++ memcpy(p, prefix->name, prefix->len); ++ p += prefix->len; ++ *p++ = '.'; ++ AuDebugOn(name + qs.len + 1 - p <= AUFS_WH_TMP_LEN); ++ ++ qs.name = name; ++ for (i = 0; i < 3; i++) { ++ sprintf(p, "%.*x", AUFS_WH_TMP_LEN, cnt++); ++ dentry = au_sio_lkup_one(&qs, h_parent); ++ if (IS_ERR(dentry) || d_is_negative(dentry)) ++ goto out_name; ++ dput(dentry); ++ } ++ /* pr_warn("could not get random name\n"); */ ++ dentry = ERR_PTR(-EEXIST); ++ AuDbg("%.*s\n", AuLNPair(&qs)); ++ BUG(); ++ ++out_name: ++ if (name != defname) ++ au_kfree_try_rcu(name); ++out: ++ AuTraceErrPtr(dentry); ++ return dentry; ++} ++ ++/* ++ * rename the @h_dentry on @br to the whiteouted temporary name. ++ */ ++int au_whtmp_ren(struct dentry *h_dentry, struct au_branch *br) ++{ ++ int err; ++ struct path h_path = { ++ .mnt = au_br_mnt(br) ++ }; ++ struct inode *h_dir, *delegated; ++ struct dentry *h_parent; ++ ++ h_parent = h_dentry->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ ++ h_path.dentry = au_whtmp_lkup(h_parent, br, &h_dentry->d_name); ++ err = PTR_ERR(h_path.dentry); ++ if (IS_ERR(h_path.dentry)) ++ goto out; ++ ++ /* under the same dir, no need to lock_rename() */ ++ delegated = NULL; ++ err = vfsub_rename(h_dir, h_dentry, h_dir, &h_path, &delegated, ++ /*flags*/0); ++ AuTraceErr(err); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal rename\n"); ++ iput(delegated); ++ } ++ dput(h_path.dentry); ++ ++out: ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * functions for removing a whiteout ++ */ ++ ++static int do_unlink_wh(struct inode *h_dir, struct path *h_path) ++{ ++ int err, force; ++ struct inode *delegated; ++ ++ /* ++ * forces superio when the dir has a sticky bit. ++ * this may be a violation of unix fs semantics. ++ */ ++ force = (h_dir->i_mode & S_ISVTX) ++ && !uid_eq(current_fsuid(), d_inode(h_path->dentry)->i_uid); ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, h_path, &delegated, force); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ return err; ++} ++ ++int au_wh_unlink_dentry(struct inode *h_dir, struct path *h_path, ++ struct dentry *dentry) ++{ ++ int err; ++ ++ err = do_unlink_wh(h_dir, h_path); ++ if (!err && dentry) ++ au_set_dbwh(dentry, -1); ++ ++ return err; ++} ++ ++static int unlink_wh_name(struct dentry *h_parent, struct qstr *wh, ++ struct au_branch *br) ++{ ++ int err; ++ struct path h_path = { ++ .mnt = au_br_mnt(br) ++ }; ++ ++ err = 0; ++ h_path.dentry = vfsub_lkup_one(wh, h_parent); ++ if (IS_ERR(h_path.dentry)) ++ err = PTR_ERR(h_path.dentry); ++ else { ++ if (d_is_reg(h_path.dentry)) ++ err = do_unlink_wh(d_inode(h_parent), &h_path); ++ dput(h_path.dentry); ++ } ++ ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * initialize/clean whiteout for a branch ++ */ ++ ++static void au_wh_clean(struct inode *h_dir, struct path *whpath, ++ const int isdir) ++{ ++ int err; ++ struct inode *delegated; ++ ++ if (d_is_negative(whpath->dentry)) ++ return; ++ ++ if (isdir) ++ err = vfsub_rmdir(h_dir, whpath); ++ else { ++ delegated = NULL; ++ err = vfsub_unlink(h_dir, whpath, &delegated, /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ } ++ if (unlikely(err)) ++ pr_warn("failed removing %pd (%d), ignored.\n", ++ whpath->dentry, err); ++} ++ ++static int test_linkable(struct dentry *h_root) ++{ ++ struct inode *h_dir = d_inode(h_root); ++ ++ if (h_dir->i_op->link) ++ return 0; ++ ++ pr_err("%pd (%s) doesn't support link(2), use noplink and rw+nolwh\n", ++ h_root, au_sbtype(h_root->d_sb)); ++ return -ENOSYS; /* the branch doesn't have its ->link() */ ++} ++ ++/* todo: should this mkdir be done in /sbin/mount.aufs helper? */ ++static int au_whdir(struct inode *h_dir, struct path *path) ++{ ++ int err; ++ ++ err = -EEXIST; ++ if (d_is_negative(path->dentry)) { ++ int mode = 0700; ++ ++ if (au_test_nfs(path->dentry->d_sb)) ++ mode |= 0111; ++ err = vfsub_mkdir(h_dir, path, mode); ++ } else if (d_is_dir(path->dentry)) ++ err = 0; ++ else ++ pr_err("unknown %pd exists\n", path->dentry); ++ ++ return err; ++} ++ ++struct au_wh_base { ++ const struct qstr *name; ++ struct dentry *dentry; ++}; ++ ++static void au_wh_init_ro(struct inode *h_dir, struct au_wh_base base[], ++ struct path *h_path) ++{ ++ h_path->dentry = base[AuBrWh_BASE].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/0); ++ h_path->dentry = base[AuBrWh_PLINK].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++ h_path->dentry = base[AuBrWh_ORPH].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++} ++ ++/* ++ * returns tri-state, ++ * minus: error, caller should print the message ++ * zero: success ++ * plus: error, caller should NOT print the message ++ */ ++static int au_wh_init_rw_nolink(struct dentry *h_root, struct au_wbr *wbr, ++ int do_plink, struct au_wh_base base[], ++ struct path *h_path) ++{ ++ int err; ++ struct inode *h_dir; ++ ++ h_dir = d_inode(h_root); ++ h_path->dentry = base[AuBrWh_BASE].dentry; ++ au_wh_clean(h_dir, h_path, /*isdir*/0); ++ h_path->dentry = base[AuBrWh_PLINK].dentry; ++ if (do_plink) { ++ err = test_linkable(h_root); ++ if (unlikely(err)) { ++ err = 1; ++ goto out; ++ } ++ ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry); ++ } else ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++ h_path->dentry = base[AuBrWh_ORPH].dentry; ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry); ++ ++out: ++ return err; ++} ++ ++/* ++ * for the moment, aufs supports the branch filesystem which does not support ++ * link(2). testing on FAT which does not support i_op->setattr() fully either, ++ * copyup failed. finally, such filesystem will not be used as the writable ++ * branch. ++ * ++ * returns tri-state, see above. ++ */ ++static int au_wh_init_rw(struct dentry *h_root, struct au_wbr *wbr, ++ int do_plink, struct au_wh_base base[], ++ struct path *h_path) ++{ ++ int err; ++ struct inode *h_dir; ++ ++ WbrWhMustWriteLock(wbr); ++ ++ err = test_linkable(h_root); ++ if (unlikely(err)) { ++ err = 1; ++ goto out; ++ } ++ ++ /* ++ * todo: should this create be done in /sbin/mount.aufs helper? ++ */ ++ err = -EEXIST; ++ h_dir = d_inode(h_root); ++ if (d_is_negative(base[AuBrWh_BASE].dentry)) { ++ h_path->dentry = base[AuBrWh_BASE].dentry; ++ err = vfsub_create(h_dir, h_path, WH_MASK, /*want_excl*/true); ++ } else if (d_is_reg(base[AuBrWh_BASE].dentry)) ++ err = 0; ++ else ++ pr_err("unknown %pd2 exists\n", base[AuBrWh_BASE].dentry); ++ if (unlikely(err)) ++ goto out; ++ ++ h_path->dentry = base[AuBrWh_PLINK].dentry; ++ if (do_plink) { ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_plink = dget(base[AuBrWh_PLINK].dentry); ++ } else ++ au_wh_clean(h_dir, h_path, /*isdir*/1); ++ wbr->wbr_whbase = dget(base[AuBrWh_BASE].dentry); ++ ++ h_path->dentry = base[AuBrWh_ORPH].dentry; ++ err = au_whdir(h_dir, h_path); ++ if (unlikely(err)) ++ goto out; ++ wbr->wbr_orph = dget(base[AuBrWh_ORPH].dentry); ++ ++out: ++ return err; ++} ++ ++/* ++ * initialize the whiteout base file/dir for @br. ++ */ ++int au_wh_init(struct au_branch *br, struct super_block *sb) ++{ ++ int err, i; ++ const unsigned char do_plink ++ = !!au_opt_test(au_mntflags(sb), PLINK); ++ struct inode *h_dir; ++ struct path path = br->br_path; ++ struct dentry *h_root = path.dentry; ++ struct au_wbr *wbr = br->br_wbr; ++ static const struct qstr base_name[] = { ++ [AuBrWh_BASE] = QSTR_INIT(AUFS_BASE_NAME, ++ sizeof(AUFS_BASE_NAME) - 1), ++ [AuBrWh_PLINK] = QSTR_INIT(AUFS_PLINKDIR_NAME, ++ sizeof(AUFS_PLINKDIR_NAME) - 1), ++ [AuBrWh_ORPH] = QSTR_INIT(AUFS_ORPHDIR_NAME, ++ sizeof(AUFS_ORPHDIR_NAME) - 1) ++ }; ++ struct au_wh_base base[] = { ++ [AuBrWh_BASE] = { ++ .name = base_name + AuBrWh_BASE, ++ .dentry = NULL ++ }, ++ [AuBrWh_PLINK] = { ++ .name = base_name + AuBrWh_PLINK, ++ .dentry = NULL ++ }, ++ [AuBrWh_ORPH] = { ++ .name = base_name + AuBrWh_ORPH, ++ .dentry = NULL ++ } ++ }; ++ ++ if (wbr) ++ WbrWhMustWriteLock(wbr); ++ ++ for (i = 0; i < AuBrWh_Last; i++) { ++ /* doubly whiteouted */ ++ struct dentry *d; ++ ++ d = au_wh_lkup(h_root, (void *)base[i].name, br); ++ err = PTR_ERR(d); ++ if (IS_ERR(d)) ++ goto out; ++ ++ base[i].dentry = d; ++ AuDebugOn(wbr ++ && wbr->wbr_wh[i] ++ && wbr->wbr_wh[i] != base[i].dentry); ++ } ++ ++ if (wbr) ++ for (i = 0; i < AuBrWh_Last; i++) { ++ dput(wbr->wbr_wh[i]); ++ wbr->wbr_wh[i] = NULL; ++ } ++ ++ err = 0; ++ if (!au_br_writable(br->br_perm)) { ++ h_dir = d_inode(h_root); ++ au_wh_init_ro(h_dir, base, &path); ++ } else if (!au_br_wh_linkable(br->br_perm)) { ++ err = au_wh_init_rw_nolink(h_root, wbr, do_plink, base, &path); ++ if (err > 0) ++ goto out; ++ else if (err) ++ goto out_err; ++ } else { ++ err = au_wh_init_rw(h_root, wbr, do_plink, base, &path); ++ if (err > 0) ++ goto out; ++ else if (err) ++ goto out_err; ++ } ++ goto out; /* success */ ++ ++out_err: ++ pr_err("an error(%d) on the writable branch %pd(%s)\n", ++ err, h_root, au_sbtype(h_root->d_sb)); ++out: ++ for (i = 0; i < AuBrWh_Last; i++) ++ dput(base[i].dentry); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++/* ++ * whiteouts are all hard-linked usually. ++ * when its link count reaches a ceiling, we create a new whiteout base ++ * asynchronously. ++ */ ++ ++struct reinit_br_wh { ++ struct super_block *sb; ++ struct au_branch *br; ++}; ++ ++static void reinit_br_wh(void *arg) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct path h_path; ++ struct reinit_br_wh *a = arg; ++ struct au_wbr *wbr; ++ struct inode *dir, *delegated; ++ struct dentry *h_root; ++ struct au_hinode *hdir; ++ ++ err = 0; ++ wbr = a->br->br_wbr; ++ /* big aufs lock */ ++ si_noflush_write_lock(a->sb); ++ if (!au_br_writable(a->br->br_perm)) ++ goto out; ++ bindex = au_br_index(a->sb, a->br->br_id); ++ if (unlikely(bindex < 0)) ++ goto out; ++ ++ di_read_lock_parent(a->sb->s_root, AuLock_IR); ++ dir = d_inode(a->sb->s_root); ++ hdir = au_hi(dir, bindex); ++ h_root = au_h_dptr(a->sb->s_root, bindex); ++ AuDebugOn(h_root != au_br_dentry(a->br)); ++ ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ wbr_wh_write_lock(wbr); ++ err = au_h_verify(wbr->wbr_whbase, au_opt_udba(a->sb), hdir->hi_inode, ++ h_root, a->br); ++ if (!err) { ++ h_path.dentry = wbr->wbr_whbase; ++ h_path.mnt = au_br_mnt(a->br); ++ delegated = NULL; ++ err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated, ++ /*force*/0); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ } else { ++ pr_warn("%pd is moved, ignored\n", wbr->wbr_whbase); ++ err = 0; ++ } ++ dput(wbr->wbr_whbase); ++ wbr->wbr_whbase = NULL; ++ if (!err) ++ err = au_wh_init(a->br, a->sb); ++ wbr_wh_write_unlock(wbr); ++ au_hn_inode_unlock(hdir); ++ di_read_unlock(a->sb->s_root, AuLock_IR); ++ if (!err) ++ au_fhsm_wrote(a->sb, bindex, /*force*/0); ++ ++out: ++ if (wbr) ++ atomic_dec(&wbr->wbr_wh_running); ++ au_lcnt_dec(&a->br->br_count); ++ si_write_unlock(a->sb); ++ au_nwt_done(&au_sbi(a->sb)->si_nowait); ++ au_kfree_rcu(a); ++ if (unlikely(err)) ++ AuIOErr("err %d\n", err); ++} ++ ++static void kick_reinit_br_wh(struct super_block *sb, struct au_branch *br) ++{ ++ int do_dec, wkq_err; ++ struct reinit_br_wh *arg; ++ ++ do_dec = 1; ++ if (atomic_inc_return(&br->br_wbr->wbr_wh_running) != 1) ++ goto out; ++ ++ /* ignore ENOMEM */ ++ arg = kmalloc(sizeof(*arg), GFP_NOFS); ++ if (arg) { ++ /* ++ * dec(wh_running), kfree(arg) and dec(br_count) ++ * in reinit function ++ */ ++ arg->sb = sb; ++ arg->br = br; ++ au_lcnt_inc(&br->br_count); ++ wkq_err = au_wkq_nowait(reinit_br_wh, arg, sb, /*flags*/0); ++ if (unlikely(wkq_err)) { ++ atomic_dec(&br->br_wbr->wbr_wh_running); ++ au_lcnt_dec(&br->br_count); ++ au_kfree_rcu(arg); ++ } ++ do_dec = 0; ++ } ++ ++out: ++ if (do_dec) ++ atomic_dec(&br->br_wbr->wbr_wh_running); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create the whiteout @wh. ++ */ ++static int link_or_create_wh(struct super_block *sb, aufs_bindex_t bindex, ++ struct dentry *wh) ++{ ++ int err; ++ struct path h_path = { ++ .dentry = wh ++ }; ++ struct au_branch *br; ++ struct au_wbr *wbr; ++ struct dentry *h_parent; ++ struct inode *h_dir, *delegated; ++ ++ h_parent = wh->d_parent; /* dir inode is locked */ ++ h_dir = d_inode(h_parent); ++ IMustLock(h_dir); ++ ++ br = au_sbr(sb, bindex); ++ h_path.mnt = au_br_mnt(br); ++ wbr = br->br_wbr; ++ wbr_wh_read_lock(wbr); ++ if (wbr->wbr_whbase) { ++ delegated = NULL; ++ err = vfsub_link(wbr->wbr_whbase, h_dir, &h_path, &delegated); ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal link\n"); ++ iput(delegated); ++ } ++ if (!err || err != -EMLINK) ++ goto out; ++ ++ /* link count full. re-initialize br_whbase. */ ++ kick_reinit_br_wh(sb, br); ++ } ++ ++ /* return this error in this context */ ++ err = vfsub_create(h_dir, &h_path, WH_MASK, /*want_excl*/true); ++ if (!err) ++ au_fhsm_wrote(sb, bindex, /*force*/0); ++ ++out: ++ wbr_wh_read_unlock(wbr); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create or remove the diropq. ++ */ ++static struct dentry *do_diropq(struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int flags) ++{ ++ struct dentry *opq_dentry, *h_dentry; ++ struct super_block *sb; ++ struct au_branch *br; ++ int err; ++ ++ sb = dentry->d_sb; ++ br = au_sbr(sb, bindex); ++ h_dentry = au_h_dptr(dentry, bindex); ++ opq_dentry = vfsub_lkup_one(&diropq_name, h_dentry); ++ if (IS_ERR(opq_dentry)) ++ goto out; ++ ++ if (au_ftest_diropq(flags, CREATE)) { ++ err = link_or_create_wh(sb, bindex, opq_dentry); ++ if (!err) { ++ au_set_dbdiropq(dentry, bindex); ++ goto out; /* success */ ++ } ++ } else { ++ struct path tmp = { ++ .dentry = opq_dentry, ++ .mnt = au_br_mnt(br) ++ }; ++ err = do_unlink_wh(au_h_iptr(d_inode(dentry), bindex), &tmp); ++ if (!err) ++ au_set_dbdiropq(dentry, -1); ++ } ++ dput(opq_dentry); ++ opq_dentry = ERR_PTR(err); ++ ++out: ++ return opq_dentry; ++} ++ ++struct do_diropq_args { ++ struct dentry **errp; ++ struct dentry *dentry; ++ aufs_bindex_t bindex; ++ unsigned int flags; ++}; ++ ++static void call_do_diropq(void *args) ++{ ++ struct do_diropq_args *a = args; ++ *a->errp = do_diropq(a->dentry, a->bindex, a->flags); ++} ++ ++struct dentry *au_diropq_sio(struct dentry *dentry, aufs_bindex_t bindex, ++ unsigned int flags) ++{ ++ struct dentry *diropq, *h_dentry; ++ ++ h_dentry = au_h_dptr(dentry, bindex); ++ if (!au_test_h_perm_sio(d_inode(h_dentry), MAY_EXEC | MAY_WRITE)) ++ diropq = do_diropq(dentry, bindex, flags); ++ else { ++ int wkq_err; ++ struct do_diropq_args args = { ++ .errp = &diropq, ++ .dentry = dentry, ++ .bindex = bindex, ++ .flags = flags ++ }; ++ ++ wkq_err = au_wkq_wait(call_do_diropq, &args); ++ if (unlikely(wkq_err)) ++ diropq = ERR_PTR(wkq_err); ++ } ++ ++ return diropq; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * lookup whiteout dentry. ++ * @h_parent: lower parent dentry which must exist and be locked ++ * @base_name: name of dentry which will be whiteouted ++ * returns dentry for whiteout. ++ */ ++struct dentry *au_wh_lkup(struct dentry *h_parent, struct qstr *base_name, ++ struct au_branch *br) ++{ ++ int err; ++ struct qstr wh_name; ++ struct dentry *wh_dentry; ++ ++ err = au_wh_name_alloc(&wh_name, base_name); ++ wh_dentry = ERR_PTR(err); ++ if (!err) { ++ wh_dentry = vfsub_lkup_one(&wh_name, h_parent); ++ au_kfree_try_rcu(wh_name.name); ++ } ++ return wh_dentry; ++} ++ ++/* ++ * link/create a whiteout for @dentry on @bindex. ++ */ ++struct dentry *au_wh_create(struct dentry *dentry, aufs_bindex_t bindex, ++ struct dentry *h_parent) ++{ ++ struct dentry *wh_dentry; ++ struct super_block *sb; ++ int err; ++ ++ sb = dentry->d_sb; ++ wh_dentry = au_wh_lkup(h_parent, &dentry->d_name, au_sbr(sb, bindex)); ++ if (!IS_ERR(wh_dentry) && d_is_negative(wh_dentry)) { ++ err = link_or_create_wh(sb, bindex, wh_dentry); ++ if (!err) { ++ au_set_dbwh(dentry, bindex); ++ au_fhsm_wrote(sb, bindex, /*force*/0); ++ } else { ++ dput(wh_dentry); ++ wh_dentry = ERR_PTR(err); ++ } ++ } ++ ++ return wh_dentry; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* Delete all whiteouts in this directory on branch bindex. */ ++static int del_wh_children(struct dentry *h_dentry, struct au_nhash *whlist, ++ aufs_bindex_t bindex, struct au_branch *br) ++{ ++ int err; ++ unsigned long ul, n; ++ struct qstr wh_name; ++ char *p; ++ struct hlist_head *head; ++ struct au_vdir_wh *pos; ++ struct au_vdir_destr *str; ++ ++ err = -ENOMEM; ++ p = (void *)__get_free_page(GFP_NOFS); ++ wh_name.name = p; ++ if (unlikely(!wh_name.name)) ++ goto out; ++ ++ err = 0; ++ memcpy(p, AUFS_WH_PFX, AUFS_WH_PFX_LEN); ++ p += AUFS_WH_PFX_LEN; ++ n = whlist->nh_num; ++ head = whlist->nh_head; ++ for (ul = 0; !err && ul < n; ul++, head++) { ++ hlist_for_each_entry(pos, head, wh_hash) { ++ if (pos->wh_bindex != bindex) ++ continue; ++ ++ str = &pos->wh_str; ++ if (str->len + AUFS_WH_PFX_LEN <= PATH_MAX) { ++ memcpy(p, str->name, str->len); ++ wh_name.len = AUFS_WH_PFX_LEN + str->len; ++ err = unlink_wh_name(h_dentry, &wh_name, br); ++ if (!err) ++ continue; ++ break; ++ } ++ AuIOErr("whiteout name too long %.*s\n", ++ str->len, str->name); ++ err = -EIO; ++ break; ++ } ++ } ++ free_page((unsigned long)wh_name.name); ++ ++out: ++ return err; ++} ++ ++struct del_wh_children_args { ++ int *errp; ++ struct dentry *h_dentry; ++ struct au_nhash *whlist; ++ aufs_bindex_t bindex; ++ struct au_branch *br; ++}; ++ ++static void call_del_wh_children(void *args) ++{ ++ struct del_wh_children_args *a = args; ++ *a->errp = del_wh_children(a->h_dentry, a->whlist, a->bindex, a->br); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_whtmp_rmdir *au_whtmp_rmdir_alloc(struct super_block *sb, gfp_t gfp) ++{ ++ struct au_whtmp_rmdir *whtmp; ++ int err; ++ unsigned int rdhash; ++ ++ SiMustAnyLock(sb); ++ ++ whtmp = kzalloc(sizeof(*whtmp), gfp); ++ if (unlikely(!whtmp)) { ++ whtmp = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ ++ /* no estimation for dir size */ ++ rdhash = au_sbi(sb)->si_rdhash; ++ if (!rdhash) ++ rdhash = AUFS_RDHASH_DEF; ++ err = au_nhash_alloc(&whtmp->whlist, rdhash, gfp); ++ if (unlikely(err)) { ++ au_kfree_rcu(whtmp); ++ whtmp = ERR_PTR(err); ++ } ++ ++out: ++ return whtmp; ++} ++ ++void au_whtmp_rmdir_free(struct au_whtmp_rmdir *whtmp) ++{ ++ if (whtmp->br) ++ au_lcnt_dec(&whtmp->br->br_count); ++ dput(whtmp->wh_dentry); ++ iput(whtmp->dir); ++ au_nhash_wh_free(&whtmp->whlist); ++ au_kfree_rcu(whtmp); ++} ++ ++/* ++ * rmdir the whiteouted temporary named dir @h_dentry. ++ * @whlist: whiteouted children. ++ */ ++int au_whtmp_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_nhash *whlist) ++{ ++ int err; ++ unsigned int h_nlink; ++ struct path h_tmp; ++ struct inode *wh_inode, *h_dir; ++ struct au_branch *br; ++ ++ h_dir = d_inode(wh_dentry->d_parent); /* dir inode is locked */ ++ IMustLock(h_dir); ++ ++ br = au_sbr(dir->i_sb, bindex); ++ wh_inode = d_inode(wh_dentry); ++ inode_lock_nested(wh_inode, AuLsc_I_CHILD); ++ ++ /* ++ * someone else might change some whiteouts while we were sleeping. ++ * it means this whlist may have an obsoleted entry. ++ */ ++ if (!au_test_h_perm_sio(wh_inode, MAY_EXEC | MAY_WRITE)) ++ err = del_wh_children(wh_dentry, whlist, bindex, br); ++ else { ++ int wkq_err; ++ struct del_wh_children_args args = { ++ .errp = &err, ++ .h_dentry = wh_dentry, ++ .whlist = whlist, ++ .bindex = bindex, ++ .br = br ++ }; ++ ++ wkq_err = au_wkq_wait(call_del_wh_children, &args); ++ if (unlikely(wkq_err)) ++ err = wkq_err; ++ } ++ inode_unlock(wh_inode); ++ ++ if (!err) { ++ h_tmp.dentry = wh_dentry; ++ h_tmp.mnt = au_br_mnt(br); ++ h_nlink = h_dir->i_nlink; ++ err = vfsub_rmdir(h_dir, &h_tmp); ++ /* some fs doesn't change the parent nlink in some cases */ ++ h_nlink -= h_dir->i_nlink; ++ } ++ ++ if (!err) { ++ if (au_ibtop(dir) == bindex) { ++ /* todo: dir->i_mutex is necessary */ ++ au_cpup_attr_timesizes(dir); ++ if (h_nlink) ++ vfsub_drop_nlink(dir); ++ } ++ return 0; /* success */ ++ } ++ ++ pr_warn("failed removing %pd(%d), ignored\n", wh_dentry, err); ++ return err; ++} ++ ++static void call_rmdir_whtmp(void *args) ++{ ++ int err; ++ aufs_bindex_t bindex; ++ struct au_whtmp_rmdir *a = args; ++ struct super_block *sb; ++ struct dentry *h_parent; ++ struct inode *h_dir; ++ struct au_hinode *hdir; ++ ++ /* rmdir by nfsd may cause deadlock with this i_mutex */ ++ /* inode_lock(a->dir); */ ++ err = -EROFS; ++ sb = a->dir->i_sb; ++ si_read_lock(sb, !AuLock_FLUSH); ++ if (!au_br_writable(a->br->br_perm)) ++ goto out; ++ bindex = au_br_index(sb, a->br->br_id); ++ if (unlikely(bindex < 0)) ++ goto out; ++ ++ err = -EIO; ++ ii_write_lock_parent(a->dir); ++ h_parent = dget_parent(a->wh_dentry); ++ h_dir = d_inode(h_parent); ++ hdir = au_hi(a->dir, bindex); ++ err = vfsub_mnt_want_write(au_br_mnt(a->br)); ++ if (unlikely(err)) ++ goto out_mnt; ++ au_hn_inode_lock_nested(hdir, AuLsc_I_PARENT); ++ err = au_h_verify(a->wh_dentry, au_opt_udba(sb), h_dir, h_parent, ++ a->br); ++ if (!err) ++ err = au_whtmp_rmdir(a->dir, bindex, a->wh_dentry, &a->whlist); ++ au_hn_inode_unlock(hdir); ++ vfsub_mnt_drop_write(au_br_mnt(a->br)); ++ ++out_mnt: ++ dput(h_parent); ++ ii_write_unlock(a->dir); ++out: ++ /* inode_unlock(a->dir); */ ++ au_whtmp_rmdir_free(a); ++ si_read_unlock(sb); ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ if (unlikely(err)) ++ AuIOErr("err %d\n", err); ++} ++ ++void au_whtmp_kick_rmdir(struct inode *dir, aufs_bindex_t bindex, ++ struct dentry *wh_dentry, struct au_whtmp_rmdir *args) ++{ ++ int wkq_err; ++ struct super_block *sb; ++ ++ IMustLock(dir); ++ ++ /* all post-process will be done in do_rmdir_whtmp(). */ ++ sb = dir->i_sb; ++ args->dir = au_igrab(dir); ++ args->br = au_sbr(sb, bindex); ++ au_lcnt_inc(&args->br->br_count); ++ args->wh_dentry = dget(wh_dentry); ++ wkq_err = au_wkq_nowait(call_rmdir_whtmp, args, sb, /*flags*/0); ++ if (unlikely(wkq_err)) { ++ pr_warn("rmdir error %pd (%d), ignored\n", wh_dentry, wkq_err); ++ au_whtmp_rmdir_free(args); ++ } ++} +diff --git a/fs/aufs/whout.h b/fs/aufs/whout.h +new file mode 100644 +index 000000000000..dc4eb41e70dd +--- /dev/null ++++ b/fs/aufs/whout.h +@@ -0,0 +1,73 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2020 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..288f5cf4b200 +--- /dev/null ++++ b/fs/aufs/wkq.c +@@ -0,0 +1,359 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 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 /* left for debugging */ ++ if (0 && au_debug_test()) ++ lockdep_print_held_locks(curr); ++#endif ++ held_locks = curr->held_locks; ++ hl = wkinfo->hlock; ++ while (n--) { ++ p = held_locks++; ++ if (au_wkq_lockdep_test(p->instance->key, p->instance->name)) ++ *hl++ = p; ++ } ++ *hl = NULL; ++ ++out: ++ return err; ++} ++ ++static void au_wkq_lockdep_free(struct au_wkinfo *wkinfo) ++{ ++ au_kfree_try_rcu(wkinfo->hlock); ++} ++ ++static void au_wkq_lockdep_pre(struct au_wkinfo *wkinfo) ++{ ++ struct held_lock *p, **hl = wkinfo->hlock; ++ int subclass; ++ ++ if (wkinfo->dont_check) ++ lockdep_off(); ++ if (!hl) ++ return; ++ while ((p = *hl++)) { /* assignment */ ++ subclass = lockdep_hlock_class(p)->subclass; ++ /* AuDbg("%s, %d\n", p->instance->name, subclass); */ ++ if (p->read) ++ rwsem_acquire_read(p->instance, subclass, 0, ++ /*p->acquire_ip*/_RET_IP_); ++ else ++ rwsem_acquire(p->instance, subclass, 0, ++ /*p->acquire_ip*/_RET_IP_); ++ } ++} ++ ++static void au_wkq_lockdep_post(struct au_wkinfo *wkinfo) ++{ ++ struct held_lock *p, **hl = wkinfo->hlock; ++ ++ if (wkinfo->dont_check) ++ lockdep_on(); ++ if (!hl) ++ return; ++ while ((p = *hl++)) /* assignment */ ++ rwsem_release(p->instance, /*p->acquire_ip*/_RET_IP_); ++} ++#endif ++ ++static void wkq_func(struct work_struct *wk) ++{ ++ struct au_wkinfo *wkinfo = container_of(wk, struct au_wkinfo, wk); ++ ++ AuDebugOn(!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)); ++ AuDebugOn(rlimit(RLIMIT_FSIZE) != RLIM_INFINITY); ++ ++ au_wkq_lockdep_pre(wkinfo); ++ wkinfo->func(wkinfo->args); ++ au_wkq_lockdep_post(wkinfo); ++ if (au_ftest_wkq(wkinfo->flags, WAIT)) ++ complete(wkinfo->comp); ++ else { ++ kobject_put(wkinfo->kobj); ++ module_put(THIS_MODULE); /* todo: ?? */ ++ au_kfree_rcu(wkinfo); ++ } ++} ++ ++/* ++ * Since struct completion is large, try allocating it dynamically. ++ */ ++#define AuWkqCompDeclare(name) struct completion *comp = NULL ++ ++static int au_wkq_comp_alloc(struct au_wkinfo *wkinfo, struct completion **comp) ++{ ++ *comp = kmalloc(sizeof(**comp), GFP_NOFS); ++ if (*comp) { ++ init_completion(*comp); ++ wkinfo->comp = *comp; ++ return 0; ++ } ++ return -ENOMEM; ++} ++ ++static void au_wkq_comp_free(struct completion *comp) ++{ ++ au_kfree_rcu(comp); ++} ++ ++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..850085fdd2d2 +--- /dev/null ++++ b/fs/aufs/wkq.h +@@ -0,0 +1,76 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2005-2020 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..a71145b741b1 +--- /dev/null ++++ b/fs/aufs/xattr.c +@@ -0,0 +1,343 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2014-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * handling xattr functions ++ */ ++ ++#include ++#include ++#include ++#include "aufs.h" ++ ++static int au_xattr_ignore(int err, char *name, unsigned int ignore_flags) ++{ ++ if (!ignore_flags) ++ goto out; ++ switch (err) { ++ case -ENOMEM: ++ case -EDQUOT: ++ goto out; ++ } ++ ++ if ((ignore_flags & AuBrAttr_ICEX) == AuBrAttr_ICEX) { ++ err = 0; ++ goto out; ++ } ++ ++#define cmp(brattr, prefix) do { \ ++ if (!strncmp(name, XATTR_##prefix##_PREFIX, \ ++ XATTR_##prefix##_PREFIX_LEN)) { \ ++ if (ignore_flags & AuBrAttr_ICEX_##brattr) \ ++ err = 0; \ ++ goto out; \ ++ } \ ++ } while (0) ++ ++ cmp(SEC, SECURITY); ++ cmp(SYS, SYSTEM); ++ cmp(TR, TRUSTED); ++ cmp(USR, USER); ++#undef cmp ++ ++ if (ignore_flags & AuBrAttr_ICEX_OTH) ++ err = 0; ++ ++out: ++ return err; ++} ++ ++static const int au_xattr_out_of_list = AuBrAttr_ICEX_OTH << 1; ++ ++static int au_do_cpup_xattr(struct dentry *h_dst, struct dentry *h_src, ++ char *name, char **buf, unsigned int ignore_flags, ++ unsigned int verbose) ++{ ++ int err; ++ ssize_t ssz; ++ struct inode *h_idst; ++ ++ ssz = vfs_getxattr_alloc(h_src, name, buf, 0, GFP_NOFS); ++ err = ssz; ++ if (unlikely(err <= 0)) { ++ if (err == -ENODATA ++ || (err == -EOPNOTSUPP ++ && ((ignore_flags & au_xattr_out_of_list) ++ || (au_test_nfs_noacl(d_inode(h_src)) ++ && (!strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS) ++ || !strcmp(name, ++ XATTR_NAME_POSIX_ACL_DEFAULT)))) ++ )) ++ err = 0; ++ if (err && (verbose || au_debug_test())) ++ pr_err("%s, err %d\n", name, err); ++ goto out; ++ } ++ ++ /* unlock it temporary */ ++ h_idst = d_inode(h_dst); ++ inode_unlock(h_idst); ++ err = vfsub_setxattr(h_dst, name, *buf, ssz, /*flags*/0); ++ inode_lock_nested(h_idst, AuLsc_I_CHILD2); ++ if (unlikely(err)) { ++ if (verbose || au_debug_test()) ++ pr_err("%s, err %d\n", name, err); ++ err = au_xattr_ignore(err, name, ignore_flags); ++ } ++ ++out: ++ return err; ++} ++ ++int au_cpup_xattr(struct dentry *h_dst, struct dentry *h_src, int ignore_flags, ++ unsigned int verbose) ++{ ++ int err, unlocked, acl_access, acl_default; ++ ssize_t ssz; ++ struct inode *h_isrc, *h_idst; ++ char *value, *p, *o, *e; ++ ++ /* try stopping to update the source inode while we are referencing */ ++ /* there should not be the parent-child relationship between them */ ++ h_isrc = d_inode(h_src); ++ h_idst = d_inode(h_dst); ++ inode_unlock(h_idst); ++ inode_lock_shared_nested(h_isrc, AuLsc_I_CHILD); ++ inode_lock_nested(h_idst, AuLsc_I_CHILD2); ++ unlocked = 0; ++ ++ /* some filesystems don't list POSIX ACL, for example tmpfs */ ++ ssz = vfs_listxattr(h_src, NULL, 0); ++ err = ssz; ++ if (unlikely(err < 0)) { ++ AuTraceErr(err); ++ if (err == -ENODATA ++ || err == -EOPNOTSUPP) ++ err = 0; /* ignore */ ++ goto out; ++ } ++ ++ err = 0; ++ p = NULL; ++ o = NULL; ++ if (ssz) { ++ err = -ENOMEM; ++ p = kmalloc(ssz, GFP_NOFS); ++ o = p; ++ if (unlikely(!p)) ++ goto out; ++ err = vfs_listxattr(h_src, p, ssz); ++ } ++ inode_unlock_shared(h_isrc); ++ unlocked = 1; ++ AuDbg("err %d, ssz %zd\n", err, ssz); ++ if (unlikely(err < 0)) ++ goto out_free; ++ ++ err = 0; ++ e = p + ssz; ++ value = NULL; ++ acl_access = 0; ++ acl_default = 0; ++ while (!err && p < e) { ++ acl_access |= !strncmp(p, XATTR_NAME_POSIX_ACL_ACCESS, ++ sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1); ++ acl_default |= !strncmp(p, XATTR_NAME_POSIX_ACL_DEFAULT, ++ sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) ++ - 1); ++ err = au_do_cpup_xattr(h_dst, h_src, p, &value, ignore_flags, ++ verbose); ++ p += strlen(p) + 1; ++ } ++ AuTraceErr(err); ++ ignore_flags |= au_xattr_out_of_list; ++ if (!err && !acl_access) { ++ err = au_do_cpup_xattr(h_dst, h_src, ++ XATTR_NAME_POSIX_ACL_ACCESS, &value, ++ ignore_flags, verbose); ++ AuTraceErr(err); ++ } ++ if (!err && !acl_default) { ++ err = au_do_cpup_xattr(h_dst, h_src, ++ XATTR_NAME_POSIX_ACL_DEFAULT, &value, ++ ignore_flags, verbose); ++ AuTraceErr(err); ++ } ++ ++ au_kfree_try_rcu(value); ++ ++out_free: ++ au_kfree_try_rcu(o); ++out: ++ if (!unlocked) ++ inode_unlock_shared(h_isrc); ++ AuTraceErr(err); ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++static int au_smack_reentering(struct super_block *sb) ++{ ++#if IS_ENABLED(CONFIG_SECURITY_SMACK) || IS_ENABLED(CONFIG_SECURITY_SELINUX) ++ /* ++ * 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 inode *inode, ++ 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, inode, /*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, /*inode*/NULL, &arg); ++} ++ ++static ssize_t au_getxattr(struct dentry *dentry, struct inode *inode, ++ 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, inode, &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..753e92a3d6d7 +--- /dev/null ++++ b/fs/aufs/xino.c +@@ -0,0 +1,1912 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2005-2020 Junjiro R. Okajima ++ */ ++ ++/* ++ * external inode number translation table and bitmap ++ * ++ * things to consider ++ * - the lifetime ++ * + au_xino object ++ * + XINO files (xino, xib, xigen) ++ * + dynamic debugfs entries (xiN) ++ * + static debugfs entries (xib, xigen) ++ * + static sysfs entry (xi_path) ++ * - several entry points to handle them. ++ * + mount(2) without xino option (default) ++ * + mount(2) with xino option ++ * + mount(2) with noxino option ++ * + umount(2) ++ * + remount with add/del branches ++ * + remount with xino/noxino options ++ */ ++ ++#include ++#include ++#include "aufs.h" ++ ++static aufs_bindex_t sbr_find_shared(struct super_block *sb, aufs_bindex_t btop, ++ aufs_bindex_t bbot, ++ struct super_block *h_sb) ++{ ++ /* todo: try binary-search if the branches are many */ ++ for (; btop <= bbot; btop++) ++ if (h_sb == au_sbr_sb(sb, btop)) ++ return btop; ++ return -1; ++} ++ ++/* ++ * find another branch who is on the same filesystem of the specified ++ * branch{@btgt}. search until @bbot. ++ */ ++static aufs_bindex_t is_sb_shared(struct super_block *sb, aufs_bindex_t btgt, ++ aufs_bindex_t bbot) ++{ ++ aufs_bindex_t bindex; ++ struct super_block *tgt_sb; ++ ++ tgt_sb = au_sbr_sb(sb, btgt); ++ bindex = sbr_find_shared(sb, /*btop*/0, btgt - 1, tgt_sb); ++ if (bindex < 0) ++ bindex = sbr_find_shared(sb, btgt + 1, bbot, tgt_sb); ++ ++ return bindex; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * stop unnecessary notify events at creating xino files ++ */ ++ ++aufs_bindex_t au_xi_root(struct super_block *sb, struct dentry *dentry) ++{ ++ aufs_bindex_t bfound, bindex, bbot; ++ struct dentry *parent; ++ struct au_branch *br; ++ ++ bfound = -1; ++ parent = dentry->d_parent; /* safe d_parent access */ ++ bbot = au_sbbot(sb); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_dentry(br) == parent) { ++ bfound = bindex; ++ break; ++ } ++ } ++ ++ AuDbg("bfound b%d\n", bfound); ++ return bfound; ++} ++ ++struct au_xino_lock_dir { ++ struct au_hinode *hdir; ++ struct dentry *parent; ++ struct inode *dir; ++}; ++ ++static struct dentry *au_dget_parent_lock(struct dentry *dentry, ++ unsigned int lsc) ++{ ++ struct dentry *parent; ++ struct inode *dir; ++ ++ parent = dget_parent(dentry); ++ dir = d_inode(parent); ++ inode_lock_nested(dir, lsc); ++#if 0 /* it should not happen */ ++ spin_lock(&dentry->d_lock); ++ if (unlikely(dentry->d_parent != parent)) { ++ spin_unlock(&dentry->d_lock); ++ inode_unlock(dir); ++ dput(parent); ++ parent = NULL; ++ goto out; ++ } ++ spin_unlock(&dentry->d_lock); ++ ++out: ++#endif ++ return parent; ++} ++ ++static void au_xino_lock_dir(struct super_block *sb, struct path *xipath, ++ struct au_xino_lock_dir *ldir) ++{ ++ aufs_bindex_t bindex; ++ ++ ldir->hdir = NULL; ++ bindex = au_xi_root(sb, xipath->dentry); ++ if (bindex >= 0) { ++ /* rw branch root */ ++ ldir->hdir = au_hi(d_inode(sb->s_root), bindex); ++ au_hn_inode_lock_nested(ldir->hdir, AuLsc_I_PARENT); ++ } else { ++ /* other */ ++ ldir->parent = au_dget_parent_lock(xipath->dentry, ++ AuLsc_I_PARENT); ++ ldir->dir = d_inode(ldir->parent); ++ } ++} ++ ++static void au_xino_unlock_dir(struct au_xino_lock_dir *ldir) ++{ ++ if (ldir->hdir) ++ au_hn_inode_unlock(ldir->hdir); ++ else { ++ inode_unlock(ldir->dir); ++ dput(ldir->parent); ++ } ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * create and set a new xino file ++ */ ++struct file *au_xino_create(struct super_block *sb, char *fpath, int silent, ++ int wbrtop) ++{ ++ struct file *file; ++ struct dentry *h_parent, *d; ++ struct inode *h_dir, *inode; ++ int err; ++ static DEFINE_MUTEX(mtx); ++ ++ /* ++ * at mount-time, and the xino file is the default path, ++ * hnotify is disabled so we have no notify events to ignore. ++ * when a user specified the xino, we cannot get au_hdir to be ignored. ++ */ ++ if (!wbrtop) ++ mutex_lock(&mtx); ++ file = vfsub_filp_open(fpath, O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE ++ /* | __FMODE_NONOTIFY */, ++ 0666); ++ if (IS_ERR(file)) { ++ if (!wbrtop) ++ mutex_unlock(&mtx); ++ if (!silent) ++ pr_err("open %s(%ld)\n", fpath, PTR_ERR(file)); ++ return file; ++ } ++ ++ /* keep file count */ ++ err = 0; ++ d = file->f_path.dentry; ++ h_parent = au_dget_parent_lock(d, AuLsc_I_PARENT); ++ if (!wbrtop) ++ mutex_unlock(&mtx); ++ /* mnt_want_write() is unnecessary here */ ++ h_dir = d_inode(h_parent); ++ inode = file_inode(file); ++ /* no delegation since it is just created */ ++ if (inode->i_nlink) ++ err = vfsub_unlink(h_dir, &file->f_path, /*delegated*/NULL, ++ /*force*/0); ++ inode_unlock(h_dir); ++ dput(h_parent); ++ if (unlikely(err)) { ++ if (!silent) ++ pr_err("unlink %s(%d)\n", fpath, err); ++ goto out; ++ } ++ ++ err = -EINVAL; ++ if (unlikely(sb == d->d_sb)) { ++ if (!silent) ++ pr_err("%s must be outside\n", fpath); ++ goto out; ++ } ++ if (unlikely(au_test_fs_bad_xino(d->d_sb))) { ++ if (!silent) ++ pr_err("xino doesn't support %s(%s)\n", ++ fpath, au_sbtype(d->d_sb)); ++ goto out; ++ } ++ return file; /* success */ ++ ++out: ++ fput(file); ++ file = ERR_PTR(err); ++ return file; ++} ++ ++/* ++ * create a new xinofile at the same place/path as @base. ++ */ ++struct file *au_xino_create2(struct super_block *sb, struct path *base, ++ struct file *copy_src) ++{ ++ struct file *file; ++ struct dentry *dentry, *parent; ++ struct inode *dir, *delegated; ++ struct qstr *name; ++ struct path path; ++ int err, do_unlock; ++ struct au_xino_lock_dir ldir; ++ ++ do_unlock = 1; ++ au_xino_lock_dir(sb, base, &ldir); ++ dentry = base->dentry; ++ parent = dentry->d_parent; /* dir inode is locked */ ++ dir = d_inode(parent); ++ IMustLock(dir); ++ ++ name = &dentry->d_name; ++ path.dentry = vfsub_lookup_one_len(name->name, parent, name->len); ++ if (IS_ERR(path.dentry)) { ++ file = (void *)path.dentry; ++ pr_err("%pd lookup err %ld\n", dentry, PTR_ERR(path.dentry)); ++ goto out; ++ } ++ ++ /* no need to mnt_want_write() since we call dentry_open() later */ ++ err = vfs_create(dir, path.dentry, 0666, NULL); ++ if (unlikely(err)) { ++ file = ERR_PTR(err); ++ pr_err("%pd create err %d\n", dentry, err); ++ goto out_dput; ++ } ++ ++ path.mnt = base->mnt; ++ file = vfsub_dentry_open(&path, ++ O_RDWR | O_CREAT | O_EXCL | O_LARGEFILE ++ /* | __FMODE_NONOTIFY */); ++ if (IS_ERR(file)) { ++ pr_err("%pd open err %ld\n", dentry, PTR_ERR(file)); ++ goto out_dput; ++ } ++ ++ delegated = NULL; ++ err = vfsub_unlink(dir, &file->f_path, &delegated, /*force*/0); ++ au_xino_unlock_dir(&ldir); ++ do_unlock = 0; ++ if (unlikely(err == -EWOULDBLOCK)) { ++ pr_warn("cannot retry for NFSv4 delegation" ++ " for an internal unlink\n"); ++ iput(delegated); ++ } ++ if (unlikely(err)) { ++ pr_err("%pd unlink err %d\n", dentry, err); ++ goto out_fput; ++ } ++ ++ if (copy_src) { ++ /* no one can touch copy_src xino */ ++ err = au_copy_file(file, copy_src, vfsub_f_size_read(copy_src)); ++ if (unlikely(err)) { ++ pr_err("%pd copy err %d\n", dentry, err); ++ goto out_fput; ++ } ++ } ++ goto out_dput; /* success */ ++ ++out_fput: ++ fput(file); ++ file = ERR_PTR(err); ++out_dput: ++ dput(path.dentry); ++out: ++ if (do_unlock) ++ au_xino_unlock_dir(&ldir); ++ return file; ++} ++ ++struct file *au_xino_file1(struct au_xino *xi) ++{ ++ struct file *file; ++ unsigned int u, nfile; ++ ++ file = NULL; ++ nfile = xi->xi_nfile; ++ for (u = 0; u < nfile; u++) { ++ file = xi->xi_file[u]; ++ if (file) ++ break; ++ } ++ ++ return file; ++} ++ ++static int au_xino_file_set(struct au_xino *xi, int idx, struct file *file) ++{ ++ int err; ++ struct file *f; ++ void *p; ++ ++ if (file) ++ get_file(file); ++ ++ err = 0; ++ f = NULL; ++ if (idx < xi->xi_nfile) { ++ f = xi->xi_file[idx]; ++ if (f) ++ fput(f); ++ } else { ++ p = au_kzrealloc(xi->xi_file, ++ sizeof(*xi->xi_file) * xi->xi_nfile, ++ sizeof(*xi->xi_file) * (idx + 1), ++ GFP_NOFS, /*may_shrink*/0); ++ if (p) { ++ MtxMustLock(&xi->xi_mtx); ++ xi->xi_file = p; ++ xi->xi_nfile = idx + 1; ++ } else { ++ err = -ENOMEM; ++ if (file) ++ fput(file); ++ goto out; ++ } ++ } ++ xi->xi_file[idx] = file; ++ ++out: ++ return err; ++} ++ ++/* ++ * if @xinew->xi is not set, then create new xigen file. ++ */ ++struct file *au_xi_new(struct super_block *sb, struct au_xi_new *xinew) ++{ ++ struct file *file; ++ int err; ++ ++ SiMustAnyLock(sb); ++ ++ file = au_xino_create2(sb, xinew->base, xinew->copy_src); ++ if (IS_ERR(file)) { ++ err = PTR_ERR(file); ++ pr_err("%s[%d], err %d\n", ++ xinew->xi ? "xino" : "xigen", ++ xinew->idx, err); ++ goto out; ++ } ++ ++ if (xinew->xi) ++ err = au_xino_file_set(xinew->xi, xinew->idx, file); ++ else { ++ BUG(); ++ /* todo: make xigen file an array */ ++ /* err = au_xigen_file_set(sb, xinew->idx, file); */ ++ } ++ fput(file); ++ if (unlikely(err)) ++ file = ERR_PTR(err); ++ ++out: ++ return file; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * truncate xino files ++ */ ++static int au_xino_do_trunc(struct super_block *sb, aufs_bindex_t bindex, ++ int idx, struct kstatfs *st) ++{ ++ int err; ++ blkcnt_t blocks; ++ struct file *file, *new_xino; ++ struct au_xi_new xinew = { ++ .idx = idx ++ }; ++ ++ err = 0; ++ xinew.xi = au_sbr(sb, bindex)->br_xino; ++ file = au_xino_file(xinew.xi, idx); ++ if (!file) ++ goto out; ++ ++ xinew.base = &file->f_path; ++ err = vfs_statfs(xinew.base, st); ++ if (unlikely(err)) { ++ AuErr1("statfs err %d, ignored\n", err); ++ err = 0; ++ goto out; ++ } ++ ++ blocks = file_inode(file)->i_blocks; ++ pr_info("begin truncating xino(b%d-%d), ib%llu, %llu/%llu free blks\n", ++ bindex, idx, (u64)blocks, st->f_bfree, st->f_blocks); ++ ++ xinew.copy_src = file; ++ new_xino = au_xi_new(sb, &xinew); ++ if (IS_ERR(new_xino)) { ++ err = PTR_ERR(new_xino); ++ pr_err("xino(b%d-%d), err %d, ignored\n", bindex, idx, err); ++ goto out; ++ } ++ ++ err = vfs_statfs(&new_xino->f_path, st); ++ if (!err) ++ pr_info("end truncating xino(b%d-%d), ib%llu, %llu/%llu free blks\n", ++ bindex, idx, (u64)file_inode(new_xino)->i_blocks, ++ st->f_bfree, st->f_blocks); ++ else { ++ AuErr1("statfs err %d, ignored\n", err); ++ err = 0; ++ } ++ ++out: ++ return err; ++} ++ ++int au_xino_trunc(struct super_block *sb, aufs_bindex_t bindex, int idx_begin) ++{ ++ int err, i; ++ unsigned long jiffy; ++ aufs_bindex_t bbot; ++ struct kstatfs *st; ++ struct au_branch *br; ++ struct au_xino *xi; ++ ++ err = -ENOMEM; ++ st = kmalloc(sizeof(*st), GFP_NOFS); ++ if (unlikely(!st)) ++ goto out; ++ ++ err = -EINVAL; ++ bbot = au_sbbot(sb); ++ if (unlikely(bindex < 0 || bbot < bindex)) ++ goto out_st; ++ ++ err = 0; ++ jiffy = jiffies; ++ br = au_sbr(sb, bindex); ++ xi = br->br_xino; ++ for (i = idx_begin; !err && i < xi->xi_nfile; i++) ++ err = au_xino_do_trunc(sb, bindex, i, st); ++ if (!err) ++ au_sbi(sb)->si_xino_jiffy = jiffy; ++ ++out_st: ++ au_kfree_rcu(st); ++out: ++ return err; ++} ++ ++struct xino_do_trunc_args { ++ struct super_block *sb; ++ struct au_branch *br; ++ int idx; ++}; ++ ++static void xino_do_trunc(void *_args) ++{ ++ struct xino_do_trunc_args *args = _args; ++ struct super_block *sb; ++ struct au_branch *br; ++ struct inode *dir; ++ int err, idx; ++ aufs_bindex_t bindex; ++ ++ err = 0; ++ sb = args->sb; ++ dir = d_inode(sb->s_root); ++ br = args->br; ++ idx = args->idx; ++ ++ si_noflush_write_lock(sb); ++ ii_read_lock_parent(dir); ++ bindex = au_br_index(sb, br->br_id); ++ err = au_xino_trunc(sb, bindex, idx); ++ ii_read_unlock(dir); ++ if (unlikely(err)) ++ pr_warn("err b%d, (%d)\n", bindex, err); ++ atomic_dec(&br->br_xino->xi_truncating); ++ au_lcnt_dec(&br->br_count); ++ si_write_unlock(sb); ++ au_nwt_done(&au_sbi(sb)->si_nowait); ++ au_kfree_rcu(args); ++} ++ ++/* ++ * returns the index in the xi_file array whose corresponding file is necessary ++ * to truncate, or -1 which means no need to truncate. ++ */ ++static int xino_trunc_test(struct super_block *sb, struct au_branch *br) ++{ ++ int err; ++ unsigned int u; ++ struct kstatfs st; ++ struct au_sbinfo *sbinfo; ++ struct au_xino *xi; ++ struct file *file; ++ ++ /* todo: si_xino_expire and the ratio should be customizable */ ++ sbinfo = au_sbi(sb); ++ if (time_before(jiffies, ++ sbinfo->si_xino_jiffy + sbinfo->si_xino_expire)) ++ return -1; ++ ++ /* truncation border */ ++ xi = br->br_xino; ++ for (u = 0; u < xi->xi_nfile; u++) { ++ file = au_xino_file(xi, u); ++ if (!file) ++ continue; ++ ++ err = vfs_statfs(&file->f_path, &st); ++ if (unlikely(err)) { ++ AuErr1("statfs err %d, ignored\n", err); ++ return -1; ++ } ++ if (div64_u64(st.f_bfree * 100, st.f_blocks) ++ >= AUFS_XINO_DEF_TRUNC) ++ return u; ++ } ++ ++ return -1; ++} ++ ++static void xino_try_trunc(struct super_block *sb, struct au_branch *br) ++{ ++ int idx; ++ struct xino_do_trunc_args *args; ++ int wkq_err; ++ ++ idx = xino_trunc_test(sb, br); ++ if (idx < 0) ++ return; ++ ++ if (atomic_inc_return(&br->br_xino->xi_truncating) > 1) ++ goto out; ++ ++ /* lock and kfree() will be called in trunc_xino() */ ++ args = kmalloc(sizeof(*args), GFP_NOFS); ++ if (unlikely(!args)) { ++ AuErr1("no memory\n"); ++ goto out; ++ } ++ ++ au_lcnt_inc(&br->br_count); ++ args->sb = sb; ++ args->br = br; ++ args->idx = idx; ++ wkq_err = au_wkq_nowait(xino_do_trunc, args, sb, /*flags*/0); ++ if (!wkq_err) ++ return; /* success */ ++ ++ pr_err("wkq %d\n", wkq_err); ++ au_lcnt_dec(&br->br_count); ++ au_kfree_rcu(args); ++ ++out: ++ atomic_dec(&br->br_xino->xi_truncating); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_xi_calc { ++ int idx; ++ loff_t pos; ++}; ++ ++static void au_xi_calc(struct super_block *sb, ino_t h_ino, ++ struct au_xi_calc *calc) ++{ ++ loff_t maxent; ++ ++ maxent = au_xi_maxent(sb); ++ calc->idx = div64_u64_rem(h_ino, maxent, &calc->pos); ++ calc->pos *= sizeof(ino_t); ++} ++ ++static int au_xino_do_new_async(struct super_block *sb, struct au_branch *br, ++ struct au_xi_calc *calc) ++{ ++ int err; ++ struct file *file; ++ struct au_xino *xi = br->br_xino; ++ struct au_xi_new xinew = { ++ .xi = xi ++ }; ++ ++ SiMustAnyLock(sb); ++ ++ err = 0; ++ if (!xi) ++ goto out; ++ ++ mutex_lock(&xi->xi_mtx); ++ file = au_xino_file(xi, calc->idx); ++ if (file) ++ goto out_mtx; ++ ++ file = au_xino_file(xi, /*idx*/-1); ++ AuDebugOn(!file); ++ xinew.idx = calc->idx; ++ xinew.base = &file->f_path; ++ /* xinew.copy_src = NULL; */ ++ file = au_xi_new(sb, &xinew); ++ if (IS_ERR(file)) ++ err = PTR_ERR(file); ++ ++out_mtx: ++ mutex_unlock(&xi->xi_mtx); ++out: ++ return err; ++} ++ ++struct au_xino_do_new_async_args { ++ struct super_block *sb; ++ struct au_branch *br; ++ struct au_xi_calc calc; ++ ino_t ino; ++}; ++ ++struct au_xi_writing { ++ struct hlist_bl_node node; ++ ino_t h_ino, ino; ++}; ++ ++static int au_xino_do_write(struct file *file, struct au_xi_calc *calc, ++ ino_t ino); ++ ++static void au_xino_call_do_new_async(void *args) ++{ ++ struct au_xino_do_new_async_args *a = args; ++ struct au_branch *br; ++ struct super_block *sb; ++ struct au_sbinfo *sbi; ++ struct inode *root; ++ struct file *file; ++ struct au_xi_writing *del, *p; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ int err; ++ ++ br = a->br; ++ sb = a->sb; ++ sbi = au_sbi(sb); ++ si_noflush_read_lock(sb); ++ root = d_inode(sb->s_root); ++ ii_read_lock_child(root); ++ err = au_xino_do_new_async(sb, br, &a->calc); ++ if (unlikely(err)) { ++ AuIOErr("err %d\n", err); ++ goto out; ++ } ++ ++ file = au_xino_file(br->br_xino, a->calc.idx); ++ AuDebugOn(!file); ++ err = au_xino_do_write(file, &a->calc, a->ino); ++ if (unlikely(err)) { ++ AuIOErr("err %d\n", err); ++ goto out; ++ } ++ ++ del = NULL; ++ hbl = &br->br_xino->xi_writing; ++ hlist_bl_lock(hbl); ++ au_hbl_for_each(pos, hbl) { ++ p = container_of(pos, struct au_xi_writing, node); ++ if (p->ino == a->ino) { ++ del = p; ++ hlist_bl_del(&p->node); ++ break; ++ } ++ } ++ hlist_bl_unlock(hbl); ++ au_kfree_rcu(del); ++ ++out: ++ au_lcnt_dec(&br->br_count); ++ ii_read_unlock(root); ++ si_read_unlock(sb); ++ au_nwt_done(&sbi->si_nowait); ++ au_kfree_rcu(a); ++} ++ ++/* ++ * create a new xino file asynchronously ++ */ ++static int au_xino_new_async(struct super_block *sb, struct au_branch *br, ++ struct au_xi_calc *calc, ino_t ino) ++{ ++ int err; ++ struct au_xino_do_new_async_args *arg; ++ ++ err = -ENOMEM; ++ arg = kmalloc(sizeof(*arg), GFP_NOFS); ++ if (unlikely(!arg)) ++ goto out; ++ ++ arg->sb = sb; ++ arg->br = br; ++ arg->calc = *calc; ++ arg->ino = ino; ++ au_lcnt_inc(&br->br_count); ++ err = au_wkq_nowait(au_xino_call_do_new_async, arg, sb, AuWkq_NEST); ++ if (unlikely(err)) { ++ pr_err("wkq %d\n", err); ++ au_lcnt_dec(&br->br_count); ++ au_kfree_rcu(arg); ++ } ++ ++out: ++ return err; ++} ++ ++/* ++ * read @ino from xinofile for the specified branch{@sb, @bindex} ++ * at the position of @h_ino. ++ */ ++int au_xino_read(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t *ino) ++{ ++ int err; ++ ssize_t sz; ++ struct au_xi_calc calc; ++ struct au_sbinfo *sbinfo; ++ struct file *file; ++ struct au_xino *xi; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos; ++ struct au_xi_writing *p; ++ ++ *ino = 0; ++ if (!au_opt_test(au_mntflags(sb), XINO)) ++ return 0; /* no xino */ ++ ++ err = 0; ++ au_xi_calc(sb, h_ino, &calc); ++ xi = au_sbr(sb, bindex)->br_xino; ++ file = au_xino_file(xi, calc.idx); ++ if (!file) { ++ hbl = &xi->xi_writing; ++ hlist_bl_lock(hbl); ++ au_hbl_for_each(pos, hbl) { ++ p = container_of(pos, struct au_xi_writing, node); ++ if (p->h_ino == h_ino) { ++ AuDbg("hi%llu, i%llu, found\n", ++ (u64)p->h_ino, (u64)p->ino); ++ *ino = p->ino; ++ break; ++ } ++ } ++ hlist_bl_unlock(hbl); ++ return 0; ++ } else if (vfsub_f_size_read(file) < calc.pos + sizeof(*ino)) ++ return 0; /* no xino */ ++ ++ sbinfo = au_sbi(sb); ++ sz = xino_fread(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(struct file *file, struct au_xi_calc *calc, ++ ino_t ino) ++{ ++ ssize_t sz; ++ ++ sz = xino_fwrite(file, &ino, sizeof(ino), &calc->pos); ++ if (sz == sizeof(ino)) ++ return 0; /* success */ ++ ++ AuIOErr("write failed (%zd)\n", sz); ++ return -EIO; ++} ++ ++/* ++ * write @ino to the xinofile for the specified branch{@sb, @bindex} ++ * at the position of @h_ino. ++ * even if @ino is zero, it is written to the xinofile and means no entry. ++ * if the size of the xino file on a specific filesystem exceeds the watermark, ++ * try truncating it. ++ */ ++int au_xino_write(struct super_block *sb, aufs_bindex_t bindex, ino_t h_ino, ++ ino_t ino) ++{ ++ int err; ++ unsigned int mnt_flags; ++ struct au_xi_calc calc; ++ struct file *file; ++ struct au_branch *br; ++ struct au_xino *xi; ++ struct au_xi_writing *p; ++ ++ SiMustAnyLock(sb); ++ ++ mnt_flags = au_mntflags(sb); ++ if (!au_opt_test(mnt_flags, XINO)) ++ return 0; ++ ++ au_xi_calc(sb, h_ino, &calc); ++ br = au_sbr(sb, bindex); ++ xi = br->br_xino; ++ file = au_xino_file(xi, calc.idx); ++ if (!file) { ++ /* store the inum pair into the list */ ++ p = kmalloc(sizeof(*p), GFP_NOFS | __GFP_NOFAIL); ++ p->h_ino = h_ino; ++ p->ino = ino; ++ au_hbl_add(&p->node, &xi->xi_writing); ++ ++ /* create and write a new xino file asynchronously */ ++ err = au_xino_new_async(sb, br, &calc, ino); ++ if (!err) ++ return 0; /* success */ ++ goto out; ++ } ++ ++ err = au_xino_do_write(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(struct file *file, void *buf, size_t size, ++ loff_t *pos); ++ ++/* todo: unnecessary to support mmap_sem since kernel-space? */ ++ssize_t xino_fread(struct file *file, void *kbuf, size_t size, loff_t *pos) ++{ ++ ssize_t err; ++ int i; ++ const int prevent_endless = 10; ++ ++ i = 0; ++ do { ++ err = vfsub_read_k(file, kbuf, size, pos); ++ if (err == -EINTR ++ && !au_wkq_test() ++ && fatal_signal_pending(current)) { ++ err = xino_fread_wkq(file, kbuf, size, pos); ++ BUG_ON(err == -EINTR); ++ } ++ } while (i++ < prevent_endless ++ && (err == -EAGAIN || err == -EINTR)); ++ ++#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; ++ 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->file, a->buf, a->size, a->pos); ++} ++ ++static ssize_t xino_fread_wkq(struct file *file, void *buf, size_t size, ++ loff_t *pos) ++{ ++ ssize_t err; ++ int wkq_err; ++ struct xino_fread_args args = { ++ .errp = &err, ++ .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(struct file *file, void *buf, size_t size, ++ loff_t *pos); ++ ++static ssize_t do_xino_fwrite(struct file *file, void *kbuf, size_t size, ++ loff_t *pos) ++{ ++ ssize_t err; ++ int i; ++ const int prevent_endless = 10; ++ ++ i = 0; ++ do { ++ err = vfsub_write_k(file, kbuf, size, pos); ++ if (err == -EINTR ++ && !au_wkq_test() ++ && fatal_signal_pending(current)) { ++ err = xino_fwrite_wkq(file, kbuf, size, pos); ++ BUG_ON(err == -EINTR); ++ } ++ } while (i++ < prevent_endless ++ && (err == -EAGAIN || err == -EINTR)); ++ ++#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; ++ 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->file, a->buf, a->size, a->pos); ++} ++ ++static ssize_t xino_fwrite_wkq(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, ++ .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(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(file, buf, size, pos); ++ lockdep_on(); ++ } else { ++ lockdep_off(); ++ err = xino_fwrite_wkq(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(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(xib, p, PAGE_SIZE, &pos); ++ else { ++ memset(p, 0, PAGE_SIZE); ++ sz = xino_fwrite(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; ++ ino_t *ino; ++ unsigned long *p; ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ MtxMustLock(&sbinfo->si_xib_mtx); ++ p = sbinfo->si_xib_buf; ++ pend = vfsub_f_size_read(file); ++ pos = 0; ++ while (pos < pend) { ++ sz = xino_fread(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_xib, p, PAGE_SIZE, &pos); ++ if (unlikely(sz != PAGE_SIZE)) { ++ err = sz; ++ AuIOErr("err %d\n", err); ++ if (sz >= 0) ++ err = -EIO; ++ goto out; ++ } ++ ++ mutex_lock(&sbinfo->si_xib_mtx); ++ /* mnt_want_write() is unnecessary here */ ++ err = xib_restore(sb); ++ mutex_unlock(&sbinfo->si_xib_mtx); ++ ++out: ++ return err; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++struct au_xino *au_xino_alloc(unsigned int nfile) ++{ ++ struct au_xino *xi; ++ ++ xi = kzalloc(sizeof(*xi), GFP_NOFS); ++ if (unlikely(!xi)) ++ goto out; ++ xi->xi_nfile = nfile; ++ xi->xi_file = kcalloc(nfile, sizeof(*xi->xi_file), GFP_NOFS); ++ if (unlikely(!xi->xi_file)) ++ goto out_free; ++ ++ xi->xi_nondir.total = 8; /* initial size */ ++ xi->xi_nondir.array = kcalloc(xi->xi_nondir.total, sizeof(ino_t), ++ GFP_NOFS); ++ if (unlikely(!xi->xi_nondir.array)) ++ goto out_file; ++ ++ spin_lock_init(&xi->xi_nondir.spin); ++ init_waitqueue_head(&xi->xi_nondir.wqh); ++ mutex_init(&xi->xi_mtx); ++ INIT_HLIST_BL_HEAD(&xi->xi_writing); ++ atomic_set(&xi->xi_truncating, 0); ++ kref_init(&xi->xi_kref); ++ goto out; /* success */ ++ ++out_file: ++ au_kfree_try_rcu(xi->xi_file); ++out_free: ++ au_kfree_rcu(xi); ++ xi = NULL; ++out: ++ return xi; ++} ++ ++static int au_xino_init(struct au_branch *br, int idx, struct file *file) ++{ ++ int err; ++ struct au_xino *xi; ++ ++ err = 0; ++ xi = au_xino_alloc(idx + 1); ++ if (unlikely(!xi)) { ++ err = -ENOMEM; ++ goto out; ++ } ++ ++ if (file) ++ get_file(file); ++ xi->xi_file[idx] = file; ++ AuDebugOn(br->br_xino); ++ br->br_xino = xi; ++ ++out: ++ return err; ++} ++ ++static void au_xino_release(struct kref *kref) ++{ ++ struct au_xino *xi; ++ int i; ++ unsigned long ul; ++ struct hlist_bl_head *hbl; ++ struct hlist_bl_node *pos, *n; ++ struct au_xi_writing *p; ++ ++ xi = container_of(kref, struct au_xino, xi_kref); ++ for (i = 0; i < xi->xi_nfile; i++) ++ if (xi->xi_file[i]) ++ fput(xi->xi_file[i]); ++ for (i = xi->xi_nondir.total - 1; i >= 0; i--) ++ AuDebugOn(xi->xi_nondir.array[i]); ++ mutex_destroy(&xi->xi_mtx); ++ hbl = &xi->xi_writing; ++ ul = au_hbl_count(hbl); ++ if (unlikely(ul)) { ++ pr_warn("xi_writing %lu\n", ul); ++ hlist_bl_lock(hbl); ++ hlist_bl_for_each_entry_safe(p, pos, n, hbl, node) { ++ hlist_bl_del(&p->node); ++ /* kmemleak reported au_kfree_rcu() doesn't free it */ ++ kfree(p); ++ } ++ hlist_bl_unlock(hbl); ++ } ++ au_kfree_try_rcu(xi->xi_file); ++ au_kfree_try_rcu(xi->xi_nondir.array); ++ au_kfree_rcu(xi); ++} ++ ++int au_xino_put(struct au_branch *br) ++{ ++ int ret; ++ struct au_xino *xi; ++ ++ ret = 0; ++ xi = br->br_xino; ++ if (xi) { ++ br->br_xino = NULL; ++ ret = kref_put(&xi->xi_kref, au_xino_release); ++ } ++ ++ return ret; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * xino mount option handlers ++ */ ++ ++/* xino bitmap */ ++static void xino_clear_xib(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ SiMustWriteLock(sb); ++ ++ sbinfo = au_sbi(sb); ++ 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; ++ 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(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 { ++ 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(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); ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ args.h_ino = au_h_iptr(inode, bindex)->i_ino; ++ args.br = au_sbr(sb, bindex); ++ args.bshared = is_sb_shared(sb, bindex, bindex - 1); ++ err = au_xino_do_set_br(sb, path, &args); ++ if (unlikely(err)) ++ break; ++ } ++ ++ AuTraceErr(err); ++ return err; ++} ++ ++void au_xino_clr(struct super_block *sb) ++{ ++ struct au_sbinfo *sbinfo; ++ ++ au_xigen_clr(sb); ++ xino_clear_xib(sb); ++ xino_clear_br(sb); ++ dbgaufs_brs_del(sb, 0); ++ sbinfo = au_sbi(sb); ++ /* lvalue, do not call au_mntflags() */ ++ au_opt_clr(sbinfo->si_mntflags, XINO); ++} ++ ++int au_xino_set(struct super_block *sb, struct au_opt_xino *xiopt, int remount) ++{ ++ int err, skip; ++ struct dentry *dentry, *parent, *cur_dentry, *cur_parent; ++ struct qstr *dname, *cur_name; ++ struct file *cur_xino; ++ struct au_sbinfo *sbinfo; ++ struct path *path, *cur_path; ++ ++ SiMustWriteLock(sb); ++ ++ err = 0; ++ sbinfo = au_sbi(sb); ++ path = &xiopt->file->f_path; ++ dentry = path->dentry; ++ parent = dget_parent(dentry); ++ if (remount) { ++ skip = 0; ++ cur_xino = sbinfo->si_xib; ++ if (cur_xino) { ++ cur_path = &cur_xino->f_path; ++ cur_dentry = cur_path->dentry; ++ cur_parent = dget_parent(cur_dentry); ++ cur_name = &cur_dentry->d_name; ++ dname = &dentry->d_name; ++ skip = (cur_parent == parent ++ && au_qstreq(dname, cur_name)); ++ dput(cur_parent); ++ } ++ if (skip) ++ goto out; ++ } ++ ++ au_opt_set(sbinfo->si_mntflags, XINO); ++ err = au_xino_set_xib(sb, path); ++ /* si_x{read,write} are set */ ++ if (!err) ++ err = au_xigen_set(sb, path); ++ if (!err) ++ err = au_xino_set_br(sb, path); ++ if (!err) { ++ dbgaufs_brs_add(sb, 0, /*topdown*/1); ++ goto out; /* success */ ++ } ++ ++ /* reset all */ ++ AuIOErr("failed setting xino(%d).\n", err); ++ au_xino_clr(sb); ++ ++out: ++ dput(parent); ++ return err; ++} ++ ++/* ++ * create a xinofile at the default place/path. ++ */ ++struct file *au_xino_def(struct super_block *sb) ++{ ++ struct file *file; ++ char *page, *p; ++ struct au_branch *br; ++ struct super_block *h_sb; ++ struct path path; ++ aufs_bindex_t bbot, bindex, bwr; ++ ++ br = NULL; ++ bbot = au_sbbot(sb); ++ bwr = -1; ++ for (bindex = 0; bindex <= bbot; bindex++) { ++ br = au_sbr(sb, bindex); ++ if (au_br_writable(br->br_perm) ++ && !au_test_fs_bad_xino(au_br_sb(br))) { ++ bwr = bindex; ++ break; ++ } ++ } ++ ++ if (bwr >= 0) { ++ file = ERR_PTR(-ENOMEM); ++ page = (void *)__get_free_page(GFP_NOFS); ++ if (unlikely(!page)) ++ goto out; ++ path.mnt = au_br_mnt(br); ++ path.dentry = au_h_dptr(sb->s_root, bwr); ++ p = d_path(&path, page, PATH_MAX - sizeof(AUFS_XINO_FNAME)); ++ file = (void *)p; ++ if (!IS_ERR(p)) { ++ strcat(p, "/" AUFS_XINO_FNAME); ++ AuDbg("%s\n", p); ++ file = au_xino_create(sb, p, /*silent*/0, /*wbrtop*/1); ++ } ++ free_page((unsigned long)page); ++ } else { ++ file = au_xino_create(sb, AUFS_XINO_DEFPATH, /*silent*/0, ++ /*wbrtop*/0); ++ if (IS_ERR(file)) ++ goto out; ++ h_sb = file->f_path.dentry->d_sb; ++ if (unlikely(au_test_fs_bad_xino(h_sb))) { ++ pr_err("xino doesn't support %s(%s)\n", ++ AUFS_XINO_DEFPATH, au_sbtype(h_sb)); ++ fput(file); ++ file = ERR_PTR(-EINVAL); ++ } ++ } ++ ++out: ++ return file; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ++ * initialize the xinofile for the specified branch @br ++ * at the place/path where @base_file indicates. ++ * test whether another branch is on the same filesystem or not, ++ * if found then share the xinofile with another branch. ++ */ ++int au_xino_init_br(struct super_block *sb, struct au_branch *br, ino_t h_ino, ++ struct path *base) ++{ ++ int err; ++ struct au_xino_do_set_br args = { ++ .h_ino = h_ino, ++ .br = br ++ }; ++ ++ args.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; ++ 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; ++ ++ 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(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 ea0485861d93..ddca6240e0db 100644 +--- a/fs/dcache.c ++++ b/fs/dcache.c +@@ -1285,7 +1285,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 19ac5baad50f..073ca6af500f 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 9d78c37b00b8..e7f0c614a58f 100644 +--- a/fs/inode.c ++++ b/fs/inode.c +@@ -1770,7 +1770,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) + { + if (inode->i_op->update_time) + return inode->i_op->update_time(inode, time, flags); +diff --git a/fs/namespace.c b/fs/namespace.c +index cebaa3e81794..451dee24a546 100644 +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -792,6 +792,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 b362523a9829..669448bb8a73 100644 +--- a/fs/proc/base.c ++++ b/fs/proc/base.c +@@ -2184,7 +2184,7 @@ static int map_files_get_link(struct dentry *dentry, struct path *path) + rc = -ENOENT; + vma = find_exact_vma(mm, vm_start, vm_end); + if (vma && vma->vm_file) { +- *path = vma->vm_file->f_path; ++ *path = vma_pr_or_file(vma)->f_path; + path_get(path); + rc = 0; + } +diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c +index 13452b32e2bd..38acccfef9d4 100644 +--- a/fs/proc/nommu.c ++++ b/fs/proc/nommu.c +@@ -40,7 +40,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 ee5a235b3056..80a46dcede7b 100644 +--- a/fs/proc/task_mmu.c ++++ b/fs/proc/task_mmu.c +@@ -280,7 +280,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; +@@ -1855,7 +1858,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 mempolicy *pol; + char buffer[64]; +diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c +index a6d21fc0033c..02c2de31196e 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/splice.c b/fs/splice.c +index 866d5c2367b2..55b535626208 100644 +--- a/fs/splice.c ++++ b/fs/splice.c +@@ -756,8 +756,8 @@ static int warn_unsupported(struct file *file, const char *op) + /* + * 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) + { + if (unlikely(!out->f_op->splice_write)) + return warn_unsupported(out, "write"); +@@ -767,9 +767,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) + { + int ret; + +diff --git a/fs/sync.c b/fs/sync.c +index 1373a610dc78..b7b5a0a0df6f 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 8667d0cdc71e..837dd6e727e4 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -1332,6 +1332,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); +@@ -1843,6 +1844,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); +@@ -2328,6 +2330,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; +@@ -2564,6 +2567,7 @@ static inline bool sb_is_blkdev_sb(struct super_block *sb) + } + + void emergency_thaw_all(void); ++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 f5594879175a..93bb86198167 100644 +--- a/include/linux/lockdep.h ++++ b/include/linux/lockdep.h +@@ -241,6 +241,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. + * +@@ -375,6 +377,7 @@ static inline void lockdep_unregister_key(struct lock_class_key *key) + + #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 db6ae4d3fb4e..1a632192d9d9 100644 +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -1712,6 +1712,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 5a9238f6caad..ad387c3cb14f 100644 +--- a/include/linux/mm_types.h ++++ b/include/linux/mm_types.h +@@ -280,6 +280,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 +@@ -359,6 +360,7 @@ struct vm_area_struct { + unsigned long vm_pgoff; /* Offset (within vm_file) in PAGE_SIZE + units */ + struct file * vm_file; /* File we map to (can be NULL). */ ++ struct file *vm_prfile; /* shadow of vm_file */ + void * vm_private_data; /* was vm_pte (shared mem) */ + + #ifdef CONFIG_SWAP +diff --git a/include/linux/mnt_namespace.h b/include/linux/mnt_namespace.h +index 8f882f5881e8..6b9808f09843 100644 +--- a/include/linux/mnt_namespace.h ++++ b/include/linux/mnt_namespace.h +@@ -7,12 +7,15 @@ struct mnt_namespace; + struct fs_struct; + struct user_namespace; + struct ns_common; ++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 struct ns_common *from_mnt_ns(struct mnt_namespace *); + ++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 a55179fd60fc..8e21c53cf883 100644 +--- a/include/linux/splice.h ++++ b/include/linux/splice.h +@@ -93,4 +93,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..a1f4e7081d06 +--- /dev/null ++++ b/include/uapi/linux/aufs_type.h +@@ -0,0 +1,439 @@ ++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ ++/* ++ * Copyright (C) 2005-2020 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 ++#include ++#else ++#include ++#include ++#include ++#endif /* __KERNEL__ */ ++ ++#define AUFS_VERSION "5.x-rcN" ++ ++/* todo? move this to linux-2.6.19/include/magic.h */ ++#define AUFS_SUPER_MAGIC ('a' << 24 | 'u' << 16 | 'f' << 8 | 's') ++ ++/* ---------------------------------------------------------------------- */ ++ ++#ifdef __KERNEL__ ++#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 ++ ++#ifndef AUFS_BRANCH_MAX ++#error unknown CONFIG_AUFS_BRANCH_MAX value ++#endif ++#endif /* __KERNEL__ */ ++ ++/* ---------------------------------------------------------------------- */ ++ ++#define AUFS_FSTYPE AUFS_NAME ++ ++#define AUFS_ROOT_INO 2 ++#define AUFS_FIRST_INO 11 ++ ++#define AUFS_WH_PFX ".wh." ++#define AUFS_WH_PFX_LEN ((int)sizeof(AUFS_WH_PFX) - 1) ++#define AUFS_WH_TMP_LEN 4 ++/* a limit for rmdir/rename a dir and copyup */ ++#define AUFS_MAX_NAMELEN (NAME_MAX \ ++ - AUFS_WH_PFX_LEN * 2 /* doubly whiteouted */\ ++ - 1 /* dot */\ ++ - AUFS_WH_TMP_LEN) /* hex */ ++#define AUFS_XINO_FNAME "." AUFS_NAME ".xino" ++#define AUFS_XINO_DEFPATH "/tmp/" AUFS_XINO_FNAME ++#define AUFS_XINO_DEF_SEC 30 /* seconds */ ++#define AUFS_XINO_DEF_TRUNC 45 /* percentage */ ++#define AUFS_DIRWH_DEF 3 ++#define AUFS_RDCACHE_DEF 10 /* seconds */ ++#define AUFS_RDCACHE_MAX 3600 /* seconds */ ++#define AUFS_RDBLK_DEF 512 /* bytes */ ++#define AUFS_RDHASH_DEF 32 ++#define AUFS_WKQ_NAME AUFS_NAME "d" ++#define AUFS_MFS_DEF_SEC 30 /* seconds */ ++#define AUFS_MFS_MAX_SEC 3600 /* seconds */ ++#define AUFS_FHSM_CACHE_DEF_SEC 30 /* seconds */ ++#define AUFS_PLINK_WARN 50 /* number of plinks in a single bucket */ ++ ++/* pseudo-link maintenace under /proc */ ++#define AUFS_PLINK_MAINT_NAME "plink_maint" ++#define AUFS_PLINK_MAINT_DIR "fs/" AUFS_NAME ++#define AUFS_PLINK_MAINT_PATH AUFS_PLINK_MAINT_DIR "/" AUFS_PLINK_MAINT_NAME ++ ++/* dirren, renamed dir */ ++#define AUFS_DR_INFO_PFX AUFS_WH_PFX ".dr." ++#define AUFS_DR_BRHINO_NAME AUFS_WH_PFX "hino" ++/* whiteouted doubly */ ++#define AUFS_WH_DR_INFO_PFX AUFS_WH_PFX AUFS_DR_INFO_PFX ++#define AUFS_WH_DR_BRHINO AUFS_WH_PFX AUFS_DR_BRHINO_NAME ++ ++#define AUFS_DIROPQ_NAME AUFS_WH_PFX ".opq" /* whiteouted doubly */ ++#define AUFS_WH_DIROPQ AUFS_WH_PFX AUFS_DIROPQ_NAME ++ ++#define AUFS_BASE_NAME AUFS_WH_PFX AUFS_NAME ++#define AUFS_PLINKDIR_NAME AUFS_WH_PFX "plnk" ++#define AUFS_ORPHDIR_NAME AUFS_WH_PFX "orph" ++ ++/* doubly whiteouted */ ++#define AUFS_WH_BASE AUFS_WH_PFX AUFS_BASE_NAME ++#define AUFS_WH_PLINKDIR AUFS_WH_PFX AUFS_PLINKDIR_NAME ++#define AUFS_WH_ORPHDIR AUFS_WH_PFX AUFS_ORPHDIR_NAME ++ ++/* branch permissions and attributes */ ++#define AUFS_BRPERM_RW "rw" ++#define AUFS_BRPERM_RO "ro" ++#define AUFS_BRPERM_RR "rr" ++#define AUFS_BRATTR_COO_REG "coo_reg" ++#define AUFS_BRATTR_COO_ALL "coo_all" ++#define AUFS_BRATTR_FHSM "fhsm" ++#define AUFS_BRATTR_UNPIN "unpin" ++#define AUFS_BRATTR_ICEX "icex" ++#define AUFS_BRATTR_ICEX_SEC "icexsec" ++#define AUFS_BRATTR_ICEX_SYS "icexsys" ++#define AUFS_BRATTR_ICEX_TR "icextr" ++#define AUFS_BRATTR_ICEX_USR "icexusr" ++#define AUFS_BRATTR_ICEX_OTH "icexoth" ++#define AUFS_BRRATTR_WH "wh" ++#define AUFS_BRWATTR_NLWH "nolwh" ++#define AUFS_BRWATTR_MOO "moo" ++ ++#define AuBrPerm_RW 1 /* writable, hardlinkable wh */ ++#define AuBrPerm_RO (1 << 1) /* readonly */ ++#define AuBrPerm_RR (1 << 2) /* natively readonly */ ++#define AuBrPerm_Mask (AuBrPerm_RW | AuBrPerm_RO | AuBrPerm_RR) ++ ++#define AuBrAttr_COO_REG (1 << 3) /* copy-up on open */ ++#define AuBrAttr_COO_ALL (1 << 4) ++#define AuBrAttr_COO_Mask (AuBrAttr_COO_REG | AuBrAttr_COO_ALL) ++ ++#define AuBrAttr_FHSM (1 << 5) /* file-based hsm */ ++#define AuBrAttr_UNPIN (1 << 6) /* rename-able top dir of ++ branch. meaningless since ++ linux-3.18-rc1 */ ++ ++/* ignore error in copying XATTR */ ++#define AuBrAttr_ICEX_SEC (1 << 7) ++#define AuBrAttr_ICEX_SYS (1 << 8) ++#define AuBrAttr_ICEX_TR (1 << 9) ++#define AuBrAttr_ICEX_USR (1 << 10) ++#define AuBrAttr_ICEX_OTH (1 << 11) ++#define AuBrAttr_ICEX (AuBrAttr_ICEX_SEC \ ++ | AuBrAttr_ICEX_SYS \ ++ | AuBrAttr_ICEX_TR \ ++ | AuBrAttr_ICEX_USR \ ++ | AuBrAttr_ICEX_OTH) ++ ++#define AuBrRAttr_WH (1 << 12) /* whiteout-able */ ++#define AuBrRAttr_Mask AuBrRAttr_WH ++ ++#define AuBrWAttr_NoLinkWH (1 << 13) /* un-hardlinkable whiteouts */ ++#define AuBrWAttr_MOO (1 << 14) /* move-up on open */ ++#define AuBrWAttr_Mask (AuBrWAttr_NoLinkWH | AuBrWAttr_MOO) ++ ++#define AuBrAttr_CMOO_Mask (AuBrAttr_COO_Mask | AuBrWAttr_MOO) ++ ++/* #warning test userspace */ ++#ifdef __KERNEL__ ++#ifndef CONFIG_AUFS_FHSM ++#undef AuBrAttr_FHSM ++#define AuBrAttr_FHSM 0 ++#endif ++#ifndef CONFIG_AUFS_XATTR ++#undef AuBrAttr_ICEX ++#define AuBrAttr_ICEX 0 ++#undef AuBrAttr_ICEX_SEC ++#define AuBrAttr_ICEX_SEC 0 ++#undef AuBrAttr_ICEX_SYS ++#define AuBrAttr_ICEX_SYS 0 ++#undef AuBrAttr_ICEX_TR ++#define AuBrAttr_ICEX_TR 0 ++#undef AuBrAttr_ICEX_USR ++#define AuBrAttr_ICEX_USR 0 ++#undef AuBrAttr_ICEX_OTH ++#define AuBrAttr_ICEX_OTH 0 ++#endif ++#endif ++ ++/* the longest combination */ ++/* AUFS_BRATTR_ICEX and AUFS_BRATTR_ICEX_TR don't affect here */ ++#define AuBrPermStrSz sizeof(AUFS_BRPERM_RW \ ++ "+" AUFS_BRATTR_COO_REG \ ++ "+" AUFS_BRATTR_FHSM \ ++ "+" AUFS_BRATTR_UNPIN \ ++ "+" AUFS_BRATTR_ICEX_SEC \ ++ "+" AUFS_BRATTR_ICEX_SYS \ ++ "+" AUFS_BRATTR_ICEX_USR \ ++ "+" AUFS_BRATTR_ICEX_OTH \ ++ "+" AUFS_BRWATTR_NLWH) ++ ++typedef struct { ++ char a[AuBrPermStrSz]; ++} au_br_perm_str_t; ++ ++static inline int au_br_writable(int brperm) ++{ ++ return brperm & AuBrPerm_RW; ++} ++ ++static inline int au_br_whable(int brperm) ++{ ++ return brperm & (AuBrPerm_RW | AuBrRAttr_WH); ++} ++ ++static inline int au_br_wh_linkable(int brperm) ++{ ++ return !(brperm & AuBrWAttr_NoLinkWH); ++} ++ ++static inline int au_br_cmoo(int brperm) ++{ ++ return brperm & AuBrAttr_CMOO_Mask; ++} ++ ++static inline int au_br_fhsm(int brperm) ++{ ++ return brperm & AuBrAttr_FHSM; ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++/* ioctl */ ++enum { ++ /* readdir in userspace */ ++ AuCtl_RDU, ++ AuCtl_RDU_INO, ++ ++ AuCtl_WBR_FD, /* pathconf wrapper */ ++ AuCtl_IBUSY, /* busy inode */ ++ AuCtl_MVDOWN, /* move-down */ ++ AuCtl_BR, /* info about branches */ ++ AuCtl_FHSM_FD /* connection for fhsm */ ++}; ++ ++/* borrowed from linux/include/linux/kernel.h */ ++#ifndef ALIGN ++#ifdef _GNU_SOURCE ++#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1) ++#else ++#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) ++#endif ++#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask)) ++#endif ++ ++/* borrowed from linux/include/linux/compiler-gcc3.h */ ++#ifndef __aligned ++#define __aligned(x) __attribute__((aligned(x))) ++#endif ++ ++#ifdef __KERNEL__ ++#ifndef __packed ++#define __packed __attribute__((packed)) ++#endif ++#endif ++ ++struct au_rdu_cookie { ++ uint64_t h_pos; ++ int16_t bindex; ++ uint8_t flags; ++ uint8_t pad; ++ uint32_t generation; ++} __aligned(8); ++ ++struct au_rdu_ent { ++ uint64_t ino; ++ int16_t bindex; ++ uint8_t type; ++ uint8_t nlen; ++ uint8_t wh; ++ char name[]; ++} __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[]; ++} __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[]; ++ }; ++} __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 6d266388d380..dd7f13c3bee7 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -554,7 +554,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) + put_write_access(inode); + i_mmap_lock_write(mapping); +diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c +index c1418b47f625..7f006a47790c 100644 +--- a/kernel/locking/lockdep.c ++++ b/kernel/locking/lockdep.c +@@ -188,7 +188,7 @@ static + struct lock_class lock_classes[MAX_LOCKDEP_KEYS]; + static DECLARE_BITMAP(lock_classes_in_use, MAX_LOCKDEP_KEYS); + +-static inline struct lock_class *hlock_class(struct held_lock *hlock) ++inline struct lock_class *lockdep_hlock_class(struct held_lock *hlock) + { + unsigned int class_idx = hlock->class_idx; + +@@ -209,6 +209,7 @@ static inline struct lock_class *hlock_class(struct held_lock *hlock) + */ + return lock_classes + class_idx; + } ++#define hlock_class(hlock) lockdep_hlock_class(hlock) + + #ifdef CONFIG_LOCK_STAT + static DEFINE_PER_CPU(struct lock_class_stats[MAX_LOCKDEP_KEYS], cpu_lock_stats); +diff --git a/mm/Makefile b/mm/Makefile +index d73aed0fc99c..93076a66ad6a 100644 +--- a/mm/Makefile ++++ b/mm/Makefile +@@ -52,7 +52,7 @@ obj-y := filemap.o mempool.o oom_kill.o fadvise.o \ + mm_init.o percpu.o slab_common.o \ + compaction.o vmacache.o \ + interval_tree.o list_lru.o workingset.o \ +- debug.o gup.o $(mmu-y) ++ prfile.o debug.o gup.o $(mmu-y) + + # Give 'page_alloc' its own module-parameter namespace + page-alloc-y := page_alloc.o +diff --git a/mm/filemap.c b/mm/filemap.c +index 0b2067b3c328..3334207431c7 100644 +--- a/mm/filemap.c ++++ b/mm/filemap.c +@@ -2909,7 +2909,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 5c8b4485860d..59f2f758d77e 100644 +--- a/mm/mmap.c ++++ b/mm/mmap.c +@@ -179,7 +179,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; +@@ -951,7 +951,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); +@@ -1897,8 +1897,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); +@@ -2757,7 +2757,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); +@@ -2776,7 +2776,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)); +@@ -2969,7 +2969,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); +@@ -3044,10 +3044,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(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: + mmap_write_unlock(mm); + if (populate) +@@ -3334,7 +3351,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 0faf39b32cdb..78ecad7204c8 100644 +--- a/mm/nommu.c ++++ b/mm/nommu.c +@@ -533,7 +533,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 */ +@@ -665,7 +665,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); + } +@@ -1188,7 +1188,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; +@@ -1265,10 +1265,10 @@ 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); ++ vma_fput(vma); + vm_area_free(vma); + return ret; + +diff --git a/mm/prfile.c b/mm/prfile.c +new file mode 100644 +index 000000000000..00d51187c325 +--- /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-2020 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/files/patches/mageia/fs-aufs5.15-symbol-exports.patch b/kernel/tools/cpupowertools/files/patches/mageia/fs-aufs5.15-symbol-exports.patch index 4f5b3d84..3a5387d5 100644 --- a/kernel/tools/cpupowertools/files/patches/mageia/fs-aufs5.15-symbol-exports.patch +++ b/kernel/tools/cpupowertools/files/patches/mageia/fs-aufs5.15-symbol-exports.patch @@ -3,7 +3,6 @@ fs/exec.c | 1 + fs/fcntl.c | 1 + fs/file_table.c | 2 ++ - fs/inode.c | 1 + fs/namespace.c | 3 +++ fs/notify/group.c | 1 + fs/open.c | 1 + @@ -14,7 +13,7 @@ kernel/locking/lockdep.c | 1 + kernel/task_work.c | 1 + security/security.c | 8 ++++++++ - 15 files changed, 28 insertions(+) + 14 files changed, 27 insertions(+) diff -Nurp linux-5.15.1-aufs/fs/dcache.c linux-5.15.1-aufs-mod/fs/dcache.c --- linux-5.15.1-aufs/fs/dcache.c 2021-11-08 23:01:48.275645778 +0200 @@ -76,17 +75,6 @@ diff -Nurp linux-5.15.1-aufs/fs/file_table.c linux-5.15.1-aufs-mod/fs/file_table void __init files_init(void) { -diff -Nurp linux-5.15.1-aufs/fs/inode.c linux-5.15.1-aufs-mod/fs/inode.c ---- linux-5.15.1-aufs/fs/inode.c 2021-11-08 23:01:48.275645778 +0200 -+++ linux-5.15.1-aufs-mod/fs/inode.c 2021-11-08 23:02:45.270309130 +0200 -@@ -1788,6 +1788,7 @@ int update_time(struct inode *inode, str - return inode->i_op->update_time(inode, time, flags); - return generic_update_time(inode, time, flags); - } -+EXPORT_SYMBOL_GPL(update_time); - - /** - * atime_needs_update - update the access time diff -Nurp linux-5.15.1-aufs/fs/namespace.c linux-5.15.1-aufs-mod/fs/namespace.c --- linux-5.15.1-aufs/fs/namespace.c 2021-11-08 23:01:48.276645825 +0200 +++ linux-5.15.1-aufs-mod/fs/namespace.c 2021-11-08 23:02:45.271309177 +0200 diff --git a/kernel/tools/cpupowertools/files/patches/mageia/fs-aufs5.15.patch b/kernel/tools/cpupowertools/files/patches/mageia/fs-aufs5.15.patch index 1e2dd6e0..eada6f7b 100644 --- a/kernel/tools/cpupowertools/files/patches/mageia/fs-aufs5.15.patch +++ b/kernel/tools/cpupowertools/files/patches/mageia/fs-aufs5.15.patch @@ -32150,7 +32150,7 @@ index 000000000000..cc0d735c4c3a +static inline int vfsub_update_time(struct inode *h_inode, + struct timespec64 *ts, int flags) +{ -+ return update_time(h_inode, ts, flags); ++ return inode_update_time(h_inode, ts, flags); + /* no vfsub_update_h_iattr() since we don't have struct path */ +} + @@ -37007,19 +37007,6 @@ index 9c6c6a3e2de5..02382fa9bd34 100644 if (error) return error; -diff --git a/fs/inode.c b/fs/inode.c -index ed0cab8a32db..7e53985e62e5 100644 ---- a/fs/inode.c -+++ b/fs/inode.c -@@ -1782,7 +1782,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) - { - if (inode->i_op->update_time) - return inode->i_op->update_time(inode, time, flags); diff --git a/fs/namespace.c b/fs/namespace.c index 659a8f39c61a..128367073782 100644 --- a/fs/namespace.c @@ -37168,14 +37155,6 @@ index e7a633353fd2..376ddf1965aa 100644 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); -@@ -2613,6 +2615,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; @@ -2776,6 +2779,7 @@ static inline bool sb_is_blkdev_sb(struct super_block *sb) } diff --git a/kernel/tools/cpupowertools/pspec.xml b/kernel/tools/cpupowertools/pspec.xml index 691d0cb6..6b59349f 100644 --- a/kernel/tools/cpupowertools/pspec.xml +++ b/kernel/tools/cpupowertools/pspec.xml @@ -18,7 +18,7 @@ - patches/linux/patch-5.15.3.xz + patches/linux/patch-5.15.5.xz patches/mageia/fs-aufs5.15.patch patches/mageia/fs-aufs5.15-symbol-exports.patch @@ -102,6 +102,13 @@ + + 2021-11-27 + 5.15.5 + Version bump. + Mustafa Cinasal + muscnsl@gmail.com + 2021-11-19 5.15.3