0001
0002
0003
0004
0005
0006 #include "xfs.h"
0007 #include "xfs_fs.h"
0008 #include "xfs_shared.h"
0009 #include "xfs_format.h"
0010 #include "xfs_trans_resv.h"
0011 #include "xfs_mount.h"
0012 #include "xfs_log_format.h"
0013 #include "xfs_inode.h"
0014 #include "xfs_icache.h"
0015 #include "xfs_dir2.h"
0016 #include "xfs_dir2_priv.h"
0017 #include "scrub/scrub.h"
0018 #include "scrub/common.h"
0019
0020
0021 int
0022 xchk_setup_parent(
0023 struct xfs_scrub *sc)
0024 {
0025 return xchk_setup_inode_contents(sc, 0);
0026 }
0027
0028
0029
0030
0031
0032 struct xchk_parent_ctx {
0033 struct dir_context dc;
0034 struct xfs_scrub *sc;
0035 xfs_ino_t ino;
0036 xfs_nlink_t nlink;
0037 bool cancelled;
0038 };
0039
0040
0041 STATIC int
0042 xchk_parent_actor(
0043 struct dir_context *dc,
0044 const char *name,
0045 int namelen,
0046 loff_t pos,
0047 u64 ino,
0048 unsigned type)
0049 {
0050 struct xchk_parent_ctx *spc;
0051 int error = 0;
0052
0053 spc = container_of(dc, struct xchk_parent_ctx, dc);
0054 if (spc->ino == ino)
0055 spc->nlink++;
0056
0057
0058
0059
0060
0061
0062 if (xchk_should_terminate(spc->sc, &error))
0063 spc->cancelled = true;
0064
0065 return error;
0066 }
0067
0068
0069 STATIC int
0070 xchk_parent_count_parent_dentries(
0071 struct xfs_scrub *sc,
0072 struct xfs_inode *parent,
0073 xfs_nlink_t *nlink)
0074 {
0075 struct xchk_parent_ctx spc = {
0076 .dc.actor = xchk_parent_actor,
0077 .ino = sc->ip->i_ino,
0078 .sc = sc,
0079 };
0080 size_t bufsize;
0081 loff_t oldpos;
0082 uint lock_mode;
0083 int error = 0;
0084
0085
0086
0087
0088
0089
0090
0091 lock_mode = xfs_ilock_data_map_shared(parent);
0092 if (parent->i_df.if_nextents > 0)
0093 error = xfs_dir3_data_readahead(parent, 0, 0);
0094 xfs_iunlock(parent, lock_mode);
0095 if (error)
0096 return error;
0097
0098
0099
0100
0101
0102
0103 bufsize = (size_t)min_t(loff_t, XFS_READDIR_BUFSIZE,
0104 parent->i_disk_size);
0105 oldpos = 0;
0106 while (true) {
0107 error = xfs_readdir(sc->tp, parent, &spc.dc, bufsize);
0108 if (error)
0109 goto out;
0110 if (spc.cancelled) {
0111 error = -EAGAIN;
0112 goto out;
0113 }
0114 if (oldpos == spc.dc.pos)
0115 break;
0116 oldpos = spc.dc.pos;
0117 }
0118 *nlink = spc.nlink;
0119 out:
0120 return error;
0121 }
0122
0123
0124
0125
0126
0127
0128 STATIC int
0129 xchk_parent_validate(
0130 struct xfs_scrub *sc,
0131 xfs_ino_t dnum,
0132 bool *try_again)
0133 {
0134 struct xfs_mount *mp = sc->mp;
0135 struct xfs_inode *dp = NULL;
0136 xfs_nlink_t expected_nlink;
0137 xfs_nlink_t nlink;
0138 int error = 0;
0139
0140 *try_again = false;
0141
0142 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
0143 goto out;
0144
0145
0146 if (sc->ip->i_ino == dnum) {
0147 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
0148 goto out;
0149 }
0150
0151
0152
0153
0154
0155 expected_nlink = VFS_I(sc->ip)->i_nlink == 0 ? 0 : 1;
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171 error = xfs_iget(mp, sc->tp, dnum, XFS_IGET_UNTRUSTED, 0, &dp);
0172 if (error == -EINVAL || error == -ENOENT) {
0173 error = -EFSCORRUPTED;
0174 xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error);
0175 goto out;
0176 }
0177 if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0, &error))
0178 goto out;
0179 if (dp == sc->ip || !S_ISDIR(VFS_I(dp)->i_mode)) {
0180 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
0181 goto out_rele;
0182 }
0183
0184
0185
0186
0187
0188
0189
0190
0191 if (xfs_ilock_nowait(dp, XFS_IOLOCK_SHARED)) {
0192 error = xchk_parent_count_parent_dentries(sc, dp, &nlink);
0193 if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0,
0194 &error))
0195 goto out_unlock;
0196 if (nlink != expected_nlink)
0197 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
0198 goto out_unlock;
0199 }
0200
0201
0202
0203
0204
0205
0206
0207 xfs_iunlock(sc->ip, sc->ilock_flags);
0208 sc->ilock_flags = 0;
0209 error = xchk_ilock_inverted(dp, XFS_IOLOCK_SHARED);
0210 if (error)
0211 goto out_rele;
0212
0213
0214 error = xchk_parent_count_parent_dentries(sc, dp, &nlink);
0215 if (!xchk_fblock_xref_process_error(sc, XFS_DATA_FORK, 0, &error))
0216 goto out_unlock;
0217
0218
0219 xfs_iunlock(dp, XFS_IOLOCK_SHARED);
0220 error = xchk_ilock_inverted(sc->ip, XFS_IOLOCK_EXCL);
0221 if (error)
0222 goto out_rele;
0223 sc->ilock_flags = XFS_IOLOCK_EXCL;
0224
0225
0226
0227
0228
0229
0230 expected_nlink = VFS_I(sc->ip)->i_nlink == 0 ? 0 : 1;
0231
0232
0233 error = xfs_dir_lookup(sc->tp, sc->ip, &xfs_name_dotdot, &dnum, NULL);
0234 if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error))
0235 goto out_rele;
0236
0237
0238 if (dnum != dp->i_ino) {
0239 xfs_irele(dp);
0240 *try_again = true;
0241 return 0;
0242 }
0243 xfs_irele(dp);
0244
0245
0246
0247
0248
0249 if (nlink != expected_nlink)
0250 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
0251 return error;
0252
0253 out_unlock:
0254 xfs_iunlock(dp, XFS_IOLOCK_SHARED);
0255 out_rele:
0256 xfs_irele(dp);
0257 out:
0258 return error;
0259 }
0260
0261
0262 int
0263 xchk_parent(
0264 struct xfs_scrub *sc)
0265 {
0266 struct xfs_mount *mp = sc->mp;
0267 xfs_ino_t dnum;
0268 bool try_again;
0269 int tries = 0;
0270 int error = 0;
0271
0272
0273
0274
0275
0276 if (!S_ISDIR(VFS_I(sc->ip)->i_mode))
0277 return -ENOENT;
0278
0279
0280 if (!xfs_verify_dir_ino(mp, sc->ip->i_ino)) {
0281 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
0282 goto out;
0283 }
0284
0285
0286
0287
0288
0289
0290
0291
0292 sc->ilock_flags &= ~(XFS_ILOCK_EXCL | XFS_MMAPLOCK_EXCL);
0293 xfs_iunlock(sc->ip, XFS_ILOCK_EXCL | XFS_MMAPLOCK_EXCL);
0294
0295
0296 error = xfs_dir_lookup(sc->tp, sc->ip, &xfs_name_dotdot, &dnum, NULL);
0297 if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error))
0298 goto out;
0299 if (!xfs_verify_dir_ino(mp, dnum)) {
0300 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
0301 goto out;
0302 }
0303
0304
0305 if (sc->ip == mp->m_rootip) {
0306 if (sc->ip->i_ino != mp->m_sb.sb_rootino ||
0307 sc->ip->i_ino != dnum)
0308 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
0309 goto out;
0310 }
0311
0312 do {
0313 error = xchk_parent_validate(sc, dnum, &try_again);
0314 if (error)
0315 goto out;
0316 } while (try_again && ++tries < 20);
0317
0318
0319
0320
0321
0322 if (try_again && tries == 20)
0323 xchk_set_incomplete(sc);
0324 out:
0325
0326
0327
0328
0329 if ((sc->flags & XCHK_TRY_HARDER) && error == -EDEADLOCK) {
0330 error = 0;
0331 xchk_set_incomplete(sc);
0332 }
0333 return error;
0334 }