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