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 | |