819 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2000-2006 Silicon Graphics, Inc.4 * All Rights Reserved.5 */6 7#include "xfs.h"8#include "xfs_fs.h"9#include "xfs_shared.h"10#include "xfs_format.h"11#include "xfs_log_format.h"12#include "xfs_trans_resv.h"13#include "xfs_mount.h"14#include "xfs_inode.h"15#include "xfs_trans.h"16#include "xfs_inode_item.h"17#include "xfs_btree.h"18#include "xfs_bmap_btree.h"19#include "xfs_bmap.h"20#include "xfs_error.h"21#include "xfs_trace.h"22#include "xfs_da_format.h"23#include "xfs_da_btree.h"24#include "xfs_dir2_priv.h"25#include "xfs_attr_leaf.h"26#include "xfs_types.h"27#include "xfs_errortag.h"28#include "xfs_health.h"29#include "xfs_symlink_remote.h"30 31struct kmem_cache *xfs_ifork_cache;32 33void34xfs_init_local_fork(35 struct xfs_inode *ip,36 int whichfork,37 const void *data,38 int64_t size)39{40 struct xfs_ifork *ifp = xfs_ifork_ptr(ip, whichfork);41 int mem_size = size;42 bool zero_terminate;43 44 /*45 * If we are using the local fork to store a symlink body we need to46 * zero-terminate it so that we can pass it back to the VFS directly.47 * Overallocate the in-memory fork by one for that and add a zero48 * to terminate it below.49 */50 zero_terminate = S_ISLNK(VFS_I(ip)->i_mode);51 if (zero_terminate)52 mem_size++;53 54 if (size) {55 char *new_data = kmalloc(mem_size,56 GFP_KERNEL | __GFP_NOLOCKDEP | __GFP_NOFAIL);57 58 memcpy(new_data, data, size);59 if (zero_terminate)60 new_data[size] = '\0';61 62 ifp->if_data = new_data;63 } else {64 ifp->if_data = NULL;65 }66 67 ifp->if_bytes = size;68}69 70/*71 * The file is in-lined in the on-disk inode.72 */73STATIC int74xfs_iformat_local(75 struct xfs_inode *ip,76 struct xfs_dinode *dip,77 int whichfork,78 int size)79{80 /*81 * If the size is unreasonable, then something82 * is wrong and we just bail out rather than crash in83 * kmalloc() or memcpy() below.84 */85 if (unlikely(size > XFS_DFORK_SIZE(dip, ip->i_mount, whichfork))) {86 xfs_warn(ip->i_mount,87 "corrupt inode %llu (bad size %d for local fork, size = %zd).",88 (unsigned long long) ip->i_ino, size,89 XFS_DFORK_SIZE(dip, ip->i_mount, whichfork));90 xfs_inode_verifier_error(ip, -EFSCORRUPTED,91 "xfs_iformat_local", dip, sizeof(*dip),92 __this_address);93 xfs_inode_mark_sick(ip, XFS_SICK_INO_CORE);94 return -EFSCORRUPTED;95 }96 97 xfs_init_local_fork(ip, whichfork, XFS_DFORK_PTR(dip, whichfork), size);98 return 0;99}100 101/*102 * The file consists of a set of extents all of which fit into the on-disk103 * inode.104 */105STATIC int106xfs_iformat_extents(107 struct xfs_inode *ip,108 struct xfs_dinode *dip,109 int whichfork)110{111 struct xfs_mount *mp = ip->i_mount;112 struct xfs_ifork *ifp = xfs_ifork_ptr(ip, whichfork);113 int state = xfs_bmap_fork_to_state(whichfork);114 xfs_extnum_t nex = xfs_dfork_nextents(dip, whichfork);115 int size = nex * sizeof(xfs_bmbt_rec_t);116 struct xfs_iext_cursor icur;117 struct xfs_bmbt_rec *dp;118 struct xfs_bmbt_irec new;119 int i;120 121 /*122 * If the number of extents is unreasonable, then something is wrong and123 * we just bail out rather than crash in kmalloc() or memcpy() below.124 */125 if (unlikely(size < 0 || size > XFS_DFORK_SIZE(dip, mp, whichfork))) {126 xfs_warn(ip->i_mount, "corrupt inode %llu ((a)extents = %llu).",127 ip->i_ino, nex);128 xfs_inode_verifier_error(ip, -EFSCORRUPTED,129 "xfs_iformat_extents(1)", dip, sizeof(*dip),130 __this_address);131 xfs_inode_mark_sick(ip, XFS_SICK_INO_CORE);132 return -EFSCORRUPTED;133 }134 135 ifp->if_bytes = 0;136 ifp->if_data = NULL;137 ifp->if_height = 0;138 if (size) {139 dp = (xfs_bmbt_rec_t *) XFS_DFORK_PTR(dip, whichfork);140 141 xfs_iext_first(ifp, &icur);142 for (i = 0; i < nex; i++, dp++) {143 xfs_failaddr_t fa;144 145 xfs_bmbt_disk_get_all(dp, &new);146 fa = xfs_bmap_validate_extent(ip, whichfork, &new);147 if (fa) {148 xfs_inode_verifier_error(ip, -EFSCORRUPTED,149 "xfs_iformat_extents(2)",150 dp, sizeof(*dp), fa);151 xfs_inode_mark_sick(ip, XFS_SICK_INO_CORE);152 return xfs_bmap_complain_bad_rec(ip, whichfork,153 fa, &new);154 }155 156 xfs_iext_insert(ip, &icur, &new, state);157 trace_xfs_read_extent(ip, &icur, state, _THIS_IP_);158 xfs_iext_next(ifp, &icur);159 }160 }161 return 0;162}163 164/*165 * The file has too many extents to fit into166 * the inode, so they are in B-tree format.167 * Allocate a buffer for the root of the B-tree168 * and copy the root into it. The i_extents169 * field will remain NULL until all of the170 * extents are read in (when they are needed).171 */172STATIC int173xfs_iformat_btree(174 struct xfs_inode *ip,175 struct xfs_dinode *dip,176 int whichfork)177{178 struct xfs_mount *mp = ip->i_mount;179 xfs_bmdr_block_t *dfp;180 struct xfs_ifork *ifp;181 /* REFERENCED */182 int nrecs;183 int size;184 int level;185 186 ifp = xfs_ifork_ptr(ip, whichfork);187 dfp = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);188 size = xfs_bmap_broot_space(mp, dfp);189 nrecs = be16_to_cpu(dfp->bb_numrecs);190 level = be16_to_cpu(dfp->bb_level);191 192 /*193 * blow out if -- fork has less extents than can fit in194 * fork (fork shouldn't be a btree format), root btree195 * block has more records than can fit into the fork,196 * or the number of extents is greater than the number of197 * blocks.198 */199 if (unlikely(ifp->if_nextents <= XFS_IFORK_MAXEXT(ip, whichfork) ||200 nrecs == 0 ||201 xfs_bmdr_space_calc(nrecs) >202 XFS_DFORK_SIZE(dip, mp, whichfork) ||203 ifp->if_nextents > ip->i_nblocks) ||204 level == 0 || level > XFS_BM_MAXLEVELS(mp, whichfork)) {205 xfs_warn(mp, "corrupt inode %llu (btree).",206 (unsigned long long) ip->i_ino);207 xfs_inode_verifier_error(ip, -EFSCORRUPTED,208 "xfs_iformat_btree", dfp, size,209 __this_address);210 xfs_inode_mark_sick(ip, XFS_SICK_INO_CORE);211 return -EFSCORRUPTED;212 }213 214 ifp->if_broot_bytes = size;215 ifp->if_broot = kmalloc(size,216 GFP_KERNEL | __GFP_NOLOCKDEP | __GFP_NOFAIL);217 ASSERT(ifp->if_broot != NULL);218 /*219 * Copy and convert from the on-disk structure220 * to the in-memory structure.221 */222 xfs_bmdr_to_bmbt(ip, dfp, XFS_DFORK_SIZE(dip, ip->i_mount, whichfork),223 ifp->if_broot, size);224 225 ifp->if_bytes = 0;226 ifp->if_data = NULL;227 ifp->if_height = 0;228 return 0;229}230 231int232xfs_iformat_data_fork(233 struct xfs_inode *ip,234 struct xfs_dinode *dip)235{236 struct inode *inode = VFS_I(ip);237 int error;238 239 /*240 * Initialize the extent count early, as the per-format routines may241 * depend on it. Use release semantics to set needextents /after/ we242 * set the format. This ensures that we can use acquire semantics on243 * needextents in xfs_need_iread_extents() and be guaranteed to see a244 * valid format value after that load.245 */246 ip->i_df.if_format = dip->di_format;247 ip->i_df.if_nextents = xfs_dfork_data_extents(dip);248 smp_store_release(&ip->i_df.if_needextents,249 ip->i_df.if_format == XFS_DINODE_FMT_BTREE ? 1 : 0);250 251 switch (inode->i_mode & S_IFMT) {252 case S_IFIFO:253 case S_IFCHR:254 case S_IFBLK:255 case S_IFSOCK:256 ip->i_disk_size = 0;257 inode->i_rdev = xfs_to_linux_dev_t(xfs_dinode_get_rdev(dip));258 return 0;259 case S_IFREG:260 case S_IFLNK:261 case S_IFDIR:262 switch (ip->i_df.if_format) {263 case XFS_DINODE_FMT_LOCAL:264 error = xfs_iformat_local(ip, dip, XFS_DATA_FORK,265 be64_to_cpu(dip->di_size));266 if (!error)267 error = xfs_ifork_verify_local_data(ip);268 return error;269 case XFS_DINODE_FMT_EXTENTS:270 return xfs_iformat_extents(ip, dip, XFS_DATA_FORK);271 case XFS_DINODE_FMT_BTREE:272 return xfs_iformat_btree(ip, dip, XFS_DATA_FORK);273 default:274 xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__,275 dip, sizeof(*dip), __this_address);276 xfs_inode_mark_sick(ip, XFS_SICK_INO_CORE);277 return -EFSCORRUPTED;278 }279 break;280 default:281 xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__, dip,282 sizeof(*dip), __this_address);283 xfs_inode_mark_sick(ip, XFS_SICK_INO_CORE);284 return -EFSCORRUPTED;285 }286}287 288static uint16_t289xfs_dfork_attr_shortform_size(290 struct xfs_dinode *dip)291{292 struct xfs_attr_sf_hdr *sf = XFS_DFORK_APTR(dip);293 294 return be16_to_cpu(sf->totsize);295}296 297void298xfs_ifork_init_attr(299 struct xfs_inode *ip,300 enum xfs_dinode_fmt format,301 xfs_extnum_t nextents)302{303 /*304 * Initialize the extent count early, as the per-format routines may305 * depend on it. Use release semantics to set needextents /after/ we306 * set the format. This ensures that we can use acquire semantics on307 * needextents in xfs_need_iread_extents() and be guaranteed to see a308 * valid format value after that load.309 */310 ip->i_af.if_format = format;311 ip->i_af.if_nextents = nextents;312 smp_store_release(&ip->i_af.if_needextents,313 ip->i_af.if_format == XFS_DINODE_FMT_BTREE ? 1 : 0);314}315 316void317xfs_ifork_zap_attr(318 struct xfs_inode *ip)319{320 xfs_idestroy_fork(&ip->i_af);321 memset(&ip->i_af, 0, sizeof(struct xfs_ifork));322 ip->i_af.if_format = XFS_DINODE_FMT_EXTENTS;323}324 325int326xfs_iformat_attr_fork(327 struct xfs_inode *ip,328 struct xfs_dinode *dip)329{330 xfs_extnum_t naextents = xfs_dfork_attr_extents(dip);331 int error = 0;332 333 /*334 * Initialize the extent count early, as the per-format routines may335 * depend on it.336 */337 xfs_ifork_init_attr(ip, dip->di_aformat, naextents);338 339 switch (ip->i_af.if_format) {340 case XFS_DINODE_FMT_LOCAL:341 error = xfs_iformat_local(ip, dip, XFS_ATTR_FORK,342 xfs_dfork_attr_shortform_size(dip));343 if (!error)344 error = xfs_ifork_verify_local_attr(ip);345 break;346 case XFS_DINODE_FMT_EXTENTS:347 error = xfs_iformat_extents(ip, dip, XFS_ATTR_FORK);348 break;349 case XFS_DINODE_FMT_BTREE:350 error = xfs_iformat_btree(ip, dip, XFS_ATTR_FORK);351 break;352 default:353 xfs_inode_verifier_error(ip, error, __func__, dip,354 sizeof(*dip), __this_address);355 xfs_inode_mark_sick(ip, XFS_SICK_INO_CORE);356 error = -EFSCORRUPTED;357 break;358 }359 360 if (error)361 xfs_ifork_zap_attr(ip);362 return error;363}364 365/*366 * Reallocate the space for if_broot based on the number of records367 * being added or deleted as indicated in rec_diff. Move the records368 * and pointers in if_broot to fit the new size. When shrinking this369 * will eliminate holes between the records and pointers created by370 * the caller. When growing this will create holes to be filled in371 * by the caller.372 *373 * The caller must not request to add more records than would fit in374 * the on-disk inode root. If the if_broot is currently NULL, then375 * if we are adding records, one will be allocated. The caller must also376 * not request that the number of records go below zero, although377 * it can go to zero.378 *379 * ip -- the inode whose if_broot area is changing380 * ext_diff -- the change in the number of records, positive or negative,381 * requested for the if_broot array.382 */383void384xfs_iroot_realloc(385 xfs_inode_t *ip,386 int rec_diff,387 int whichfork)388{389 struct xfs_mount *mp = ip->i_mount;390 int cur_max;391 struct xfs_ifork *ifp;392 struct xfs_btree_block *new_broot;393 int new_max;394 size_t new_size;395 char *np;396 char *op;397 398 /*399 * Handle the degenerate case quietly.400 */401 if (rec_diff == 0) {402 return;403 }404 405 ifp = xfs_ifork_ptr(ip, whichfork);406 if (rec_diff > 0) {407 /*408 * If there wasn't any memory allocated before, just409 * allocate it now and get out.410 */411 if (ifp->if_broot_bytes == 0) {412 new_size = xfs_bmap_broot_space_calc(mp, rec_diff);413 ifp->if_broot = kmalloc(new_size,414 GFP_KERNEL | __GFP_NOFAIL);415 ifp->if_broot_bytes = (int)new_size;416 return;417 }418 419 /*420 * If there is already an existing if_broot, then we need421 * to realloc() it and shift the pointers to their new422 * location. The records don't change location because423 * they are kept butted up against the btree block header.424 */425 cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, false);426 new_max = cur_max + rec_diff;427 new_size = xfs_bmap_broot_space_calc(mp, new_max);428 ifp->if_broot = krealloc(ifp->if_broot, new_size,429 GFP_KERNEL | __GFP_NOFAIL);430 op = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1,431 ifp->if_broot_bytes);432 np = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1,433 (int)new_size);434 ifp->if_broot_bytes = (int)new_size;435 ASSERT(xfs_bmap_bmdr_space(ifp->if_broot) <=436 xfs_inode_fork_size(ip, whichfork));437 memmove(np, op, cur_max * (uint)sizeof(xfs_fsblock_t));438 return;439 }440 441 /*442 * rec_diff is less than 0. In this case, we are shrinking the443 * if_broot buffer. It must already exist. If we go to zero444 * records, just get rid of the root and clear the status bit.445 */446 ASSERT((ifp->if_broot != NULL) && (ifp->if_broot_bytes > 0));447 cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, false);448 new_max = cur_max + rec_diff;449 ASSERT(new_max >= 0);450 if (new_max > 0)451 new_size = xfs_bmap_broot_space_calc(mp, new_max);452 else453 new_size = 0;454 if (new_size > 0) {455 new_broot = kmalloc(new_size, GFP_KERNEL | __GFP_NOFAIL);456 /*457 * First copy over the btree block header.458 */459 memcpy(new_broot, ifp->if_broot,460 xfs_bmbt_block_len(ip->i_mount));461 } else {462 new_broot = NULL;463 }464 465 /*466 * Only copy the keys and pointers if there are any.467 */468 if (new_max > 0) {469 /*470 * First copy the keys.471 */472 op = (char *)xfs_bmbt_key_addr(mp, ifp->if_broot, 1);473 np = (char *)xfs_bmbt_key_addr(mp, new_broot, 1);474 memcpy(np, op, new_max * (uint)sizeof(xfs_bmbt_key_t));475 476 /*477 * Then copy the pointers.478 */479 op = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1,480 ifp->if_broot_bytes);481 np = (char *)xfs_bmap_broot_ptr_addr(mp, new_broot, 1,482 (int)new_size);483 memcpy(np, op, new_max * (uint)sizeof(xfs_fsblock_t));484 }485 kfree(ifp->if_broot);486 ifp->if_broot = new_broot;487 ifp->if_broot_bytes = (int)new_size;488 if (ifp->if_broot)489 ASSERT(xfs_bmap_bmdr_space(ifp->if_broot) <=490 xfs_inode_fork_size(ip, whichfork));491 return;492}493 494 495/*496 * This is called when the amount of space needed for if_data497 * is increased or decreased. The change in size is indicated by498 * the number of bytes that need to be added or deleted in the499 * byte_diff parameter.500 *501 * If the amount of space needed has decreased below the size of the502 * inline buffer, then switch to using the inline buffer. Otherwise,503 * use krealloc() or kmalloc() to adjust the size of the buffer504 * to what is needed.505 *506 * ip -- the inode whose if_data area is changing507 * byte_diff -- the change in the number of bytes, positive or negative,508 * requested for the if_data array.509 */510void *511xfs_idata_realloc(512 struct xfs_inode *ip,513 int64_t byte_diff,514 int whichfork)515{516 struct xfs_ifork *ifp = xfs_ifork_ptr(ip, whichfork);517 int64_t new_size = ifp->if_bytes + byte_diff;518 519 ASSERT(new_size >= 0);520 ASSERT(new_size <= xfs_inode_fork_size(ip, whichfork));521 522 if (byte_diff) {523 ifp->if_data = krealloc(ifp->if_data, new_size,524 GFP_KERNEL | __GFP_NOFAIL);525 if (new_size == 0)526 ifp->if_data = NULL;527 ifp->if_bytes = new_size;528 }529 530 return ifp->if_data;531}532 533/* Free all memory and reset a fork back to its initial state. */534void535xfs_idestroy_fork(536 struct xfs_ifork *ifp)537{538 if (ifp->if_broot != NULL) {539 kfree(ifp->if_broot);540 ifp->if_broot = NULL;541 }542 543 switch (ifp->if_format) {544 case XFS_DINODE_FMT_LOCAL:545 kfree(ifp->if_data);546 ifp->if_data = NULL;547 break;548 case XFS_DINODE_FMT_EXTENTS:549 case XFS_DINODE_FMT_BTREE:550 if (ifp->if_height)551 xfs_iext_destroy(ifp);552 break;553 }554}555 556/*557 * Convert in-core extents to on-disk form558 *559 * In the case of the data fork, the in-core and on-disk fork sizes can be560 * different due to delayed allocation extents. We only copy on-disk extents561 * here, so callers must always use the physical fork size to determine the562 * size of the buffer passed to this routine. We will return the size actually563 * used.564 */565int566xfs_iextents_copy(567 struct xfs_inode *ip,568 struct xfs_bmbt_rec *dp,569 int whichfork)570{571 int state = xfs_bmap_fork_to_state(whichfork);572 struct xfs_ifork *ifp = xfs_ifork_ptr(ip, whichfork);573 struct xfs_iext_cursor icur;574 struct xfs_bmbt_irec rec;575 int64_t copied = 0;576 577 xfs_assert_ilocked(ip, XFS_ILOCK_EXCL | XFS_ILOCK_SHARED);578 ASSERT(ifp->if_bytes > 0);579 580 for_each_xfs_iext(ifp, &icur, &rec) {581 if (isnullstartblock(rec.br_startblock))582 continue;583 ASSERT(xfs_bmap_validate_extent(ip, whichfork, &rec) == NULL);584 xfs_bmbt_disk_set_all(dp, &rec);585 trace_xfs_write_extent(ip, &icur, state, _RET_IP_);586 copied += sizeof(struct xfs_bmbt_rec);587 dp++;588 }589 590 ASSERT(copied > 0);591 ASSERT(copied <= ifp->if_bytes);592 return copied;593}594 595/*596 * Each of the following cases stores data into the same region597 * of the on-disk inode, so only one of them can be valid at598 * any given time. While it is possible to have conflicting formats599 * and log flags, e.g. having XFS_ILOG_?DATA set when the fork is600 * in EXTENTS format, this can only happen when the fork has601 * changed formats after being modified but before being flushed.602 * In these cases, the format always takes precedence, because the603 * format indicates the current state of the fork.604 */605void606xfs_iflush_fork(607 struct xfs_inode *ip,608 struct xfs_dinode *dip,609 struct xfs_inode_log_item *iip,610 int whichfork)611{612 char *cp;613 struct xfs_ifork *ifp;614 xfs_mount_t *mp;615 static const short brootflag[2] =616 { XFS_ILOG_DBROOT, XFS_ILOG_ABROOT };617 static const short dataflag[2] =618 { XFS_ILOG_DDATA, XFS_ILOG_ADATA };619 static const short extflag[2] =620 { XFS_ILOG_DEXT, XFS_ILOG_AEXT };621 622 if (!iip)623 return;624 ifp = xfs_ifork_ptr(ip, whichfork);625 /*626 * This can happen if we gave up in iformat in an error path,627 * for the attribute fork.628 */629 if (!ifp) {630 ASSERT(whichfork == XFS_ATTR_FORK);631 return;632 }633 cp = XFS_DFORK_PTR(dip, whichfork);634 mp = ip->i_mount;635 switch (ifp->if_format) {636 case XFS_DINODE_FMT_LOCAL:637 if ((iip->ili_fields & dataflag[whichfork]) &&638 (ifp->if_bytes > 0)) {639 ASSERT(ifp->if_data != NULL);640 ASSERT(ifp->if_bytes <= xfs_inode_fork_size(ip, whichfork));641 memcpy(cp, ifp->if_data, ifp->if_bytes);642 }643 break;644 645 case XFS_DINODE_FMT_EXTENTS:646 if ((iip->ili_fields & extflag[whichfork]) &&647 (ifp->if_bytes > 0)) {648 ASSERT(ifp->if_nextents > 0);649 (void)xfs_iextents_copy(ip, (xfs_bmbt_rec_t *)cp,650 whichfork);651 }652 break;653 654 case XFS_DINODE_FMT_BTREE:655 if ((iip->ili_fields & brootflag[whichfork]) &&656 (ifp->if_broot_bytes > 0)) {657 ASSERT(ifp->if_broot != NULL);658 ASSERT(xfs_bmap_bmdr_space(ifp->if_broot) <=659 xfs_inode_fork_size(ip, whichfork));660 xfs_bmbt_to_bmdr(mp, ifp->if_broot, ifp->if_broot_bytes,661 (xfs_bmdr_block_t *)cp,662 XFS_DFORK_SIZE(dip, mp, whichfork));663 }664 break;665 666 case XFS_DINODE_FMT_DEV:667 if (iip->ili_fields & XFS_ILOG_DEV) {668 ASSERT(whichfork == XFS_DATA_FORK);669 xfs_dinode_put_rdev(dip,670 linux_to_xfs_dev_t(VFS_I(ip)->i_rdev));671 }672 break;673 674 default:675 ASSERT(0);676 break;677 }678}679 680/* Convert bmap state flags to an inode fork. */681struct xfs_ifork *682xfs_iext_state_to_fork(683 struct xfs_inode *ip,684 int state)685{686 if (state & BMAP_COWFORK)687 return ip->i_cowfp;688 else if (state & BMAP_ATTRFORK)689 return &ip->i_af;690 return &ip->i_df;691}692 693/*694 * Initialize an inode's copy-on-write fork.695 */696void697xfs_ifork_init_cow(698 struct xfs_inode *ip)699{700 if (ip->i_cowfp)701 return;702 703 ip->i_cowfp = kmem_cache_zalloc(xfs_ifork_cache,704 GFP_KERNEL | __GFP_NOLOCKDEP | __GFP_NOFAIL);705 ip->i_cowfp->if_format = XFS_DINODE_FMT_EXTENTS;706}707 708/* Verify the inline contents of the data fork of an inode. */709int710xfs_ifork_verify_local_data(711 struct xfs_inode *ip)712{713 xfs_failaddr_t fa = NULL;714 715 switch (VFS_I(ip)->i_mode & S_IFMT) {716 case S_IFDIR: {717 struct xfs_mount *mp = ip->i_mount;718 struct xfs_ifork *ifp = xfs_ifork_ptr(ip, XFS_DATA_FORK);719 struct xfs_dir2_sf_hdr *sfp = ifp->if_data;720 721 fa = xfs_dir2_sf_verify(mp, sfp, ifp->if_bytes);722 break;723 }724 case S_IFLNK: {725 struct xfs_ifork *ifp = xfs_ifork_ptr(ip, XFS_DATA_FORK);726 727 fa = xfs_symlink_shortform_verify(ifp->if_data, ifp->if_bytes);728 break;729 }730 default:731 break;732 }733 734 if (fa) {735 xfs_inode_verifier_error(ip, -EFSCORRUPTED, "data fork",736 ip->i_df.if_data, ip->i_df.if_bytes, fa);737 return -EFSCORRUPTED;738 }739 740 return 0;741}742 743/* Verify the inline contents of the attr fork of an inode. */744int745xfs_ifork_verify_local_attr(746 struct xfs_inode *ip)747{748 struct xfs_ifork *ifp = &ip->i_af;749 xfs_failaddr_t fa;750 751 if (!xfs_inode_has_attr_fork(ip)) {752 fa = __this_address;753 } else {754 struct xfs_ifork *ifp = &ip->i_af;755 756 ASSERT(ifp->if_format == XFS_DINODE_FMT_LOCAL);757 fa = xfs_attr_shortform_verify(ifp->if_data, ifp->if_bytes);758 }759 if (fa) {760 xfs_inode_verifier_error(ip, -EFSCORRUPTED, "attr fork",761 ifp->if_data, ifp->if_bytes, fa);762 return -EFSCORRUPTED;763 }764 765 return 0;766}767 768/*769 * Check if the inode fork supports adding nr_to_add more extents.770 *771 * If it doesn't but we can upgrade it to large extent counters, do the upgrade.772 * If we can't upgrade or are already using big counters but still can't fit the773 * additional extents, return -EFBIG.774 */775int776xfs_iext_count_extend(777 struct xfs_trans *tp,778 struct xfs_inode *ip,779 int whichfork,780 uint nr_to_add)781{782 struct xfs_mount *mp = ip->i_mount;783 bool has_large =784 xfs_inode_has_large_extent_counts(ip);785 struct xfs_ifork *ifp = xfs_ifork_ptr(ip, whichfork);786 uint64_t nr_exts;787 788 ASSERT(nr_to_add <= XFS_MAX_EXTCNT_UPGRADE_NR);789 790 if (whichfork == XFS_COW_FORK)791 return 0;792 793 /* no point in upgrading if if_nextents overflows */794 nr_exts = ifp->if_nextents + nr_to_add;795 if (nr_exts < ifp->if_nextents)796 return -EFBIG;797 798 if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_REDUCE_MAX_IEXTENTS) &&799 nr_exts > 10)800 return -EFBIG;801 802 if (nr_exts > xfs_iext_max_nextents(has_large, whichfork)) {803 if (has_large || !xfs_has_large_extent_counts(mp))804 return -EFBIG;805 ip->i_diflags2 |= XFS_DIFLAG2_NREXT64;806 xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);807 }808 return 0;809}810 811/* Decide if a file mapping is on the realtime device or not. */812bool813xfs_ifork_is_realtime(814 struct xfs_inode *ip,815 int whichfork)816{817 return XFS_IS_REALTIME_INODE(ip) && whichfork != XFS_ATTR_FORK;818}819