833 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2000-2006 Silicon Graphics, Inc.4 * All Rights Reserved.5 */6#include "xfs.h"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_ag.h"14#include "xfs_inode.h"15#include "xfs_errortag.h"16#include "xfs_error.h"17#include "xfs_icache.h"18#include "xfs_trans.h"19#include "xfs_ialloc.h"20#include "xfs_dir2.h"21#include "xfs_health.h"22 23#include <linux/iversion.h>24 25/*26 * If we are doing readahead on an inode buffer, we might be in log recovery27 * reading an inode allocation buffer that hasn't yet been replayed, and hence28 * has not had the inode cores stamped into it. Hence for readahead, the buffer29 * may be potentially invalid.30 *31 * If the readahead buffer is invalid, we need to mark it with an error and32 * clear the DONE status of the buffer so that a followup read will re-read it33 * from disk. We don't report the error otherwise to avoid warnings during log34 * recovery and we don't get unnecessary panics on debug kernels. We use EIO here35 * because all we want to do is say readahead failed; there is no-one to report36 * the error to, so this will distinguish it from a non-ra verifier failure.37 * Changes to this readahead error behaviour also need to be reflected in38 * xfs_dquot_buf_readahead_verify().39 */40static void41xfs_inode_buf_verify(42 struct xfs_buf *bp,43 bool readahead)44{45 struct xfs_mount *mp = bp->b_mount;46 int i;47 int ni;48 49 /*50 * Validate the magic number and version of every inode in the buffer51 */52 ni = XFS_BB_TO_FSB(mp, bp->b_length) * mp->m_sb.sb_inopblock;53 for (i = 0; i < ni; i++) {54 struct xfs_dinode *dip;55 xfs_agino_t unlinked_ino;56 int di_ok;57 58 dip = xfs_buf_offset(bp, (i << mp->m_sb.sb_inodelog));59 unlinked_ino = be32_to_cpu(dip->di_next_unlinked);60 di_ok = xfs_verify_magic16(bp, dip->di_magic) &&61 xfs_dinode_good_version(mp, dip->di_version) &&62 xfs_verify_agino_or_null(bp->b_pag, unlinked_ino);63 if (unlikely(XFS_TEST_ERROR(!di_ok, mp,64 XFS_ERRTAG_ITOBP_INOTOBP))) {65 if (readahead) {66 bp->b_flags &= ~XBF_DONE;67 xfs_buf_ioerror(bp, -EIO);68 return;69 }70 71#ifdef DEBUG72 xfs_alert(mp,73 "bad inode magic/vsn daddr %lld #%d (magic=%x)",74 (unsigned long long)xfs_buf_daddr(bp), i,75 be16_to_cpu(dip->di_magic));76#endif77 xfs_buf_verifier_error(bp, -EFSCORRUPTED,78 __func__, dip, sizeof(*dip),79 NULL);80 return;81 }82 }83}84 85 86static void87xfs_inode_buf_read_verify(88 struct xfs_buf *bp)89{90 xfs_inode_buf_verify(bp, false);91}92 93static void94xfs_inode_buf_readahead_verify(95 struct xfs_buf *bp)96{97 xfs_inode_buf_verify(bp, true);98}99 100static void101xfs_inode_buf_write_verify(102 struct xfs_buf *bp)103{104 xfs_inode_buf_verify(bp, false);105}106 107const struct xfs_buf_ops xfs_inode_buf_ops = {108 .name = "xfs_inode",109 .magic16 = { cpu_to_be16(XFS_DINODE_MAGIC),110 cpu_to_be16(XFS_DINODE_MAGIC) },111 .verify_read = xfs_inode_buf_read_verify,112 .verify_write = xfs_inode_buf_write_verify,113};114 115const struct xfs_buf_ops xfs_inode_buf_ra_ops = {116 .name = "xfs_inode_ra",117 .magic16 = { cpu_to_be16(XFS_DINODE_MAGIC),118 cpu_to_be16(XFS_DINODE_MAGIC) },119 .verify_read = xfs_inode_buf_readahead_verify,120 .verify_write = xfs_inode_buf_write_verify,121};122 123 124/*125 * This routine is called to map an inode to the buffer containing the on-disk126 * version of the inode. It returns a pointer to the buffer containing the127 * on-disk inode in the bpp parameter.128 */129int130xfs_imap_to_bp(131 struct xfs_mount *mp,132 struct xfs_trans *tp,133 struct xfs_imap *imap,134 struct xfs_buf **bpp)135{136 int error;137 138 error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap->im_blkno,139 imap->im_len, XBF_UNMAPPED, bpp, &xfs_inode_buf_ops);140 if (xfs_metadata_is_sick(error))141 xfs_agno_mark_sick(mp, xfs_daddr_to_agno(mp, imap->im_blkno),142 XFS_SICK_AG_INODES);143 return error;144}145 146static inline struct timespec64 xfs_inode_decode_bigtime(uint64_t ts)147{148 struct timespec64 tv;149 uint32_t n;150 151 tv.tv_sec = xfs_bigtime_to_unix(div_u64_rem(ts, NSEC_PER_SEC, &n));152 tv.tv_nsec = n;153 154 return tv;155}156 157/* Convert an ondisk timestamp to an incore timestamp. */158struct timespec64159xfs_inode_from_disk_ts(160 struct xfs_dinode *dip,161 const xfs_timestamp_t ts)162{163 struct timespec64 tv;164 struct xfs_legacy_timestamp *lts;165 166 if (xfs_dinode_has_bigtime(dip))167 return xfs_inode_decode_bigtime(be64_to_cpu(ts));168 169 lts = (struct xfs_legacy_timestamp *)&ts;170 tv.tv_sec = (int)be32_to_cpu(lts->t_sec);171 tv.tv_nsec = (int)be32_to_cpu(lts->t_nsec);172 173 return tv;174}175 176int177xfs_inode_from_disk(178 struct xfs_inode *ip,179 struct xfs_dinode *from)180{181 struct inode *inode = VFS_I(ip);182 int error;183 xfs_failaddr_t fa;184 185 ASSERT(ip->i_cowfp == NULL);186 187 fa = xfs_dinode_verify(ip->i_mount, ip->i_ino, from);188 if (fa) {189 xfs_inode_verifier_error(ip, -EFSCORRUPTED, "dinode", from,190 sizeof(*from), fa);191 return -EFSCORRUPTED;192 }193 194 /*195 * First get the permanent information that is needed to allocate an196 * inode. If the inode is unused, mode is zero and we shouldn't mess197 * with the uninitialized part of it.198 */199 if (!xfs_has_v3inodes(ip->i_mount))200 ip->i_flushiter = be16_to_cpu(from->di_flushiter);201 inode->i_generation = be32_to_cpu(from->di_gen);202 inode->i_mode = be16_to_cpu(from->di_mode);203 if (!inode->i_mode)204 return 0;205 206 /*207 * Convert v1 inodes immediately to v2 inode format as this is the208 * minimum inode version format we support in the rest of the code.209 * They will also be unconditionally written back to disk as v2 inodes.210 */211 if (unlikely(from->di_version == 1)) {212 set_nlink(inode, be16_to_cpu(from->di_onlink));213 ip->i_projid = 0;214 } else {215 set_nlink(inode, be32_to_cpu(from->di_nlink));216 ip->i_projid = (prid_t)be16_to_cpu(from->di_projid_hi) << 16 |217 be16_to_cpu(from->di_projid_lo);218 }219 220 i_uid_write(inode, be32_to_cpu(from->di_uid));221 i_gid_write(inode, be32_to_cpu(from->di_gid));222 223 /*224 * Time is signed, so need to convert to signed 32 bit before225 * storing in inode timestamp which may be 64 bit. Otherwise226 * a time before epoch is converted to a time long after epoch227 * on 64 bit systems.228 */229 inode_set_atime_to_ts(inode,230 xfs_inode_from_disk_ts(from, from->di_atime));231 inode_set_mtime_to_ts(inode,232 xfs_inode_from_disk_ts(from, from->di_mtime));233 inode_set_ctime_to_ts(inode,234 xfs_inode_from_disk_ts(from, from->di_ctime));235 236 ip->i_disk_size = be64_to_cpu(from->di_size);237 ip->i_nblocks = be64_to_cpu(from->di_nblocks);238 ip->i_extsize = be32_to_cpu(from->di_extsize);239 ip->i_forkoff = from->di_forkoff;240 ip->i_diflags = be16_to_cpu(from->di_flags);241 ip->i_next_unlinked = be32_to_cpu(from->di_next_unlinked);242 243 if (from->di_dmevmask || from->di_dmstate)244 xfs_iflags_set(ip, XFS_IPRESERVE_DM_FIELDS);245 246 if (xfs_has_v3inodes(ip->i_mount)) {247 inode_set_iversion_queried(inode,248 be64_to_cpu(from->di_changecount));249 ip->i_crtime = xfs_inode_from_disk_ts(from, from->di_crtime);250 ip->i_diflags2 = be64_to_cpu(from->di_flags2);251 ip->i_cowextsize = be32_to_cpu(from->di_cowextsize);252 }253 254 error = xfs_iformat_data_fork(ip, from);255 if (error)256 return error;257 if (from->di_forkoff) {258 error = xfs_iformat_attr_fork(ip, from);259 if (error)260 goto out_destroy_data_fork;261 }262 if (xfs_is_reflink_inode(ip))263 xfs_ifork_init_cow(ip);264 return 0;265 266out_destroy_data_fork:267 xfs_idestroy_fork(&ip->i_df);268 return error;269}270 271/* Convert an incore timestamp to an ondisk timestamp. */272static inline xfs_timestamp_t273xfs_inode_to_disk_ts(274 struct xfs_inode *ip,275 const struct timespec64 tv)276{277 struct xfs_legacy_timestamp *lts;278 xfs_timestamp_t ts;279 280 if (xfs_inode_has_bigtime(ip))281 return cpu_to_be64(xfs_inode_encode_bigtime(tv));282 283 lts = (struct xfs_legacy_timestamp *)&ts;284 lts->t_sec = cpu_to_be32(tv.tv_sec);285 lts->t_nsec = cpu_to_be32(tv.tv_nsec);286 287 return ts;288}289 290static inline void291xfs_inode_to_disk_iext_counters(292 struct xfs_inode *ip,293 struct xfs_dinode *to)294{295 if (xfs_inode_has_large_extent_counts(ip)) {296 to->di_big_nextents = cpu_to_be64(xfs_ifork_nextents(&ip->i_df));297 to->di_big_anextents = cpu_to_be32(xfs_ifork_nextents(&ip->i_af));298 /*299 * We might be upgrading the inode to use larger extent counters300 * than was previously used. Hence zero the unused field.301 */302 to->di_nrext64_pad = cpu_to_be16(0);303 } else {304 to->di_nextents = cpu_to_be32(xfs_ifork_nextents(&ip->i_df));305 to->di_anextents = cpu_to_be16(xfs_ifork_nextents(&ip->i_af));306 }307}308 309void310xfs_inode_to_disk(311 struct xfs_inode *ip,312 struct xfs_dinode *to,313 xfs_lsn_t lsn)314{315 struct inode *inode = VFS_I(ip);316 317 to->di_magic = cpu_to_be16(XFS_DINODE_MAGIC);318 to->di_onlink = 0;319 320 to->di_format = xfs_ifork_format(&ip->i_df);321 to->di_uid = cpu_to_be32(i_uid_read(inode));322 to->di_gid = cpu_to_be32(i_gid_read(inode));323 to->di_projid_lo = cpu_to_be16(ip->i_projid & 0xffff);324 to->di_projid_hi = cpu_to_be16(ip->i_projid >> 16);325 326 to->di_atime = xfs_inode_to_disk_ts(ip, inode_get_atime(inode));327 to->di_mtime = xfs_inode_to_disk_ts(ip, inode_get_mtime(inode));328 to->di_ctime = xfs_inode_to_disk_ts(ip, inode_get_ctime(inode));329 to->di_nlink = cpu_to_be32(inode->i_nlink);330 to->di_gen = cpu_to_be32(inode->i_generation);331 to->di_mode = cpu_to_be16(inode->i_mode);332 333 to->di_size = cpu_to_be64(ip->i_disk_size);334 to->di_nblocks = cpu_to_be64(ip->i_nblocks);335 to->di_extsize = cpu_to_be32(ip->i_extsize);336 to->di_forkoff = ip->i_forkoff;337 to->di_aformat = xfs_ifork_format(&ip->i_af);338 to->di_flags = cpu_to_be16(ip->i_diflags);339 340 if (xfs_has_v3inodes(ip->i_mount)) {341 to->di_version = 3;342 to->di_changecount = cpu_to_be64(inode_peek_iversion(inode));343 to->di_crtime = xfs_inode_to_disk_ts(ip, ip->i_crtime);344 to->di_flags2 = cpu_to_be64(ip->i_diflags2);345 to->di_cowextsize = cpu_to_be32(ip->i_cowextsize);346 to->di_ino = cpu_to_be64(ip->i_ino);347 to->di_lsn = cpu_to_be64(lsn);348 memset(to->di_pad2, 0, sizeof(to->di_pad2));349 uuid_copy(&to->di_uuid, &ip->i_mount->m_sb.sb_meta_uuid);350 to->di_v3_pad = 0;351 } else {352 to->di_version = 2;353 to->di_flushiter = cpu_to_be16(ip->i_flushiter);354 memset(to->di_v2_pad, 0, sizeof(to->di_v2_pad));355 }356 357 xfs_inode_to_disk_iext_counters(ip, to);358}359 360static xfs_failaddr_t361xfs_dinode_verify_fork(362 struct xfs_dinode *dip,363 struct xfs_mount *mp,364 int whichfork)365{366 xfs_extnum_t di_nextents;367 xfs_extnum_t max_extents;368 mode_t mode = be16_to_cpu(dip->di_mode);369 uint32_t fork_size = XFS_DFORK_SIZE(dip, mp, whichfork);370 uint32_t fork_format = XFS_DFORK_FORMAT(dip, whichfork);371 372 di_nextents = xfs_dfork_nextents(dip, whichfork);373 374 /*375 * For fork types that can contain local data, check that the fork376 * format matches the size of local data contained within the fork.377 */378 if (whichfork == XFS_DATA_FORK) {379 /*380 * A directory small enough to fit in the inode must be stored381 * in local format. The directory sf <-> extents conversion382 * code updates the directory size accordingly. Directories383 * being truncated have zero size and are not subject to this384 * check.385 */386 if (S_ISDIR(mode)) {387 if (dip->di_size &&388 be64_to_cpu(dip->di_size) <= fork_size &&389 fork_format != XFS_DINODE_FMT_LOCAL)390 return __this_address;391 }392 393 /*394 * A symlink with a target small enough to fit in the inode can395 * be stored in extents format if xattrs were added (thus396 * converting the data fork from shortform to remote format)397 * and then removed.398 */399 if (S_ISLNK(mode)) {400 if (be64_to_cpu(dip->di_size) <= fork_size &&401 fork_format != XFS_DINODE_FMT_EXTENTS &&402 fork_format != XFS_DINODE_FMT_LOCAL)403 return __this_address;404 }405 406 /*407 * For all types, check that when the size says the fork should408 * be in extent or btree format, the inode isn't claiming to be409 * in local format.410 */411 if (be64_to_cpu(dip->di_size) > fork_size &&412 fork_format == XFS_DINODE_FMT_LOCAL)413 return __this_address;414 }415 416 switch (fork_format) {417 case XFS_DINODE_FMT_LOCAL:418 /*419 * No local regular files yet.420 */421 if (S_ISREG(mode) && whichfork == XFS_DATA_FORK)422 return __this_address;423 if (di_nextents)424 return __this_address;425 break;426 case XFS_DINODE_FMT_EXTENTS:427 if (di_nextents > XFS_DFORK_MAXEXT(dip, mp, whichfork))428 return __this_address;429 break;430 case XFS_DINODE_FMT_BTREE:431 max_extents = xfs_iext_max_nextents(432 xfs_dinode_has_large_extent_counts(dip),433 whichfork);434 if (di_nextents > max_extents)435 return __this_address;436 break;437 default:438 return __this_address;439 }440 return NULL;441}442 443static xfs_failaddr_t444xfs_dinode_verify_forkoff(445 struct xfs_dinode *dip,446 struct xfs_mount *mp)447{448 if (!dip->di_forkoff)449 return NULL;450 451 switch (dip->di_format) {452 case XFS_DINODE_FMT_DEV:453 if (dip->di_forkoff != (roundup(sizeof(xfs_dev_t), 8) >> 3))454 return __this_address;455 break;456 case XFS_DINODE_FMT_LOCAL: /* fall through ... */457 case XFS_DINODE_FMT_EXTENTS: /* fall through ... */458 case XFS_DINODE_FMT_BTREE:459 if (dip->di_forkoff >= (XFS_LITINO(mp) >> 3))460 return __this_address;461 break;462 default:463 return __this_address;464 }465 return NULL;466}467 468static xfs_failaddr_t469xfs_dinode_verify_nrext64(470 struct xfs_mount *mp,471 struct xfs_dinode *dip)472{473 if (xfs_dinode_has_large_extent_counts(dip)) {474 if (!xfs_has_large_extent_counts(mp))475 return __this_address;476 if (dip->di_nrext64_pad != 0)477 return __this_address;478 } else if (dip->di_version >= 3) {479 if (dip->di_v3_pad != 0)480 return __this_address;481 }482 483 return NULL;484}485 486xfs_failaddr_t487xfs_dinode_verify(488 struct xfs_mount *mp,489 xfs_ino_t ino,490 struct xfs_dinode *dip)491{492 xfs_failaddr_t fa;493 uint16_t mode;494 uint16_t flags;495 uint64_t flags2;496 uint64_t di_size;497 xfs_extnum_t nextents;498 xfs_extnum_t naextents;499 xfs_filblks_t nblocks;500 501 if (dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC))502 return __this_address;503 504 /* Verify v3 integrity information first */505 if (dip->di_version >= 3) {506 if (!xfs_has_v3inodes(mp))507 return __this_address;508 if (!xfs_verify_cksum((char *)dip, mp->m_sb.sb_inodesize,509 XFS_DINODE_CRC_OFF))510 return __this_address;511 if (be64_to_cpu(dip->di_ino) != ino)512 return __this_address;513 if (!uuid_equal(&dip->di_uuid, &mp->m_sb.sb_meta_uuid))514 return __this_address;515 }516 517 /*518 * Historical note: xfsprogs in the 3.2 era set up its incore inodes to519 * have di_nlink track the link count, even if the actual filesystem520 * only supported V1 inodes (i.e. di_onlink). When writing out the521 * ondisk inode, it would set both the ondisk di_nlink and di_onlink to522 * the the incore di_nlink value, which is why we cannot check for523 * di_nlink==0 on a V1 inode. V2/3 inodes would get written out with524 * di_onlink==0, so we can check that.525 */526 if (dip->di_version >= 2) {527 if (dip->di_onlink)528 return __this_address;529 }530 531 /* don't allow invalid i_size */532 di_size = be64_to_cpu(dip->di_size);533 if (di_size & (1ULL << 63))534 return __this_address;535 536 mode = be16_to_cpu(dip->di_mode);537 if (mode && xfs_mode_to_ftype(mode) == XFS_DIR3_FT_UNKNOWN)538 return __this_address;539 540 /*541 * No zero-length symlinks/dirs unless they're unlinked and hence being542 * inactivated.543 */544 if ((S_ISLNK(mode) || S_ISDIR(mode)) && di_size == 0) {545 if (dip->di_version > 1) {546 if (dip->di_nlink)547 return __this_address;548 } else {549 if (dip->di_onlink)550 return __this_address;551 }552 }553 554 fa = xfs_dinode_verify_nrext64(mp, dip);555 if (fa)556 return fa;557 558 nextents = xfs_dfork_data_extents(dip);559 naextents = xfs_dfork_attr_extents(dip);560 nblocks = be64_to_cpu(dip->di_nblocks);561 562 /* Fork checks carried over from xfs_iformat_fork */563 if (mode && nextents + naextents > nblocks)564 return __this_address;565 566 if (nextents + naextents == 0 && nblocks != 0)567 return __this_address;568 569 if (S_ISDIR(mode) && nextents > mp->m_dir_geo->max_extents)570 return __this_address;571 572 if (mode && XFS_DFORK_BOFF(dip) > mp->m_sb.sb_inodesize)573 return __this_address;574 575 flags = be16_to_cpu(dip->di_flags);576 577 if (mode && (flags & XFS_DIFLAG_REALTIME) && !mp->m_rtdev_targp)578 return __this_address;579 580 /* check for illegal values of forkoff */581 fa = xfs_dinode_verify_forkoff(dip, mp);582 if (fa)583 return fa;584 585 /* Do we have appropriate data fork formats for the mode? */586 switch (mode & S_IFMT) {587 case S_IFIFO:588 case S_IFCHR:589 case S_IFBLK:590 case S_IFSOCK:591 if (dip->di_format != XFS_DINODE_FMT_DEV)592 return __this_address;593 break;594 case S_IFREG:595 case S_IFLNK:596 case S_IFDIR:597 fa = xfs_dinode_verify_fork(dip, mp, XFS_DATA_FORK);598 if (fa)599 return fa;600 break;601 case 0:602 /* Uninitialized inode ok. */603 break;604 default:605 return __this_address;606 }607 608 if (dip->di_forkoff) {609 fa = xfs_dinode_verify_fork(dip, mp, XFS_ATTR_FORK);610 if (fa)611 return fa;612 } else {613 /*614 * If there is no fork offset, this may be a freshly-made inode615 * in a new disk cluster, in which case di_aformat is zeroed.616 * Otherwise, such an inode must be in EXTENTS format; this goes617 * for freed inodes as well.618 */619 switch (dip->di_aformat) {620 case 0:621 case XFS_DINODE_FMT_EXTENTS:622 break;623 default:624 return __this_address;625 }626 if (naextents)627 return __this_address;628 }629 630 /* extent size hint validation */631 fa = xfs_inode_validate_extsize(mp, be32_to_cpu(dip->di_extsize),632 mode, flags);633 if (fa)634 return fa;635 636 /* only version 3 or greater inodes are extensively verified here */637 if (dip->di_version < 3)638 return NULL;639 640 flags2 = be64_to_cpu(dip->di_flags2);641 642 /* don't allow reflink/cowextsize if we don't have reflink */643 if ((flags2 & (XFS_DIFLAG2_REFLINK | XFS_DIFLAG2_COWEXTSIZE)) &&644 !xfs_has_reflink(mp))645 return __this_address;646 647 /* only regular files get reflink */648 if ((flags2 & XFS_DIFLAG2_REFLINK) && (mode & S_IFMT) != S_IFREG)649 return __this_address;650 651 /* don't let reflink and realtime mix */652 if ((flags2 & XFS_DIFLAG2_REFLINK) && (flags & XFS_DIFLAG_REALTIME))653 return __this_address;654 655 /* COW extent size hint validation */656 fa = xfs_inode_validate_cowextsize(mp, be32_to_cpu(dip->di_cowextsize),657 mode, flags, flags2);658 if (fa)659 return fa;660 661 /* bigtime iflag can only happen on bigtime filesystems */662 if (xfs_dinode_has_bigtime(dip) &&663 !xfs_has_bigtime(mp))664 return __this_address;665 666 return NULL;667}668 669void670xfs_dinode_calc_crc(671 struct xfs_mount *mp,672 struct xfs_dinode *dip)673{674 uint32_t crc;675 676 if (dip->di_version < 3)677 return;678 679 ASSERT(xfs_has_crc(mp));680 crc = xfs_start_cksum_update((char *)dip, mp->m_sb.sb_inodesize,681 XFS_DINODE_CRC_OFF);682 dip->di_crc = xfs_end_cksum(crc);683}684 685/*686 * Validate di_extsize hint.687 *688 * 1. Extent size hint is only valid for directories and regular files.689 * 2. FS_XFLAG_EXTSIZE is only valid for regular files.690 * 3. FS_XFLAG_EXTSZINHERIT is only valid for directories.691 * 4. Hint cannot be larger than MAXTEXTLEN.692 * 5. Can be changed on directories at any time.693 * 6. Hint value of 0 turns off hints, clears inode flags.694 * 7. Extent size must be a multiple of the appropriate block size.695 * For realtime files, this is the rt extent size.696 * 8. For non-realtime files, the extent size hint must be limited697 * to half the AG size to avoid alignment extending the extent beyond the698 * limits of the AG.699 */700xfs_failaddr_t701xfs_inode_validate_extsize(702 struct xfs_mount *mp,703 uint32_t extsize,704 uint16_t mode,705 uint16_t flags)706{707 bool rt_flag;708 bool hint_flag;709 bool inherit_flag;710 uint32_t extsize_bytes;711 uint32_t blocksize_bytes;712 713 rt_flag = (flags & XFS_DIFLAG_REALTIME);714 hint_flag = (flags & XFS_DIFLAG_EXTSIZE);715 inherit_flag = (flags & XFS_DIFLAG_EXTSZINHERIT);716 extsize_bytes = XFS_FSB_TO_B(mp, extsize);717 718 /*719 * This comment describes a historic gap in this verifier function.720 *721 * For a directory with both RTINHERIT and EXTSZINHERIT flags set, this722 * function has never checked that the extent size hint is an integer723 * multiple of the realtime extent size. Since we allow users to set724 * this combination on non-rt filesystems /and/ to change the rt725 * extent size when adding a rt device to a filesystem, the net effect726 * is that users can configure a filesystem anticipating one rt727 * geometry and change their minds later. Directories do not use the728 * extent size hint, so this is harmless for them.729 *730 * If a directory with a misaligned extent size hint is allowed to731 * propagate that hint into a new regular realtime file, the result732 * is that the inode cluster buffer verifier will trigger a corruption733 * shutdown the next time it is run, because the verifier has always734 * enforced the alignment rule for regular files.735 *736 * Because we allow administrators to set a new rt extent size when737 * adding a rt section, we cannot add a check to this verifier because738 * that will result a new source of directory corruption errors when739 * reading an existing filesystem. Instead, we rely on callers to740 * decide when alignment checks are appropriate, and fix things up as741 * needed.742 */743 744 if (rt_flag)745 blocksize_bytes = XFS_FSB_TO_B(mp, mp->m_sb.sb_rextsize);746 else747 blocksize_bytes = mp->m_sb.sb_blocksize;748 749 if ((hint_flag || inherit_flag) && !(S_ISDIR(mode) || S_ISREG(mode)))750 return __this_address;751 752 if (hint_flag && !S_ISREG(mode))753 return __this_address;754 755 if (inherit_flag && !S_ISDIR(mode))756 return __this_address;757 758 if ((hint_flag || inherit_flag) && extsize == 0)759 return __this_address;760 761 /* free inodes get flags set to zero but extsize remains */762 if (mode && !(hint_flag || inherit_flag) && extsize != 0)763 return __this_address;764 765 if (extsize_bytes % blocksize_bytes)766 return __this_address;767 768 if (extsize > XFS_MAX_BMBT_EXTLEN)769 return __this_address;770 771 if (!rt_flag && extsize > mp->m_sb.sb_agblocks / 2)772 return __this_address;773 774 return NULL;775}776 777/*778 * Validate di_cowextsize hint.779 *780 * 1. CoW extent size hint can only be set if reflink is enabled on the fs.781 * The inode does not have to have any shared blocks, but it must be a v3.782 * 2. FS_XFLAG_COWEXTSIZE is only valid for directories and regular files;783 * for a directory, the hint is propagated to new files.784 * 3. Can be changed on files & directories at any time.785 * 4. Hint value of 0 turns off hints, clears inode flags.786 * 5. Extent size must be a multiple of the appropriate block size.787 * 6. The extent size hint must be limited to half the AG size to avoid788 * alignment extending the extent beyond the limits of the AG.789 */790xfs_failaddr_t791xfs_inode_validate_cowextsize(792 struct xfs_mount *mp,793 uint32_t cowextsize,794 uint16_t mode,795 uint16_t flags,796 uint64_t flags2)797{798 bool rt_flag;799 bool hint_flag;800 uint32_t cowextsize_bytes;801 802 rt_flag = (flags & XFS_DIFLAG_REALTIME);803 hint_flag = (flags2 & XFS_DIFLAG2_COWEXTSIZE);804 cowextsize_bytes = XFS_FSB_TO_B(mp, cowextsize);805 806 if (hint_flag && !xfs_has_reflink(mp))807 return __this_address;808 809 if (hint_flag && !(S_ISDIR(mode) || S_ISREG(mode)))810 return __this_address;811 812 if (hint_flag && cowextsize == 0)813 return __this_address;814 815 /* free inodes get flags set to zero but cowextsize remains */816 if (mode && !hint_flag && cowextsize != 0)817 return __this_address;818 819 if (hint_flag && rt_flag)820 return __this_address;821 822 if (cowextsize_bytes % mp->m_sb.sb_blocksize)823 return __this_address;824 825 if (cowextsize > XFS_MAX_BMBT_EXTLEN)826 return __this_address;827 828 if (cowextsize > mp->m_sb.sb_agblocks / 2)829 return __this_address;830 831 return NULL;832}833