1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 2017-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_trans_resv.h" 11 #include "xfs_mount.h" 12 #include "xfs_log_format.h" 13 #include "xfs_inode.h" 14 #include "xfs_symlink.h" 15 #include "xfs_health.h" 16 #include "xfs_symlink_remote.h" 17 #include "scrub/scrub.h" 18 #include "scrub/common.h" 19 #include "scrub/health.h" 20 21 /* Set us up to scrub a symbolic link. */ 22 int 23 xchk_setup_symlink( 24 struct xfs_scrub *sc) 25 { 26 /* Allocate the buffer without the inode lock held. */ 27 sc->buf = kvzalloc(XFS_SYMLINK_MAXLEN + 1, XCHK_GFP_FLAGS); 28 if (!sc->buf) 29 return -ENOMEM; 30 31 return xchk_setup_inode_contents(sc, 0); 32 } 33 34 /* Symbolic links. */ 35 36 int 37 xchk_symlink( 38 struct xfs_scrub *sc) 39 { 40 struct xfs_inode *ip = sc->ip; 41 struct xfs_ifork *ifp; 42 loff_t len; 43 int error = 0; 44 45 if (!S_ISLNK(VFS_I(ip)->i_mode)) 46 return -ENOENT; 47 48 if (xchk_file_looks_zapped(sc, XFS_SICK_INO_SYMLINK_ZAPPED)) { 49 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0); 50 return 0; 51 } 52 53 ifp = xfs_ifork_ptr(ip, XFS_DATA_FORK); 54 len = ip->i_disk_size; 55 56 /* Plausible size? */ 57 if (len > XFS_SYMLINK_MAXLEN || len <= 0) { 58 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0); 59 return 0; 60 } 61 62 /* Inline symlink? */ 63 if (ifp->if_format == XFS_DINODE_FMT_LOCAL) { 64 if (len > xfs_inode_data_fork_size(ip) || 65 len > strnlen(ifp->if_data, xfs_inode_data_fork_size(ip))) 66 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0); 67 return 0; 68 } 69 70 /* Remote symlink; must read the contents. */ 71 error = xfs_symlink_remote_read(sc->ip, sc->buf); 72 if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error)) 73 return error; 74 if (strnlen(sc->buf, XFS_SYMLINK_MAXLEN) < len) 75 xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0); 76 77 /* If a remote symlink is clean, it is clearly not zapped. */ 78 xchk_mark_healthy_if_clean(sc, XFS_SICK_INO_SYMLINK_ZAPPED); 79 return 0; 80 } 81