1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
4 * Copyright (C) 2017 Oracle.
5 * All Rights Reserved.
6 */
7#include "xfs.h"
8#include "xfs_fs.h"
9#include "xfs_format.h"
10#include "xfs_shared.h"
11#include "xfs_trans_resv.h"
12#include "xfs_bit.h"
13#include "xfs_mount.h"
14#include "xfs_ag.h"
15
16
17/*
18 * Verify that an AG block number pointer neither points outside the AG
19 * nor points at static metadata.
20 */
21static inline bool
22xfs_verify_agno_agbno(
23	struct xfs_mount	*mp,
24	xfs_agnumber_t		agno,
25	xfs_agblock_t		agbno)
26{
27	xfs_agblock_t		eoag;
28
29	eoag = xfs_ag_block_count(mp, agno);
30	if (agbno >= eoag)
31		return false;
32	if (agbno <= XFS_AGFL_BLOCK(mp))
33		return false;
34	return true;
35}
36
37/*
38 * Verify that an FS block number pointer neither points outside the
39 * filesystem nor points at static AG metadata.
40 */
41inline bool
42xfs_verify_fsbno(
43	struct xfs_mount	*mp,
44	xfs_fsblock_t		fsbno)
45{
46	xfs_agnumber_t		agno = XFS_FSB_TO_AGNO(mp, fsbno);
47
48	if (agno >= mp->m_sb.sb_agcount)
49		return false;
50	return xfs_verify_agno_agbno(mp, agno, XFS_FSB_TO_AGBNO(mp, fsbno));
51}
52
53/*
54 * Verify that a data device extent is fully contained inside the filesystem,
55 * does not cross an AG boundary, and does not point at static metadata.
56 */
57bool
58xfs_verify_fsbext(
59	struct xfs_mount	*mp,
60	xfs_fsblock_t		fsbno,
61	xfs_fsblock_t		len)
62{
63	if (fsbno + len <= fsbno)
64		return false;
65
66	if (!xfs_verify_fsbno(mp, fsbno))
67		return false;
68
69	if (!xfs_verify_fsbno(mp, fsbno + len - 1))
70		return false;
71
72	return  XFS_FSB_TO_AGNO(mp, fsbno) ==
73		XFS_FSB_TO_AGNO(mp, fsbno + len - 1);
74}
75
76/*
77 * Verify that an AG inode number pointer neither points outside the AG
78 * nor points at static metadata.
79 */
80static inline bool
81xfs_verify_agno_agino(
82	struct xfs_mount	*mp,
83	xfs_agnumber_t		agno,
84	xfs_agino_t		agino)
85{
86	xfs_agino_t		first;
87	xfs_agino_t		last;
88
89	xfs_agino_range(mp, agno, &first, &last);
90	return agino >= first && agino <= last;
91}
92
93/*
94 * Verify that an FS inode number pointer neither points outside the
95 * filesystem nor points at static AG metadata.
96 */
97inline bool
98xfs_verify_ino(
99	struct xfs_mount	*mp,
100	xfs_ino_t		ino)
101{
102	xfs_agnumber_t		agno = XFS_INO_TO_AGNO(mp, ino);
103	xfs_agino_t		agino = XFS_INO_TO_AGINO(mp, ino);
104
105	if (agno >= mp->m_sb.sb_agcount)
106		return false;
107	if (XFS_AGINO_TO_INO(mp, agno, agino) != ino)
108		return false;
109	return xfs_verify_agno_agino(mp, agno, agino);
110}
111
112/* Is this an internal inode number? */
113inline bool
114xfs_internal_inum(
115	struct xfs_mount	*mp,
116	xfs_ino_t		ino)
117{
118	return ino == mp->m_sb.sb_rbmino || ino == mp->m_sb.sb_rsumino ||
119		(xfs_has_quota(mp) &&
120		 xfs_is_quota_inode(&mp->m_sb, ino));
121}
122
123/*
124 * Verify that a directory entry's inode number doesn't point at an internal
125 * inode, empty space, or static AG metadata.
126 */
127bool
128xfs_verify_dir_ino(
129	struct xfs_mount	*mp,
130	xfs_ino_t		ino)
131{
132	if (xfs_internal_inum(mp, ino))
133		return false;
134	return xfs_verify_ino(mp, ino);
135}
136
137/*
138 * Verify that an realtime block number pointer doesn't point off the
139 * end of the realtime device.
140 */
141inline bool
142xfs_verify_rtbno(
143	struct xfs_mount	*mp,
144	xfs_rtblock_t		rtbno)
145{
146	return rtbno < mp->m_sb.sb_rblocks;
147}
148
149/* Verify that a realtime device extent is fully contained inside the volume. */
150bool
151xfs_verify_rtbext(
152	struct xfs_mount	*mp,
153	xfs_rtblock_t		rtbno,
154	xfs_filblks_t		len)
155{
156	if (rtbno + len <= rtbno)
157		return false;
158
159	if (!xfs_verify_rtbno(mp, rtbno))
160		return false;
161
162	return xfs_verify_rtbno(mp, rtbno + len - 1);
163}
164
165/* Calculate the range of valid icount values. */
166inline void
167xfs_icount_range(
168	struct xfs_mount	*mp,
169	unsigned long long	*min,
170	unsigned long long	*max)
171{
172	unsigned long long	nr_inos = 0;
173	struct xfs_perag	*pag;
174	xfs_agnumber_t		agno;
175
176	/* root, rtbitmap, rtsum all live in the first chunk */
177	*min = XFS_INODES_PER_CHUNK;
178
179	for_each_perag(mp, agno, pag)
180		nr_inos += pag->agino_max - pag->agino_min + 1;
181	*max = nr_inos;
182}
183
184/* Sanity-checking of inode counts. */
185bool
186xfs_verify_icount(
187	struct xfs_mount	*mp,
188	unsigned long long	icount)
189{
190	unsigned long long	min, max;
191
192	xfs_icount_range(mp, &min, &max);
193	return icount >= min && icount <= max;
194}
195
196/* Sanity-checking of dir/attr block offsets. */
197bool
198xfs_verify_dablk(
199	struct xfs_mount	*mp,
200	xfs_fileoff_t		dabno)
201{
202	xfs_dablk_t		max_dablk = -1U;
203
204	return dabno <= max_dablk;
205}
206
207/* Check that a file block offset does not exceed the maximum. */
208bool
209xfs_verify_fileoff(
210	struct xfs_mount	*mp,
211	xfs_fileoff_t		off)
212{
213	return off <= XFS_MAX_FILEOFF;
214}
215
216/* Check that a range of file block offsets do not exceed the maximum. */
217bool
218xfs_verify_fileext(
219	struct xfs_mount	*mp,
220	xfs_fileoff_t		off,
221	xfs_fileoff_t		len)
222{
223	if (off + len <= off)
224		return false;
225
226	if (!xfs_verify_fileoff(mp, off))
227		return false;
228
229	return xfs_verify_fileoff(mp, off + len - 1);
230}
231