]>
Commit | Line | Data |
---|---|---|
37b3b4d6 | 1 | // SPDX-License-Identifier: GPL-2.0 |
2bd0ea18 | 2 | /* |
5e656dbb | 3 | * Copyright (c) 2000-2006 Silicon Graphics, Inc. |
da23017d | 4 | * All Rights Reserved. |
2bd0ea18 | 5 | */ |
9c799827 | 6 | #include "libxfs_priv.h" |
b626fb59 DC |
7 | #include "xfs_fs.h" |
8 | #include "xfs_shared.h" | |
9 | #include "xfs_format.h" | |
10 | #include "xfs_log_format.h" | |
11 | #include "xfs_trans_resv.h" | |
12 | #include "xfs_mount.h" | |
8aa34dc9 | 13 | #include "xfs_ag.h" |
b626fb59 | 14 | #include "xfs_inode.h" |
2cf10e4c | 15 | #include "xfs_errortag.h" |
b626fb59 DC |
16 | #include "xfs_trans.h" |
17 | #include "xfs_ialloc.h" | |
0962b5b3 | 18 | #include "xfs_dir2.h" |
2bd0ea18 | 19 | |
998aed52 | 20 | |
f85fc622 DC |
21 | /* |
22 | * If we are doing readahead on an inode buffer, we might be in log recovery | |
23 | * reading an inode allocation buffer that hasn't yet been replayed, and hence | |
24 | * has not had the inode cores stamped into it. Hence for readahead, the buffer | |
25 | * may be potentially invalid. | |
26 | * | |
736e1cf6 DC |
27 | * If the readahead buffer is invalid, we need to mark it with an error and |
28 | * clear the DONE status of the buffer so that a followup read will re-read it | |
29 | * from disk. We don't report the error otherwise to avoid warnings during log | |
c2f0ae02 | 30 | * recovery and we don't get unnecessary panics on debug kernels. We use EIO here |
736e1cf6 DC |
31 | * because all we want to do is say readahead failed; there is no-one to report |
32 | * the error to, so this will distinguish it from a non-ra verifier failure. | |
c2f0ae02 | 33 | * Changes to this readahead error behaviour also need to be reflected in |
6daba42a | 34 | * xfs_dquot_buf_readahead_verify(). |
f85fc622 | 35 | */ |
a2ceac1f DC |
36 | static void |
37 | xfs_inode_buf_verify( | |
f85fc622 DC |
38 | struct xfs_buf *bp, |
39 | bool readahead) | |
5e656dbb | 40 | { |
7861ef77 | 41 | struct xfs_mount *mp = bp->b_mount; |
5e656dbb BN |
42 | int i; |
43 | int ni; | |
5e656dbb BN |
44 | |
45 | /* | |
46 | * Validate the magic number and version of every inode in the buffer | |
5e656dbb | 47 | */ |
a2ceac1f | 48 | ni = XFS_BB_TO_FSB(mp, bp->b_length) * mp->m_sb.sb_inopblock; |
5e656dbb | 49 | for (i = 0; i < ni; i++) { |
7328ea6e CH |
50 | struct xfs_dinode *dip; |
51 | xfs_agino_t unlinked_ino; | |
52 | int di_ok; | |
5e656dbb | 53 | |
92acb899 | 54 | dip = xfs_buf_offset(bp, (i << mp->m_sb.sb_inodelog)); |
2949b467 | 55 | unlinked_ino = be32_to_cpu(dip->di_next_unlinked); |
9e26de8f | 56 | di_ok = xfs_verify_magic16(bp, dip->di_magic) && |
03d8044d | 57 | xfs_dinode_good_version(mp, dip->di_version) && |
8aa34dc9 | 58 | xfs_verify_agino_or_null(bp->b_pag, unlinked_ino); |
5e656dbb | 59 | if (unlikely(XFS_TEST_ERROR(!di_ok, mp, |
e2a190dd | 60 | XFS_ERRTAG_ITOBP_INOTOBP))) { |
f85fc622 DC |
61 | if (readahead) { |
62 | bp->b_flags &= ~XBF_DONE; | |
736e1cf6 | 63 | xfs_buf_ioerror(bp, -EIO); |
f85fc622 DC |
64 | return; |
65 | } | |
66 | ||
5e656dbb | 67 | #ifdef DEBUG |
ea6a00d4 | 68 | xfs_alert(mp, |
a2ceac1f | 69 | "bad inode magic/vsn daddr %lld #%d (magic=%x)", |
f1208396 | 70 | (unsigned long long)xfs_buf_daddr(bp), i, |
56b2de80 | 71 | be16_to_cpu(dip->di_magic)); |
5e656dbb | 72 | #endif |
43f7ceb5 DW |
73 | xfs_buf_verifier_error(bp, -EFSCORRUPTED, |
74 | __func__, dip, sizeof(*dip), | |
75 | NULL); | |
2949b467 | 76 | return; |
5e656dbb BN |
77 | } |
78 | } | |
a2ceac1f | 79 | } |
5e656dbb | 80 | |
e6d77a21 | 81 | |
a2ceac1f DC |
82 | static void |
83 | xfs_inode_buf_read_verify( | |
84 | struct xfs_buf *bp) | |
85 | { | |
f85fc622 DC |
86 | xfs_inode_buf_verify(bp, false); |
87 | } | |
88 | ||
89 | static void | |
90 | xfs_inode_buf_readahead_verify( | |
91 | struct xfs_buf *bp) | |
92 | { | |
93 | xfs_inode_buf_verify(bp, true); | |
5e656dbb | 94 | } |
2bd0ea18 | 95 | |
a2ceac1f DC |
96 | static void |
97 | xfs_inode_buf_write_verify( | |
98 | struct xfs_buf *bp) | |
56b2de80 | 99 | { |
f85fc622 | 100 | xfs_inode_buf_verify(bp, false); |
56b2de80 DC |
101 | } |
102 | ||
a2ceac1f | 103 | const struct xfs_buf_ops xfs_inode_buf_ops = { |
a3fac935 | 104 | .name = "xfs_inode", |
9e26de8f DW |
105 | .magic16 = { cpu_to_be16(XFS_DINODE_MAGIC), |
106 | cpu_to_be16(XFS_DINODE_MAGIC) }, | |
a2ceac1f DC |
107 | .verify_read = xfs_inode_buf_read_verify, |
108 | .verify_write = xfs_inode_buf_write_verify, | |
109 | }; | |
110 | ||
f85fc622 | 111 | const struct xfs_buf_ops xfs_inode_buf_ra_ops = { |
7563fc9c | 112 | .name = "xfs_inode_ra", |
9e26de8f DW |
113 | .magic16 = { cpu_to_be16(XFS_DINODE_MAGIC), |
114 | cpu_to_be16(XFS_DINODE_MAGIC) }, | |
f85fc622 DC |
115 | .verify_read = xfs_inode_buf_readahead_verify, |
116 | .verify_write = xfs_inode_buf_write_verify, | |
117 | }; | |
118 | ||
119 | ||
2bd0ea18 | 120 | /* |
a2ceac1f DC |
121 | * This routine is called to map an inode to the buffer containing the on-disk |
122 | * version of the inode. It returns a pointer to the buffer containing the | |
c074900b | 123 | * on-disk inode in the bpp parameter. |
2bd0ea18 NS |
124 | */ |
125 | int | |
a2ceac1f DC |
126 | xfs_imap_to_bp( |
127 | struct xfs_mount *mp, | |
128 | struct xfs_trans *tp, | |
129 | struct xfs_imap *imap, | |
c074900b | 130 | struct xfs_buf **bpp) |
2bd0ea18 | 131 | { |
c074900b CH |
132 | return xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap->im_blkno, |
133 | imap->im_len, XBF_UNMAPPED, bpp, | |
a2ceac1f | 134 | &xfs_inode_buf_ops); |
2bd0ea18 NS |
135 | } |
136 | ||
e7e3beb9 DW |
137 | static inline struct timespec64 xfs_inode_decode_bigtime(uint64_t ts) |
138 | { | |
139 | struct timespec64 tv; | |
140 | uint32_t n; | |
141 | ||
142 | tv.tv_sec = xfs_bigtime_to_unix(div_u64_rem(ts, NSEC_PER_SEC, &n)); | |
143 | tv.tv_nsec = n; | |
144 | ||
145 | return tv; | |
146 | } | |
147 | ||
a252aadf DW |
148 | /* Convert an ondisk timestamp to an incore timestamp. */ |
149 | struct timespec64 | |
150 | xfs_inode_from_disk_ts( | |
e7e3beb9 | 151 | struct xfs_dinode *dip, |
a252aadf DW |
152 | const xfs_timestamp_t ts) |
153 | { | |
154 | struct timespec64 tv; | |
155 | struct xfs_legacy_timestamp *lts; | |
156 | ||
e7e3beb9 DW |
157 | if (xfs_dinode_has_bigtime(dip)) |
158 | return xfs_inode_decode_bigtime(be64_to_cpu(ts)); | |
159 | ||
a252aadf DW |
160 | lts = (struct xfs_legacy_timestamp *)&ts; |
161 | tv.tv_sec = (int)be32_to_cpu(lts->t_sec); | |
162 | tv.tv_nsec = (int)be32_to_cpu(lts->t_nsec); | |
163 | ||
164 | return tv; | |
165 | } | |
166 | ||
3eb685ae | 167 | int |
1bc6cbe3 DC |
168 | xfs_inode_from_disk( |
169 | struct xfs_inode *ip, | |
138659f1 | 170 | struct xfs_dinode *from) |
2bd0ea18 | 171 | { |
1bc6cbe3 | 172 | struct inode *inode = VFS_I(ip); |
07973a77 | 173 | int error; |
d1eeae6b | 174 | xfs_failaddr_t fa; |
07973a77 CH |
175 | |
176 | ASSERT(ip->i_cowfp == NULL); | |
1bc6cbe3 | 177 | |
d1eeae6b CH |
178 | fa = xfs_dinode_verify(ip->i_mount, ip->i_ino, from); |
179 | if (fa) { | |
180 | xfs_inode_verifier_error(ip, -EFSCORRUPTED, "dinode", from, | |
181 | sizeof(*from), fa); | |
182 | return -EFSCORRUPTED; | |
183 | } | |
184 | ||
f47e002f CH |
185 | /* |
186 | * First get the permanent information that is needed to allocate an | |
187 | * inode. If the inode is unused, mode is zero and we shouldn't mess | |
c2f0ae02 | 188 | * with the uninitialized part of it. |
f47e002f | 189 | */ |
94541a16 | 190 | if (!xfs_has_v3inodes(ip->i_mount)) |
dc1d7a09 | 191 | ip->i_flushiter = be16_to_cpu(from->di_flushiter); |
f47e002f CH |
192 | inode->i_generation = be32_to_cpu(from->di_gen); |
193 | inode->i_mode = be16_to_cpu(from->di_mode); | |
194 | if (!inode->i_mode) | |
195 | return 0; | |
196 | ||
f089fc42 DC |
197 | /* |
198 | * Convert v1 inodes immediately to v2 inode format as this is the | |
199 | * minimum inode version format we support in the rest of the code. | |
fd82a87e | 200 | * They will also be unconditionally written back to disk as v2 inodes. |
f089fc42 | 201 | */ |
fd82a87e | 202 | if (unlikely(from->di_version == 1)) { |
bcbe04c1 | 203 | set_nlink(inode, be16_to_cpu(from->di_onlink)); |
0ca7fa97 | 204 | ip->i_projid = 0; |
f089fc42 | 205 | } else { |
bcbe04c1 | 206 | set_nlink(inode, be32_to_cpu(from->di_nlink)); |
0ca7fa97 | 207 | ip->i_projid = (prid_t)be16_to_cpu(from->di_projid_hi) << 16 | |
e6bd76f0 | 208 | be16_to_cpu(from->di_projid_lo); |
f089fc42 DC |
209 | } |
210 | ||
100eb9e9 CH |
211 | i_uid_write(inode, be32_to_cpu(from->di_uid)); |
212 | i_gid_write(inode, be32_to_cpu(from->di_gid)); | |
1bc6cbe3 DC |
213 | |
214 | /* | |
215 | * Time is signed, so need to convert to signed 32 bit before | |
216 | * storing in inode timestamp which may be 64 bit. Otherwise | |
217 | * a time before epoch is converted to a time long after epoch | |
218 | * on 64 bit systems. | |
219 | */ | |
e7e3beb9 DW |
220 | inode->i_atime = xfs_inode_from_disk_ts(from, from->di_atime); |
221 | inode->i_mtime = xfs_inode_from_disk_ts(from, from->di_mtime); | |
6cfd0b48 JL |
222 | inode_set_ctime_to_ts(inode, |
223 | xfs_inode_from_disk_ts(from, from->di_ctime)); | |
1bc6cbe3 | 224 | |
509dcb4b | 225 | ip->i_disk_size = be64_to_cpu(from->di_size); |
aa00f286 | 226 | ip->i_nblocks = be64_to_cpu(from->di_nblocks); |
fd2f92c8 | 227 | ip->i_extsize = be32_to_cpu(from->di_extsize); |
073f2424 | 228 | ip->i_forkoff = from->di_forkoff; |
69535dad DC |
229 | ip->i_diflags = be16_to_cpu(from->di_flags); |
230 | ip->i_next_unlinked = be32_to_cpu(from->di_next_unlinked); | |
41ce5f36 | 231 | |
ed6a3429 CH |
232 | if (from->di_dmevmask || from->di_dmstate) |
233 | xfs_iflags_set(ip, XFS_IPRESERVE_DM_FIELDS); | |
234 | ||
94541a16 | 235 | if (xfs_has_v3inodes(ip->i_mount)) { |
d5105a89 JL |
236 | inode_set_iversion_queried(inode, |
237 | be64_to_cpu(from->di_changecount)); | |
a1f6b388 | 238 | ip->i_crtime = xfs_inode_from_disk_ts(from, from->di_crtime); |
defd6446 | 239 | ip->i_diflags2 = be64_to_cpu(from->di_flags2); |
fd535ea4 | 240 | ip->i_cowextsize = be32_to_cpu(from->di_cowextsize); |
41ce5f36 | 241 | } |
3eb685ae | 242 | |
07973a77 CH |
243 | error = xfs_iformat_data_fork(ip, from); |
244 | if (error) | |
245 | return error; | |
8c6cccd7 | 246 | if (from->di_forkoff) { |
07973a77 CH |
247 | error = xfs_iformat_attr_fork(ip, from); |
248 | if (error) | |
249 | goto out_destroy_data_fork; | |
250 | } | |
251 | if (xfs_is_reflink_inode(ip)) | |
252 | xfs_ifork_init_cow(ip); | |
253 | return 0; | |
254 | ||
255 | out_destroy_data_fork: | |
a87a40a2 | 256 | xfs_idestroy_fork(&ip->i_df); |
07973a77 | 257 | return error; |
5e656dbb BN |
258 | } |
259 | ||
a252aadf DW |
260 | /* Convert an incore timestamp to an ondisk timestamp. */ |
261 | static inline xfs_timestamp_t | |
262 | xfs_inode_to_disk_ts( | |
e7e3beb9 | 263 | struct xfs_inode *ip, |
a252aadf DW |
264 | const struct timespec64 tv) |
265 | { | |
266 | struct xfs_legacy_timestamp *lts; | |
267 | xfs_timestamp_t ts; | |
268 | ||
e7e3beb9 DW |
269 | if (xfs_inode_has_bigtime(ip)) |
270 | return cpu_to_be64(xfs_inode_encode_bigtime(tv)); | |
271 | ||
a252aadf DW |
272 | lts = (struct xfs_legacy_timestamp *)&ts; |
273 | lts->t_sec = cpu_to_be32(tv.tv_sec); | |
274 | lts->t_nsec = cpu_to_be32(tv.tv_nsec); | |
275 | ||
276 | return ts; | |
277 | } | |
278 | ||
8be26c6a CB |
279 | static inline void |
280 | xfs_inode_to_disk_iext_counters( | |
281 | struct xfs_inode *ip, | |
282 | struct xfs_dinode *to) | |
283 | { | |
284 | if (xfs_inode_has_large_extent_counts(ip)) { | |
285 | to->di_big_nextents = cpu_to_be64(xfs_ifork_nextents(&ip->i_df)); | |
7ff5f1ed | 286 | to->di_big_anextents = cpu_to_be32(xfs_ifork_nextents(&ip->i_af)); |
8be26c6a CB |
287 | /* |
288 | * We might be upgrading the inode to use larger extent counters | |
289 | * than was previously used. Hence zero the unused field. | |
290 | */ | |
291 | to->di_nrext64_pad = cpu_to_be16(0); | |
292 | } else { | |
293 | to->di_nextents = cpu_to_be32(xfs_ifork_nextents(&ip->i_df)); | |
7ff5f1ed | 294 | to->di_anextents = cpu_to_be16(xfs_ifork_nextents(&ip->i_af)); |
8be26c6a CB |
295 | } |
296 | } | |
297 | ||
5e656dbb | 298 | void |
1bc6cbe3 DC |
299 | xfs_inode_to_disk( |
300 | struct xfs_inode *ip, | |
db17aebe DC |
301 | struct xfs_dinode *to, |
302 | xfs_lsn_t lsn) | |
1bc6cbe3 | 303 | { |
1bc6cbe3 DC |
304 | struct inode *inode = VFS_I(ip); |
305 | ||
db17aebe | 306 | to->di_magic = cpu_to_be16(XFS_DINODE_MAGIC); |
f089fc42 | 307 | to->di_onlink = 0; |
db17aebe | 308 | |
d967a68d | 309 | to->di_format = xfs_ifork_format(&ip->i_df); |
100eb9e9 CH |
310 | to->di_uid = cpu_to_be32(i_uid_read(inode)); |
311 | to->di_gid = cpu_to_be32(i_gid_read(inode)); | |
0ca7fa97 CH |
312 | to->di_projid_lo = cpu_to_be16(ip->i_projid & 0xffff); |
313 | to->di_projid_hi = cpu_to_be16(ip->i_projid >> 16); | |
1bc6cbe3 | 314 | |
e7e3beb9 DW |
315 | to->di_atime = xfs_inode_to_disk_ts(ip, inode->i_atime); |
316 | to->di_mtime = xfs_inode_to_disk_ts(ip, inode->i_mtime); | |
6cfd0b48 | 317 | to->di_ctime = xfs_inode_to_disk_ts(ip, inode_get_ctime(inode)); |
bcbe04c1 | 318 | to->di_nlink = cpu_to_be32(inode->i_nlink); |
6652c253 | 319 | to->di_gen = cpu_to_be32(inode->i_generation); |
e37bf53c | 320 | to->di_mode = cpu_to_be16(inode->i_mode); |
1bc6cbe3 | 321 | |
509dcb4b | 322 | to->di_size = cpu_to_be64(ip->i_disk_size); |
aa00f286 | 323 | to->di_nblocks = cpu_to_be64(ip->i_nblocks); |
fd2f92c8 | 324 | to->di_extsize = cpu_to_be32(ip->i_extsize); |
073f2424 | 325 | to->di_forkoff = ip->i_forkoff; |
7ff5f1ed | 326 | to->di_aformat = xfs_ifork_format(&ip->i_af); |
4350eee7 | 327 | to->di_flags = cpu_to_be16(ip->i_diflags); |
1bc6cbe3 | 328 | |
94541a16 | 329 | if (xfs_has_v3inodes(ip->i_mount)) { |
fd82a87e | 330 | to->di_version = 3; |
d5105a89 | 331 | to->di_changecount = cpu_to_be64(inode_peek_iversion(inode)); |
a1f6b388 | 332 | to->di_crtime = xfs_inode_to_disk_ts(ip, ip->i_crtime); |
defd6446 | 333 | to->di_flags2 = cpu_to_be64(ip->i_diflags2); |
fd535ea4 | 334 | to->di_cowextsize = cpu_to_be32(ip->i_cowextsize); |
db17aebe DC |
335 | to->di_ino = cpu_to_be64(ip->i_ino); |
336 | to->di_lsn = cpu_to_be64(lsn); | |
337 | memset(to->di_pad2, 0, sizeof(to->di_pad2)); | |
338 | uuid_copy(&to->di_uuid, &ip->i_mount->m_sb.sb_meta_uuid); | |
8be26c6a | 339 | to->di_v3_pad = 0; |
1bc6cbe3 | 340 | } else { |
fd82a87e | 341 | to->di_version = 2; |
36e4f363 | 342 | to->di_flushiter = cpu_to_be16(ip->i_flushiter); |
8be26c6a | 343 | memset(to->di_v2_pad, 0, sizeof(to->di_v2_pad)); |
1bc6cbe3 | 344 | } |
8be26c6a CB |
345 | |
346 | xfs_inode_to_disk_iext_counters(ip, to); | |
1bc6cbe3 DC |
347 | } |
348 | ||
8ac50baf DC |
349 | static xfs_failaddr_t |
350 | xfs_dinode_verify_fork( | |
351 | struct xfs_dinode *dip, | |
352 | struct xfs_mount *mp, | |
353 | int whichfork) | |
354 | { | |
5f70c91b | 355 | xfs_extnum_t di_nextents; |
099e5eb3 | 356 | xfs_extnum_t max_extents; |
173809af DC |
357 | mode_t mode = be16_to_cpu(dip->di_mode); |
358 | uint32_t fork_size = XFS_DFORK_SIZE(dip, mp, whichfork); | |
359 | uint32_t fork_format = XFS_DFORK_FORMAT(dip, whichfork); | |
8ac50baf | 360 | |
5f70c91b CB |
361 | di_nextents = xfs_dfork_nextents(dip, whichfork); |
362 | ||
173809af DC |
363 | /* |
364 | * For fork types that can contain local data, check that the fork | |
365 | * format matches the size of local data contained within the fork. | |
366 | * | |
367 | * For all types, check that when the size says the should be in extent | |
368 | * or btree format, the inode isn't claiming it is in local format. | |
369 | */ | |
370 | if (whichfork == XFS_DATA_FORK) { | |
371 | if (S_ISDIR(mode) || S_ISLNK(mode)) { | |
372 | if (be64_to_cpu(dip->di_size) <= fork_size && | |
373 | fork_format != XFS_DINODE_FMT_LOCAL) | |
374 | return __this_address; | |
375 | } | |
376 | ||
377 | if (be64_to_cpu(dip->di_size) > fork_size && | |
378 | fork_format == XFS_DINODE_FMT_LOCAL) | |
379 | return __this_address; | |
380 | } | |
381 | ||
382 | switch (fork_format) { | |
8ac50baf DC |
383 | case XFS_DINODE_FMT_LOCAL: |
384 | /* | |
173809af | 385 | * No local regular files yet. |
8ac50baf | 386 | */ |
173809af DC |
387 | if (S_ISREG(mode) && whichfork == XFS_DATA_FORK) |
388 | return __this_address; | |
8ac50baf DC |
389 | if (di_nextents) |
390 | return __this_address; | |
391 | break; | |
392 | case XFS_DINODE_FMT_EXTENTS: | |
393 | if (di_nextents > XFS_DFORK_MAXEXT(dip, mp, whichfork)) | |
394 | return __this_address; | |
395 | break; | |
396 | case XFS_DINODE_FMT_BTREE: | |
5a8b4d6a CB |
397 | max_extents = xfs_iext_max_nextents( |
398 | xfs_dinode_has_large_extent_counts(dip), | |
399 | whichfork); | |
099e5eb3 | 400 | if (di_nextents > max_extents) |
8ac50baf | 401 | return __this_address; |
8ac50baf DC |
402 | break; |
403 | default: | |
404 | return __this_address; | |
405 | } | |
406 | return NULL; | |
407 | } | |
408 | ||
91b32a08 ES |
409 | static xfs_failaddr_t |
410 | xfs_dinode_verify_forkoff( | |
411 | struct xfs_dinode *dip, | |
412 | struct xfs_mount *mp) | |
413 | { | |
8c6cccd7 | 414 | if (!dip->di_forkoff) |
91b32a08 ES |
415 | return NULL; |
416 | ||
417 | switch (dip->di_format) { | |
418 | case XFS_DINODE_FMT_DEV: | |
419 | if (dip->di_forkoff != (roundup(sizeof(xfs_dev_t), 8) >> 3)) | |
420 | return __this_address; | |
421 | break; | |
422 | case XFS_DINODE_FMT_LOCAL: /* fall through ... */ | |
423 | case XFS_DINODE_FMT_EXTENTS: /* fall through ... */ | |
424 | case XFS_DINODE_FMT_BTREE: | |
4de63245 | 425 | if (dip->di_forkoff >= (XFS_LITINO(mp) >> 3)) |
91b32a08 ES |
426 | return __this_address; |
427 | break; | |
428 | default: | |
429 | return __this_address; | |
430 | } | |
431 | return NULL; | |
432 | } | |
433 | ||
8be26c6a CB |
434 | static xfs_failaddr_t |
435 | xfs_dinode_verify_nrext64( | |
436 | struct xfs_mount *mp, | |
437 | struct xfs_dinode *dip) | |
438 | { | |
439 | if (xfs_dinode_has_large_extent_counts(dip)) { | |
440 | if (!xfs_has_large_extent_counts(mp)) | |
441 | return __this_address; | |
442 | if (dip->di_nrext64_pad != 0) | |
443 | return __this_address; | |
444 | } else if (dip->di_version >= 3) { | |
445 | if (dip->di_v3_pad != 0) | |
446 | return __this_address; | |
447 | } | |
448 | ||
449 | return NULL; | |
450 | } | |
451 | ||
bc01119d | 452 | xfs_failaddr_t |
41ce5f36 DC |
453 | xfs_dinode_verify( |
454 | struct xfs_mount *mp, | |
e515cca1 | 455 | xfs_ino_t ino, |
41ce5f36 DC |
456 | struct xfs_dinode *dip) |
457 | { | |
316d5a9f | 458 | xfs_failaddr_t fa; |
3cfabff6 | 459 | uint16_t mode; |
183537ed DW |
460 | uint16_t flags; |
461 | uint64_t flags2; | |
ad42e5a1 | 462 | uint64_t di_size; |
5f70c91b CB |
463 | xfs_extnum_t nextents; |
464 | xfs_extnum_t naextents; | |
465 | xfs_filblks_t nblocks; | |
183537ed | 466 | |
41ce5f36 | 467 | if (dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC)) |
bc01119d | 468 | return __this_address; |
41ce5f36 | 469 | |
98703400 DW |
470 | /* Verify v3 integrity information first */ |
471 | if (dip->di_version >= 3) { | |
94541a16 | 472 | if (!xfs_has_v3inodes(mp)) |
98703400 DW |
473 | return __this_address; |
474 | if (!xfs_verify_cksum((char *)dip, mp->m_sb.sb_inodesize, | |
475 | XFS_DINODE_CRC_OFF)) | |
476 | return __this_address; | |
477 | if (be64_to_cpu(dip->di_ino) != ino) | |
478 | return __this_address; | |
479 | if (!uuid_equal(&dip->di_uuid, &mp->m_sb.sb_meta_uuid)) | |
480 | return __this_address; | |
481 | } | |
482 | ||
9d85eb44 | 483 | /* don't allow invalid i_size */ |
ad42e5a1 DW |
484 | di_size = be64_to_cpu(dip->di_size); |
485 | if (di_size & (1ULL << 63)) | |
bc01119d | 486 | return __this_address; |
9d85eb44 | 487 | |
3cfabff6 | 488 | mode = be16_to_cpu(dip->di_mode); |
0962b5b3 | 489 | if (mode && xfs_mode_to_ftype(mode) == XFS_DIR3_FT_UNKNOWN) |
bc01119d | 490 | return __this_address; |
3cfabff6 AG |
491 | |
492 | /* No zero-length symlinks/dirs. */ | |
ad42e5a1 | 493 | if ((S_ISLNK(mode) || S_ISDIR(mode)) && di_size == 0) |
bc01119d | 494 | return __this_address; |
9d85eb44 | 495 | |
8be26c6a CB |
496 | fa = xfs_dinode_verify_nrext64(mp, dip); |
497 | if (fa) | |
498 | return fa; | |
499 | ||
5f70c91b CB |
500 | nextents = xfs_dfork_data_extents(dip); |
501 | naextents = xfs_dfork_attr_extents(dip); | |
502 | nblocks = be64_to_cpu(dip->di_nblocks); | |
503 | ||
ad42e5a1 | 504 | /* Fork checks carried over from xfs_iformat_fork */ |
5f70c91b | 505 | if (mode && nextents + naextents > nblocks) |
ad42e5a1 DW |
506 | return __this_address; |
507 | ||
f0683d63 CB |
508 | if (S_ISDIR(mode) && nextents > mp->m_dir_geo->max_extents) |
509 | return __this_address; | |
510 | ||
ad42e5a1 DW |
511 | if (mode && XFS_DFORK_BOFF(dip) > mp->m_sb.sb_inodesize) |
512 | return __this_address; | |
513 | ||
514 | flags = be16_to_cpu(dip->di_flags); | |
515 | ||
516 | if (mode && (flags & XFS_DIFLAG_REALTIME) && !mp->m_rtdev_targp) | |
517 | return __this_address; | |
518 | ||
91b32a08 ES |
519 | /* check for illegal values of forkoff */ |
520 | fa = xfs_dinode_verify_forkoff(dip, mp); | |
521 | if (fa) | |
522 | return fa; | |
523 | ||
ad42e5a1 DW |
524 | /* Do we have appropriate data fork formats for the mode? */ |
525 | switch (mode & S_IFMT) { | |
526 | case S_IFIFO: | |
527 | case S_IFCHR: | |
528 | case S_IFBLK: | |
529 | case S_IFSOCK: | |
530 | if (dip->di_format != XFS_DINODE_FMT_DEV) | |
531 | return __this_address; | |
532 | break; | |
533 | case S_IFREG: | |
534 | case S_IFLNK: | |
535 | case S_IFDIR: | |
8ac50baf DC |
536 | fa = xfs_dinode_verify_fork(dip, mp, XFS_DATA_FORK); |
537 | if (fa) | |
538 | return fa; | |
ad42e5a1 DW |
539 | break; |
540 | case 0: | |
541 | /* Uninitialized inode ok. */ | |
542 | break; | |
543 | default: | |
544 | return __this_address; | |
545 | } | |
546 | ||
8c6cccd7 | 547 | if (dip->di_forkoff) { |
8ac50baf DC |
548 | fa = xfs_dinode_verify_fork(dip, mp, XFS_ATTR_FORK); |
549 | if (fa) | |
550 | return fa; | |
3060f26a ES |
551 | } else { |
552 | /* | |
553 | * If there is no fork offset, this may be a freshly-made inode | |
554 | * in a new disk cluster, in which case di_aformat is zeroed. | |
555 | * Otherwise, such an inode must be in EXTENTS format; this goes | |
556 | * for freed inodes as well. | |
557 | */ | |
558 | switch (dip->di_aformat) { | |
559 | case 0: | |
560 | case XFS_DINODE_FMT_EXTENTS: | |
561 | break; | |
562 | default: | |
563 | return __this_address; | |
564 | } | |
5f70c91b | 565 | if (naextents) |
3060f26a | 566 | return __this_address; |
ad42e5a1 DW |
567 | } |
568 | ||
316d5a9f DC |
569 | /* extent size hint validation */ |
570 | fa = xfs_inode_validate_extsize(mp, be32_to_cpu(dip->di_extsize), | |
571 | mode, flags); | |
572 | if (fa) | |
573 | return fa; | |
574 | ||
41ce5f36 DC |
575 | /* only version 3 or greater inodes are extensively verified here */ |
576 | if (dip->di_version < 3) | |
bc01119d | 577 | return NULL; |
41ce5f36 | 578 | |
183537ed DW |
579 | flags2 = be64_to_cpu(dip->di_flags2); |
580 | ||
581 | /* don't allow reflink/cowextsize if we don't have reflink */ | |
582 | if ((flags2 & (XFS_DIFLAG2_REFLINK | XFS_DIFLAG2_COWEXTSIZE)) && | |
b16a427a | 583 | !xfs_has_reflink(mp)) |
bc01119d | 584 | return __this_address; |
183537ed | 585 | |
ad42e5a1 DW |
586 | /* only regular files get reflink */ |
587 | if ((flags2 & XFS_DIFLAG2_REFLINK) && (mode & S_IFMT) != S_IFREG) | |
588 | return __this_address; | |
589 | ||
183537ed DW |
590 | /* don't let reflink and realtime mix */ |
591 | if ((flags2 & XFS_DIFLAG2_REFLINK) && (flags & XFS_DIFLAG_REALTIME)) | |
bc01119d | 592 | return __this_address; |
183537ed | 593 | |
77e17d58 DC |
594 | /* COW extent size hint validation */ |
595 | fa = xfs_inode_validate_cowextsize(mp, be32_to_cpu(dip->di_cowextsize), | |
596 | mode, flags, flags2); | |
597 | if (fa) | |
598 | return fa; | |
599 | ||
e7e3beb9 DW |
600 | /* bigtime iflag can only happen on bigtime filesystems */ |
601 | if (xfs_dinode_has_bigtime(dip) && | |
94541a16 | 602 | !xfs_has_bigtime(mp)) |
e7e3beb9 DW |
603 | return __this_address; |
604 | ||
bc01119d | 605 | return NULL; |
41ce5f36 | 606 | } |
e6d77a21 | 607 | |
41ce5f36 DC |
608 | void |
609 | xfs_dinode_calc_crc( | |
610 | struct xfs_mount *mp, | |
611 | struct xfs_dinode *dip) | |
612 | { | |
4a492e72 | 613 | uint32_t crc; |
41ce5f36 DC |
614 | |
615 | if (dip->di_version < 3) | |
616 | return; | |
617 | ||
b16a427a | 618 | ASSERT(xfs_has_crc(mp)); |
0bb90214 | 619 | crc = xfs_start_cksum_update((char *)dip, mp->m_sb.sb_inodesize, |
3faddc54 | 620 | XFS_DINODE_CRC_OFF); |
41ce5f36 | 621 | dip->di_crc = xfs_end_cksum(crc); |
2bd0ea18 NS |
622 | } |
623 | ||
fd0c360d DW |
624 | /* |
625 | * Validate di_extsize hint. | |
626 | * | |
ef39c7c7 DW |
627 | * 1. Extent size hint is only valid for directories and regular files. |
628 | * 2. FS_XFLAG_EXTSIZE is only valid for regular files. | |
629 | * 3. FS_XFLAG_EXTSZINHERIT is only valid for directories. | |
630 | * 4. Hint cannot be larger than MAXTEXTLEN. | |
631 | * 5. Can be changed on directories at any time. | |
632 | * 6. Hint value of 0 turns off hints, clears inode flags. | |
633 | * 7. Extent size must be a multiple of the appropriate block size. | |
634 | * For realtime files, this is the rt extent size. | |
635 | * 8. For non-realtime files, the extent size hint must be limited | |
636 | * to half the AG size to avoid alignment extending the extent beyond the | |
637 | * limits of the AG. | |
fd0c360d DW |
638 | */ |
639 | xfs_failaddr_t | |
640 | xfs_inode_validate_extsize( | |
641 | struct xfs_mount *mp, | |
642 | uint32_t extsize, | |
643 | uint16_t mode, | |
644 | uint16_t flags) | |
645 | { | |
646 | bool rt_flag; | |
647 | bool hint_flag; | |
648 | bool inherit_flag; | |
649 | uint32_t extsize_bytes; | |
650 | uint32_t blocksize_bytes; | |
651 | ||
652 | rt_flag = (flags & XFS_DIFLAG_REALTIME); | |
653 | hint_flag = (flags & XFS_DIFLAG_EXTSIZE); | |
654 | inherit_flag = (flags & XFS_DIFLAG_EXTSZINHERIT); | |
655 | extsize_bytes = XFS_FSB_TO_B(mp, extsize); | |
656 | ||
c16edcd7 DW |
657 | /* |
658 | * This comment describes a historic gap in this verifier function. | |
659 | * | |
d7de0c3e DW |
660 | * For a directory with both RTINHERIT and EXTSZINHERIT flags set, this |
661 | * function has never checked that the extent size hint is an integer | |
662 | * multiple of the realtime extent size. Since we allow users to set | |
663 | * this combination on non-rt filesystems /and/ to change the rt | |
664 | * extent size when adding a rt device to a filesystem, the net effect | |
665 | * is that users can configure a filesystem anticipating one rt | |
666 | * geometry and change their minds later. Directories do not use the | |
667 | * extent size hint, so this is harmless for them. | |
c16edcd7 DW |
668 | * |
669 | * If a directory with a misaligned extent size hint is allowed to | |
670 | * propagate that hint into a new regular realtime file, the result | |
671 | * is that the inode cluster buffer verifier will trigger a corruption | |
d7de0c3e DW |
672 | * shutdown the next time it is run, because the verifier has always |
673 | * enforced the alignment rule for regular files. | |
c16edcd7 | 674 | * |
d7de0c3e DW |
675 | * Because we allow administrators to set a new rt extent size when |
676 | * adding a rt section, we cannot add a check to this verifier because | |
677 | * that will result a new source of directory corruption errors when | |
678 | * reading an existing filesystem. Instead, we rely on callers to | |
679 | * decide when alignment checks are appropriate, and fix things up as | |
680 | * needed. | |
c16edcd7 DW |
681 | */ |
682 | ||
fd0c360d | 683 | if (rt_flag) |
6d211aaa | 684 | blocksize_bytes = XFS_FSB_TO_B(mp, mp->m_sb.sb_rextsize); |
fd0c360d DW |
685 | else |
686 | blocksize_bytes = mp->m_sb.sb_blocksize; | |
687 | ||
688 | if ((hint_flag || inherit_flag) && !(S_ISDIR(mode) || S_ISREG(mode))) | |
689 | return __this_address; | |
690 | ||
691 | if (hint_flag && !S_ISREG(mode)) | |
692 | return __this_address; | |
693 | ||
694 | if (inherit_flag && !S_ISDIR(mode)) | |
695 | return __this_address; | |
696 | ||
697 | if ((hint_flag || inherit_flag) && extsize == 0) | |
698 | return __this_address; | |
699 | ||
206bef93 ES |
700 | /* free inodes get flags set to zero but extsize remains */ |
701 | if (mode && !(hint_flag || inherit_flag) && extsize != 0) | |
fd0c360d DW |
702 | return __this_address; |
703 | ||
704 | if (extsize_bytes % blocksize_bytes) | |
705 | return __this_address; | |
706 | ||
d3e0c71f | 707 | if (extsize > XFS_MAX_BMBT_EXTLEN) |
fd0c360d DW |
708 | return __this_address; |
709 | ||
710 | if (!rt_flag && extsize > mp->m_sb.sb_agblocks / 2) | |
711 | return __this_address; | |
712 | ||
713 | return NULL; | |
714 | } | |
715 | ||
716 | /* | |
717 | * Validate di_cowextsize hint. | |
718 | * | |
ef39c7c7 DW |
719 | * 1. CoW extent size hint can only be set if reflink is enabled on the fs. |
720 | * The inode does not have to have any shared blocks, but it must be a v3. | |
721 | * 2. FS_XFLAG_COWEXTSIZE is only valid for directories and regular files; | |
722 | * for a directory, the hint is propagated to new files. | |
723 | * 3. Can be changed on files & directories at any time. | |
724 | * 4. Hint value of 0 turns off hints, clears inode flags. | |
725 | * 5. Extent size must be a multiple of the appropriate block size. | |
726 | * 6. The extent size hint must be limited to half the AG size to avoid | |
727 | * alignment extending the extent beyond the limits of the AG. | |
fd0c360d DW |
728 | */ |
729 | xfs_failaddr_t | |
730 | xfs_inode_validate_cowextsize( | |
731 | struct xfs_mount *mp, | |
732 | uint32_t cowextsize, | |
733 | uint16_t mode, | |
734 | uint16_t flags, | |
735 | uint64_t flags2) | |
736 | { | |
737 | bool rt_flag; | |
738 | bool hint_flag; | |
739 | uint32_t cowextsize_bytes; | |
740 | ||
741 | rt_flag = (flags & XFS_DIFLAG_REALTIME); | |
742 | hint_flag = (flags2 & XFS_DIFLAG2_COWEXTSIZE); | |
743 | cowextsize_bytes = XFS_FSB_TO_B(mp, cowextsize); | |
744 | ||
b16a427a | 745 | if (hint_flag && !xfs_has_reflink(mp)) |
fd0c360d DW |
746 | return __this_address; |
747 | ||
748 | if (hint_flag && !(S_ISDIR(mode) || S_ISREG(mode))) | |
749 | return __this_address; | |
750 | ||
751 | if (hint_flag && cowextsize == 0) | |
752 | return __this_address; | |
753 | ||
206bef93 ES |
754 | /* free inodes get flags set to zero but cowextsize remains */ |
755 | if (mode && !hint_flag && cowextsize != 0) | |
fd0c360d DW |
756 | return __this_address; |
757 | ||
758 | if (hint_flag && rt_flag) | |
759 | return __this_address; | |
760 | ||
761 | if (cowextsize_bytes % mp->m_sb.sb_blocksize) | |
762 | return __this_address; | |
763 | ||
d3e0c71f | 764 | if (cowextsize > XFS_MAX_BMBT_EXTLEN) |
fd0c360d DW |
765 | return __this_address; |
766 | ||
767 | if (cowextsize > mp->m_sb.sb_agblocks / 2) | |
768 | return __this_address; | |
769 | ||
770 | return NULL; | |
771 | } |