| 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 2 | /* |
| 3 | * Copyright (c) 2018-2024 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_trans_resv.h" |
| 11 | #include "xfs_mount.h" |
| 12 | #include "xfs_defer.h" |
| 13 | #include "xfs_btree.h" |
| 14 | #include "xfs_bit.h" |
| 15 | #include "xfs_log_format.h" |
| 16 | #include "xfs_trans.h" |
| 17 | #include "xfs_sb.h" |
| 18 | #include "xfs_inode.h" |
| 19 | #include "xfs_inode_fork.h" |
| 20 | #include "xfs_symlink.h" |
| 21 | #include "xfs_bmap.h" |
| 22 | #include "xfs_quota.h" |
| 23 | #include "xfs_da_format.h" |
| 24 | #include "xfs_da_btree.h" |
| 25 | #include "xfs_bmap_btree.h" |
| 26 | #include "xfs_trans_space.h" |
| 27 | #include "xfs_symlink_remote.h" |
| 28 | #include "xfs_exchmaps.h" |
| 29 | #include "xfs_exchrange.h" |
| 30 | #include "xfs_health.h" |
| 31 | #include "scrub/xfs_scrub.h" |
| 32 | #include "scrub/scrub.h" |
| 33 | #include "scrub/common.h" |
| 34 | #include "scrub/trace.h" |
| 35 | #include "scrub/repair.h" |
| 36 | #include "scrub/tempfile.h" |
| 37 | #include "scrub/tempexch.h" |
| 38 | #include "scrub/reap.h" |
| 39 | #include "scrub/health.h" |
| 40 | |
| 41 | /* |
| 42 | * Symbolic Link Repair |
| 43 | * ==================== |
| 44 | * |
| 45 | * We repair symbolic links by reading whatever target data we can find, up to |
| 46 | * the first NULL byte. If the recovered target strlen matches i_size, then |
| 47 | * we rewrite the target. In all other cases, we replace the target with an |
| 48 | * overly long string that cannot possibly resolve. The new target is written |
| 49 | * into a private hidden temporary file, and then a file contents exchange |
| 50 | * commits the new symlink target to the file being repaired. |
| 51 | */ |
| 52 | |
| 53 | /* Set us up to repair the symlink file. */ |
| 54 | int |
| 55 | xrep_setup_symlink( |
| 56 | struct xfs_scrub *sc, |
| 57 | unsigned int *resblks) |
| 58 | { |
| 59 | struct xfs_mount *mp = sc->mp; |
| 60 | unsigned long long blocks; |
| 61 | int error; |
| 62 | |
| 63 | error = xrep_tempfile_create(sc, S_IFLNK); |
| 64 | if (error) |
| 65 | return error; |
| 66 | |
| 67 | /* |
| 68 | * If we're doing a repair, we reserve enough blocks to write out a |
| 69 | * completely new symlink file, plus twice as many blocks as we would |
| 70 | * need if we can only allocate one block per data fork mapping. This |
| 71 | * should cover the preallocation of the temporary file and exchanging |
| 72 | * the extent mappings. |
| 73 | * |
| 74 | * We cannot use xfs_exchmaps_estimate because we have not yet |
| 75 | * constructed the replacement symlink and therefore do not know how |
| 76 | * many extents it will use. By the time we do, we will have a dirty |
| 77 | * transaction (which we cannot drop because we cannot drop the |
| 78 | * symlink ILOCK) and cannot ask for more reservation. |
| 79 | */ |
| 80 | blocks = xfs_symlink_blocks(sc->mp, XFS_SYMLINK_MAXLEN); |
| 81 | blocks += xfs_bmbt_calc_size(mp, blocks) * 2; |
| 82 | if (blocks > UINT_MAX) |
| 83 | return -EOPNOTSUPP; |
| 84 | |
| 85 | *resblks += blocks; |
| 86 | return 0; |
| 87 | } |
| 88 | |
| 89 | /* |
| 90 | * Try to salvage the pathname from remote blocks. Returns the number of bytes |
| 91 | * salvaged or a negative errno. |
| 92 | */ |
| 93 | STATIC ssize_t |
| 94 | xrep_symlink_salvage_remote( |
| 95 | struct xfs_scrub *sc) |
| 96 | { |
| 97 | struct xfs_bmbt_irec mval[XFS_SYMLINK_MAPS]; |
| 98 | struct xfs_inode *ip = sc->ip; |
| 99 | struct xfs_buf *bp; |
| 100 | char *target_buf = sc->buf; |
| 101 | xfs_failaddr_t fa; |
| 102 | xfs_filblks_t fsblocks; |
| 103 | xfs_daddr_t d; |
| 104 | loff_t len; |
| 105 | loff_t offset = 0; |
| 106 | unsigned int byte_cnt; |
| 107 | bool magic_ok; |
| 108 | bool hdr_ok; |
| 109 | int n; |
| 110 | int nmaps = XFS_SYMLINK_MAPS; |
| 111 | int error; |
| 112 | |
| 113 | /* We'll only read until the buffer is full. */ |
| 114 | len = min_t(loff_t, ip->i_disk_size, XFS_SYMLINK_MAXLEN); |
| 115 | fsblocks = xfs_symlink_blocks(sc->mp, len); |
| 116 | error = xfs_bmapi_read(ip, 0, fsblocks, mval, &nmaps, 0); |
| 117 | if (error) |
| 118 | return error; |
| 119 | |
| 120 | for (n = 0; n < nmaps; n++) { |
| 121 | struct xfs_dsymlink_hdr *dsl; |
| 122 | |
| 123 | d = XFS_FSB_TO_DADDR(sc->mp, mval[n].br_startblock); |
| 124 | |
| 125 | /* Read the rmt block. We'll run the verifiers manually. */ |
| 126 | error = xfs_trans_read_buf(sc->mp, sc->tp, sc->mp->m_ddev_targp, |
| 127 | d, XFS_FSB_TO_BB(sc->mp, mval[n].br_blockcount), |
| 128 | 0, &bp, NULL); |
| 129 | if (error) |
| 130 | return error; |
| 131 | bp->b_ops = &xfs_symlink_buf_ops; |
| 132 | |
| 133 | /* How many bytes do we expect to get out of this buffer? */ |
| 134 | byte_cnt = XFS_FSB_TO_B(sc->mp, mval[n].br_blockcount); |
| 135 | byte_cnt = XFS_SYMLINK_BUF_SPACE(sc->mp, byte_cnt); |
| 136 | byte_cnt = min_t(unsigned int, byte_cnt, len); |
| 137 | |
| 138 | /* |
| 139 | * See if the verifiers accept this block. We're willing to |
| 140 | * salvage if the if the offset/byte/ino are ok and either the |
| 141 | * verifier passed or the magic is ok. Anything else and we |
| 142 | * stop dead in our tracks. |
| 143 | */ |
| 144 | fa = bp->b_ops->verify_struct(bp); |
| 145 | dsl = bp->b_addr; |
| 146 | magic_ok = dsl->sl_magic == cpu_to_be32(XFS_SYMLINK_MAGIC); |
| 147 | hdr_ok = xfs_symlink_hdr_ok(ip->i_ino, offset, byte_cnt, bp); |
| 148 | if (!hdr_ok || (fa != NULL && !magic_ok)) |
| 149 | break; |
| 150 | |
| 151 | memcpy(target_buf + offset, dsl + 1, byte_cnt); |
| 152 | |
| 153 | len -= byte_cnt; |
| 154 | offset += byte_cnt; |
| 155 | } |
| 156 | return offset; |
| 157 | } |
| 158 | |
| 159 | /* |
| 160 | * Try to salvage an inline symlink's contents. Returns the number of bytes |
| 161 | * salvaged or a negative errno. |
| 162 | */ |
| 163 | STATIC ssize_t |
| 164 | xrep_symlink_salvage_inline( |
| 165 | struct xfs_scrub *sc) |
| 166 | { |
| 167 | struct xfs_inode *ip = sc->ip; |
| 168 | char *target_buf = sc->buf; |
| 169 | char *old_target; |
| 170 | struct xfs_ifork *ifp; |
| 171 | unsigned int nr; |
| 172 | |
| 173 | ifp = xfs_ifork_ptr(ip, XFS_DATA_FORK); |
| 174 | if (!ifp->if_data) |
| 175 | return 0; |
| 176 | |
| 177 | /* |
| 178 | * If inode repair zapped the link target, pretend that we didn't find |
| 179 | * any bytes at all so that we can replace the (now totally lost) link |
| 180 | * target with a warning message. |
| 181 | */ |
| 182 | old_target = ifp->if_data; |
| 183 | if (xfs_inode_has_sickness(sc->ip, XFS_SICK_INO_SYMLINK_ZAPPED) && |
| 184 | sc->ip->i_disk_size == 1 && old_target[0] == '?') |
| 185 | return 0; |
| 186 | |
| 187 | nr = min(XFS_SYMLINK_MAXLEN, ifp->if_bytes); |
| 188 | memcpy(target_buf, ifp->if_data, nr); |
| 189 | return nr; |
| 190 | } |
| 191 | |
| 192 | #define DUMMY_TARGET \ |
| 193 | "The target of this symbolic link could not be recovered at all and " \ |
| 194 | "has been replaced with this explanatory message. To avoid " \ |
| 195 | "accidentally pointing to an existing file path, this message is " \ |
| 196 | "longer than the maximum supported file name length. That is an " \ |
| 197 | "acceptable length for a symlink target on XFS but will produce " \ |
| 198 | "File Name Too Long errors if resolved." |
| 199 | |
| 200 | /* Salvage whatever we can of the target. */ |
| 201 | STATIC int |
| 202 | xrep_symlink_salvage( |
| 203 | struct xfs_scrub *sc) |
| 204 | { |
| 205 | char *target_buf = sc->buf; |
| 206 | ssize_t buflen = 0; |
| 207 | |
| 208 | BUILD_BUG_ON(sizeof(DUMMY_TARGET) - 1 <= NAME_MAX); |
| 209 | |
| 210 | /* |
| 211 | * Salvage the target if there weren't any corruption problems observed |
| 212 | * while scanning it. |
| 213 | */ |
| 214 | if (!(sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)) { |
| 215 | if (sc->ip->i_df.if_format == XFS_DINODE_FMT_LOCAL) |
| 216 | buflen = xrep_symlink_salvage_inline(sc); |
| 217 | else |
| 218 | buflen = xrep_symlink_salvage_remote(sc); |
| 219 | if (buflen < 0) |
| 220 | return buflen; |
| 221 | |
| 222 | /* |
| 223 | * NULL-terminate the buffer because the ondisk target does not |
| 224 | * do that for us. If salvage didn't find the exact amount of |
| 225 | * data that we expected to find, don't salvage anything. |
| 226 | */ |
| 227 | target_buf[buflen] = 0; |
| 228 | if (strlen(target_buf) != sc->ip->i_disk_size) |
| 229 | buflen = 0; |
| 230 | } |
| 231 | |
| 232 | /* |
| 233 | * Change an empty target into a dummy target and clear the symlink |
| 234 | * target zapped flag. |
| 235 | */ |
| 236 | if (buflen == 0) { |
| 237 | xchk_mark_healthy_if_clean(sc, XFS_SICK_INO_SYMLINK_ZAPPED); |
| 238 | sprintf(target_buf, DUMMY_TARGET); |
| 239 | } |
| 240 | |
| 241 | trace_xrep_symlink_salvage_target(sc->ip, target_buf, |
| 242 | strlen(target_buf)); |
| 243 | return 0; |
| 244 | } |
| 245 | |
| 246 | STATIC void |
| 247 | xrep_symlink_local_to_remote( |
| 248 | struct xfs_trans *tp, |
| 249 | struct xfs_buf *bp, |
| 250 | struct xfs_inode *ip, |
| 251 | struct xfs_ifork *ifp, |
| 252 | void *priv) |
| 253 | { |
| 254 | struct xfs_scrub *sc = priv; |
| 255 | struct xfs_dsymlink_hdr *dsl = bp->b_addr; |
| 256 | |
| 257 | xfs_symlink_local_to_remote(tp, bp, ip, ifp, NULL); |
| 258 | |
| 259 | if (!xfs_has_crc(sc->mp)) |
| 260 | return; |
| 261 | |
| 262 | dsl->sl_owner = cpu_to_be64(sc->ip->i_ino); |
| 263 | xfs_trans_log_buf(tp, bp, 0, |
| 264 | sizeof(struct xfs_dsymlink_hdr) + ifp->if_bytes - 1); |
| 265 | } |
| 266 | |
| 267 | /* |
| 268 | * Prepare both links' data forks for an exchange. Promote the tempfile from |
| 269 | * local format to extents format, and if the file being repaired has a short |
| 270 | * format data fork, turn it into an empty extent list. |
| 271 | */ |
| 272 | STATIC int |
| 273 | xrep_symlink_swap_prep( |
| 274 | struct xfs_scrub *sc, |
| 275 | bool temp_local, |
| 276 | bool ip_local) |
| 277 | { |
| 278 | int error; |
| 279 | |
| 280 | /* |
| 281 | * If the temp link is in shortform format, convert that to a remote |
| 282 | * target so that we can use the atomic mapping exchange. |
| 283 | */ |
| 284 | if (temp_local) { |
| 285 | int logflags = XFS_ILOG_CORE; |
| 286 | |
| 287 | error = xfs_bmap_local_to_extents(sc->tp, sc->tempip, 1, |
| 288 | &logflags, XFS_DATA_FORK, |
| 289 | xrep_symlink_local_to_remote, |
| 290 | sc); |
| 291 | if (error) |
| 292 | return error; |
| 293 | |
| 294 | xfs_trans_log_inode(sc->tp, sc->ip, 0); |
| 295 | |
| 296 | error = xfs_defer_finish(&sc->tp); |
| 297 | if (error) |
| 298 | return error; |
| 299 | } |
| 300 | |
| 301 | /* |
| 302 | * If the file being repaired had a shortform data fork, convert that |
| 303 | * to an empty extent list in preparation for the atomic mapping |
| 304 | * exchange. |
| 305 | */ |
| 306 | if (ip_local) { |
| 307 | struct xfs_ifork *ifp; |
| 308 | |
| 309 | ifp = xfs_ifork_ptr(sc->ip, XFS_DATA_FORK); |
| 310 | xfs_idestroy_fork(ifp); |
| 311 | ifp->if_format = XFS_DINODE_FMT_EXTENTS; |
| 312 | ifp->if_nextents = 0; |
| 313 | ifp->if_bytes = 0; |
| 314 | ifp->if_data = NULL; |
| 315 | ifp->if_height = 0; |
| 316 | |
| 317 | xfs_trans_log_inode(sc->tp, sc->ip, |
| 318 | XFS_ILOG_CORE | XFS_ILOG_DDATA); |
| 319 | } |
| 320 | |
| 321 | return 0; |
| 322 | } |
| 323 | |
| 324 | /* Exchange the temporary symlink's data fork with the one being repaired. */ |
| 325 | STATIC int |
| 326 | xrep_symlink_swap( |
| 327 | struct xfs_scrub *sc) |
| 328 | { |
| 329 | struct xrep_tempexch *tx = sc->buf; |
| 330 | bool ip_local, temp_local; |
| 331 | int error; |
| 332 | |
| 333 | ip_local = sc->ip->i_df.if_format == XFS_DINODE_FMT_LOCAL; |
| 334 | temp_local = sc->tempip->i_df.if_format == XFS_DINODE_FMT_LOCAL; |
| 335 | |
| 336 | /* |
| 337 | * If the both links have a local format data fork and the rebuilt |
| 338 | * remote data would fit in the repaired file's data fork, copy the |
| 339 | * contents from the tempfile and declare ourselves done. |
| 340 | */ |
| 341 | if (ip_local && temp_local && |
| 342 | sc->tempip->i_disk_size <= xfs_inode_data_fork_size(sc->ip)) { |
| 343 | xrep_tempfile_copyout_local(sc, XFS_DATA_FORK); |
| 344 | return 0; |
| 345 | } |
| 346 | |
| 347 | /* Otherwise, make sure both data forks are in block-mapping mode. */ |
| 348 | error = xrep_symlink_swap_prep(sc, temp_local, ip_local); |
| 349 | if (error) |
| 350 | return error; |
| 351 | |
| 352 | return xrep_tempexch_contents(sc, tx); |
| 353 | } |
| 354 | |
| 355 | /* |
| 356 | * Free all the remote blocks and reset the data fork. The caller must join |
| 357 | * the inode to the transaction. This function returns with the inode joined |
| 358 | * to a clean scrub transaction. |
| 359 | */ |
| 360 | STATIC int |
| 361 | xrep_symlink_reset_fork( |
| 362 | struct xfs_scrub *sc) |
| 363 | { |
| 364 | struct xfs_ifork *ifp = xfs_ifork_ptr(sc->tempip, XFS_DATA_FORK); |
| 365 | int error; |
| 366 | |
| 367 | /* Unmap all the remote target buffers. */ |
| 368 | if (xfs_ifork_has_extents(ifp)) { |
| 369 | error = xrep_reap_ifork(sc, sc->tempip, XFS_DATA_FORK); |
| 370 | if (error) |
| 371 | return error; |
| 372 | } |
| 373 | |
| 374 | trace_xrep_symlink_reset_fork(sc->tempip); |
| 375 | |
| 376 | /* Reset the temp symlink target to dummy content. */ |
| 377 | xfs_idestroy_fork(ifp); |
| 378 | return xfs_symlink_write_target(sc->tp, sc->tempip, sc->tempip->i_ino, |
| 379 | "?" , 1, 0, 0); |
| 380 | } |
| 381 | |
| 382 | /* |
| 383 | * Reinitialize a link target. Caller must ensure the inode is joined to |
| 384 | * the transaction. |
| 385 | */ |
| 386 | STATIC int |
| 387 | xrep_symlink_rebuild( |
| 388 | struct xfs_scrub *sc) |
| 389 | { |
| 390 | struct xrep_tempexch *tx; |
| 391 | char *target_buf = sc->buf; |
| 392 | xfs_fsblock_t fs_blocks; |
| 393 | unsigned int target_len; |
| 394 | unsigned int resblks; |
| 395 | int error; |
| 396 | |
| 397 | /* How many blocks do we need? */ |
| 398 | target_len = strlen(target_buf); |
| 399 | ASSERT(target_len != 0); |
| 400 | if (target_len == 0 || target_len > XFS_SYMLINK_MAXLEN) |
| 401 | return -EFSCORRUPTED; |
| 402 | |
| 403 | trace_xrep_symlink_rebuild(sc->ip); |
| 404 | |
| 405 | /* |
| 406 | * In preparation to write the new symlink target to the temporary |
| 407 | * file, drop the ILOCK of the file being repaired (it shouldn't be |
| 408 | * joined) and take the ILOCK of the temporary file. |
| 409 | * |
| 410 | * The VFS does not take the IOLOCK while reading a symlink (and new |
| 411 | * symlinks are hidden with INEW until they've been written) so it's |
| 412 | * possible that a readlink() could see the old corrupted contents |
| 413 | * while we're doing this. |
| 414 | */ |
| 415 | xchk_iunlock(sc, XFS_ILOCK_EXCL); |
| 416 | xrep_tempfile_ilock(sc); |
| 417 | xfs_trans_ijoin(sc->tp, sc->tempip, 0); |
| 418 | |
| 419 | /* |
| 420 | * Reserve resources to reinitialize the target. We're allowed to |
| 421 | * exceed file quota to repair inconsistent metadata, though this is |
| 422 | * unlikely. |
| 423 | */ |
| 424 | fs_blocks = xfs_symlink_blocks(sc->mp, target_len); |
| 425 | resblks = xfs_symlink_space_res(sc->mp, target_len, fs_blocks); |
| 426 | error = xfs_trans_reserve_quota_nblks(sc->tp, sc->tempip, resblks, 0, |
| 427 | true); |
| 428 | if (error) |
| 429 | return error; |
| 430 | |
| 431 | /* Erase the dummy target set up by the tempfile initialization. */ |
| 432 | xfs_idestroy_fork(&sc->tempip->i_df); |
| 433 | sc->tempip->i_df.if_bytes = 0; |
| 434 | sc->tempip->i_df.if_format = XFS_DINODE_FMT_EXTENTS; |
| 435 | |
| 436 | /* Write the salvaged target to the temporary link. */ |
| 437 | error = xfs_symlink_write_target(sc->tp, sc->tempip, sc->ip->i_ino, |
| 438 | target_buf, target_len, fs_blocks, resblks); |
| 439 | if (error) |
| 440 | return error; |
| 441 | |
| 442 | /* |
| 443 | * Commit the repair transaction so that we can use the atomic mapping |
| 444 | * exchange functions to compute the correct block reservations and |
| 445 | * re-lock the inodes. |
| 446 | */ |
| 447 | target_buf = NULL; |
| 448 | error = xrep_trans_commit(sc); |
| 449 | if (error) |
| 450 | return error; |
| 451 | |
| 452 | /* Last chance to abort before we start committing fixes. */ |
| 453 | if (xchk_should_terminate(sc, &error)) |
| 454 | return error; |
| 455 | |
| 456 | xrep_tempfile_iunlock(sc); |
| 457 | |
| 458 | /* |
| 459 | * We're done with the temporary buffer, so we can reuse it for the |
| 460 | * tempfile contents exchange information. |
| 461 | */ |
| 462 | tx = sc->buf; |
| 463 | error = xrep_tempexch_trans_alloc(sc, XFS_DATA_FORK, tx); |
| 464 | if (error) |
| 465 | return error; |
| 466 | |
| 467 | /* |
| 468 | * Exchange the temp link's data fork with the file being repaired. |
| 469 | * This recreates the transaction and takes the ILOCKs of the file |
| 470 | * being repaired and the temporary file. |
| 471 | */ |
| 472 | error = xrep_symlink_swap(sc); |
| 473 | if (error) |
| 474 | return error; |
| 475 | |
| 476 | /* |
| 477 | * Release the old symlink blocks and reset the data fork of the temp |
| 478 | * link to an empty shortform link. This is the last repair action we |
| 479 | * perform on the symlink, so we don't need to clean the transaction. |
| 480 | */ |
| 481 | return xrep_symlink_reset_fork(sc); |
| 482 | } |
| 483 | |
| 484 | /* Repair a symbolic link. */ |
| 485 | int |
| 486 | xrep_symlink( |
| 487 | struct xfs_scrub *sc) |
| 488 | { |
| 489 | int error; |
| 490 | |
| 491 | /* The rmapbt is required to reap the old data fork. */ |
| 492 | if (!xfs_has_rmapbt(sc->mp)) |
| 493 | return -EOPNOTSUPP; |
| 494 | /* We require atomic file exchange range to rebuild anything. */ |
| 495 | if (!xfs_has_exchange_range(sc->mp)) |
| 496 | return -EOPNOTSUPP; |
| 497 | |
| 498 | ASSERT(sc->ilock_flags & XFS_ILOCK_EXCL); |
| 499 | |
| 500 | error = xrep_symlink_salvage(sc); |
| 501 | if (error) |
| 502 | return error; |
| 503 | |
| 504 | /* Now reset the target. */ |
| 505 | error = xrep_symlink_rebuild(sc); |
| 506 | if (error) |
| 507 | return error; |
| 508 | |
| 509 | return xrep_trans_commit(sc); |
| 510 | } |
| 511 | |