396 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2000-2005 Silicon Graphics, Inc.4 * Copyright (c) 2013 Red Hat, Inc.5 * All Rights Reserved.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_bit.h"14#include "xfs_mount.h"15#include "xfs_da_format.h"16#include "xfs_da_btree.h"17#include "xfs_inode.h"18#include "xfs_attr.h"19#include "xfs_attr_remote.h"20#include "xfs_trans.h"21#include "xfs_bmap.h"22#include "xfs_attr_leaf.h"23#include "xfs_quota.h"24#include "xfs_dir2.h"25#include "xfs_error.h"26#include "xfs_health.h"27 28/*29 * Invalidate any incore buffers associated with this remote attribute value30 * extent. We never log remote attribute value buffers, which means that they31 * won't be attached to a transaction and are therefore safe to mark stale.32 * The actual bunmapi will be taken care of later.33 */34STATIC int35xfs_attr3_rmt_stale(36 struct xfs_inode *dp,37 xfs_dablk_t blkno,38 int blkcnt)39{40 struct xfs_bmbt_irec map;41 int nmap;42 int error;43 44 /*45 * Roll through the "value", invalidating the attribute value's46 * blocks.47 */48 while (blkcnt > 0) {49 /*50 * Try to remember where we decided to put the value.51 */52 nmap = 1;53 error = xfs_bmapi_read(dp, (xfs_fileoff_t)blkno, blkcnt,54 &map, &nmap, XFS_BMAPI_ATTRFORK);55 if (error)56 return error;57 if (XFS_IS_CORRUPT(dp->i_mount, nmap != 1))58 return -EFSCORRUPTED;59 60 /*61 * Mark any incore buffers for the remote value as stale. We62 * never log remote attr value buffers, so the buffer should be63 * easy to kill.64 */65 error = xfs_attr_rmtval_stale(dp, &map, 0);66 if (error)67 return error;68 69 blkno += map.br_blockcount;70 blkcnt -= map.br_blockcount;71 }72 73 return 0;74}75 76/*77 * Invalidate all of the "remote" value regions pointed to by a particular78 * leaf block.79 * Note that we must release the lock on the buffer so that we are not80 * caught holding something that the logging code wants to flush to disk.81 */82STATIC int83xfs_attr3_leaf_inactive(84 struct xfs_trans **trans,85 struct xfs_inode *dp,86 struct xfs_buf *bp)87{88 struct xfs_attr3_icleaf_hdr ichdr;89 struct xfs_mount *mp = bp->b_mount;90 struct xfs_attr_leafblock *leaf = bp->b_addr;91 struct xfs_attr_leaf_entry *entry;92 struct xfs_attr_leaf_name_remote *name_rmt;93 int error = 0;94 int i;95 96 xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, leaf);97 98 /*99 * Find the remote value extents for this leaf and invalidate their100 * incore buffers.101 */102 entry = xfs_attr3_leaf_entryp(leaf);103 for (i = 0; i < ichdr.count; entry++, i++) {104 int blkcnt;105 106 if (!entry->nameidx || (entry->flags & XFS_ATTR_LOCAL))107 continue;108 109 name_rmt = xfs_attr3_leaf_name_remote(leaf, i);110 if (!name_rmt->valueblk)111 continue;112 113 blkcnt = xfs_attr3_rmt_blocks(dp->i_mount,114 be32_to_cpu(name_rmt->valuelen));115 error = xfs_attr3_rmt_stale(dp,116 be32_to_cpu(name_rmt->valueblk), blkcnt);117 if (error)118 goto err;119 }120 121 xfs_trans_brelse(*trans, bp);122err:123 return error;124}125 126/*127 * Recurse (gasp!) through the attribute nodes until we find leaves.128 * We're doing a depth-first traversal in order to invalidate everything.129 */130STATIC int131xfs_attr3_node_inactive(132 struct xfs_trans **trans,133 struct xfs_inode *dp,134 struct xfs_buf *bp,135 int level)136{137 struct xfs_mount *mp = dp->i_mount;138 struct xfs_da_blkinfo *info;139 xfs_dablk_t child_fsb;140 xfs_daddr_t parent_blkno, child_blkno;141 struct xfs_buf *child_bp;142 struct xfs_da3_icnode_hdr ichdr;143 int error, i;144 145 /*146 * Since this code is recursive (gasp!) we must protect ourselves.147 */148 if (level > XFS_DA_NODE_MAXDEPTH) {149 xfs_buf_mark_corrupt(bp);150 xfs_trans_brelse(*trans, bp); /* no locks for later trans */151 xfs_dirattr_mark_sick(dp, XFS_ATTR_FORK);152 return -EFSCORRUPTED;153 }154 155 xfs_da3_node_hdr_from_disk(dp->i_mount, &ichdr, bp->b_addr);156 parent_blkno = xfs_buf_daddr(bp);157 if (!ichdr.count) {158 xfs_trans_brelse(*trans, bp);159 return 0;160 }161 child_fsb = be32_to_cpu(ichdr.btree[0].before);162 xfs_trans_brelse(*trans, bp); /* no locks for later trans */163 bp = NULL;164 165 /*166 * If this is the node level just above the leaves, simply loop167 * over the leaves removing all of them. If this is higher up168 * in the tree, recurse downward.169 */170 for (i = 0; i < ichdr.count; i++) {171 /*172 * Read the subsidiary block to see what we have to work with.173 * Don't do this in a transaction. This is a depth-first174 * traversal of the tree so we may deal with many blocks175 * before we come back to this one.176 */177 error = xfs_da3_node_read(*trans, dp, child_fsb, &child_bp,178 XFS_ATTR_FORK);179 if (error)180 return error;181 182 /* save for re-read later */183 child_blkno = xfs_buf_daddr(child_bp);184 185 /*186 * Invalidate the subtree, however we have to.187 */188 info = child_bp->b_addr;189 switch (info->magic) {190 case cpu_to_be16(XFS_DA_NODE_MAGIC):191 case cpu_to_be16(XFS_DA3_NODE_MAGIC):192 error = xfs_attr3_node_inactive(trans, dp, child_bp,193 level + 1);194 break;195 case cpu_to_be16(XFS_ATTR_LEAF_MAGIC):196 case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC):197 error = xfs_attr3_leaf_inactive(trans, dp, child_bp);198 break;199 default:200 xfs_buf_mark_corrupt(child_bp);201 xfs_trans_brelse(*trans, child_bp);202 xfs_dirattr_mark_sick(dp, XFS_ATTR_FORK);203 error = -EFSCORRUPTED;204 break;205 }206 if (error)207 return error;208 209 /*210 * Remove the subsidiary block from the cache and from the log.211 */212 error = xfs_trans_get_buf(*trans, mp->m_ddev_targp,213 child_blkno,214 XFS_FSB_TO_BB(mp, mp->m_attr_geo->fsbcount), 0,215 &child_bp);216 if (error)217 return error;218 xfs_trans_binval(*trans, child_bp);219 child_bp = NULL;220 221 /*222 * If we're not done, re-read the parent to get the next223 * child block number.224 */225 if (i + 1 < ichdr.count) {226 struct xfs_da3_icnode_hdr phdr;227 228 error = xfs_da3_node_read_mapped(*trans, dp,229 parent_blkno, &bp, XFS_ATTR_FORK);230 if (error)231 return error;232 xfs_da3_node_hdr_from_disk(dp->i_mount, &phdr,233 bp->b_addr);234 child_fsb = be32_to_cpu(phdr.btree[i + 1].before);235 xfs_trans_brelse(*trans, bp);236 bp = NULL;237 }238 /*239 * Atomically commit the whole invalidate stuff.240 */241 error = xfs_trans_roll_inode(trans, dp);242 if (error)243 return error;244 }245 246 return 0;247}248 249/*250 * Indiscriminately delete the entire attribute fork251 *252 * Recurse (gasp!) through the attribute nodes until we find leaves.253 * We're doing a depth-first traversal in order to invalidate everything.254 */255static int256xfs_attr3_root_inactive(257 struct xfs_trans **trans,258 struct xfs_inode *dp)259{260 struct xfs_mount *mp = dp->i_mount;261 struct xfs_da_blkinfo *info;262 struct xfs_buf *bp;263 xfs_daddr_t blkno;264 int error;265 266 /*267 * Read block 0 to see what we have to work with.268 * We only get here if we have extents, since we remove269 * the extents in reverse order the extent containing270 * block 0 must still be there.271 */272 error = xfs_da3_node_read(*trans, dp, 0, &bp, XFS_ATTR_FORK);273 if (error)274 return error;275 blkno = xfs_buf_daddr(bp);276 277 /*278 * Invalidate the tree, even if the "tree" is only a single leaf block.279 * This is a depth-first traversal!280 */281 info = bp->b_addr;282 switch (info->magic) {283 case cpu_to_be16(XFS_DA_NODE_MAGIC):284 case cpu_to_be16(XFS_DA3_NODE_MAGIC):285 error = xfs_attr3_node_inactive(trans, dp, bp, 1);286 break;287 case cpu_to_be16(XFS_ATTR_LEAF_MAGIC):288 case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC):289 error = xfs_attr3_leaf_inactive(trans, dp, bp);290 break;291 default:292 xfs_dirattr_mark_sick(dp, XFS_ATTR_FORK);293 error = -EFSCORRUPTED;294 xfs_buf_mark_corrupt(bp);295 xfs_trans_brelse(*trans, bp);296 break;297 }298 if (error)299 return error;300 301 /*302 * Invalidate the incore copy of the root block.303 */304 error = xfs_trans_get_buf(*trans, mp->m_ddev_targp, blkno,305 XFS_FSB_TO_BB(mp, mp->m_attr_geo->fsbcount), 0, &bp);306 if (error)307 return error;308 error = bp->b_error;309 if (error) {310 xfs_trans_brelse(*trans, bp);311 return error;312 }313 xfs_trans_binval(*trans, bp); /* remove from cache */314 /*315 * Commit the invalidate and start the next transaction.316 */317 error = xfs_trans_roll_inode(trans, dp);318 319 return error;320}321 322/*323 * xfs_attr_inactive kills all traces of an attribute fork on an inode. It324 * removes both the on-disk and in-memory inode fork. Note that this also has to325 * handle the condition of inodes without attributes but with an attribute fork326 * configured, so we can't use xfs_inode_hasattr() here.327 *328 * The in-memory attribute fork is removed even on error.329 */330int331xfs_attr_inactive(332 struct xfs_inode *dp)333{334 struct xfs_trans *trans;335 struct xfs_mount *mp;336 int lock_mode = XFS_ILOCK_SHARED;337 int error = 0;338 339 mp = dp->i_mount;340 341 xfs_ilock(dp, lock_mode);342 if (!xfs_inode_has_attr_fork(dp))343 goto out_destroy_fork;344 xfs_iunlock(dp, lock_mode);345 346 lock_mode = 0;347 348 error = xfs_trans_alloc(mp, &M_RES(mp)->tr_attrinval, 0, 0, 0, &trans);349 if (error)350 goto out_destroy_fork;351 352 lock_mode = XFS_ILOCK_EXCL;353 xfs_ilock(dp, lock_mode);354 355 if (!xfs_inode_has_attr_fork(dp))356 goto out_cancel;357 358 /*359 * No need to make quota reservations here. We expect to release some360 * blocks, not allocate, in the common case.361 */362 xfs_trans_ijoin(trans, dp, 0);363 364 /*365 * Invalidate and truncate the attribute fork extents. Make sure the366 * fork actually has xattr blocks as otherwise the invalidation has no367 * blocks to read and returns an error. In this case, just do the fork368 * removal below.369 */370 if (dp->i_af.if_nextents > 0) {371 error = xfs_attr3_root_inactive(&trans, dp);372 if (error)373 goto out_cancel;374 375 error = xfs_itruncate_extents(&trans, dp, XFS_ATTR_FORK, 0);376 if (error)377 goto out_cancel;378 }379 380 /* Reset the attribute fork - this also destroys the in-core fork */381 xfs_attr_fork_remove(dp, trans);382 383 error = xfs_trans_commit(trans);384 xfs_iunlock(dp, lock_mode);385 return error;386 387out_cancel:388 xfs_trans_cancel(trans);389out_destroy_fork:390 /* kill the in-core attr fork before we drop the inode lock */391 xfs_ifork_zap_attr(dp);392 if (lock_mode)393 xfs_iunlock(dp, lock_mode);394 return error;395}396