From c63044e0f5dd9fa907c827d79eb5bbb3dd5a99bd Mon Sep 17 00:00:00 2001 From: Li Dongyang Date: Tue, 30 Mar 2021 22:22:40 +1100 Subject: [PATCH] LU-11446 e2fsck: check trusted.link when fixing nlink The inode link count could be higher than what is stored in the local MDT inode because of remote file links from DNE MDTs. If we find a mismatched link count, look up the "trusted.link" xattr. If it exists, do a sanity check on it, and use the leh_reccount stored there if larger than the local link count. If leh_overflow_time is set, then the "trusted.link" xattr may not hold all of the links, so assume the maximum of available link counts is valid until LFSCK clears leh_overflow_time. If the inode is not linked into the namespace, link it into lost+found before checking trusted.link for the DNE link count. Update the f_trusted_link test case to include a locally unreferenced inode that has a trusted.link xattr. The inode should be linked into lost+found because of the xattr, even if it has no blocks/data, and the link cound should be extracted from the trusted.link xattr. Signed-off-by: Li Dongyang Change-Id: I213d816a92043c348eb55374aaa98e98957ccf23 Reviewed-on: https://review.whamcloud.com/43169 Reviewed-by: Artem Blagodarenko Reviewed-by: Andreas Dilger --- e2fsck/pass4.c | 72 ++++++++++++++++++++++++++++++++++++++++++ tests/f_trusted_link/expect.1 | 16 ++++++++++ tests/f_trusted_link/expect.2 | 7 ++++ tests/f_trusted_link/image.gz | Bin 0 -> 18213 bytes tests/f_trusted_link/name | 1 + 5 files changed, 96 insertions(+) create mode 100644 tests/f_trusted_link/expect.1 create mode 100644 tests/f_trusted_link/expect.2 create mode 100644 tests/f_trusted_link/image.gz create mode 100644 tests/f_trusted_link/name diff --git a/e2fsck/pass4.c b/e2fsck/pass4.c index cf0cf7c..46fee97 100644 --- a/e2fsck/pass4.c +++ b/e2fsck/pass4.c @@ -17,6 +17,7 @@ #include "config.h" #include "e2fsck.h" #include "problem.h" +#include "ext2fs/lfsck.h" #include /* @@ -150,6 +151,73 @@ static void check_ea_inode(e2fsck_t ctx, ext2_ino_t i, ext2_ino_t *last_ino, } } +static errcode_t check_link_ea(e2fsck_t ctx, ext2_ino_t ino, + ext2_ino_t *last_ino, + struct ext2_inode_large *inode, + __u16 *link_counted) +{ + struct ext2_xattr_handle *handle; + struct link_ea_header *leh; + void *buf; + size_t ea_len; + errcode_t retval; + + if (*last_ino != ino) { + e2fsck_read_inode_full(ctx, ino, EXT2_INODE(inode), + EXT2_INODE_SIZE(ctx->fs->super), + "pass4: get link ea count"); + *last_ino = ino; + } + + retval = ext2fs_xattrs_open(ctx->fs, ino, &handle); + if (retval) + return retval; + + retval = ext2fs_xattrs_read_inode(handle, inode); + if (retval) + goto err; + + retval = ext2fs_xattr_get(handle, EXT2_ATTR_INDEX_TRUSTED_PREFIX + LUSTRE_XATTR_MDT_LINK, &buf, &ea_len); + if (retval) + goto err; + + leh = (struct link_ea_header *)buf; + if (leh->leh_magic == ext2fs_swab32(LINK_EA_MAGIC)) { + leh->leh_magic = LINK_EA_MAGIC; + leh->leh_reccount = ext2fs_swab32(leh->leh_reccount); + leh->leh_len = ext2fs_swab64(leh->leh_len); + } + if (leh->leh_magic != LINK_EA_MAGIC) { + retval = EINVAL; + goto err_free; + } + if (leh->leh_reccount == 0 && !leh->leh_overflow_time) { + retval = ENODATA; + goto err_free; + } + if (leh->leh_len > ea_len) { + retval = EINVAL; + goto err_free; + } + + /* if linkEA overflowed and does not hold all links, assume *some* + * links exist until LFSCK is next run and resets leh_overflow_time */ + if (leh->leh_overflow_time) { + if (inode->i_links_count > *link_counted) + *link_counted = inode->i_links_count; + else if (*link_counted == 0) + *link_counted = 1111; + } + if (leh->leh_reccount > *link_counted) + *link_counted = leh->leh_reccount; +err_free: + ext2fs_free_mem(&buf); +err: + ext2fs_xattrs_close(&handle); + return retval; +} + void e2fsck_pass4(e2fsck_t ctx) { ext2_filsys fs = ctx->fs; @@ -249,6 +317,7 @@ void e2fsck_pass4(e2fsck_t ctx) &link_count); ext2fs_icount_fetch(ctx->inode_count, i, &link_counted); + check_link_ea(ctx, i, &last_ino, inode, &link_counted); } isdir = ext2fs_test_inode_bitmap2(ctx->inode_dir_map, i); if (isdir && (link_counted > EXT2_LINK_MAX)) { @@ -260,6 +329,9 @@ void e2fsck_pass4(e2fsck_t ctx) } link_counted = 1; } + if (link_counted != link_count) + check_link_ea(ctx, i, &last_ino, inode, &link_counted); + if (link_counted != link_count) { int fix_nlink = 0; diff --git a/tests/f_trusted_link/expect.1 b/tests/f_trusted_link/expect.1 new file mode 100644 index 0000000..1063d22 --- /dev/null +++ b/tests/f_trusted_link/expect.1 @@ -0,0 +1,16 @@ +Pass 1: Checking inodes, blocks, and sizes +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Inode 15 ref count is 7, should be 6. Fix? yes + +Inode 16 ref count is 3, should be 6. Fix? yes + +Unattached inode 18 +Connect to /lost+found? yes + +Pass 5: Checking group summary information + +test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** +test_filesys: 18/4096 files (0.0% non-contiguous), 6424/16384 blocks +Exit status is 1 diff --git a/tests/f_trusted_link/expect.2 b/tests/f_trusted_link/expect.2 new file mode 100644 index 0000000..a8ff12a --- /dev/null +++ b/tests/f_trusted_link/expect.2 @@ -0,0 +1,7 @@ +Pass 1: Checking inodes, blocks, and sizes +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information +test_filesys: 18/4096 files (0.0% non-contiguous), 6424/16384 blocks +Exit status is 0 diff --git a/tests/f_trusted_link/image.gz b/tests/f_trusted_link/image.gz new file mode 100644 index 0000000000000000000000000000000000000000..8e2587355ca36dd17d16613f9d9705b0a8309914 GIT binary patch literal 18213 zcmeI0`BzhC8pl~?iXKPM7J;G=x4LnHRV1P@;0B@`#8_D*1vH3=EaJju2%()LDzV0D zB`QL!hzz?IkR>R=QDB4uvL#_n2Sv63vLz)U_s(`}vFT(R?Pyg@{}O+v zSGT_SnKD>-Dw=QL8p;kk&n%Id*U0Sn{gn%ynd14_>1vl*5o10mz=Qd1`7``nX1y%x zZmH^+q(s9FtfyEevroorbjgn$J{Ju(?!2Taypw_t@ZY8iZsKQWla@~lcQ_8+W(w2N zFDAVAXyR5(1!NKJUcU^_jSObC_Oq4M*pwn;SbKC%z^&OXI*SJsNak`bHhTA^7}m?q zy~VJ7S_zBuaB3>BaiDVXn4O!ror1VyMYOT*G>10=63x>303JsW=Y-N z+~RJ%qO<9fS}>C7HB9)f1}QpxOpTZwAjbGzn4;DYAI3qY02S!Z~ZWd-f3| zS7%H@7x!bC{eD zkN2D$#D~-$9(=Y4k`543m^uQ+b1z73NP|3E2=G{7d5?io$!G2BNLM*x2KjYxJ16$gVMwmReqmSER#lf`)+J8%zlMzj(tyrCn`*60a1Mu#INhrlx4;pJmzrB zkb)3ycI=4P$qIRTdgXBm-U&L7h9iYUw#`$s=LF$IiO-~nG41Apc^x76FoHM#V?;8Z znv@jaWu2U0A9--%CZlq`;XGY4t&rT`HdUk@alT{Yk?q{#@aeVSrLF(A zvUpiKOY6#NTr*}bxYWL@HSRbOoKZQV*&OoXE1jsrX`_bnc%bxwuB<~T$v;hm+iTA) z?;!?T{GxQicExSnN%sGWTm==GQu6XNF$NV$5m7N2=dT`5AJGuig9UTbL~}%SGa)SC zMG_LJ)9XA!y4X-XxJPHw5_F&ur=L|Rn8n1+2Rf4#!(rl?dEQVNm(ejBu(dyB7ZD&% zXeQQj@QJ)mUNDqHRf^-qM3Y-HLH--)hX^17hyWsh2p|H803v`0AOeU0B7g`W0)Hj~ zJ^mx?K>pF*7yPWzk&iX^x185BJaCleI0suG7;QYK&$~hA8ix9`SY)iMT## zB=I%hT}@ny{fO1d|0N&t`G(0A>}LL?n6`7It)gwAZHzt;c7d5tc!b%rtddUqie^uv z(iqVmVJ^x(ITzCgHeyC>lUnO!#tP0_nw{#55|ii2-(#KF4y*#3Vtw(k&X=8!mHKe< z)=0nPtX7>;X3N{KzhlAdMS;z=>3nK3^(OT?gTk_8nX#-{OF64bx0Y^Fv6Y$f2CM_K z#|q?KavN+)n}RJD%RxE9^!-4yx~x&_@-yFqGBU!iq~UaLB&Jfrkc#wzzKpHwDX z)=dmApT{MWI-$_l=<;S!#PXr4cro`8;nXfXWEJ6Jky5J@;=!hO+^F1eYLFGxYLTzT zH;{U_?w_yfx;E9-3rr;05{(aMz#@`!A3pI^&AsH5MU1COg6h(r)_2xl=MSp94|_U_ zEB;LHBia=aKm-s0L;w*$1P}p401-e05CKHsuR#ER?Pyh8vdmdu&#}<`AbZg|2h+0c z3->N4Ih<+y{Yu-`pBvv%UsdF~9bEKu*2whAd?LPNxRv4NZDjQ7)t;?U&(xEvxt{xX z9(xu~c^ESuH{oxqo-+P}qpR)>&Gg~>#95pdn{G)H{3k~-eSBN}lxJzLpu9Ym>(yj4 z+ByKAUoui^&K^?GR`+G~`1O5hRVEXt%s+em@l>w*obmKzSE@@;&zwfp@Jih%%Aho7 zw25vMhf&ktOk8YC3uaap#cn53b<;MU_@G~tDQCreu!PBF+Vmc%+~}Aocbkkz@Z}vD zP7KjC7I#YpN8@d!S^jgMN`~$oxQp)ysW|!jLM(SO4ydxoI%bo*+CF&?jUOs*pl7^S zX@&(7NdW literal 0 HcmV?d00001 diff --git a/tests/f_trusted_link/name b/tests/f_trusted_link/name new file mode 100644 index 0000000..a6e424b --- /dev/null +++ b/tests/f_trusted_link/name @@ -0,0 +1 @@ +inode nlink according to trusted.link xattr -- 1.8.3.1