18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2017 Oracle. All Rights Reserved. 48c2ecf20Sopenharmony_ci * Author: Darrick J. Wong <darrick.wong@oracle.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci#include "xfs.h" 78c2ecf20Sopenharmony_ci#include "xfs_fs.h" 88c2ecf20Sopenharmony_ci#include "xfs_shared.h" 98c2ecf20Sopenharmony_ci#include "xfs_format.h" 108c2ecf20Sopenharmony_ci#include "xfs_trans_resv.h" 118c2ecf20Sopenharmony_ci#include "xfs_mount.h" 128c2ecf20Sopenharmony_ci#include "xfs_log_format.h" 138c2ecf20Sopenharmony_ci#include "xfs_inode.h" 148c2ecf20Sopenharmony_ci#include "xfs_symlink.h" 158c2ecf20Sopenharmony_ci#include "scrub/scrub.h" 168c2ecf20Sopenharmony_ci#include "scrub/common.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/* Set us up to scrub a symbolic link. */ 198c2ecf20Sopenharmony_ciint 208c2ecf20Sopenharmony_cixchk_setup_symlink( 218c2ecf20Sopenharmony_ci struct xfs_scrub *sc, 228c2ecf20Sopenharmony_ci struct xfs_inode *ip) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci /* Allocate the buffer without the inode lock held. */ 258c2ecf20Sopenharmony_ci sc->buf = kvzalloc(XFS_SYMLINK_MAXLEN + 1, GFP_KERNEL); 268c2ecf20Sopenharmony_ci if (!sc->buf) 278c2ecf20Sopenharmony_ci return -ENOMEM; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci return xchk_setup_inode_contents(sc, ip, 0); 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* Symbolic links. */ 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ciint 358c2ecf20Sopenharmony_cixchk_symlink( 368c2ecf20Sopenharmony_ci struct xfs_scrub *sc) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci struct xfs_inode *ip = sc->ip; 398c2ecf20Sopenharmony_ci struct xfs_ifork *ifp; 408c2ecf20Sopenharmony_ci loff_t len; 418c2ecf20Sopenharmony_ci int error = 0; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci if (!S_ISLNK(VFS_I(ip)->i_mode)) 448c2ecf20Sopenharmony_ci return -ENOENT; 458c2ecf20Sopenharmony_ci ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK); 468c2ecf20Sopenharmony_ci len = ip->i_d.di_size; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci /* Plausible size? */ 498c2ecf20Sopenharmony_ci if (len > XFS_SYMLINK_MAXLEN || len <= 0) { 508c2ecf20Sopenharmony_ci xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0); 518c2ecf20Sopenharmony_ci goto out; 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci /* Inline symlink? */ 558c2ecf20Sopenharmony_ci if (ifp->if_flags & XFS_IFINLINE) { 568c2ecf20Sopenharmony_ci if (len > XFS_IFORK_DSIZE(ip) || 578c2ecf20Sopenharmony_ci len > strnlen(ifp->if_u1.if_data, XFS_IFORK_DSIZE(ip))) 588c2ecf20Sopenharmony_ci xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0); 598c2ecf20Sopenharmony_ci goto out; 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci /* Remote symlink; must read the contents. */ 638c2ecf20Sopenharmony_ci error = xfs_readlink_bmap_ilocked(sc->ip, sc->buf); 648c2ecf20Sopenharmony_ci if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error)) 658c2ecf20Sopenharmony_ci goto out; 668c2ecf20Sopenharmony_ci if (strnlen(sc->buf, XFS_SYMLINK_MAXLEN) < len) 678c2ecf20Sopenharmony_ci xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0); 688c2ecf20Sopenharmony_ciout: 698c2ecf20Sopenharmony_ci return error; 708c2ecf20Sopenharmony_ci} 71