1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 2022-2023 Oracle. All Rights Reserved. 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 */ 6 #include "xfs.h" 7 #include "xfs_fs.h" 8 #include "xfs_shared.h" 9 #include "xfs_format.h" 10 #include "xfs_log_format.h" 11 #include "xfs_trans_resv.h" 12 #include "xfs_mount.h" 13 #include "xfs_inode.h" 14 #include "xfs_dir2.h" 15 #include "xfs_dir2_priv.h" 16 #include "xfs_trace.h" 17 #include "xfs_bmap.h" 18 #include "xfs_trans.h" 19 #include "xfs_error.h" 20 #include "scrub/scrub.h" 21 #include "scrub/readdir.h" 22 23 /* Call a function for every entry in a shortform directory. */ 24 STATIC int 25 xchk_dir_walk_sf( 26 struct xfs_scrub *sc, 27 struct xfs_inode *dp, 28 xchk_dirent_fn dirent_fn, 29 void *priv) 30 { 31 struct xfs_name name = { 32 .name = ".", 33 .len = 1, 34 .type = XFS_DIR3_FT_DIR, 35 }; 36 struct xfs_mount *mp = dp->i_mount; 37 struct xfs_da_geometry *geo = mp->m_dir_geo; 38 struct xfs_dir2_sf_entry *sfep; 39 struct xfs_dir2_sf_hdr *sfp; 40 xfs_ino_t ino; 41 xfs_dir2_dataptr_t dapos; 42 unsigned int i; 43 int error; 44 45 ASSERT(dp->i_df.if_bytes == dp->i_disk_size); 46 ASSERT(dp->i_df.if_u1.if_data != NULL); 47 48 sfp = (struct xfs_dir2_sf_hdr *)dp->i_df.if_u1.if_data; 49 50 /* dot entry */ 51 dapos = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, 52 geo->data_entry_offset); 53 54 error = dirent_fn(sc, dp, dapos, &name, dp->i_ino, priv); 55 if (error) 56 return error; 57 58 /* dotdot entry */ 59 dapos = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, 60 geo->data_entry_offset + 61 xfs_dir2_data_entsize(mp, sizeof(".") - 1)); 62 ino = xfs_dir2_sf_get_parent_ino(sfp); 63 name.name = ".."; 64 name.len = 2; 65 66 error = dirent_fn(sc, dp, dapos, &name, ino, priv); 67 if (error) 68 return error; 69 70 /* iterate everything else */ 71 sfep = xfs_dir2_sf_firstentry(sfp); 72 for (i = 0; i < sfp->count; i++) { 73 dapos = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, 74 xfs_dir2_sf_get_offset(sfep)); 75 ino = xfs_dir2_sf_get_ino(mp, sfp, sfep); 76 name.name = sfep->name; 77 name.len = sfep->namelen; 78 name.type = xfs_dir2_sf_get_ftype(mp, sfep); 79 80 error = dirent_fn(sc, dp, dapos, &name, ino, priv); 81 if (error) 82 return error; 83 84 sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep); 85 } 86 87 return 0; 88 } 89 90 /* Call a function for every entry in a block directory. */ 91 STATIC int 92 xchk_dir_walk_block( 93 struct xfs_scrub *sc, 94 struct xfs_inode *dp, 95 xchk_dirent_fn dirent_fn, 96 void *priv) 97 { 98 struct xfs_mount *mp = dp->i_mount; 99 struct xfs_da_geometry *geo = mp->m_dir_geo; 100 struct xfs_buf *bp; 101 unsigned int off, next_off, end; 102 int error; 103 104 error = xfs_dir3_block_read(sc->tp, dp, &bp); 105 if (error) 106 return error; 107 108 /* Walk each directory entry. */ 109 end = xfs_dir3_data_end_offset(geo, bp->b_addr); 110 for (off = geo->data_entry_offset; off < end; off = next_off) { 111 struct xfs_name name = { }; 112 struct xfs_dir2_data_unused *dup = bp->b_addr + off; 113 struct xfs_dir2_data_entry *dep = bp->b_addr + off; 114 xfs_ino_t ino; 115 xfs_dir2_dataptr_t dapos; 116 117 /* Skip an empty entry. */ 118 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { 119 next_off = off + be16_to_cpu(dup->length); 120 continue; 121 } 122 123 /* Otherwise, find the next entry and report it. */ 124 next_off = off + xfs_dir2_data_entsize(mp, dep->namelen); 125 if (next_off > end) 126 break; 127 128 dapos = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, off); 129 ino = be64_to_cpu(dep->inumber); 130 name.name = dep->name; 131 name.len = dep->namelen; 132 name.type = xfs_dir2_data_get_ftype(mp, dep); 133 134 error = dirent_fn(sc, dp, dapos, &name, ino, priv); 135 if (error) 136 break; 137 } 138 139 xfs_trans_brelse(sc->tp, bp); 140 return error; 141 } 142 143 /* Read a leaf-format directory buffer. */ 144 STATIC int 145 xchk_read_leaf_dir_buf( 146 struct xfs_trans *tp, 147 struct xfs_inode *dp, 148 struct xfs_da_geometry *geo, 149 xfs_dir2_off_t *curoff, 150 struct xfs_buf **bpp) 151 { 152 struct xfs_iext_cursor icur; 153 struct xfs_bmbt_irec map; 154 struct xfs_ifork *ifp = xfs_ifork_ptr(dp, XFS_DATA_FORK); 155 xfs_dablk_t last_da; 156 xfs_dablk_t map_off; 157 xfs_dir2_off_t new_off; 158 159 *bpp = NULL; 160 161 /* 162 * Look for mapped directory blocks at or above the current offset. 163 * Truncate down to the nearest directory block to start the scanning 164 * operation. 165 */ 166 last_da = xfs_dir2_byte_to_da(geo, XFS_DIR2_LEAF_OFFSET); 167 map_off = xfs_dir2_db_to_da(geo, xfs_dir2_byte_to_db(geo, *curoff)); 168 169 if (!xfs_iext_lookup_extent(dp, ifp, map_off, &icur, &map)) 170 return 0; 171 if (map.br_startoff >= last_da) 172 return 0; 173 xfs_trim_extent(&map, map_off, last_da - map_off); 174 175 /* Read the directory block of that first mapping. */ 176 new_off = xfs_dir2_da_to_byte(geo, map.br_startoff); 177 if (new_off > *curoff) 178 *curoff = new_off; 179 180 return xfs_dir3_data_read(tp, dp, map.br_startoff, 0, bpp); 181 } 182 183 /* Call a function for every entry in a leaf directory. */ 184 STATIC int 185 xchk_dir_walk_leaf( 186 struct xfs_scrub *sc, 187 struct xfs_inode *dp, 188 xchk_dirent_fn dirent_fn, 189 void *priv) 190 { 191 struct xfs_mount *mp = dp->i_mount; 192 struct xfs_da_geometry *geo = mp->m_dir_geo; 193 struct xfs_buf *bp = NULL; 194 xfs_dir2_off_t curoff = 0; 195 unsigned int offset = 0; 196 int error; 197 198 /* Iterate every directory offset in this directory. */ 199 while (curoff < XFS_DIR2_LEAF_OFFSET) { 200 struct xfs_name name = { }; 201 struct xfs_dir2_data_unused *dup; 202 struct xfs_dir2_data_entry *dep; 203 xfs_ino_t ino; 204 unsigned int length; 205 xfs_dir2_dataptr_t dapos; 206 207 /* 208 * If we have no buffer, or we're off the end of the 209 * current buffer, need to get another one. 210 */ 211 if (!bp || offset >= geo->blksize) { 212 if (bp) { 213 xfs_trans_brelse(sc->tp, bp); 214 bp = NULL; 215 } 216 217 error = xchk_read_leaf_dir_buf(sc->tp, dp, geo, &curoff, 218 &bp); 219 if (error || !bp) 220 break; 221 222 /* 223 * Find our position in the block. 224 */ 225 offset = geo->data_entry_offset; 226 curoff += geo->data_entry_offset; 227 } 228 229 /* Skip an empty entry. */ 230 dup = bp->b_addr + offset; 231 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { 232 length = be16_to_cpu(dup->length); 233 offset += length; 234 curoff += length; 235 continue; 236 } 237 238 /* Otherwise, find the next entry and report it. */ 239 dep = bp->b_addr + offset; 240 length = xfs_dir2_data_entsize(mp, dep->namelen); 241 242 dapos = xfs_dir2_byte_to_dataptr(curoff) & 0x7fffffff; 243 ino = be64_to_cpu(dep->inumber); 244 name.name = dep->name; 245 name.len = dep->namelen; 246 name.type = xfs_dir2_data_get_ftype(mp, dep); 247 248 error = dirent_fn(sc, dp, dapos, &name, ino, priv); 249 if (error) 250 break; 251 252 /* Advance to the next entry. */ 253 offset += length; 254 curoff += length; 255 } 256 257 if (bp) 258 xfs_trans_brelse(sc->tp, bp); 259 return error; 260 } 261 262 /* 263 * Call a function for every entry in a directory. 264 * 265 * Callers must hold the ILOCK. File types are XFS_DIR3_FT_*. 266 */ 267 int 268 xchk_dir_walk( 269 struct xfs_scrub *sc, 270 struct xfs_inode *dp, 271 xchk_dirent_fn dirent_fn, 272 void *priv) 273 { 274 struct xfs_da_args args = { 275 .dp = dp, 276 .geo = dp->i_mount->m_dir_geo, 277 .trans = sc->tp, 278 }; 279 bool isblock; 280 int error; 281 282 if (xfs_is_shutdown(dp->i_mount)) 283 return -EIO; 284 285 ASSERT(S_ISDIR(VFS_I(dp)->i_mode)); 286 ASSERT(xfs_isilocked(dp, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)); 287 288 if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) 289 return xchk_dir_walk_sf(sc, dp, dirent_fn, priv); 290 291 /* dir2 functions require that the data fork is loaded */ 292 error = xfs_iread_extents(sc->tp, dp, XFS_DATA_FORK); 293 if (error) 294 return error; 295 296 error = xfs_dir2_isblock(&args, &isblock); 297 if (error) 298 return error; 299 300 if (isblock) 301 return xchk_dir_walk_block(sc, dp, dirent_fn, priv); 302 303 return xchk_dir_walk_leaf(sc, dp, dirent_fn, priv); 304 } 305 306 /* 307 * Look up the inode number for an exact name in a directory. 308 * 309 * Callers must hold the ILOCK. File types are XFS_DIR3_FT_*. Names are not 310 * checked for correctness. 311 */ 312 int 313 xchk_dir_lookup( 314 struct xfs_scrub *sc, 315 struct xfs_inode *dp, 316 const struct xfs_name *name, 317 xfs_ino_t *ino) 318 { 319 struct xfs_da_args args = { 320 .dp = dp, 321 .geo = dp->i_mount->m_dir_geo, 322 .trans = sc->tp, 323 .name = name->name, 324 .namelen = name->len, 325 .filetype = name->type, 326 .hashval = xfs_dir2_hashname(dp->i_mount, name), 327 .whichfork = XFS_DATA_FORK, 328 .op_flags = XFS_DA_OP_OKNOENT, 329 }; 330 bool isblock, isleaf; 331 int error; 332 333 if (xfs_is_shutdown(dp->i_mount)) 334 return -EIO; 335 336 ASSERT(S_ISDIR(VFS_I(dp)->i_mode)); 337 ASSERT(xfs_isilocked(dp, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)); 338 339 if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) { 340 error = xfs_dir2_sf_lookup(&args); 341 goto out_check_rval; 342 } 343 344 /* dir2 functions require that the data fork is loaded */ 345 error = xfs_iread_extents(sc->tp, dp, XFS_DATA_FORK); 346 if (error) 347 return error; 348 349 error = xfs_dir2_isblock(&args, &isblock); 350 if (error) 351 return error; 352 353 if (isblock) { 354 error = xfs_dir2_block_lookup(&args); 355 goto out_check_rval; 356 } 357 358 error = xfs_dir2_isleaf(&args, &isleaf); 359 if (error) 360 return error; 361 362 if (isleaf) { 363 error = xfs_dir2_leaf_lookup(&args); 364 goto out_check_rval; 365 } 366 367 error = xfs_dir2_node_lookup(&args); 368 369 out_check_rval: 370 if (error == -EEXIST) 371 error = 0; 372 if (!error) 373 *ino = args.inumber; 374 return error; 375 } 376