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. */ 22int 23xchk_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 36int 37xchk_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