Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'xfs-merge-7.0' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux

Pull xfs updates from Carlos Maiolino:
"This contains several improvements to zoned device support,
performance improvements for the parent pointers, and a new health
monitoring feature. There are some improvements in the journaling code
too but no behavior change expected.

Last but not least, some code refactoring and bug fixes are also
included in this series"

* tag 'xfs-merge-7.0' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: (67 commits)
xfs: add sysfs stats for zoned GC
xfs: give the defer_relog stat a xs_ prefix
xfs: add zone reset error injection
xfs: refactor zone reset handling
xfs: don't mark all discard issued by zoned GC as sync
xfs: allow setting errortags at mount time
xfs: use WRITE_ONCE/READ_ONCE for m_errortag
xfs: move the guts of XFS_ERRORTAG_DELAY out of line
xfs: don't validate error tags in the I/O path
xfs: allocate m_errortag early
xfs: fix the errno sign for the xfs_errortag_{add,clearall} stubs
xfs: validate log record version against superblock log version
xfs: fix spacing style issues in xfs_alloc.c
xfs: remove xfs_zone_gc_space_available
xfs: use a seprate member to track space availabe in the GC scatch buffer
xfs: check for deleted cursors when revalidating two btrees
xfs: fix UAF in xchk_btree_check_block_owner
xfs: check return value of xchk_scrub_create_subord
xfs: only call xf{array,blob}_destroy if we have a valid pointer
xfs: get rid of the xchk_xfile_*_descr calls
...

+4257 -1344
+8
Documentation/admin-guide/xfs.rst
··· 215 215 inconsistent namespace presentation during or after a 216 216 failover event. 217 217 218 + errortag=tagname 219 + When specified, enables the error inject tag named "tagname" with the 220 + default frequency. Can be specified multiple times to enable multiple 221 + errortags. Specifying this option on remount will reset the error tag 222 + to the default value if it was set to any other value before. 223 + This option is only supported when CONFIG_XFS_DEBUG is enabled, and 224 + will not be reflected in /proc/self/mounts. 225 + 218 226 Deprecation of V4 Format 219 227 ======================== 220 228
+34
block/bio.c
··· 311 311 } 312 312 EXPORT_SYMBOL(bio_reset); 313 313 314 + /** 315 + * bio_reuse - reuse a bio with the payload left intact 316 + * @bio: bio to reuse 317 + * @opf: operation and flags for the next I/O 318 + * 319 + * Allow reusing an existing bio for another operation with all set up 320 + * fields including the payload, device and end_io handler left intact. 321 + * 322 + * Typically used when @bio is first used to read data which is then written 323 + * to another location without modification. @bio must not be in-flight and 324 + * owned by the caller. Can't be used for cloned bios. 325 + * 326 + * Note: Can't be used when @bio has integrity or blk-crypto contexts for now. 327 + * Feel free to add that support when you need it, though. 328 + */ 329 + void bio_reuse(struct bio *bio, blk_opf_t opf) 330 + { 331 + unsigned short vcnt = bio->bi_vcnt, i; 332 + bio_end_io_t *end_io = bio->bi_end_io; 333 + void *private = bio->bi_private; 334 + 335 + WARN_ON_ONCE(bio_flagged(bio, BIO_CLONED)); 336 + WARN_ON_ONCE(bio_integrity(bio)); 337 + WARN_ON_ONCE(bio_has_crypt_ctx(bio)); 338 + 339 + bio_reset(bio, bio->bi_bdev, opf); 340 + for (i = 0; i < vcnt; i++) 341 + bio->bi_iter.bi_size += bio->bi_io_vec[i].bv_len; 342 + bio->bi_vcnt = vcnt; 343 + bio->bi_private = private; 344 + bio->bi_end_io = end_io; 345 + } 346 + EXPORT_SYMBOL_GPL(bio_reuse); 347 + 314 348 static struct bio *__bio_chain_endio(struct bio *bio) 315 349 { 316 350 struct bio *parent = bio->bi_private;
+2
fs/xfs/Makefile
··· 88 88 xfs_globals.o \ 89 89 xfs_handle.o \ 90 90 xfs_health.o \ 91 + xfs_healthmon.o \ 91 92 xfs_icache.o \ 92 93 xfs_ioctl.o \ 93 94 xfs_iomap.o \ ··· 106 105 xfs_symlink.o \ 107 106 xfs_sysfs.o \ 108 107 xfs_trans.o \ 108 + xfs_verify_media.o \ 109 109 xfs_xattr.o 110 110 111 111 # low-level transaction/log code
+1 -1
fs/xfs/libxfs/xfs_ag.c
··· 5 5 * All rights reserved. 6 6 */ 7 7 8 - #include "xfs.h" 8 + #include "xfs_platform.h" 9 9 #include "xfs_fs.h" 10 10 #include "xfs_shared.h" 11 11 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_ag_resv.c
··· 3 3 * Copyright (C) 2016 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <darrick.wong@oracle.com> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+5 -5
fs/xfs/libxfs/xfs_alloc.c
··· 3 3 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_format.h" 9 9 #include "xfs_log_format.h" ··· 376 376 xfs_agblock_t freeend; /* end of freespace extent */ 377 377 xfs_agblock_t newbno1; /* return block number */ 378 378 xfs_agblock_t newbno2; /* other new block number */ 379 - xfs_extlen_t newlen1=0; /* length with newbno1 */ 380 - xfs_extlen_t newlen2=0; /* length with newbno2 */ 379 + xfs_extlen_t newlen1 = 0; /* length with newbno1 */ 380 + xfs_extlen_t newlen2 = 0; /* length with newbno2 */ 381 381 xfs_agblock_t wantend; /* end of target extent */ 382 382 bool userdata = datatype & XFS_ALLOC_USERDATA; 383 383 ··· 577 577 int i; /* operation results */ 578 578 xfs_agblock_t nfbno1; /* first new free startblock */ 579 579 xfs_agblock_t nfbno2; /* second new free startblock */ 580 - xfs_extlen_t nflen1=0; /* first new free length */ 581 - xfs_extlen_t nflen2=0; /* second new free length */ 580 + xfs_extlen_t nflen1 = 0; /* first new free length */ 581 + xfs_extlen_t nflen2 = 0; /* second new free length */ 582 582 struct xfs_mount *mp; 583 583 bool fixup_longest = false; 584 584
+1 -1
fs/xfs/libxfs/xfs_alloc_btree.c
··· 3 3 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+129 -62
fs/xfs/libxfs/xfs_attr.c
··· 3 3 * Copyright (c) 2000-2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 50 50 */ 51 51 STATIC int xfs_attr_leaf_get(xfs_da_args_t *args); 52 52 STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args); 53 - STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp); 54 53 55 54 /* 56 55 * Internal routines when attribute list is more than one block. ··· 350 351 */ 351 352 STATIC int 352 353 xfs_attr_try_sf_addname( 353 - struct xfs_inode *dp, 354 354 struct xfs_da_args *args) 355 355 { 356 - 357 356 int error; 358 357 359 358 /* 360 359 * Build initial attribute list (if required). 361 360 */ 362 - if (dp->i_af.if_format == XFS_DINODE_FMT_EXTENTS) 361 + if (args->dp->i_af.if_format == XFS_DINODE_FMT_EXTENTS) 363 362 xfs_attr_shortform_create(args); 364 363 365 364 error = xfs_attr_shortform_addname(args); ··· 369 372 * NOTE: this is also the error path (EEXIST, etc). 370 373 */ 371 374 if (!error) 372 - xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG); 375 + xfs_trans_ichgtime(args->trans, args->dp, XFS_ICHGTIME_CHG); 373 376 374 - if (xfs_has_wsync(dp->i_mount)) 377 + if (xfs_has_wsync(args->dp->i_mount)) 375 378 xfs_trans_set_sync(args->trans); 376 379 377 380 return error; ··· 382 385 struct xfs_attr_intent *attr) 383 386 { 384 387 struct xfs_da_args *args = attr->xattri_da_args; 385 - struct xfs_inode *dp = args->dp; 386 388 int error = 0; 387 389 388 - error = xfs_attr_try_sf_addname(dp, args); 390 + error = xfs_attr_try_sf_addname(args); 389 391 if (error != -ENOSPC) { 390 392 ASSERT(!error || error == -EEXIST); 391 393 attr->xattri_dela_state = XFS_DAS_DONE; ··· 975 979 return error; 976 980 977 981 if (xfs_attr_is_leaf(dp)) { 978 - error = xfs_attr_leaf_hasname(args, &bp); 979 - 980 - if (bp) 981 - xfs_trans_brelse(args->trans, bp); 982 - 982 + error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner, 983 + 0, &bp); 984 + if (error) 985 + return error; 986 + error = xfs_attr3_leaf_lookup_int(bp, args); 987 + xfs_trans_brelse(args->trans, bp); 983 988 return error; 984 989 } 985 990 ··· 1026 1029 xfs_trans_cancel(tp); 1027 1030 xfs_iunlock(ip, XFS_ILOCK_EXCL); 1028 1031 return error; 1032 + } 1033 + 1034 + /* 1035 + * Decide if it is theoretically possible to try to bypass the attr intent 1036 + * mechanism for better performance. Other constraints (e.g. available space 1037 + * in the existing structure) are not considered here. 1038 + */ 1039 + static inline bool 1040 + xfs_attr_can_shortcut( 1041 + const struct xfs_inode *ip) 1042 + { 1043 + return xfs_inode_has_attr_fork(ip) && xfs_attr_is_shortform(ip); 1044 + } 1045 + 1046 + /* Try to set an attr in one transaction or fall back to attr intents. */ 1047 + int 1048 + xfs_attr_setname( 1049 + struct xfs_da_args *args, 1050 + int rmt_blks) 1051 + { 1052 + int error; 1053 + 1054 + if (!rmt_blks && xfs_attr_can_shortcut(args->dp)) { 1055 + args->op_flags |= XFS_DA_OP_ADDNAME; 1056 + 1057 + error = xfs_attr_try_sf_addname(args); 1058 + if (error != -ENOSPC) 1059 + return error; 1060 + } 1061 + 1062 + xfs_attr_defer_add(args, XFS_ATTR_DEFER_SET); 1063 + return 0; 1064 + } 1065 + 1066 + /* Try to remove an attr in one transaction or fall back to attr intents. */ 1067 + int 1068 + xfs_attr_removename( 1069 + struct xfs_da_args *args) 1070 + { 1071 + if (xfs_attr_can_shortcut(args->dp)) 1072 + return xfs_attr_sf_removename(args); 1073 + 1074 + xfs_attr_defer_add(args, XFS_ATTR_DEFER_REMOVE); 1075 + return 0; 1076 + } 1077 + 1078 + /* Try to replace an attr in one transaction or fall back to attr intents. */ 1079 + int 1080 + xfs_attr_replacename( 1081 + struct xfs_da_args *args, 1082 + int rmt_blks) 1083 + { 1084 + int error; 1085 + 1086 + if (rmt_blks || !xfs_attr_can_shortcut(args->dp)) { 1087 + xfs_attr_defer_add(args, XFS_ATTR_DEFER_REPLACE); 1088 + return 0; 1089 + } 1090 + 1091 + error = xfs_attr_shortform_replace(args); 1092 + if (error != -ENOSPC) 1093 + return error; 1094 + 1095 + args->op_flags |= XFS_DA_OP_ADDNAME | XFS_DA_OP_REPLACE; 1096 + 1097 + error = xfs_attr_sf_removename(args); 1098 + if (error) 1099 + return error; 1100 + 1101 + if (args->attr_filter & XFS_ATTR_PARENT) { 1102 + /* 1103 + * Move the new name/value to the regular name/value slots and 1104 + * zero out the new name/value slots because we don't need to 1105 + * log them for a PPTR_SET operation. 1106 + */ 1107 + xfs_attr_update_pptr_replace_args(args); 1108 + args->new_name = NULL; 1109 + args->new_namelen = 0; 1110 + args->new_value = NULL; 1111 + args->new_valuelen = 0; 1112 + } 1113 + args->op_flags &= ~XFS_DA_OP_REPLACE; 1114 + 1115 + error = xfs_attr_try_sf_addname(args); 1116 + if (error != -ENOSPC) 1117 + return error; 1118 + 1119 + xfs_attr_defer_add(args, XFS_ATTR_DEFER_SET); 1120 + return 0; 1029 1121 } 1030 1122 1031 1123 /* ··· 1197 1111 case -EEXIST: 1198 1112 if (op == XFS_ATTRUPDATE_REMOVE) { 1199 1113 /* if no value, we are performing a remove operation */ 1200 - xfs_attr_defer_add(args, XFS_ATTR_DEFER_REMOVE); 1114 + error = xfs_attr_removename(args); 1115 + if (error) 1116 + goto out_trans_cancel; 1201 1117 break; 1202 1118 } 1203 1119 1204 1120 /* Pure create fails if the attr already exists */ 1205 1121 if (op == XFS_ATTRUPDATE_CREATE) 1206 1122 goto out_trans_cancel; 1207 - xfs_attr_defer_add(args, XFS_ATTR_DEFER_REPLACE); 1123 + 1124 + error = xfs_attr_replacename(args, rmt_blks); 1125 + if (error) 1126 + goto out_trans_cancel; 1208 1127 break; 1209 1128 case -ENOATTR: 1210 1129 /* Can't remove what isn't there. */ ··· 1219 1128 /* Pure replace fails if no existing attr to replace. */ 1220 1129 if (op == XFS_ATTRUPDATE_REPLACE) 1221 1130 goto out_trans_cancel; 1222 - xfs_attr_defer_add(args, XFS_ATTR_DEFER_SET); 1131 + 1132 + error = xfs_attr_setname(args, rmt_blks); 1133 + if (error) 1134 + goto out_trans_cancel; 1223 1135 break; 1224 1136 default: 1225 1137 goto out_trans_cancel; ··· 1317 1223 *========================================================================*/ 1318 1224 1319 1225 /* 1320 - * Return EEXIST if attr is found, or ENOATTR if not 1321 - */ 1322 - STATIC int 1323 - xfs_attr_leaf_hasname( 1324 - struct xfs_da_args *args, 1325 - struct xfs_buf **bp) 1326 - { 1327 - int error = 0; 1328 - 1329 - error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner, 0, bp); 1330 - if (error) 1331 - return error; 1332 - 1333 - error = xfs_attr3_leaf_lookup_int(*bp, args); 1334 - if (error != -ENOATTR && error != -EEXIST) 1335 - xfs_trans_brelse(args->trans, *bp); 1336 - 1337 - return error; 1338 - } 1339 - 1340 - /* 1341 1226 * Remove a name from the leaf attribute list structure 1342 1227 * 1343 1228 * This leaf block cannot have a "remote" value, we only call this routine ··· 1326 1253 xfs_attr_leaf_removename( 1327 1254 struct xfs_da_args *args) 1328 1255 { 1329 - struct xfs_inode *dp; 1330 - struct xfs_buf *bp; 1256 + struct xfs_inode *dp = args->dp; 1331 1257 int error, forkoff; 1258 + struct xfs_buf *bp; 1332 1259 1333 1260 trace_xfs_attr_leaf_removename(args); 1334 1261 1335 - /* 1336 - * Remove the attribute. 1337 - */ 1338 - dp = args->dp; 1339 - 1340 - error = xfs_attr_leaf_hasname(args, &bp); 1341 - if (error == -ENOATTR) { 1262 + error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner, 0, &bp); 1263 + if (error) 1264 + return error; 1265 + error = xfs_attr3_leaf_lookup_int(bp, args); 1266 + if (error != -EEXIST) { 1342 1267 xfs_trans_brelse(args->trans, bp); 1343 - if (args->op_flags & XFS_DA_OP_RECOVERY) 1268 + if (error == -ENOATTR && (args->op_flags & XFS_DA_OP_RECOVERY)) 1344 1269 return 0; 1345 1270 return error; 1346 - } else if (error != -EEXIST) 1347 - return error; 1271 + } 1348 1272 1349 1273 xfs_attr3_leaf_remove(bp, args); 1350 1274 ··· 1365 1295 * Returns 0 on successful retrieval, otherwise an error. 1366 1296 */ 1367 1297 STATIC int 1368 - xfs_attr_leaf_get(xfs_da_args_t *args) 1298 + xfs_attr_leaf_get( 1299 + struct xfs_da_args *args) 1369 1300 { 1370 - struct xfs_buf *bp; 1371 - int error; 1301 + struct xfs_buf *bp; 1302 + int error; 1372 1303 1373 1304 trace_xfs_attr_leaf_get(args); 1374 1305 1375 - error = xfs_attr_leaf_hasname(args, &bp); 1376 - 1377 - if (error == -ENOATTR) { 1378 - xfs_trans_brelse(args->trans, bp); 1306 + error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner, 0, &bp); 1307 + if (error) 1379 1308 return error; 1380 - } else if (error != -EEXIST) 1381 - return error; 1382 - 1383 - 1384 - error = xfs_attr3_leaf_getvalue(bp, args); 1309 + error = xfs_attr3_leaf_lookup_int(bp, args); 1310 + if (error == -EEXIST) 1311 + error = xfs_attr3_leaf_getvalue(bp, args); 1385 1312 xfs_trans_brelse(args->trans, bp); 1386 1313 return error; 1387 1314 }
+5 -1
fs/xfs/libxfs/xfs_attr.h
··· 573 573 */ 574 574 static inline bool 575 575 xfs_attr_is_shortform( 576 - struct xfs_inode *ip) 576 + const struct xfs_inode *ip) 577 577 { 578 578 return ip->i_af.if_format == XFS_DINODE_FMT_LOCAL || 579 579 (ip->i_af.if_format == XFS_DINODE_FMT_EXTENTS && ··· 648 648 649 649 int xfs_attr_sf_totsize(struct xfs_inode *dp); 650 650 int xfs_attr_add_fork(struct xfs_inode *ip, int size, int rsvd); 651 + 652 + int xfs_attr_setname(struct xfs_da_args *args, int rmt_blks); 653 + int xfs_attr_removename(struct xfs_da_args *args); 654 + int xfs_attr_replacename(struct xfs_da_args *args, int rmt_blks); 651 655 652 656 #endif /* __XFS_ATTR_H__ */
+162 -35
fs/xfs/libxfs/xfs_attr_leaf.c
··· 4 4 * Copyright (c) 2013 Red Hat, Inc. 5 5 * All Rights Reserved. 6 6 */ 7 - #include "xfs.h" 7 + #include "xfs_platform.h" 8 8 #include "xfs_fs.h" 9 9 #include "xfs_shared.h" 10 10 #include "xfs_format.h" ··· 74 74 struct xfs_attr3_icleaf_hdr *dst_ichdr, int dst_start, 75 75 int move_count); 76 76 STATIC int xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index); 77 + 78 + /* Compute the byte offset of the end of the leaf entry array. */ 79 + static inline int 80 + xfs_attr_leaf_entries_end( 81 + unsigned int hdrcount, 82 + const struct xfs_attr_leafblock *leaf) 83 + { 84 + return hdrcount * sizeof(struct xfs_attr_leaf_entry) + 85 + xfs_attr3_leaf_hdr_size(leaf); 86 + } 87 + 88 + static inline bool 89 + ichdr_freemaps_overlap( 90 + const struct xfs_attr3_icleaf_hdr *ichdr, 91 + unsigned int x, 92 + unsigned int y) 93 + { 94 + const unsigned int xend = 95 + ichdr->freemap[x].base + ichdr->freemap[x].size; 96 + const unsigned int yend = 97 + ichdr->freemap[y].base + ichdr->freemap[y].size; 98 + 99 + /* empty slots do not overlap */ 100 + if (!ichdr->freemap[x].size || !ichdr->freemap[y].size) 101 + return false; 102 + 103 + return ichdr->freemap[x].base < yend && xend > ichdr->freemap[y].base; 104 + } 105 + 106 + static inline xfs_failaddr_t 107 + xfs_attr_leaf_ichdr_freemaps_verify( 108 + const struct xfs_attr3_icleaf_hdr *ichdr, 109 + const struct xfs_attr_leafblock *leaf) 110 + { 111 + unsigned int entries_end = 112 + xfs_attr_leaf_entries_end(ichdr->count, leaf); 113 + int i; 114 + 115 + if (ichdr_freemaps_overlap(ichdr, 0, 1)) 116 + return __this_address; 117 + if (ichdr_freemaps_overlap(ichdr, 0, 2)) 118 + return __this_address; 119 + if (ichdr_freemaps_overlap(ichdr, 1, 2)) 120 + return __this_address; 121 + 122 + for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) { 123 + if (ichdr->freemap[i].size > 0 && 124 + ichdr->freemap[i].base < entries_end) 125 + return __this_address; 126 + } 127 + 128 + return NULL; 129 + } 77 130 78 131 /* 79 132 * attr3 block 'firstused' conversion helpers. ··· 271 218 hdr3->freemap[i].base = cpu_to_be16(from->freemap[i].base); 272 219 hdr3->freemap[i].size = cpu_to_be16(from->freemap[i].size); 273 220 } 221 + 222 + ASSERT(xfs_attr_leaf_ichdr_freemaps_verify(from, to) == NULL); 274 223 return; 275 224 } 276 225 to->hdr.info.forw = cpu_to_be32(from->forw); ··· 288 233 to->hdr.freemap[i].base = cpu_to_be16(from->freemap[i].base); 289 234 to->hdr.freemap[i].size = cpu_to_be16(from->freemap[i].size); 290 235 } 236 + 237 + ASSERT(xfs_attr_leaf_ichdr_freemaps_verify(from, to) == NULL); 291 238 } 292 239 293 240 static xfs_failaddr_t ··· 441 384 if (end > mp->m_attr_geo->blksize) 442 385 return __this_address; 443 386 } 387 + 388 + fa = xfs_attr_leaf_ichdr_freemaps_verify(&ichdr, leaf); 389 + if (fa) 390 + return fa; 444 391 445 392 return NULL; 446 393 } ··· 840 779 } 841 780 842 781 return NULL; 782 + } 783 + 784 + /* 785 + * Replace a shortform xattr if it's the right length. Returns 0 on success, 786 + * -ENOSPC if the length is wrong, or -ENOATTR if the attr was not found. 787 + */ 788 + int 789 + xfs_attr_shortform_replace( 790 + struct xfs_da_args *args) 791 + { 792 + struct xfs_attr_sf_entry *sfe; 793 + 794 + ASSERT(args->dp->i_af.if_format == XFS_DINODE_FMT_LOCAL); 795 + 796 + trace_xfs_attr_sf_replace(args); 797 + 798 + sfe = xfs_attr_sf_findname(args); 799 + if (!sfe) 800 + return -ENOATTR; 801 + 802 + if (args->attr_filter & XFS_ATTR_PARENT) { 803 + if (sfe->namelen != args->new_namelen || 804 + sfe->valuelen != args->new_valuelen) 805 + return -ENOSPC; 806 + 807 + memcpy(sfe->nameval, args->new_name, sfe->namelen); 808 + memcpy(&sfe->nameval[sfe->namelen], args->new_value, 809 + sfe->valuelen); 810 + } else { 811 + if (sfe->valuelen != args->valuelen) 812 + return -ENOSPC; 813 + memcpy(&sfe->nameval[sfe->namelen], args->value, 814 + sfe->valuelen); 815 + } 816 + 817 + xfs_trans_log_inode(args->trans, args->dp, 818 + XFS_ILOG_CORE | XFS_ILOG_ADATA); 819 + return 0; 843 820 } 844 821 845 822 /* ··· 1508 1409 * Search through freemap for first-fit on new name length. 1509 1410 * (may need to figure in size of entry struct too) 1510 1411 */ 1511 - tablesize = (ichdr.count + 1) * sizeof(xfs_attr_leaf_entry_t) 1512 - + xfs_attr3_leaf_hdr_size(leaf); 1412 + tablesize = xfs_attr_leaf_entries_end(ichdr.count + 1, leaf); 1513 1413 for (sum = 0, i = XFS_ATTR_LEAF_MAPSIZE - 1; i >= 0; i--) { 1514 1414 if (tablesize > ichdr.firstused) { 1515 1415 sum += ichdr.freemap[i].size; ··· 1574 1476 struct xfs_attr_leaf_name_local *name_loc; 1575 1477 struct xfs_attr_leaf_name_remote *name_rmt; 1576 1478 struct xfs_mount *mp; 1479 + int old_end, new_end; 1577 1480 int tmp; 1578 1481 int i; 1579 1482 ··· 1667 1568 if (be16_to_cpu(entry->nameidx) < ichdr->firstused) 1668 1569 ichdr->firstused = be16_to_cpu(entry->nameidx); 1669 1570 1670 - ASSERT(ichdr->firstused >= ichdr->count * sizeof(xfs_attr_leaf_entry_t) 1671 - + xfs_attr3_leaf_hdr_size(leaf)); 1672 - tmp = (ichdr->count - 1) * sizeof(xfs_attr_leaf_entry_t) 1673 - + xfs_attr3_leaf_hdr_size(leaf); 1571 + new_end = xfs_attr_leaf_entries_end(ichdr->count, leaf); 1572 + old_end = new_end - sizeof(struct xfs_attr_leaf_entry); 1573 + 1574 + ASSERT(ichdr->firstused >= new_end); 1674 1575 1675 1576 for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) { 1676 - if (ichdr->freemap[i].base == tmp) { 1677 - ichdr->freemap[i].base += sizeof(xfs_attr_leaf_entry_t); 1577 + int diff = 0; 1578 + 1579 + if (ichdr->freemap[i].base == old_end) { 1580 + /* 1581 + * This freemap entry starts at the old end of the 1582 + * leaf entry array, so we need to adjust its base 1583 + * upward to accomodate the larger array. 1584 + */ 1585 + diff = sizeof(struct xfs_attr_leaf_entry); 1586 + } else if (ichdr->freemap[i].size > 0 && 1587 + ichdr->freemap[i].base < new_end) { 1588 + /* 1589 + * This freemap entry starts in the space claimed by 1590 + * the new leaf entry. Adjust its base upward to 1591 + * reflect that. 1592 + */ 1593 + diff = new_end - ichdr->freemap[i].base; 1594 + } 1595 + 1596 + if (diff) { 1597 + ichdr->freemap[i].base += diff; 1678 1598 ichdr->freemap[i].size -= 1679 - min_t(uint16_t, ichdr->freemap[i].size, 1680 - sizeof(xfs_attr_leaf_entry_t)); 1599 + min_t(uint16_t, ichdr->freemap[i].size, diff); 1600 + } 1601 + 1602 + /* 1603 + * Don't leave zero-length freemaps with nonzero base lying 1604 + * around, because we don't want the code in _remove that 1605 + * matches on base address to get confused and create 1606 + * overlapping freemaps. If we end up with no freemap entries 1607 + * then the next _add will compact the leaf block and 1608 + * regenerate the freemaps. 1609 + */ 1610 + if (ichdr->freemap[i].size == 0 && ichdr->freemap[i].base > 0) { 1611 + ichdr->freemap[i].base = 0; 1612 + ichdr->holes = 1; 1681 1613 } 1682 1614 } 1683 1615 ichdr->usedbytes += xfs_attr_leaf_entsize(leaf, args->index); ··· 1753 1623 ichdr_dst->freemap[0].base = xfs_attr3_leaf_hdr_size(leaf_src); 1754 1624 ichdr_dst->freemap[0].size = ichdr_dst->firstused - 1755 1625 ichdr_dst->freemap[0].base; 1626 + ichdr_dst->freemap[1].base = 0; 1627 + ichdr_dst->freemap[2].base = 0; 1628 + ichdr_dst->freemap[1].size = 0; 1629 + ichdr_dst->freemap[2].size = 0; 1756 1630 1757 1631 /* write the header back to initialise the underlying buffer */ 1758 1632 xfs_attr3_leaf_hdr_to_disk(args->geo, leaf_dst, ichdr_dst); ··· 1908 1774 /* 1909 1775 * leaf2 is the destination, compact it if it looks tight. 1910 1776 */ 1911 - max = ichdr2.firstused - xfs_attr3_leaf_hdr_size(leaf1); 1912 - max -= ichdr2.count * sizeof(xfs_attr_leaf_entry_t); 1777 + max = ichdr2.firstused - 1778 + xfs_attr_leaf_entries_end(ichdr2.count, leaf1); 1913 1779 if (space > max) 1914 1780 xfs_attr3_leaf_compact(args, &ichdr2, blk2->bp); 1915 1781 ··· 1937 1803 /* 1938 1804 * leaf1 is the destination, compact it if it looks tight. 1939 1805 */ 1940 - max = ichdr1.firstused - xfs_attr3_leaf_hdr_size(leaf1); 1941 - max -= ichdr1.count * sizeof(xfs_attr_leaf_entry_t); 1806 + max = ichdr1.firstused - 1807 + xfs_attr_leaf_entries_end(ichdr1.count, leaf1); 1942 1808 if (space > max) 1943 1809 xfs_attr3_leaf_compact(args, &ichdr1, blk1->bp); 1944 1810 ··· 2144 2010 blk = &state->path.blk[ state->path.active-1 ]; 2145 2011 leaf = blk->bp->b_addr; 2146 2012 xfs_attr3_leaf_hdr_from_disk(state->args->geo, &ichdr, leaf); 2147 - bytes = xfs_attr3_leaf_hdr_size(leaf) + 2148 - ichdr.count * sizeof(xfs_attr_leaf_entry_t) + 2149 - ichdr.usedbytes; 2013 + bytes = xfs_attr_leaf_entries_end(ichdr.count, leaf) + ichdr.usedbytes; 2150 2014 if (bytes > (state->args->geo->blksize >> 1)) { 2151 2015 *action = 0; /* blk over 50%, don't try to join */ 2152 2016 return 0; ··· 2202 2070 bytes = state->args->geo->blksize - 2203 2071 (state->args->geo->blksize >> 2) - 2204 2072 ichdr.usedbytes - ichdr2.usedbytes - 2205 - ((ichdr.count + ichdr2.count) * 2206 - sizeof(xfs_attr_leaf_entry_t)) - 2207 - xfs_attr3_leaf_hdr_size(leaf); 2073 + xfs_attr_leaf_entries_end(ichdr.count + ichdr2.count, 2074 + leaf); 2208 2075 2209 2076 xfs_trans_brelse(state->args->trans, bp); 2210 2077 if (bytes >= 0) ··· 2265 2134 2266 2135 ASSERT(ichdr.count > 0 && ichdr.count < args->geo->blksize / 8); 2267 2136 ASSERT(args->index >= 0 && args->index < ichdr.count); 2268 - ASSERT(ichdr.firstused >= ichdr.count * sizeof(*entry) + 2269 - xfs_attr3_leaf_hdr_size(leaf)); 2137 + ASSERT(ichdr.firstused >= xfs_attr_leaf_entries_end(ichdr.count, leaf)); 2270 2138 2271 2139 entry = &xfs_attr3_leaf_entryp(leaf)[args->index]; 2272 2140 ··· 2278 2148 * find smallest free region in case we need to replace it, 2279 2149 * adjust any map that borders the entry table, 2280 2150 */ 2281 - tablesize = ichdr.count * sizeof(xfs_attr_leaf_entry_t) 2282 - + xfs_attr3_leaf_hdr_size(leaf); 2151 + tablesize = xfs_attr_leaf_entries_end(ichdr.count, leaf); 2283 2152 tmp = ichdr.freemap[0].size; 2284 2153 before = after = -1; 2285 2154 smallest = XFS_ATTR_LEAF_MAPSIZE - 1; ··· 2385 2256 * Check if leaf is less than 50% full, caller may want to 2386 2257 * "join" the leaf with a sibling if so. 2387 2258 */ 2388 - tmp = ichdr.usedbytes + xfs_attr3_leaf_hdr_size(leaf) + 2389 - ichdr.count * sizeof(xfs_attr_leaf_entry_t); 2259 + tmp = ichdr.usedbytes + xfs_attr_leaf_entries_end(ichdr.count, leaf); 2390 2260 2391 2261 return tmp < args->geo->magicpct; /* leaf is < 37% full */ 2392 2262 } ··· 2708 2580 ichdr_s->magic == XFS_ATTR3_LEAF_MAGIC); 2709 2581 ASSERT(ichdr_s->magic == ichdr_d->magic); 2710 2582 ASSERT(ichdr_s->count > 0 && ichdr_s->count < args->geo->blksize / 8); 2711 - ASSERT(ichdr_s->firstused >= (ichdr_s->count * sizeof(*entry_s)) 2712 - + xfs_attr3_leaf_hdr_size(leaf_s)); 2583 + ASSERT(ichdr_s->firstused >= 2584 + xfs_attr_leaf_entries_end(ichdr_s->count, leaf_s)); 2713 2585 ASSERT(ichdr_d->count < args->geo->blksize / 8); 2714 - ASSERT(ichdr_d->firstused >= (ichdr_d->count * sizeof(*entry_d)) 2715 - + xfs_attr3_leaf_hdr_size(leaf_d)); 2586 + ASSERT(ichdr_d->firstused >= 2587 + xfs_attr_leaf_entries_end(ichdr_d->count, leaf_d)); 2716 2588 2717 2589 ASSERT(start_s < ichdr_s->count); 2718 2590 ASSERT(start_d <= ichdr_d->count); ··· 2772 2644 ichdr_d->usedbytes += tmp; 2773 2645 ichdr_s->count -= 1; 2774 2646 ichdr_d->count += 1; 2775 - tmp = ichdr_d->count * sizeof(xfs_attr_leaf_entry_t) 2776 - + xfs_attr3_leaf_hdr_size(leaf_d); 2647 + tmp = xfs_attr_leaf_entries_end(ichdr_d->count, leaf_d); 2777 2648 ASSERT(ichdr_d->firstused >= tmp); 2778 2649 #ifdef GROT 2779 2650 } ··· 2808 2681 /* 2809 2682 * Fill in the freemap information 2810 2683 */ 2811 - ichdr_d->freemap[0].base = xfs_attr3_leaf_hdr_size(leaf_d); 2812 - ichdr_d->freemap[0].base += ichdr_d->count * sizeof(xfs_attr_leaf_entry_t); 2684 + ichdr_d->freemap[0].base = 2685 + xfs_attr_leaf_entries_end(ichdr_d->count, leaf_d); 2813 2686 ichdr_d->freemap[0].size = ichdr_d->firstused - ichdr_d->freemap[0].base; 2814 2687 ichdr_d->freemap[1].base = 0; 2815 2688 ichdr_d->freemap[2].base = 0;
+1
fs/xfs/libxfs/xfs_attr_leaf.h
··· 46 46 * Internal routines when attribute fork size < XFS_LITINO(mp). 47 47 */ 48 48 void xfs_attr_shortform_create(struct xfs_da_args *args); 49 + int xfs_attr_shortform_replace(struct xfs_da_args *args); 49 50 void xfs_attr_shortform_add(struct xfs_da_args *args, int forkoff); 50 51 int xfs_attr_shortform_getvalue(struct xfs_da_args *args); 51 52 int xfs_attr_shortform_to_leaf(struct xfs_da_args *args);
+1 -1
fs/xfs/libxfs/xfs_attr_remote.c
··· 4 4 * Copyright (c) 2013 Red Hat, Inc. 5 5 * All Rights Reserved. 6 6 */ 7 - #include "xfs.h" 7 + #include "xfs_platform.h" 8 8 #include "xfs_fs.h" 9 9 #include "xfs_shared.h" 10 10 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_bit.c
··· 3 3 * Copyright (c) 2000-2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_log_format.h" 8 8 #include "xfs_bit.h" 9 9
+1 -1
fs/xfs/libxfs/xfs_bmap.c
··· 3 3 * Copyright (c) 2000-2006 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_bmap_btree.c
··· 3 3 * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_btree.c
··· 3 3 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_btree_mem.c
··· 3 3 * Copyright (c) 2021-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_btree_staging.c
··· 3 3 * Copyright (C) 2020 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <darrick.wong@oracle.com> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_da_btree.c
··· 4 4 * Copyright (c) 2013 Red Hat, Inc. 5 5 * All Rights Reserved. 6 6 */ 7 - #include "xfs.h" 7 + #include "xfs_platform.h" 8 8 #include "xfs_fs.h" 9 9 #include "xfs_shared.h" 10 10 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_da_format.h
··· 746 746 #define XFS_ATTR_LEAF_NAME_ALIGN ((uint)sizeof(xfs_dablk_t)) 747 747 748 748 static inline int 749 - xfs_attr3_leaf_hdr_size(struct xfs_attr_leafblock *leafp) 749 + xfs_attr3_leaf_hdr_size(const struct xfs_attr_leafblock *leafp) 750 750 { 751 751 if (leafp->hdr.info.magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC)) 752 752 return sizeof(struct xfs_attr3_leaf_hdr);
+2 -2
fs/xfs/libxfs/xfs_defer.c
··· 3 3 * Copyright (C) 2016 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <darrick.wong@oracle.com> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 565 565 continue; 566 566 567 567 trace_xfs_defer_relog_intent((*tpp)->t_mountp, dfp); 568 - XFS_STATS_INC((*tpp)->t_mountp, defer_relog); 568 + XFS_STATS_INC((*tpp)->t_mountp, xs_defer_relog); 569 569 570 570 xfs_defer_relog_intent(*tpp, dfp); 571 571 }
+1 -1
fs/xfs/libxfs/xfs_dir2.c
··· 3 3 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_dir2_block.c
··· 4 4 * Copyright (c) 2013 Red Hat, Inc. 5 5 * All Rights Reserved. 6 6 */ 7 - #include "xfs.h" 7 + #include "xfs_platform.h" 8 8 #include "xfs_fs.h" 9 9 #include "xfs_shared.h" 10 10 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_dir2_data.c
··· 4 4 * Copyright (c) 2013 Red Hat, Inc. 5 5 * All Rights Reserved. 6 6 */ 7 - #include "xfs.h" 7 + #include "xfs_platform.h" 8 8 #include "xfs_fs.h" 9 9 #include "xfs_shared.h" 10 10 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_dir2_leaf.c
··· 4 4 * Copyright (c) 2013 Red Hat, Inc. 5 5 * All Rights Reserved. 6 6 */ 7 - #include "xfs.h" 7 + #include "xfs_platform.h" 8 8 #include "xfs_fs.h" 9 9 #include "xfs_shared.h" 10 10 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_dir2_node.c
··· 4 4 * Copyright (c) 2013 Red Hat, Inc. 5 5 * All Rights Reserved. 6 6 */ 7 - #include "xfs.h" 7 + #include "xfs_platform.h" 8 8 #include "xfs_fs.h" 9 9 #include "xfs_shared.h" 10 10 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_dir2_sf.c
··· 3 3 * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_dquot_buf.c
··· 4 4 * Copyright (c) 2013 Red Hat, Inc. 5 5 * All Rights Reserved. 6 6 */ 7 - #include "xfs.h" 7 + #include "xfs_platform.h" 8 8 #include "xfs_fs.h" 9 9 #include "xfs_shared.h" 10 10 #include "xfs_format.h"
+5 -3
fs/xfs/libxfs/xfs_errortag.h
··· 53 53 * Drop-writes support removed because write error handling cannot trash 54 54 * pre-existing delalloc extents in any useful way anymore. We retain the 55 55 * definition so that we can reject it as an invalid value in 56 - * xfs_errortag_valid(). 56 + * xfs_errortag_add(). 57 57 */ 58 58 #define XFS_ERRTAG_DROP_WRITES 28 59 59 #define XFS_ERRTAG_LOG_BAD_CRC 29 ··· 74 74 #define XFS_ERRTAG_EXCHMAPS_FINISH_ONE 44 75 75 #define XFS_ERRTAG_METAFILE_RESV_CRITICAL 45 76 76 #define XFS_ERRTAG_FORCE_ZERO_RANGE 46 77 - #define XFS_ERRTAG_MAX 47 77 + #define XFS_ERRTAG_ZONE_RESET 47 78 + #define XFS_ERRTAG_MAX 48 78 79 79 80 /* 80 81 * Random factors for above tags, 1 means always, 2 means 1/2 time, etc. ··· 136 135 XFS_ERRTAG(WRITE_DELAY_MS, write_delay_ms, 3000) \ 137 136 XFS_ERRTAG(EXCHMAPS_FINISH_ONE, exchmaps_finish_one, 1) \ 138 137 XFS_ERRTAG(METAFILE_RESV_CRITICAL, metafile_resv_crit, 4) \ 139 - XFS_ERRTAG(FORCE_ZERO_RANGE, force_zero_range, 4) 138 + XFS_ERRTAG(FORCE_ZERO_RANGE, force_zero_range, 4) \ 139 + XFS_ERRTAG(ZONE_RESET, zone_reset, 1) 140 140 #endif /* XFS_ERRTAG */ 141 141 142 142 #endif /* __XFS_ERRORTAG_H_ */
+1 -1
fs/xfs/libxfs/xfs_exchmaps.c
··· 3 3 * Copyright (c) 2020-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+189
fs/xfs/libxfs/xfs_fs.h
··· 1003 1003 #define XFS_RTGROUP_GEOM_SICK_RMAPBT (1U << 3) /* reverse mappings */ 1004 1004 #define XFS_RTGROUP_GEOM_SICK_REFCNTBT (1U << 4) /* reference counts */ 1005 1005 1006 + /* Health monitor event domains */ 1007 + 1008 + /* affects the whole fs */ 1009 + #define XFS_HEALTH_MONITOR_DOMAIN_MOUNT (0) 1010 + 1011 + /* metadata health events */ 1012 + #define XFS_HEALTH_MONITOR_DOMAIN_FS (1) 1013 + #define XFS_HEALTH_MONITOR_DOMAIN_AG (2) 1014 + #define XFS_HEALTH_MONITOR_DOMAIN_INODE (3) 1015 + #define XFS_HEALTH_MONITOR_DOMAIN_RTGROUP (4) 1016 + 1017 + /* disk events */ 1018 + #define XFS_HEALTH_MONITOR_DOMAIN_DATADEV (5) 1019 + #define XFS_HEALTH_MONITOR_DOMAIN_RTDEV (6) 1020 + #define XFS_HEALTH_MONITOR_DOMAIN_LOGDEV (7) 1021 + 1022 + /* file range events */ 1023 + #define XFS_HEALTH_MONITOR_DOMAIN_FILERANGE (8) 1024 + 1025 + /* Health monitor event types */ 1026 + 1027 + /* status of the monitor itself */ 1028 + #define XFS_HEALTH_MONITOR_TYPE_RUNNING (0) 1029 + #define XFS_HEALTH_MONITOR_TYPE_LOST (1) 1030 + 1031 + /* filesystem was unmounted */ 1032 + #define XFS_HEALTH_MONITOR_TYPE_UNMOUNT (2) 1033 + 1034 + /* metadata health events */ 1035 + #define XFS_HEALTH_MONITOR_TYPE_SICK (3) 1036 + #define XFS_HEALTH_MONITOR_TYPE_CORRUPT (4) 1037 + #define XFS_HEALTH_MONITOR_TYPE_HEALTHY (5) 1038 + 1039 + /* filesystem shutdown */ 1040 + #define XFS_HEALTH_MONITOR_TYPE_SHUTDOWN (6) 1041 + 1042 + /* media errors */ 1043 + #define XFS_HEALTH_MONITOR_TYPE_MEDIA_ERROR (7) 1044 + 1045 + /* pagecache I/O to a file range failed */ 1046 + #define XFS_HEALTH_MONITOR_TYPE_BUFREAD (8) 1047 + #define XFS_HEALTH_MONITOR_TYPE_BUFWRITE (9) 1048 + 1049 + /* direct I/O to a file range failed */ 1050 + #define XFS_HEALTH_MONITOR_TYPE_DIOREAD (10) 1051 + #define XFS_HEALTH_MONITOR_TYPE_DIOWRITE (11) 1052 + 1053 + /* out of band media error reported for a file range */ 1054 + #define XFS_HEALTH_MONITOR_TYPE_DATALOST (12) 1055 + 1056 + /* lost events */ 1057 + struct xfs_health_monitor_lost { 1058 + __u64 count; 1059 + }; 1060 + 1061 + /* fs/rt metadata */ 1062 + struct xfs_health_monitor_fs { 1063 + /* XFS_FSOP_GEOM_SICK_* flags */ 1064 + __u32 mask; 1065 + }; 1066 + 1067 + /* ag/rtgroup metadata */ 1068 + struct xfs_health_monitor_group { 1069 + /* XFS_{AG,RTGROUP}_SICK_* flags */ 1070 + __u32 mask; 1071 + __u32 gno; 1072 + }; 1073 + 1074 + /* inode metadata */ 1075 + struct xfs_health_monitor_inode { 1076 + /* XFS_BS_SICK_* flags */ 1077 + __u32 mask; 1078 + __u32 gen; 1079 + __u64 ino; 1080 + }; 1081 + 1082 + /* shutdown reasons */ 1083 + #define XFS_HEALTH_SHUTDOWN_META_IO_ERROR (1u << 0) 1084 + #define XFS_HEALTH_SHUTDOWN_LOG_IO_ERROR (1u << 1) 1085 + #define XFS_HEALTH_SHUTDOWN_FORCE_UMOUNT (1u << 2) 1086 + #define XFS_HEALTH_SHUTDOWN_CORRUPT_INCORE (1u << 3) 1087 + #define XFS_HEALTH_SHUTDOWN_CORRUPT_ONDISK (1u << 4) 1088 + #define XFS_HEALTH_SHUTDOWN_DEVICE_REMOVED (1u << 5) 1089 + 1090 + /* shutdown */ 1091 + struct xfs_health_monitor_shutdown { 1092 + /* XFS_HEALTH_SHUTDOWN_* flags */ 1093 + __u32 reasons; 1094 + }; 1095 + 1096 + /* file range events */ 1097 + struct xfs_health_monitor_filerange { 1098 + __u64 pos; 1099 + __u64 len; 1100 + __u64 ino; 1101 + __u32 gen; 1102 + __u32 error; 1103 + }; 1104 + 1105 + /* disk media errors */ 1106 + struct xfs_health_monitor_media { 1107 + __u64 daddr; 1108 + __u64 bbcount; 1109 + }; 1110 + 1111 + struct xfs_health_monitor_event { 1112 + /* XFS_HEALTH_MONITOR_DOMAIN_* */ 1113 + __u32 domain; 1114 + 1115 + /* XFS_HEALTH_MONITOR_TYPE_* */ 1116 + __u32 type; 1117 + 1118 + /* Timestamp of the event, in nanoseconds since the Unix epoch */ 1119 + __u64 time_ns; 1120 + 1121 + /* 1122 + * Details of the event. The primary clients are written in python 1123 + * and rust, so break this up because bindgen hates anonymous structs 1124 + * and unions. 1125 + */ 1126 + union { 1127 + struct xfs_health_monitor_lost lost; 1128 + struct xfs_health_monitor_fs fs; 1129 + struct xfs_health_monitor_group group; 1130 + struct xfs_health_monitor_inode inode; 1131 + struct xfs_health_monitor_shutdown shutdown; 1132 + struct xfs_health_monitor_media media; 1133 + struct xfs_health_monitor_filerange filerange; 1134 + } e; 1135 + 1136 + /* zeroes */ 1137 + __u64 pad[2]; 1138 + }; 1139 + 1140 + struct xfs_health_monitor { 1141 + __u64 flags; /* flags */ 1142 + __u8 format; /* output format */ 1143 + __u8 pad[23]; /* zeroes */ 1144 + }; 1145 + 1146 + /* Return all health status events, not just deltas */ 1147 + #define XFS_HEALTH_MONITOR_VERBOSE (1ULL << 0) 1148 + 1149 + #define XFS_HEALTH_MONITOR_ALL (XFS_HEALTH_MONITOR_VERBOSE) 1150 + 1151 + /* Initial return format version */ 1152 + #define XFS_HEALTH_MONITOR_FMT_V0 (0) 1153 + 1154 + /* 1155 + * Check that a given fd points to the same filesystem that the health monitor 1156 + * is monitoring. 1157 + */ 1158 + struct xfs_health_file_on_monitored_fs { 1159 + __s32 fd; 1160 + __u32 flags; /* zero for now */ 1161 + }; 1162 + 1163 + /* Verify the media of the underlying devices */ 1164 + struct xfs_verify_media { 1165 + __u32 me_dev; /* I: XFS_DEV_{DATA,LOG,RT} */ 1166 + __u32 me_flags; /* I: XFS_VERIFY_MEDIA_* */ 1167 + 1168 + /* 1169 + * IO: inclusive start of disk range to verify, in 512b blocks. 1170 + * Will be adjusted upwards as media verification succeeds. 1171 + */ 1172 + __u64 me_start_daddr; 1173 + 1174 + /* 1175 + * IO: exclusive end of the disk range to verify, in 512b blocks. 1176 + * Can be adjusted downwards to match device size. 1177 + */ 1178 + __u64 me_end_daddr; 1179 + 1180 + __u32 me_ioerror; /* O: I/O error (positive) */ 1181 + __u32 me_max_io_size; /* I: maximum IO size in bytes */ 1182 + 1183 + __u32 me_rest_us; /* I: rest time between IOs, usecs */ 1184 + __u32 me_pad; /* zero */ 1185 + }; 1186 + 1187 + #define XFS_VERIFY_MEDIA_REPORT (1 << 0) /* report to fsnotify */ 1188 + 1189 + #define XFS_VERIFY_MEDIA_FLAGS (XFS_VERIFY_MEDIA_REPORT) 1190 + 1006 1191 /* 1007 1192 * ioctl commands that are used by Linux filesystems 1008 1193 */ ··· 1227 1042 #define XFS_IOC_GETPARENTS_BY_HANDLE _IOWR('X', 63, struct xfs_getparents_by_handle) 1228 1043 #define XFS_IOC_SCRUBV_METADATA _IOWR('X', 64, struct xfs_scrub_vec_head) 1229 1044 #define XFS_IOC_RTGROUP_GEOMETRY _IOWR('X', 65, struct xfs_rtgroup_geometry) 1045 + #define XFS_IOC_HEALTH_MONITOR _IOW ('X', 68, struct xfs_health_monitor) 1046 + #define XFS_IOC_HEALTH_FD_ON_MONITORED_FS \ 1047 + _IOW ('X', 69, struct xfs_health_file_on_monitored_fs) 1048 + #define XFS_IOC_VERIFY_MEDIA _IOWR('X', 70, struct xfs_verify_media) 1230 1049 1231 1050 /* 1232 1051 * ioctl commands that replace IRIX syssgi()'s
+1 -1
fs/xfs/libxfs/xfs_group.c
··· 3 3 * Copyright (c) 2018 Red Hat, Inc. 4 4 */ 5 5 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_shared.h" 8 8 #include "xfs_format.h" 9 9 #include "xfs_trans_resv.h"
+5
fs/xfs/libxfs/xfs_health.h
··· 289 289 #define xfs_metadata_is_sick(error) \ 290 290 (unlikely((error) == -EFSCORRUPTED || (error) == -EFSBADCRC)) 291 291 292 + unsigned int xfs_healthmon_inode_mask(unsigned int sick_mask); 293 + unsigned int xfs_healthmon_rtgroup_mask(unsigned int sick_mask); 294 + unsigned int xfs_healthmon_perag_mask(unsigned int sick_mask); 295 + unsigned int xfs_healthmon_fs_mask(unsigned int sick_mask); 296 + 292 297 #endif /* __XFS_HEALTH_H__ */
+1 -1
fs/xfs/libxfs/xfs_ialloc.c
··· 3 3 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_ialloc_btree.c
··· 3 3 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_iext_tree.c
··· 3 3 * Copyright (c) 2017 Christoph Hellwig. 4 4 */ 5 5 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_shared.h" 8 8 #include "xfs_format.h" 9 9 #include "xfs_bit.h"
+1 -1
fs/xfs/libxfs/xfs_inode_buf.c
··· 3 3 * Copyright (c) 2000-2006 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_inode_fork.c
··· 4 4 * All Rights Reserved. 5 5 */ 6 6 7 - #include "xfs.h" 7 + #include "xfs_platform.h" 8 8 #include "xfs_fs.h" 9 9 #include "xfs_shared.h" 10 10 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_inode_util.c
··· 4 4 * All Rights Reserved. 5 5 */ 6 6 #include <linux/iversion.h> 7 - #include "xfs.h" 7 + #include "xfs_platform.h" 8 8 #include "xfs_fs.h" 9 9 #include "xfs_shared.h" 10 10 #include "xfs_format.h"
-7
fs/xfs/libxfs/xfs_log_format.h
··· 184 184 #define XLOG_REC_SIZE_OTHER offsetofend(struct xlog_rec_header, h_size) 185 185 #endif /* __i386__ */ 186 186 187 - /* not an on-disk structure, but needed by log recovery in userspace */ 188 - struct xfs_log_iovec { 189 - void *i_addr; /* beginning address of region */ 190 - int i_len; /* length in bytes of region */ 191 - uint i_type; /* type of region */ 192 - }; 193 - 194 187 /* 195 188 * Transaction Header definitions. 196 189 *
+1 -1
fs/xfs/libxfs/xfs_log_rlimit.c
··· 3 3 * Copyright (c) 2013 Jie Liu. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_metadir.c
··· 3 3 * Copyright (c) 2018-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_metafile.c
··· 3 3 * Copyright (c) 2018-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+9 -7
fs/xfs/libxfs/xfs_parent.c
··· 3 3 * Copyright (c) 2022-2024 Oracle. 4 4 * All rights reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_format.h" 9 9 #include "xfs_da_format.h" ··· 29 29 #include "xfs_trans_space.h" 30 30 #include "xfs_attr_item.h" 31 31 #include "xfs_health.h" 32 + #include "xfs_attr_leaf.h" 32 33 33 34 struct kmem_cache *xfs_parent_args_cache; 34 35 ··· 203 202 xfs_inode_to_parent_rec(&ppargs->rec, dp); 204 203 xfs_parent_da_args_init(&ppargs->args, tp, &ppargs->rec, child, 205 204 child->i_ino, parent_name); 206 - xfs_attr_defer_add(&ppargs->args, XFS_ATTR_DEFER_SET); 207 - return 0; 205 + 206 + return xfs_attr_setname(&ppargs->args, 0); 208 207 } 209 208 210 209 /* Remove a parent pointer to reflect a dirent removal. */ ··· 225 224 xfs_inode_to_parent_rec(&ppargs->rec, dp); 226 225 xfs_parent_da_args_init(&ppargs->args, tp, &ppargs->rec, child, 227 226 child->i_ino, parent_name); 228 - xfs_attr_defer_add(&ppargs->args, XFS_ATTR_DEFER_REMOVE); 229 - return 0; 227 + 228 + return xfs_attr_removename(&ppargs->args); 230 229 } 231 230 232 231 /* Replace one parent pointer with another to reflect a rename. */ ··· 251 250 child->i_ino, old_name); 252 251 253 252 xfs_inode_to_parent_rec(&ppargs->new_rec, new_dp); 253 + 254 254 ppargs->args.new_name = new_name->name; 255 255 ppargs->args.new_namelen = new_name->len; 256 256 ppargs->args.new_value = &ppargs->new_rec; 257 257 ppargs->args.new_valuelen = sizeof(struct xfs_parent_rec); 258 - xfs_attr_defer_add(&ppargs->args, XFS_ATTR_DEFER_REPLACE); 259 - return 0; 258 + 259 + return xfs_attr_replacename(&ppargs->args, 0); 260 260 } 261 261 262 262 /*
+1 -1
fs/xfs/libxfs/xfs_refcount.c
··· 3 3 * Copyright (C) 2016 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <darrick.wong@oracle.com> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_refcount_btree.c
··· 3 3 * Copyright (C) 2016 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <darrick.wong@oracle.com> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_rmap.c
··· 3 3 * Copyright (c) 2014 Red Hat, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_rmap_btree.c
··· 3 3 * Copyright (c) 2014 Red Hat, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_rtbitmap.c
··· 3 3 * Copyright (c) 2000-2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_rtgroup.c
··· 3 3 * Copyright (c) 2022-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+15
fs/xfs/libxfs/xfs_rtgroup.h
··· 371 371 return xfs_groups_to_rfsbs(mp, nr_groups, XG_TYPE_RTG); 372 372 } 373 373 374 + /* 375 + * Return the "raw" size of a group on the hardware device. This includes the 376 + * daddr gaps present for XFS_SB_FEAT_INCOMPAT_ZONE_GAPS file systems. 377 + */ 378 + static inline xfs_rgblock_t 379 + xfs_rtgroup_raw_size( 380 + struct xfs_mount *mp) 381 + { 382 + struct xfs_groups *g = &mp->m_groups[XG_TYPE_RTG]; 383 + 384 + if (g->has_daddr_gaps) 385 + return 1U << g->blklog; 386 + return g->blocks; 387 + } 388 + 374 389 #endif /* __LIBXFS_RTGROUP_H */
+1 -1
fs/xfs/libxfs/xfs_rtrefcount_btree.c
··· 3 3 * Copyright (c) 2021-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_rtrmap_btree.c
··· 3 3 * Copyright (c) 2018-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_sb.c
··· 3 3 * Copyright (c) 2000-2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_trans_inode.c
··· 3 3 * Copyright (c) 2000,2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_trans_resv.c
··· 4 4 * Copyright (C) 2010 Red Hat, Inc. 5 5 * All Rights Reserved. 6 6 */ 7 - #include "xfs.h" 7 + #include "xfs_platform.h" 8 8 #include "xfs_fs.h" 9 9 #include "xfs_shared.h" 10 10 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_trans_space.c
··· 3 3 * Copyright (c) 2000,2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/libxfs/xfs_types.c
··· 4 4 * Copyright (C) 2017 Oracle. 5 5 * All Rights Reserved. 6 6 */ 7 - #include "xfs.h" 7 + #include "xfs_platform.h" 8 8 #include "xfs_fs.h" 9 9 #include "xfs_format.h" 10 10 #include "xfs_shared.h"
+40 -111
fs/xfs/libxfs/xfs_zones.c
··· 3 3 * Copyright (c) 2023-2025 Christoph Hellwig. 4 4 * Copyright (c) 2024-2025, Western Digital Corporation or its affiliates. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 15 15 #include "xfs_zones.h" 16 16 17 17 static bool 18 - xfs_zone_validate_empty( 18 + xfs_validate_blk_zone_seq( 19 + struct xfs_mount *mp, 19 20 struct blk_zone *zone, 20 - struct xfs_rtgroup *rtg, 21 + unsigned int zone_no, 21 22 xfs_rgblock_t *write_pointer) 22 23 { 23 - struct xfs_mount *mp = rtg_mount(rtg); 24 - 25 - if (rtg_rmap(rtg)->i_used_blocks > 0) { 26 - xfs_warn(mp, "empty zone %u has non-zero used counter (0x%x).", 27 - rtg_rgno(rtg), rtg_rmap(rtg)->i_used_blocks); 28 - return false; 29 - } 30 - 31 - *write_pointer = 0; 32 - return true; 33 - } 34 - 35 - static bool 36 - xfs_zone_validate_wp( 37 - struct blk_zone *zone, 38 - struct xfs_rtgroup *rtg, 39 - xfs_rgblock_t *write_pointer) 40 - { 41 - struct xfs_mount *mp = rtg_mount(rtg); 42 - xfs_rtblock_t wp_fsb = xfs_daddr_to_rtb(mp, zone->wp); 43 - 44 - if (rtg_rmap(rtg)->i_used_blocks > rtg->rtg_extents) { 45 - xfs_warn(mp, "zone %u has too large used counter (0x%x).", 46 - rtg_rgno(rtg), rtg_rmap(rtg)->i_used_blocks); 47 - return false; 48 - } 49 - 50 - if (xfs_rtb_to_rgno(mp, wp_fsb) != rtg_rgno(rtg)) { 51 - xfs_warn(mp, "zone %u write pointer (0x%llx) outside of zone.", 52 - rtg_rgno(rtg), wp_fsb); 53 - return false; 54 - } 55 - 56 - *write_pointer = xfs_rtb_to_rgbno(mp, wp_fsb); 57 - if (*write_pointer >= rtg->rtg_extents) { 58 - xfs_warn(mp, "zone %u has invalid write pointer (0x%x).", 59 - rtg_rgno(rtg), *write_pointer); 60 - return false; 61 - } 62 - 63 - return true; 64 - } 65 - 66 - static bool 67 - xfs_zone_validate_full( 68 - struct blk_zone *zone, 69 - struct xfs_rtgroup *rtg, 70 - xfs_rgblock_t *write_pointer) 71 - { 72 - struct xfs_mount *mp = rtg_mount(rtg); 73 - 74 - if (rtg_rmap(rtg)->i_used_blocks > rtg->rtg_extents) { 75 - xfs_warn(mp, "zone %u has too large used counter (0x%x).", 76 - rtg_rgno(rtg), rtg_rmap(rtg)->i_used_blocks); 77 - return false; 78 - } 79 - 80 - *write_pointer = rtg->rtg_extents; 81 - return true; 82 - } 83 - 84 - static bool 85 - xfs_zone_validate_seq( 86 - struct blk_zone *zone, 87 - struct xfs_rtgroup *rtg, 88 - xfs_rgblock_t *write_pointer) 89 - { 90 - struct xfs_mount *mp = rtg_mount(rtg); 91 - 92 24 switch (zone->cond) { 93 25 case BLK_ZONE_COND_EMPTY: 94 - return xfs_zone_validate_empty(zone, rtg, write_pointer); 26 + *write_pointer = 0; 27 + return true; 95 28 case BLK_ZONE_COND_IMP_OPEN: 96 29 case BLK_ZONE_COND_EXP_OPEN: 97 30 case BLK_ZONE_COND_CLOSED: 98 31 case BLK_ZONE_COND_ACTIVE: 99 - return xfs_zone_validate_wp(zone, rtg, write_pointer); 32 + if (zone->wp < zone->start || 33 + zone->wp >= zone->start + zone->capacity) { 34 + xfs_warn(mp, 35 + "zone %u write pointer (%llu) outside of zone.", 36 + zone_no, zone->wp); 37 + return false; 38 + } 39 + 40 + *write_pointer = XFS_BB_TO_FSB(mp, zone->wp - zone->start); 41 + return true; 100 42 case BLK_ZONE_COND_FULL: 101 - return xfs_zone_validate_full(zone, rtg, write_pointer); 43 + *write_pointer = XFS_BB_TO_FSB(mp, zone->capacity); 44 + return true; 102 45 case BLK_ZONE_COND_NOT_WP: 103 46 case BLK_ZONE_COND_OFFLINE: 104 47 case BLK_ZONE_COND_READONLY: 105 48 xfs_warn(mp, "zone %u has unsupported zone condition 0x%x.", 106 - rtg_rgno(rtg), zone->cond); 49 + zone_no, zone->cond); 107 50 return false; 108 51 default: 109 52 xfs_warn(mp, "zone %u has unknown zone condition 0x%x.", 110 - rtg_rgno(rtg), zone->cond); 53 + zone_no, zone->cond); 111 54 return false; 112 55 } 113 56 } 114 57 115 58 static bool 116 - xfs_zone_validate_conv( 59 + xfs_validate_blk_zone_conv( 60 + struct xfs_mount *mp, 117 61 struct blk_zone *zone, 118 - struct xfs_rtgroup *rtg) 62 + unsigned int zone_no) 119 63 { 120 - struct xfs_mount *mp = rtg_mount(rtg); 121 - 122 64 switch (zone->cond) { 123 65 case BLK_ZONE_COND_NOT_WP: 124 66 return true; 125 67 default: 126 68 xfs_warn(mp, 127 69 "conventional zone %u has unsupported zone condition 0x%x.", 128 - rtg_rgno(rtg), zone->cond); 70 + zone_no, zone->cond); 129 71 return false; 130 72 } 131 73 } 132 74 133 75 bool 134 - xfs_zone_validate( 76 + xfs_validate_blk_zone( 77 + struct xfs_mount *mp, 135 78 struct blk_zone *zone, 136 - struct xfs_rtgroup *rtg, 79 + unsigned int zone_no, 80 + uint32_t expected_size, 81 + uint32_t expected_capacity, 137 82 xfs_rgblock_t *write_pointer) 138 83 { 139 - struct xfs_mount *mp = rtg_mount(rtg); 140 - struct xfs_groups *g = &mp->m_groups[XG_TYPE_RTG]; 141 - uint32_t expected_size; 142 - 143 84 /* 144 85 * Check that the zone capacity matches the rtgroup size stored in the 145 86 * superblock. Note that all zones including the last one must have a 146 87 * uniform capacity. 147 88 */ 148 - if (XFS_BB_TO_FSB(mp, zone->capacity) != g->blocks) { 89 + if (XFS_BB_TO_FSB(mp, zone->capacity) != expected_capacity) { 149 90 xfs_warn(mp, 150 - "zone %u capacity (0x%llx) does not match RT group size (0x%x).", 151 - rtg_rgno(rtg), XFS_BB_TO_FSB(mp, zone->capacity), 152 - g->blocks); 91 + "zone %u capacity (%llu) does not match RT group size (%u).", 92 + zone_no, XFS_BB_TO_FSB(mp, zone->capacity), 93 + expected_capacity); 153 94 return false; 154 - } 155 - 156 - if (g->has_daddr_gaps) { 157 - expected_size = 1 << g->blklog; 158 - } else { 159 - if (zone->len != zone->capacity) { 160 - xfs_warn(mp, 161 - "zone %u has capacity != size ((0x%llx vs 0x%llx)", 162 - rtg_rgno(rtg), 163 - XFS_BB_TO_FSB(mp, zone->len), 164 - XFS_BB_TO_FSB(mp, zone->capacity)); 165 - return false; 166 - } 167 - expected_size = g->blocks; 168 95 } 169 96 170 97 if (XFS_BB_TO_FSB(mp, zone->len) != expected_size) { 171 98 xfs_warn(mp, 172 - "zone %u length (0x%llx) does match geometry (0x%x).", 173 - rtg_rgno(rtg), XFS_BB_TO_FSB(mp, zone->len), 99 + "zone %u length (%llu) does not match geometry (%u).", 100 + zone_no, XFS_BB_TO_FSB(mp, zone->len), 174 101 expected_size); 102 + return false; 175 103 } 176 104 177 105 switch (zone->type) { 178 106 case BLK_ZONE_TYPE_CONVENTIONAL: 179 - return xfs_zone_validate_conv(zone, rtg); 107 + return xfs_validate_blk_zone_conv(mp, zone, zone_no); 180 108 case BLK_ZONE_TYPE_SEQWRITE_REQ: 181 - return xfs_zone_validate_seq(zone, rtg, write_pointer); 109 + return xfs_validate_blk_zone_seq(mp, zone, zone_no, 110 + write_pointer); 182 111 default: 183 112 xfs_warn(mp, "zoned %u has unsupported type 0x%x.", 184 - rtg_rgno(rtg), zone->type); 113 + zone_no, zone->type); 185 114 return false; 186 115 } 187 116 }
+4 -2
fs/xfs/libxfs/xfs_zones.h
··· 3 3 #define _LIBXFS_ZONES_H 4 4 5 5 struct xfs_rtgroup; 6 + struct blk_zone; 6 7 7 8 /* 8 9 * In order to guarantee forward progress for GC we need to reserve at least ··· 37 36 */ 38 37 #define XFS_DEFAULT_MAX_OPEN_ZONES 128 39 38 40 - bool xfs_zone_validate(struct blk_zone *zone, struct xfs_rtgroup *rtg, 41 - xfs_rgblock_t *write_pointer); 39 + bool xfs_validate_blk_zone(struct xfs_mount *mp, struct blk_zone *zone, 40 + unsigned int zone_no, uint32_t expected_size, 41 + uint32_t expected_capacity, xfs_rgblock_t *write_pointer); 42 42 43 43 #endif /* _LIBXFS_ZONES_H */
+1 -1
fs/xfs/scrub/agb_bitmap.c
··· 3 3 * Copyright (C) 2018-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_shared.h" 8 8 #include "xfs_bit.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/scrub/agheader.c
··· 3 3 * Copyright (C) 2017-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+11 -12
fs/xfs/scrub/agheader_repair.c
··· 3 3 * Copyright (C) 2018-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 837 837 { 838 838 struct xrep_agi *ragi = buf; 839 839 840 - xfarray_destroy(ragi->iunlink_prev); 841 - xfarray_destroy(ragi->iunlink_next); 840 + if (ragi->iunlink_prev) 841 + xfarray_destroy(ragi->iunlink_prev); 842 + ragi->iunlink_prev = NULL; 843 + if (ragi->iunlink_next) 844 + xfarray_destroy(ragi->iunlink_next); 845 + ragi->iunlink_next = NULL; 842 846 xagino_bitmap_destroy(&ragi->iunlink_bmp); 843 847 } 844 848 ··· 1712 1708 { 1713 1709 struct xrep_agi *ragi; 1714 1710 struct xfs_mount *mp = sc->mp; 1715 - char *descr; 1716 1711 unsigned int i; 1717 1712 int error; 1718 1713 ··· 1745 1742 xagino_bitmap_init(&ragi->iunlink_bmp); 1746 1743 sc->buf_cleanup = xrep_agi_buf_cleanup; 1747 1744 1748 - descr = xchk_xfile_ag_descr(sc, "iunlinked next pointers"); 1749 - error = xfarray_create(descr, 0, sizeof(xfs_agino_t), 1750 - &ragi->iunlink_next); 1751 - kfree(descr); 1745 + error = xfarray_create("iunlinked next pointers", 0, 1746 + sizeof(xfs_agino_t), &ragi->iunlink_next); 1752 1747 if (error) 1753 1748 return error; 1754 1749 1755 - descr = xchk_xfile_ag_descr(sc, "iunlinked prev pointers"); 1756 - error = xfarray_create(descr, 0, sizeof(xfs_agino_t), 1757 - &ragi->iunlink_prev); 1758 - kfree(descr); 1750 + error = xfarray_create("iunlinked prev pointers", 0, 1751 + sizeof(xfs_agino_t), &ragi->iunlink_prev); 1759 1752 if (error) 1760 1753 return error; 1761 1754
+1 -1
fs/xfs/scrub/alloc.c
··· 3 3 * Copyright (C) 2017-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+17 -5
fs/xfs/scrub/alloc_repair.c
··· 3 3 * Copyright (C) 2018-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 850 850 struct xrep_abt *ra; 851 851 struct xfs_mount *mp = sc->mp; 852 852 unsigned int busy_gen; 853 - char *descr; 854 853 int error; 855 854 856 855 /* We require the rmapbt to rebuild anything. */ ··· 875 876 } 876 877 877 878 /* Set up enough storage to handle maximally fragmented free space. */ 878 - descr = xchk_xfile_ag_descr(sc, "free space records"); 879 - error = xfarray_create(descr, mp->m_sb.sb_agblocks / 2, 879 + error = xfarray_create("free space records", mp->m_sb.sb_agblocks / 2, 880 880 sizeof(struct xfs_alloc_rec_incore), 881 881 &ra->free_records); 882 - kfree(descr); 883 882 if (error) 884 883 goto out_ra; 885 884 ··· 923 926 if (error) 924 927 goto out; 925 928 929 + /* 930 + * If the bnobt is still corrupt, we've failed to repair the filesystem 931 + * and should just bail out. 932 + * 933 + * If the bnobt fails cross-examination with the cntbt, the scan will 934 + * free the cntbt cursor, so we need to mark the repair incomplete 935 + * and avoid walking off the end of the NULL cntbt cursor. 936 + */ 937 + if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 938 + goto out; 939 + 926 940 sc->sm->sm_type = XFS_SCRUB_TYPE_CNTBT; 941 + if (!sc->sa.cnt_cur) { 942 + xchk_set_incomplete(sc); 943 + goto out; 944 + } 927 945 error = xchk_allocbt(sc); 928 946 out: 929 947 sc->sm->sm_type = old_type;
+32 -29
fs/xfs/scrub/attr.c
··· 3 3 * Copyright (C) 2017-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 288 288 } 289 289 290 290 /* 291 - * Check the leaf freemap from the usage bitmap. Returns false if the 292 - * attr freemap has problems or points to used space. 293 - */ 294 - STATIC bool 295 - xchk_xattr_check_freemap( 296 - struct xfs_scrub *sc, 297 - struct xfs_attr3_icleaf_hdr *leafhdr) 298 - { 299 - struct xchk_xattr_buf *ab = sc->buf; 300 - unsigned int mapsize = sc->mp->m_attr_geo->blksize; 301 - int i; 302 - 303 - /* Construct bitmap of freemap contents. */ 304 - bitmap_zero(ab->freemap, mapsize); 305 - for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) { 306 - if (!xchk_xattr_set_map(sc, ab->freemap, 307 - leafhdr->freemap[i].base, 308 - leafhdr->freemap[i].size)) 309 - return false; 310 - } 311 - 312 - /* Look for bits that are set in freemap and are marked in use. */ 313 - return !bitmap_intersects(ab->freemap, ab->usedmap, mapsize); 314 - } 315 - 316 - /* 317 291 * Check this leaf entry's relations to everything else. 318 292 * Returns the number of bytes used for the name/value data. 319 293 */ ··· 338 364 rentry = xfs_attr3_leaf_name_remote(leaf, idx); 339 365 namesize = xfs_attr_leaf_entsize_remote(rentry->namelen); 340 366 name_end = (char *)rentry + namesize; 341 - if (rentry->namelen == 0 || rentry->valueblk == 0) 367 + if (rentry->namelen == 0) 368 + xchk_da_set_corrupt(ds, level); 369 + if (rentry->valueblk == 0 && 370 + !(ent->flags & XFS_ATTR_INCOMPLETE)) 342 371 xchk_da_set_corrupt(ds, level); 343 372 } 344 373 if (name_end > buf_end) ··· 380 403 381 404 *last_checked = blk->blkno; 382 405 bitmap_zero(ab->usedmap, mp->m_attr_geo->blksize); 406 + bitmap_zero(ab->freemap, mp->m_attr_geo->blksize); 383 407 384 408 /* Check all the padding. */ 385 409 if (xfs_has_crc(ds->sc->mp)) { ··· 427 449 if ((char *)&entries[leafhdr.count] > (char *)leaf + leafhdr.firstused) 428 450 xchk_da_set_corrupt(ds, level); 429 451 452 + if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 453 + goto out; 454 + 430 455 buf_end = (char *)bp->b_addr + mp->m_attr_geo->blksize; 431 456 for (i = 0, ent = entries; i < leafhdr.count; ent++, i++) { 432 457 /* Mark the leaf entry itself. */ ··· 448 467 goto out; 449 468 } 450 469 451 - if (!xchk_xattr_check_freemap(ds->sc, &leafhdr)) 470 + /* Construct bitmap of freemap contents. */ 471 + for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) { 472 + if (!xchk_xattr_set_map(ds->sc, ab->freemap, 473 + leafhdr.freemap[i].base, 474 + leafhdr.freemap[i].size)) 475 + xchk_da_set_corrupt(ds, level); 476 + 477 + /* 478 + * freemap entries with zero length and nonzero base can cause 479 + * problems with older kernels, so we mark these for preening 480 + * even though there's no inconsistency. 481 + */ 482 + if (leafhdr.freemap[i].size == 0 && 483 + leafhdr.freemap[i].base > 0) 484 + xchk_da_set_preen(ds, level); 485 + 486 + if (ds->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 487 + goto out; 488 + } 489 + 490 + /* Look for bits that are set in freemap and are marked in use. */ 491 + if (bitmap_intersects(ab->freemap, ab->usedmap, 492 + mp->m_attr_geo->blksize)) 452 493 xchk_da_set_corrupt(ds, level); 453 494 454 495 if (leafhdr.usedbytes != usedbytes)
+10 -18
fs/xfs/scrub/attr_repair.c
··· 3 3 * Copyright (c) 2018-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 1516 1516 xfblob_destroy(rx->pptr_names); 1517 1517 if (rx->pptr_recs) 1518 1518 xfarray_destroy(rx->pptr_recs); 1519 - xfblob_destroy(rx->xattr_blobs); 1520 - xfarray_destroy(rx->xattr_records); 1519 + if (rx->xattr_blobs) 1520 + xfblob_destroy(rx->xattr_blobs); 1521 + if (rx->xattr_records) 1522 + xfarray_destroy(rx->xattr_records); 1521 1523 mutex_destroy(&rx->lock); 1522 1524 kfree(rx); 1523 1525 } ··· 1531 1529 struct xrep_xattr **rxp) 1532 1530 { 1533 1531 struct xrep_xattr *rx; 1534 - char *descr; 1535 1532 int max_len; 1536 1533 int error; 1537 1534 ··· 1556 1555 goto out_rx; 1557 1556 1558 1557 /* Set up some staging for salvaged attribute keys and values */ 1559 - descr = xchk_xfile_ino_descr(sc, "xattr keys"); 1560 - error = xfarray_create(descr, 0, sizeof(struct xrep_xattr_key), 1558 + error = xfarray_create("xattr keys", 0, sizeof(struct xrep_xattr_key), 1561 1559 &rx->xattr_records); 1562 - kfree(descr); 1563 1560 if (error) 1564 1561 goto out_rx; 1565 1562 1566 - descr = xchk_xfile_ino_descr(sc, "xattr names"); 1567 - error = xfblob_create(descr, &rx->xattr_blobs); 1568 - kfree(descr); 1563 + error = xfblob_create("xattr names", &rx->xattr_blobs); 1569 1564 if (error) 1570 1565 goto out_keys; 1571 1566 1572 1567 if (xfs_has_parent(sc->mp)) { 1573 1568 ASSERT(sc->flags & XCHK_FSGATES_DIRENTS); 1574 1569 1575 - descr = xchk_xfile_ino_descr(sc, 1576 - "xattr retained parent pointer entries"); 1577 - error = xfarray_create(descr, 0, 1570 + error = xfarray_create("xattr parent pointer entries", 0, 1578 1571 sizeof(struct xrep_xattr_pptr), 1579 1572 &rx->pptr_recs); 1580 - kfree(descr); 1581 1573 if (error) 1582 1574 goto out_values; 1583 1575 1584 - descr = xchk_xfile_ino_descr(sc, 1585 - "xattr retained parent pointer names"); 1586 - error = xfblob_create(descr, &rx->pptr_names); 1587 - kfree(descr); 1576 + error = xfblob_create("xattr parent pointer names", 1577 + &rx->pptr_names); 1588 1578 if (error) 1589 1579 goto out_pprecs; 1590 1580
+1 -1
fs/xfs/scrub/bitmap.c
··· 3 3 * Copyright (C) 2018-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_bit.h"
+1 -1
fs/xfs/scrub/bmap.c
··· 3 3 * Copyright (C) 2017-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+2 -6
fs/xfs/scrub/bmap_repair.c
··· 3 3 * Copyright (C) 2018-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 923 923 bool allow_unwritten) 924 924 { 925 925 struct xrep_bmap *rb; 926 - char *descr; 927 926 xfs_extnum_t max_bmbt_recs; 928 927 bool large_extcount; 929 928 int error = 0; ··· 944 945 /* Set up enough storage to handle the max records for this fork. */ 945 946 large_extcount = xfs_has_large_extent_counts(sc->mp); 946 947 max_bmbt_recs = xfs_iext_max_nextents(large_extcount, whichfork); 947 - descr = xchk_xfile_ino_descr(sc, "%s fork mapping records", 948 - whichfork == XFS_DATA_FORK ? "data" : "attr"); 949 - error = xfarray_create(descr, max_bmbt_recs, 948 + error = xfarray_create("fork mapping records", max_bmbt_recs, 950 949 sizeof(struct xfs_bmbt_rec), &rb->bmap_records); 951 - kfree(descr); 952 950 if (error) 953 951 goto out_rb; 954 952
+8 -3
fs/xfs/scrub/btree.c
··· 3 3 * Copyright (C) 2017-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 42 42 break; 43 43 case -EFSBADCRC: 44 44 case -EFSCORRUPTED: 45 + case -EIO: 46 + case -ENODATA: 45 47 /* Note the badness but don't abort. */ 46 48 sc->sm->sm_flags |= errflag; 47 49 *error = 0; ··· 372 370 { 373 371 xfs_agnumber_t agno; 374 372 xfs_agblock_t agbno; 373 + bool is_bnobt, is_rmapbt; 375 374 bool init_sa; 376 375 int error = 0; 377 376 378 377 if (!bs->cur) 379 378 return 0; 380 379 380 + is_bnobt = xfs_btree_is_bno(bs->cur->bc_ops); 381 + is_rmapbt = xfs_btree_is_rmap(bs->cur->bc_ops); 381 382 agno = xfs_daddr_to_agno(bs->cur->bc_mp, daddr); 382 383 agbno = xfs_daddr_to_agbno(bs->cur->bc_mp, daddr); 383 384 ··· 403 398 * have to nullify it (to shut down further block owner checks) if 404 399 * self-xref encounters problems. 405 400 */ 406 - if (!bs->sc->sa.bno_cur && xfs_btree_is_bno(bs->cur->bc_ops)) 401 + if (!bs->sc->sa.bno_cur && is_bnobt) 407 402 bs->cur = NULL; 408 403 409 404 xchk_xref_is_only_owned_by(bs->sc, agbno, 1, bs->oinfo); 410 - if (!bs->sc->sa.rmap_cur && xfs_btree_is_rmap(bs->cur->bc_ops)) 405 + if (!bs->sc->sa.rmap_cur && is_rmapbt) 411 406 bs->cur = NULL; 412 407 413 408 out_free:
+8 -1
fs/xfs/scrub/common.c
··· 3 3 * Copyright (C) 2017-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 103 103 break; 104 104 case -EFSBADCRC: 105 105 case -EFSCORRUPTED: 106 + case -EIO: 107 + case -ENODATA: 106 108 /* Note the badness but don't abort. */ 107 109 sc->sm->sm_flags |= errflag; 108 110 *error = 0; ··· 179 177 break; 180 178 case -EFSBADCRC: 181 179 case -EFSCORRUPTED: 180 + case -EIO: 181 + case -ENODATA: 182 182 /* Note the badness but don't abort. */ 183 183 sc->sm->sm_flags |= errflag; 184 184 *error = 0; ··· 1399 1395 int error; 1400 1396 1401 1397 sub = xchk_scrub_create_subord(sc, scrub_type); 1398 + if (!sub) 1399 + return -ENOMEM; 1400 + 1402 1401 error = sub->sc.ops->scrub(&sub->sc); 1403 1402 xchk_scrub_free_subord(sub); 1404 1403 return error;
-25
fs/xfs/scrub/common.h
··· 247 247 int xchk_metadata_inode_forks(struct xfs_scrub *sc); 248 248 249 249 /* 250 - * Helper macros to allocate and format xfile description strings. 251 - * Callers must kfree the pointer returned. 252 - */ 253 - #define xchk_xfile_descr(sc, fmt, ...) \ 254 - kasprintf(XCHK_GFP_FLAGS, "XFS (%s): " fmt, \ 255 - (sc)->mp->m_super->s_id, ##__VA_ARGS__) 256 - #define xchk_xfile_ag_descr(sc, fmt, ...) \ 257 - kasprintf(XCHK_GFP_FLAGS, "XFS (%s): AG 0x%x " fmt, \ 258 - (sc)->mp->m_super->s_id, \ 259 - (sc)->sa.pag ? \ 260 - pag_agno((sc)->sa.pag) : (sc)->sm->sm_agno, \ 261 - ##__VA_ARGS__) 262 - #define xchk_xfile_ino_descr(sc, fmt, ...) \ 263 - kasprintf(XCHK_GFP_FLAGS, "XFS (%s): inode 0x%llx " fmt, \ 264 - (sc)->mp->m_super->s_id, \ 265 - (sc)->ip ? (sc)->ip->i_ino : (sc)->sm->sm_ino, \ 266 - ##__VA_ARGS__) 267 - #define xchk_xfile_rtgroup_descr(sc, fmt, ...) \ 268 - kasprintf(XCHK_GFP_FLAGS, "XFS (%s): rtgroup 0x%x " fmt, \ 269 - (sc)->mp->m_super->s_id, \ 270 - (sc)->sa.pag ? \ 271 - rtg_rgno((sc)->sr.rtg) : (sc)->sm->sm_agno, \ 272 - ##__VA_ARGS__) 273 - 274 - /* 275 250 * Setting up a hook to wait for intents to drain is costly -- we have to take 276 251 * the CPU hotplug lock and force an i-cache flush on all CPUs once to set it 277 252 * up, and again to tear it down. These costs add up quickly, so we only want
+1 -1
fs/xfs/scrub/cow_repair.c
··· 3 3 * Copyright (C) 2022-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+3 -1
fs/xfs/scrub/dabtree.c
··· 3 3 * Copyright (C) 2017-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 45 45 break; 46 46 case -EFSBADCRC: 47 47 case -EFSCORRUPTED: 48 + case -EIO: 49 + case -ENODATA: 48 50 /* Note the badness but don't abort. */ 49 51 sc->sm->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT; 50 52 *error = 0;
+5 -10
fs/xfs/scrub/dir.c
··· 3 3 * Copyright (C) 2017-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 1102 1102 sd->xname.name = sd->namebuf; 1103 1103 1104 1104 if (xfs_has_parent(sc->mp)) { 1105 - char *descr; 1106 - 1107 1105 /* 1108 1106 * Set up some staging memory for dirents that we can't check 1109 1107 * due to locking contention. 1110 1108 */ 1111 - descr = xchk_xfile_ino_descr(sc, "slow directory entries"); 1112 - error = xfarray_create(descr, 0, sizeof(struct xchk_dirent), 1113 - &sd->dir_entries); 1114 - kfree(descr); 1109 + error = xfarray_create("slow directory entries", 0, 1110 + sizeof(struct xchk_dirent), &sd->dir_entries); 1115 1111 if (error) 1116 1112 goto out_sd; 1117 1113 1118 - descr = xchk_xfile_ino_descr(sc, "slow directory entry names"); 1119 - error = xfblob_create(descr, &sd->dir_names); 1120 - kfree(descr); 1114 + error = xfblob_create("slow directory entry names", 1115 + &sd->dir_names); 1121 1116 if (error) 1122 1117 goto out_entries; 1123 1118 }
+10 -11
fs/xfs/scrub/dir_repair.c
··· 3 3 * Copyright (c) 2020-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 172 172 struct xrep_dir *rd = sc->buf; 173 173 174 174 xrep_findparent_scan_teardown(&rd->pscan); 175 - xfblob_destroy(rd->dir_names); 176 - xfarray_destroy(rd->dir_entries); 175 + if (rd->dir_names) 176 + xfblob_destroy(rd->dir_names); 177 + rd->dir_names = NULL; 178 + if (rd->dir_entries) 179 + xfarray_destroy(rd->dir_entries); 180 + rd->dir_names = NULL; 177 181 } 178 182 179 183 /* Set up for a directory repair. */ ··· 1788 1784 struct xrep_dir *rd) 1789 1785 { 1790 1786 struct xfs_scrub *sc = rd->sc; 1791 - char *descr; 1792 1787 int error; 1793 1788 1794 1789 /* Set up some staging memory for salvaging dirents. */ 1795 - descr = xchk_xfile_ino_descr(sc, "directory entries"); 1796 - error = xfarray_create(descr, 0, sizeof(struct xrep_dirent), 1797 - &rd->dir_entries); 1798 - kfree(descr); 1790 + error = xfarray_create("directory entries", 0, 1791 + sizeof(struct xrep_dirent), &rd->dir_entries); 1799 1792 if (error) 1800 1793 return error; 1801 1794 1802 - descr = xchk_xfile_ino_descr(sc, "directory entry names"); 1803 - error = xfblob_create(descr, &rd->dir_names); 1804 - kfree(descr); 1795 + error = xfblob_create("directory entry names", &rd->dir_names); 1805 1796 if (error) 1806 1797 goto out_xfarray; 1807 1798
+10 -11
fs/xfs/scrub/dirtree.c
··· 3 3 * Copyright (c) 2023-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 81 81 kfree(path); 82 82 } 83 83 84 - xfblob_destroy(dl->path_names); 85 - xfarray_destroy(dl->path_steps); 84 + if (dl->path_names) 85 + xfblob_destroy(dl->path_names); 86 + dl->path_names = NULL; 87 + if (dl->path_steps) 88 + xfarray_destroy(dl->path_steps); 89 + dl->path_steps = NULL; 86 90 mutex_destroy(&dl->lock); 87 91 } 88 92 ··· 96 92 struct xfs_scrub *sc) 97 93 { 98 94 struct xchk_dirtree *dl; 99 - char *descr; 100 95 int error; 101 96 102 97 xchk_fsgates_enable(sc, XCHK_FSGATES_DIRENTS); ··· 119 116 120 117 mutex_init(&dl->lock); 121 118 122 - descr = xchk_xfile_ino_descr(sc, "dirtree path steps"); 123 - error = xfarray_create(descr, 0, sizeof(struct xchk_dirpath_step), 124 - &dl->path_steps); 125 - kfree(descr); 119 + error = xfarray_create("dirtree path steps", 0, 120 + sizeof(struct xchk_dirpath_step), &dl->path_steps); 126 121 if (error) 127 122 goto out_dl; 128 123 129 - descr = xchk_xfile_ino_descr(sc, "dirtree path names"); 130 - error = xfblob_create(descr, &dl->path_names); 131 - kfree(descr); 124 + error = xfblob_create("dirtree path names", &dl->path_names); 132 125 if (error) 133 126 goto out_steps; 134 127
+1 -1
fs/xfs/scrub/dirtree_repair.c
··· 3 3 * Copyright (c) 2023-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/scrub/dqiterate.c
··· 3 3 * Copyright (C) 2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_bit.h"
+1 -1
fs/xfs/scrub/findparent.c
··· 3 3 * Copyright (c) 2020-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/scrub/fscounters.c
··· 3 3 * Copyright (C) 2019-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/scrub/fscounters_repair.c
··· 3 3 * Copyright (c) 2018-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/scrub/health.c
··· 3 3 * Copyright (C) 2019-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/scrub/ialloc.c
··· 3 3 * Copyright (C) 2017-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+19 -8
fs/xfs/scrub/ialloc_repair.c
··· 3 3 * Copyright (C) 2018-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 797 797 { 798 798 struct xrep_ibt *ri; 799 799 struct xfs_mount *mp = sc->mp; 800 - char *descr; 801 800 xfs_agino_t first_agino, last_agino; 802 801 int error = 0; 803 802 ··· 815 816 /* Set up enough storage to handle an AG with nothing but inodes. */ 816 817 xfs_agino_range(mp, pag_agno(sc->sa.pag), &first_agino, &last_agino); 817 818 last_agino /= XFS_INODES_PER_CHUNK; 818 - descr = xchk_xfile_ag_descr(sc, "inode index records"); 819 - error = xfarray_create(descr, last_agino, 819 + error = xfarray_create("inode index records", last_agino, 820 820 sizeof(struct xfs_inobt_rec_incore), 821 821 &ri->inode_records); 822 - kfree(descr); 823 822 if (error) 824 823 goto out_ri; 825 824 ··· 863 866 if (error) 864 867 goto out; 865 868 866 - if (xfs_has_finobt(sc->mp)) { 867 - sc->sm->sm_type = XFS_SCRUB_TYPE_FINOBT; 868 - error = xchk_iallocbt(sc); 869 + /* 870 + * If the inobt is still corrupt, we've failed to repair the filesystem 871 + * and should just bail out. 872 + * 873 + * If the inobt fails cross-examination with the finobt, the scan will 874 + * free the finobt cursor, so we need to mark the repair incomplete 875 + * and avoid walking off the end of the NULL finobt cursor. 876 + */ 877 + if (!xfs_has_finobt(sc->mp) || 878 + (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)) 879 + goto out; 880 + 881 + sc->sm->sm_type = XFS_SCRUB_TYPE_FINOBT; 882 + if (!sc->sa.fino_cur) { 883 + xchk_set_incomplete(sc); 884 + goto out; 869 885 } 886 + error = xchk_iallocbt(sc); 870 887 871 888 out: 872 889 sc->sm->sm_type = old_type;
+1 -1
fs/xfs/scrub/inode.c
··· 3 3 * Copyright (C) 2017-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/scrub/inode_repair.c
··· 3 3 * Copyright (C) 2018-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/scrub/iscan.c
··· 3 3 * Copyright (c) 2021-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/scrub/listxattr.c
··· 3 3 * Copyright (c) 2022-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/scrub/metapath.c
··· 3 3 * Copyright (c) 2023-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/scrub/newbt.c
··· 3 3 * Copyright (C) 2022-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+5 -6
fs/xfs/scrub/nlinks.c
··· 3 3 * Copyright (c) 2021-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 971 971 972 972 xfs_dir_hook_del(xnc->sc->mp, &xnc->dhook); 973 973 974 - xfarray_destroy(xnc->nlinks); 974 + if (xnc->nlinks) 975 + xfarray_destroy(xnc->nlinks); 975 976 xnc->nlinks = NULL; 976 977 977 978 xchk_iscan_teardown(&xnc->collect_iscan); ··· 991 990 struct xchk_nlink_ctrs *xnc) 992 991 { 993 992 struct xfs_mount *mp = sc->mp; 994 - char *descr; 995 993 unsigned long long max_inos; 996 994 xfs_agnumber_t last_agno = mp->m_sb.sb_agcount - 1; 997 995 xfs_agino_t first_agino, last_agino; ··· 1007 1007 */ 1008 1008 xfs_agino_range(mp, last_agno, &first_agino, &last_agino); 1009 1009 max_inos = XFS_AGINO_TO_INO(mp, last_agno, last_agino) + 1; 1010 - descr = xchk_xfile_descr(sc, "file link counts"); 1011 - error = xfarray_create(descr, min(XFS_MAXINUMBER + 1, max_inos), 1010 + error = xfarray_create("file link counts", 1011 + min(XFS_MAXINUMBER + 1, max_inos), 1012 1012 sizeof(struct xchk_nlink), &xnc->nlinks); 1013 - kfree(descr); 1014 1013 if (error) 1015 1014 goto out_teardown; 1016 1015
+1 -1
fs/xfs/scrub/orphanage.c
··· 3 3 * Copyright (c) 2021-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+4 -9
fs/xfs/scrub/parent.c
··· 3 3 * Copyright (C) 2017-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 755 755 struct xfs_scrub *sc) 756 756 { 757 757 struct xchk_pptrs *pp; 758 - char *descr; 759 758 int error; 760 759 761 760 pp = kvzalloc(sizeof(struct xchk_pptrs), XCHK_GFP_FLAGS); ··· 767 768 * Set up some staging memory for parent pointers that we can't check 768 769 * due to locking contention. 769 770 */ 770 - descr = xchk_xfile_ino_descr(sc, "slow parent pointer entries"); 771 - error = xfarray_create(descr, 0, sizeof(struct xchk_pptr), 772 - &pp->pptr_entries); 773 - kfree(descr); 771 + error = xfarray_create("slow parent pointer entries", 0, 772 + sizeof(struct xchk_pptr), &pp->pptr_entries); 774 773 if (error) 775 774 goto out_pp; 776 775 777 - descr = xchk_xfile_ino_descr(sc, "slow parent pointer names"); 778 - error = xfblob_create(descr, &pp->pptr_names); 779 - kfree(descr); 776 + error = xfblob_create("slow parent pointer names", &pp->pptr_names); 780 777 if (error) 781 778 goto out_entries; 782 779
+7 -18
fs/xfs/scrub/parent_repair.c
··· 3 3 * Copyright (c) 2020-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 1497 1497 struct xrep_parent *rp) 1498 1498 { 1499 1499 struct xfs_scrub *sc = rp->sc; 1500 - char *descr; 1501 1500 struct xfs_da_geometry *geo = sc->mp->m_attr_geo; 1502 1501 int max_len; 1503 1502 int error; ··· 1524 1525 goto out_xattr_name; 1525 1526 1526 1527 /* Set up some staging memory for logging parent pointer updates. */ 1527 - descr = xchk_xfile_ino_descr(sc, "parent pointer entries"); 1528 - error = xfarray_create(descr, 0, sizeof(struct xrep_pptr), 1529 - &rp->pptr_recs); 1530 - kfree(descr); 1528 + error = xfarray_create("parent pointer entries", 0, 1529 + sizeof(struct xrep_pptr), &rp->pptr_recs); 1531 1530 if (error) 1532 1531 goto out_xattr_value; 1533 1532 1534 - descr = xchk_xfile_ino_descr(sc, "parent pointer names"); 1535 - error = xfblob_create(descr, &rp->pptr_names); 1536 - kfree(descr); 1533 + error = xfblob_create("parent pointer names", &rp->pptr_names); 1537 1534 if (error) 1538 1535 goto out_recs; 1539 1536 1540 1537 /* Set up some storage for copying attrs before the mapping exchange */ 1541 - descr = xchk_xfile_ino_descr(sc, 1542 - "parent pointer retained xattr entries"); 1543 - error = xfarray_create(descr, 0, sizeof(struct xrep_parent_xattr), 1544 - &rp->xattr_records); 1545 - kfree(descr); 1538 + error = xfarray_create("parent pointer xattr entries", 0, 1539 + sizeof(struct xrep_parent_xattr), &rp->xattr_records); 1546 1540 if (error) 1547 1541 goto out_names; 1548 1542 1549 - descr = xchk_xfile_ino_descr(sc, 1550 - "parent pointer retained xattr values"); 1551 - error = xfblob_create(descr, &rp->xattr_blobs); 1552 - kfree(descr); 1543 + error = xfblob_create("parent pointer xattr values", &rp->xattr_blobs); 1553 1544 if (error) 1554 1545 goto out_attr_keys; 1555 1546
+1 -1
fs/xfs/scrub/quota.c
··· 3 3 * Copyright (C) 2017-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_bit.h"
+1 -1
fs/xfs/scrub/quota_repair.c
··· 3 3 * Copyright (C) 2018-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+4 -11
fs/xfs/scrub/quotacheck.c
··· 3 3 * Copyright (c) 2020-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 741 741 struct xfs_scrub *sc, 742 742 struct xqcheck *xqc) 743 743 { 744 - char *descr; 745 744 struct xfs_quotainfo *qi = sc->mp->m_quotainfo; 746 745 unsigned long long max_dquots = XFS_DQ_ID_MAX + 1ULL; 747 746 int error; ··· 755 756 756 757 error = -ENOMEM; 757 758 if (xfs_this_quota_on(sc->mp, XFS_DQTYPE_USER)) { 758 - descr = xchk_xfile_descr(sc, "user dquot records"); 759 - error = xfarray_create(descr, max_dquots, 759 + error = xfarray_create("user dquot records", max_dquots, 760 760 sizeof(struct xqcheck_dquot), &xqc->ucounts); 761 - kfree(descr); 762 761 if (error) 763 762 goto out_teardown; 764 763 } 765 764 766 765 if (xfs_this_quota_on(sc->mp, XFS_DQTYPE_GROUP)) { 767 - descr = xchk_xfile_descr(sc, "group dquot records"); 768 - error = xfarray_create(descr, max_dquots, 766 + error = xfarray_create("group dquot records", max_dquots, 769 767 sizeof(struct xqcheck_dquot), &xqc->gcounts); 770 - kfree(descr); 771 768 if (error) 772 769 goto out_teardown; 773 770 } 774 771 775 772 if (xfs_this_quota_on(sc->mp, XFS_DQTYPE_PROJ)) { 776 - descr = xchk_xfile_descr(sc, "project dquot records"); 777 - error = xfarray_create(descr, max_dquots, 773 + error = xfarray_create("project dquot records", max_dquots, 778 774 sizeof(struct xqcheck_dquot), &xqc->pcounts); 779 - kfree(descr); 780 775 if (error) 781 776 goto out_teardown; 782 777 }
+1 -1
fs/xfs/scrub/quotacheck_repair.c
··· 3 3 * Copyright (c) 2020-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/scrub/rcbag.c
··· 3 3 * Copyright (c) 2022-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/scrub/rcbag_btree.c
··· 3 3 * Copyright (c) 2022-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/scrub/readdir.c
··· 3 3 * Copyright (C) 2022-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/scrub/reap.c
··· 3 3 * Copyright (C) 2022-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/scrub/refcount.c
··· 3 3 * Copyright (C) 2017-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+3 -12
fs/xfs/scrub/refcount_repair.c
··· 3 3 * Copyright (C) 2018-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 123 123 xrep_setup_ag_refcountbt( 124 124 struct xfs_scrub *sc) 125 125 { 126 - char *descr; 127 - int error; 128 - 129 - descr = xchk_xfile_ag_descr(sc, "rmap record bag"); 130 - error = xrep_setup_xfbtree(sc, descr); 131 - kfree(descr); 132 - return error; 126 + return xrep_setup_xfbtree(sc, "rmap record bag"); 133 127 } 134 128 135 129 /* Check for any obvious conflicts with this shared/CoW staging extent. */ ··· 698 704 { 699 705 struct xrep_refc *rr; 700 706 struct xfs_mount *mp = sc->mp; 701 - char *descr; 702 707 int error; 703 708 704 709 /* We require the rmapbt to rebuild anything. */ ··· 710 717 rr->sc = sc; 711 718 712 719 /* Set up enough storage to handle one refcount record per block. */ 713 - descr = xchk_xfile_ag_descr(sc, "reference count records"); 714 - error = xfarray_create(descr, mp->m_sb.sb_agblocks, 720 + error = xfarray_create("reference count records", mp->m_sb.sb_agblocks, 715 721 sizeof(struct xfs_refcount_irec), 716 722 &rr->refcount_records); 717 - kfree(descr); 718 723 if (error) 719 724 goto out_rr; 720 725
+4 -1
fs/xfs/scrub/repair.c
··· 3 3 * Copyright (C) 2018-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 1136 1136 * setup/teardown routines. 1137 1137 */ 1138 1138 sub = xchk_scrub_create_subord(sc, scrub_type); 1139 + if (!sub) 1140 + return -ENOMEM; 1141 + 1139 1142 error = sub->sc.ops->scrub(&sub->sc); 1140 1143 if (error) 1141 1144 goto out;
+1 -1
fs/xfs/scrub/rgsuper.c
··· 3 3 * Copyright (c) 2022-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/scrub/rmap.c
··· 3 3 * Copyright (C) 2017-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+2 -5
fs/xfs/scrub/rmap_repair.c
··· 3 3 * Copyright (c) 2018-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 164 164 struct xfs_scrub *sc) 165 165 { 166 166 struct xrep_rmap *rr; 167 - char *descr; 168 167 int error; 169 168 170 169 xchk_fsgates_enable(sc, XCHK_FSGATES_RMAP); 171 170 172 - descr = xchk_xfile_ag_descr(sc, "reverse mapping records"); 173 - error = xrep_setup_xfbtree(sc, descr); 174 - kfree(descr); 171 + error = xrep_setup_xfbtree(sc, "reverse mapping records"); 175 172 if (error) 176 173 return error; 177 174
+1 -1
fs/xfs/scrub/rtbitmap.c
··· 3 3 * Copyright (C) 2017-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+3 -5
fs/xfs/scrub/rtbitmap_repair.c
··· 3 3 * Copyright (C) 2020-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 43 43 struct xchk_rtbitmap *rtb) 44 44 { 45 45 struct xfs_mount *mp = sc->mp; 46 - char *descr; 47 46 unsigned long long blocks = mp->m_sb.sb_rbmblocks; 48 47 int error; 49 48 ··· 51 52 return error; 52 53 53 54 /* Create an xfile to hold our reconstructed bitmap. */ 54 - descr = xchk_xfile_rtgroup_descr(sc, "bitmap file"); 55 - error = xfile_create(descr, blocks * mp->m_sb.sb_blocksize, &sc->xfile); 56 - kfree(descr); 55 + error = xfile_create("realtime bitmap file", 56 + blocks * mp->m_sb.sb_blocksize, &sc->xfile); 57 57 if (error) 58 58 return error; 59 59
+1 -1
fs/xfs/scrub/rtrefcount.c
··· 3 3 * Copyright (c) 2021-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+4 -13
fs/xfs/scrub/rtrefcount_repair.c
··· 3 3 * Copyright (c) 2021-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 128 128 xrep_setup_rtrefcountbt( 129 129 struct xfs_scrub *sc) 130 130 { 131 - char *descr; 132 - int error; 133 - 134 - descr = xchk_xfile_ag_descr(sc, "rmap record bag"); 135 - error = xrep_setup_xfbtree(sc, descr); 136 - kfree(descr); 137 - return error; 131 + return xrep_setup_xfbtree(sc, "realtime rmap record bag"); 138 132 } 139 133 140 134 /* Check for any obvious conflicts with this shared/CoW staging extent. */ ··· 698 704 { 699 705 struct xrep_rtrefc *rr; 700 706 struct xfs_mount *mp = sc->mp; 701 - char *descr; 702 707 int error; 703 708 704 709 /* We require the rmapbt to rebuild anything. */ ··· 715 722 rr->sc = sc; 716 723 717 724 /* Set up enough storage to handle one refcount record per rt extent. */ 718 - descr = xchk_xfile_ag_descr(sc, "reference count records"); 719 - error = xfarray_create(descr, mp->m_sb.sb_rextents, 720 - sizeof(struct xfs_refcount_irec), 725 + error = xfarray_create("realtime reference count records", 726 + mp->m_sb.sb_rextents, sizeof(struct xfs_refcount_irec), 721 727 &rr->refcount_records); 722 - kfree(descr); 723 728 if (error) 724 729 goto out_rr; 725 730
+1 -1
fs/xfs/scrub/rtrmap.c
··· 3 3 * Copyright (c) 2018-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+2 -5
fs/xfs/scrub/rtrmap_repair.c
··· 3 3 * Copyright (c) 2020-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 103 103 struct xfs_scrub *sc) 104 104 { 105 105 struct xrep_rtrmap *rr; 106 - char *descr; 107 106 int error; 108 107 109 108 xchk_fsgates_enable(sc, XCHK_FSGATES_RMAP); 110 109 111 - descr = xchk_xfile_rtgroup_descr(sc, "reverse mapping records"); 112 - error = xrep_setup_xfbtree(sc, descr); 113 - kfree(descr); 110 + error = xrep_setup_xfbtree(sc, "realtime reverse mapping records"); 114 111 if (error) 115 112 return error; 116 113
+3 -6
fs/xfs/scrub/rtsummary.c
··· 3 3 * Copyright (C) 2017-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 43 43 struct xfs_scrub *sc) 44 44 { 45 45 struct xfs_mount *mp = sc->mp; 46 - char *descr; 47 46 struct xchk_rtsummary *rts; 48 47 int error; 49 48 ··· 69 70 * Create an xfile to construct a new rtsummary file. The xfile allows 70 71 * us to avoid pinning kernel memory for this purpose. 71 72 */ 72 - descr = xchk_xfile_descr(sc, "realtime summary file"); 73 - error = xfile_create(descr, XFS_FSB_TO_B(mp, mp->m_rsumblocks), 74 - &sc->xfile); 75 - kfree(descr); 73 + error = xfile_create("realtime summary file", 74 + XFS_FSB_TO_B(mp, mp->m_rsumblocks), &sc->xfile); 76 75 if (error) 77 76 return error; 78 77
+1 -1
fs/xfs/scrub/rtsummary_repair.c
··· 3 3 * Copyright (c) 2020-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+2 -2
fs/xfs/scrub/scrub.c
··· 3 3 * Copyright (C) 2017-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 634 634 635 635 sub = kzalloc(sizeof(*sub), XCHK_GFP_FLAGS); 636 636 if (!sub) 637 - return ERR_PTR(-ENOMEM); 637 + return NULL; 638 638 639 639 sub->old_smtype = sc->sm->sm_type; 640 640 sub->old_smflags = sc->sm->sm_flags;
+1 -1
fs/xfs/scrub/stats.c
··· 3 3 * Copyright (C) 2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/scrub/symlink.c
··· 3 3 * Copyright (C) 2017-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/scrub/tempfile.c
··· 3 3 * Copyright (c) 2021-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/scrub/trace.c
··· 3 3 * Copyright (C) 2017-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/scrub/xfarray.c
··· 3 3 * Copyright (C) 2021-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/scrub/xfblob.c
··· 3 3 * Copyright (c) 2021-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/scrub/xfile.c
··· 3 3 * Copyright (C) 2018-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
-28
fs/xfs/xfs.h
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - /* 3 - * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. 4 - * All Rights Reserved. 5 - */ 6 - #ifndef __XFS_H__ 7 - #define __XFS_H__ 8 - 9 - #ifdef CONFIG_XFS_DEBUG 10 - #define DEBUG 1 11 - #endif 12 - 13 - #ifdef CONFIG_XFS_DEBUG_EXPENSIVE 14 - #define DEBUG_EXPENSIVE 1 15 - #endif 16 - 17 - #ifdef CONFIG_XFS_ASSERT_FATAL 18 - #define XFS_ASSERT_FATAL 1 19 - #endif 20 - 21 - #ifdef CONFIG_XFS_WARN 22 - #define XFS_WARN 1 23 - #endif 24 - 25 - 26 - #include "xfs_linux.h" 27 - 28 - #endif /* __XFS_H__ */
+1 -1
fs/xfs/xfs_acl.c
··· 3 3 * Copyright (c) 2008, Christoph Hellwig 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_shared.h" 8 8 #include "xfs_format.h" 9 9 #include "xfs_log_format.h"
+1 -1
fs/xfs/xfs_aops.c
··· 4 4 * Copyright (c) 2016-2025 Christoph Hellwig. 5 5 * All Rights Reserved. 6 6 */ 7 - #include "xfs.h" 7 + #include "xfs_platform.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" 10 10 #include "xfs_log_format.h"
+1 -1
fs/xfs/xfs_attr_inactive.c
··· 4 4 * Copyright (c) 2013 Red Hat, Inc. 5 5 * All Rights Reserved. 6 6 */ 7 - #include "xfs.h" 7 + #include "xfs_platform.h" 8 8 #include "xfs_fs.h" 9 9 #include "xfs_shared.h" 10 10 #include "xfs_format.h"
+13 -16
fs/xfs/xfs_attr_item.c
··· 4 4 * Author: Allison Henderson <allison.henderson@oracle.com> 5 5 */ 6 6 7 - #include "xfs.h" 7 + #include "xfs_platform.h" 8 8 #include "xfs_fs.h" 9 9 #include "xfs_format.h" 10 10 #include "xfs_trans_resv.h" ··· 192 192 STATIC void 193 193 xfs_attri_item_format( 194 194 struct xfs_log_item *lip, 195 - struct xfs_log_vec *lv) 195 + struct xlog_format_buf *lfb) 196 196 { 197 197 struct xfs_attri_log_item *attrip = ATTRI_ITEM(lip); 198 - struct xfs_log_iovec *vecp = NULL; 199 198 struct xfs_attri_log_nameval *nv = attrip->attri_nameval; 200 199 201 200 attrip->attri_format.alfi_type = XFS_LI_ATTRI; ··· 219 220 if (nv->new_value.iov_len > 0) 220 221 attrip->attri_format.alfi_size++; 221 222 222 - xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRI_FORMAT, 223 - &attrip->attri_format, 223 + xlog_format_copy(lfb, XLOG_REG_TYPE_ATTRI_FORMAT, &attrip->attri_format, 224 224 sizeof(struct xfs_attri_log_format)); 225 225 226 - xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTR_NAME, nv->name.iov_base, 226 + xlog_format_copy(lfb, XLOG_REG_TYPE_ATTR_NAME, nv->name.iov_base, 227 227 nv->name.iov_len); 228 228 229 229 if (nv->new_name.iov_len > 0) 230 - xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTR_NEWNAME, 231 - nv->new_name.iov_base, nv->new_name.iov_len); 230 + xlog_format_copy(lfb, XLOG_REG_TYPE_ATTR_NEWNAME, 231 + nv->new_name.iov_base, nv->new_name.iov_len); 232 232 233 233 if (nv->value.iov_len > 0) 234 - xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTR_VALUE, 235 - nv->value.iov_base, nv->value.iov_len); 234 + xlog_format_copy(lfb, XLOG_REG_TYPE_ATTR_VALUE, 235 + nv->value.iov_base, nv->value.iov_len); 236 236 237 237 if (nv->new_value.iov_len > 0) 238 - xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTR_NEWVALUE, 239 - nv->new_value.iov_base, nv->new_value.iov_len); 238 + xlog_format_copy(lfb, XLOG_REG_TYPE_ATTR_NEWVALUE, 239 + nv->new_value.iov_base, nv->new_value.iov_len); 240 240 } 241 241 242 242 /* ··· 320 322 */ 321 323 STATIC void 322 324 xfs_attrd_item_format( 323 - struct xfs_log_item *lip, 324 - struct xfs_log_vec *lv) 325 + struct xfs_log_item *lip, 326 + struct xlog_format_buf *lfb) 325 327 { 326 328 struct xfs_attrd_log_item *attrdp = ATTRD_ITEM(lip); 327 - struct xfs_log_iovec *vecp = NULL; 328 329 329 330 attrdp->attrd_format.alfd_type = XFS_LI_ATTRD; 330 331 attrdp->attrd_format.alfd_size = 1; 331 332 332 - xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ATTRD_FORMAT, 333 + xlog_format_copy(lfb, XLOG_REG_TYPE_ATTRD_FORMAT, 333 334 &attrdp->attrd_format, 334 335 sizeof(struct xfs_attrd_log_format)); 335 336 }
+1 -1
fs/xfs/xfs_attr_list.c
··· 4 4 * Copyright (c) 2013 Red Hat, Inc. 5 5 * All Rights Reserved. 6 6 */ 7 - #include "xfs.h" 7 + #include "xfs_platform.h" 8 8 #include "xfs_fs.h" 9 9 #include "xfs_shared.h" 10 10 #include "xfs_format.h"
+1 -1
fs/xfs/xfs_bio_io.c
··· 2 2 /* 3 3 * Copyright (c) 2019 Christoph Hellwig. 4 4 */ 5 - #include "xfs.h" 5 + #include "xfs_platform.h" 6 6 7 7 static inline unsigned int bio_max_vecs(unsigned int count) 8 8 {
+5 -7
fs/xfs/xfs_bmap_item.c
··· 3 3 * Copyright (C) 2016 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <darrick.wong@oracle.com> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_format.h" 9 9 #include "xfs_log_format.h" ··· 92 92 STATIC void 93 93 xfs_bui_item_format( 94 94 struct xfs_log_item *lip, 95 - struct xfs_log_vec *lv) 95 + struct xlog_format_buf *lfb) 96 96 { 97 97 struct xfs_bui_log_item *buip = BUI_ITEM(lip); 98 - struct xfs_log_iovec *vecp = NULL; 99 98 100 99 ASSERT(atomic_read(&buip->bui_next_extent) == 101 100 buip->bui_format.bui_nextents); ··· 102 103 buip->bui_format.bui_type = XFS_LI_BUI; 103 104 buip->bui_format.bui_size = 1; 104 105 105 - xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_BUI_FORMAT, &buip->bui_format, 106 + xlog_format_copy(lfb, XLOG_REG_TYPE_BUI_FORMAT, &buip->bui_format, 106 107 xfs_bui_log_format_sizeof(buip->bui_format.bui_nextents)); 107 108 } 108 109 ··· 187 188 STATIC void 188 189 xfs_bud_item_format( 189 190 struct xfs_log_item *lip, 190 - struct xfs_log_vec *lv) 191 + struct xlog_format_buf *lfb) 191 192 { 192 193 struct xfs_bud_log_item *budp = BUD_ITEM(lip); 193 - struct xfs_log_iovec *vecp = NULL; 194 194 195 195 budp->bud_format.bud_type = XFS_LI_BUD; 196 196 budp->bud_format.bud_size = 1; 197 197 198 - xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_BUD_FORMAT, &budp->bud_format, 198 + xlog_format_copy(lfb, XLOG_REG_TYPE_BUD_FORMAT, &budp->bud_format, 199 199 sizeof(struct xfs_bud_log_format)); 200 200 } 201 201
+1 -1
fs/xfs/xfs_bmap_util.c
··· 4 4 * Copyright (c) 2012 Red Hat, Inc. 5 5 * All Rights Reserved. 6 6 */ 7 - #include "xfs.h" 7 + #include "xfs_platform.h" 8 8 #include "xfs_fs.h" 9 9 #include "xfs_shared.h" 10 10 #include "xfs_format.h"
+1 -1
fs/xfs/xfs_buf.c
··· 3 3 * Copyright (c) 2000-2006 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include <linux/backing-dev.h> 8 8 #include <linux/dax.h> 9 9
+8 -13
fs/xfs/xfs_buf_item.c
··· 3 3 * Copyright (c) 2000-2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 263 263 264 264 static inline void 265 265 xfs_buf_item_copy_iovec( 266 - struct xfs_log_vec *lv, 267 - struct xfs_log_iovec **vecp, 266 + struct xlog_format_buf *lfb, 268 267 struct xfs_buf *bp, 269 268 uint offset, 270 269 int first_bit, 271 270 uint nbits) 272 271 { 273 272 offset += first_bit * XFS_BLF_CHUNK; 274 - xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_BCHUNK, 275 - xfs_buf_offset(bp, offset), 273 + xlog_format_copy(lfb, XLOG_REG_TYPE_BCHUNK, xfs_buf_offset(bp, offset), 276 274 nbits * XFS_BLF_CHUNK); 277 275 } 278 276 279 277 static void 280 278 xfs_buf_item_format_segment( 281 279 struct xfs_buf_log_item *bip, 282 - struct xfs_log_vec *lv, 283 - struct xfs_log_iovec **vecp, 280 + struct xlog_format_buf *lfb, 284 281 uint offset, 285 282 struct xfs_buf_log_format *blfp) 286 283 { ··· 305 308 return; 306 309 } 307 310 308 - blfp = xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_BFORMAT, blfp, base_size); 311 + blfp = xlog_format_copy(lfb, XLOG_REG_TYPE_BFORMAT, blfp, base_size); 309 312 blfp->blf_size = 1; 310 313 311 314 if (bip->bli_flags & XFS_BLI_STALE) { ··· 328 331 nbits = xfs_contig_bits(blfp->blf_data_map, 329 332 blfp->blf_map_size, first_bit); 330 333 ASSERT(nbits > 0); 331 - xfs_buf_item_copy_iovec(lv, vecp, bp, offset, 332 - first_bit, nbits); 334 + xfs_buf_item_copy_iovec(lfb, bp, offset, first_bit, nbits); 333 335 blfp->blf_size++; 334 336 335 337 /* ··· 353 357 STATIC void 354 358 xfs_buf_item_format( 355 359 struct xfs_log_item *lip, 356 - struct xfs_log_vec *lv) 360 + struct xlog_format_buf *lfb) 357 361 { 358 362 struct xfs_buf_log_item *bip = BUF_ITEM(lip); 359 363 struct xfs_buf *bp = bip->bli_buf; 360 - struct xfs_log_iovec *vecp = NULL; 361 364 uint offset = 0; 362 365 int i; 363 366 ··· 393 398 } 394 399 395 400 for (i = 0; i < bip->bli_format_count; i++) { 396 - xfs_buf_item_format_segment(bip, lv, &vecp, offset, 401 + xfs_buf_item_format_segment(bip, lfb, offset, 397 402 &bip->bli_formats[i]); 398 403 offset += BBTOB(bp->b_maps[i].bm_len); 399 404 }
+1 -1
fs/xfs/xfs_buf_item_recover.c
··· 3 3 * Copyright (c) 2000-2006 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/xfs_buf_mem.c
··· 3 3 * Copyright (c) 2023-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_buf.h" 9 9 #include "xfs_buf_mem.h"
+1 -1
fs/xfs/xfs_dahash_test.c
··· 3 3 * Copyright (C) 2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/xfs_dir2_readdir.c
··· 4 4 * Copyright (c) 2013 Red Hat, Inc. 5 5 * All Rights Reserved. 6 6 */ 7 - #include "xfs.h" 7 + #include "xfs_platform.h" 8 8 #include "xfs_fs.h" 9 9 #include "xfs_shared.h" 10 10 #include "xfs_format.h"
+1 -1
fs/xfs/xfs_discard.c
··· 3 3 * Copyright (C) 2010, 2023 Red Hat, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_shared.h" 8 8 #include "xfs_format.h" 9 9 #include "xfs_log_format.h"
+1 -1
fs/xfs/xfs_dquot.c
··· 3 3 * Copyright (c) 2000-2003 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_format.h" 9 9 #include "xfs_log_format.h"
+5 -6
fs/xfs/xfs_dquot_item.c
··· 3 3 * Copyright (c) 2000-2003 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 44 44 STATIC void 45 45 xfs_qm_dquot_logitem_format( 46 46 struct xfs_log_item *lip, 47 - struct xfs_log_vec *lv) 47 + struct xlog_format_buf *lfb) 48 48 { 49 49 struct xfs_disk_dquot ddq; 50 50 struct xfs_dq_logitem *qlip = DQUOT_ITEM(lip); 51 - struct xfs_log_iovec *vecp = NULL; 52 51 struct xfs_dq_logformat *qlf; 53 52 54 - qlf = xlog_prepare_iovec(lv, &vecp, XLOG_REG_TYPE_QFORMAT); 53 + qlf = xlog_format_start(lfb, XLOG_REG_TYPE_QFORMAT); 55 54 qlf->qlf_type = XFS_LI_DQUOT; 56 55 qlf->qlf_size = 2; 57 56 qlf->qlf_id = qlip->qli_dquot->q_id; 58 57 qlf->qlf_blkno = qlip->qli_dquot->q_blkno; 59 58 qlf->qlf_len = 1; 60 59 qlf->qlf_boffset = qlip->qli_dquot->q_bufoffset; 61 - xlog_finish_iovec(lv, vecp, sizeof(struct xfs_dq_logformat)); 60 + xlog_format_commit(lfb, sizeof(struct xfs_dq_logformat)); 62 61 63 62 xfs_dquot_to_disk(&ddq, qlip->qli_dquot); 64 63 65 - xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_DQUOT, &ddq, 64 + xlog_format_copy(lfb, XLOG_REG_TYPE_DQUOT, &ddq, 66 65 sizeof(struct xfs_disk_dquot)); 67 66 } 68 67
+1 -1
fs/xfs/xfs_dquot_item_recover.c
··· 3 3 * Copyright (c) 2000-2006 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/xfs_drain.c
··· 3 3 * Copyright (C) 2022-2023 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+82 -62
fs/xfs/xfs_error.c
··· 3 3 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_shared.h" 8 8 #include "xfs_format.h" 9 9 #include "xfs_fs.h" ··· 20 20 [XFS_ERRTAG_##_tag] = (_default), 21 21 #include "xfs_errortag.h" 22 22 static const unsigned int xfs_errortag_random_default[] = { XFS_ERRTAGS }; 23 + #undef XFS_ERRTAG 24 + 25 + #define XFS_ERRTAG(_tag, _name, _default) \ 26 + [XFS_ERRTAG_##_tag] = __stringify(_name), 27 + #include "xfs_errortag.h" 28 + static const char *xfs_errortag_names[] = { XFS_ERRTAGS }; 23 29 #undef XFS_ERRTAG 24 30 25 31 struct xfs_errortag_attr { ··· 56 50 { 57 51 struct xfs_mount *mp = to_mp(kobject); 58 52 unsigned int error_tag = to_attr(attr)->tag; 53 + unsigned int val; 59 54 int ret; 60 55 61 56 if (strcmp(buf, "default") == 0) { 62 - mp->m_errortag[error_tag] = 63 - xfs_errortag_random_default[error_tag]; 57 + val = xfs_errortag_random_default[error_tag]; 64 58 } else { 65 - ret = kstrtouint(buf, 0, &mp->m_errortag[error_tag]); 59 + ret = kstrtouint(buf, 0, &val); 66 60 if (ret) 67 61 return ret; 68 62 } 69 63 64 + WRITE_ONCE(mp->m_errortag[error_tag], val); 70 65 return count; 71 66 } 72 67 ··· 78 71 char *buf) 79 72 { 80 73 struct xfs_mount *mp = to_mp(kobject); 81 - unsigned int error_tag = to_attr(attr)->tag; 82 74 83 - return snprintf(buf, PAGE_SIZE, "%u\n", mp->m_errortag[error_tag]); 75 + return snprintf(buf, PAGE_SIZE, "%u\n", 76 + READ_ONCE(mp->m_errortag[to_attr(attr)->tag])); 84 77 } 85 78 86 79 static const struct sysfs_ops xfs_errortag_sysfs_ops = { ··· 121 114 xfs_errortag_init( 122 115 struct xfs_mount *mp) 123 116 { 124 - int ret; 125 - 126 - mp->m_errortag = kzalloc(sizeof(unsigned int) * XFS_ERRTAG_MAX, 127 - GFP_KERNEL | __GFP_RETRY_MAYFAIL); 128 - if (!mp->m_errortag) 129 - return -ENOMEM; 130 - 131 - ret = xfs_sysfs_init(&mp->m_errortag_kobj, &xfs_errortag_ktype, 117 + return xfs_sysfs_init(&mp->m_errortag_kobj, &xfs_errortag_ktype, 132 118 &mp->m_kobj, "errortag"); 133 - if (ret) 134 - kfree(mp->m_errortag); 135 - return ret; 136 119 } 137 120 138 121 void ··· 130 133 struct xfs_mount *mp) 131 134 { 132 135 xfs_sysfs_del(&mp->m_errortag_kobj); 133 - kfree(mp->m_errortag); 134 - } 135 - 136 - static bool 137 - xfs_errortag_valid( 138 - unsigned int error_tag) 139 - { 140 - if (error_tag >= XFS_ERRTAG_MAX) 141 - return false; 142 - 143 - /* Error out removed injection types */ 144 - if (error_tag == XFS_ERRTAG_DROP_WRITES) 145 - return false; 146 - return true; 147 - } 148 - 149 - bool 150 - xfs_errortag_enabled( 151 - struct xfs_mount *mp, 152 - unsigned int tag) 153 - { 154 - if (!mp->m_errortag) 155 - return false; 156 - if (!xfs_errortag_valid(tag)) 157 - return false; 158 - 159 - return mp->m_errortag[tag] != 0; 160 136 } 161 137 162 138 bool ··· 141 171 { 142 172 unsigned int randfactor; 143 173 144 - /* 145 - * To be able to use error injection anywhere, we need to ensure error 146 - * injection mechanism is already initialized. 147 - * 148 - * Code paths like I/O completion can be called before the 149 - * initialization is complete, but be able to inject errors in such 150 - * places is still useful. 151 - */ 152 - if (!mp->m_errortag) 153 - return false; 154 - 155 - if (!xfs_errortag_valid(error_tag)) 156 - return false; 157 - 158 - randfactor = mp->m_errortag[error_tag]; 174 + randfactor = READ_ONCE(mp->m_errortag[error_tag]); 159 175 if (!randfactor || get_random_u32_below(randfactor)) 160 176 return false; 161 177 ··· 151 195 return true; 152 196 } 153 197 198 + void 199 + xfs_errortag_delay( 200 + struct xfs_mount *mp, 201 + const char *file, 202 + int line, 203 + unsigned int error_tag) 204 + { 205 + unsigned int delay = READ_ONCE(mp->m_errortag[error_tag]); 206 + 207 + might_sleep(); 208 + 209 + if (!delay) 210 + return; 211 + 212 + xfs_warn_ratelimited(mp, 213 + "Injecting %ums delay at file %s, line %d, on filesystem \"%s\"", 214 + delay, file, line, 215 + mp->m_super->s_id); 216 + mdelay(delay); 217 + } 218 + 154 219 int 155 220 xfs_errortag_add( 156 221 struct xfs_mount *mp, ··· 179 202 { 180 203 BUILD_BUG_ON(ARRAY_SIZE(xfs_errortag_random_default) != XFS_ERRTAG_MAX); 181 204 182 - if (!xfs_errortag_valid(error_tag)) 205 + if (error_tag >= XFS_ERRTAG_MAX) 183 206 return -EINVAL; 184 - mp->m_errortag[error_tag] = xfs_errortag_random_default[error_tag]; 207 + 208 + /* Error out removed injection types */ 209 + switch (error_tag) { 210 + case XFS_ERRTAG_DROP_WRITES: 211 + return -EINVAL; 212 + default: 213 + break; 214 + } 215 + 216 + WRITE_ONCE(mp->m_errortag[error_tag], 217 + xfs_errortag_random_default[error_tag]); 185 218 return 0; 219 + } 220 + 221 + int 222 + xfs_errortag_add_name( 223 + struct xfs_mount *mp, 224 + const char *tag_name) 225 + { 226 + unsigned int i; 227 + 228 + for (i = 0; i < XFS_ERRTAG_MAX; i++) { 229 + if (xfs_errortag_names[i] && 230 + !strcmp(xfs_errortag_names[i], tag_name)) 231 + return xfs_errortag_add(mp, i); 232 + } 233 + 234 + return -EINVAL; 235 + } 236 + 237 + void 238 + xfs_errortag_copy( 239 + struct xfs_mount *dst_mp, 240 + struct xfs_mount *src_mp) 241 + { 242 + unsigned int val, i; 243 + 244 + for (i = 0; i < XFS_ERRTAG_MAX; i++) { 245 + val = READ_ONCE(src_mp->m_errortag[i]); 246 + if (val) 247 + WRITE_ONCE(dst_mp->m_errortag[i], val); 248 + } 186 249 } 187 250 188 251 int 189 252 xfs_errortag_clearall( 190 253 struct xfs_mount *mp) 191 254 { 192 - memset(mp->m_errortag, 0, sizeof(unsigned int) * XFS_ERRTAG_MAX); 255 + unsigned int i; 256 + 257 + for (i = 0; i < XFS_ERRTAG_MAX; i++) 258 + WRITE_ONCE(mp->m_errortag[i], 0); 193 259 return 0; 194 260 } 195 261 #endif /* DEBUG */
+9 -14
fs/xfs/xfs_error.h
··· 40 40 unsigned int error_tag); 41 41 #define XFS_TEST_ERROR(mp, tag) \ 42 42 xfs_errortag_test((mp), __FILE__, __LINE__, (tag)) 43 - bool xfs_errortag_enabled(struct xfs_mount *mp, unsigned int tag); 43 + void xfs_errortag_delay(struct xfs_mount *mp, const char *file, int line, 44 + unsigned int error_tag); 44 45 #define XFS_ERRORTAG_DELAY(mp, tag) \ 45 - do { \ 46 - might_sleep(); \ 47 - if (!xfs_errortag_enabled((mp), (tag))) \ 48 - break; \ 49 - xfs_warn_ratelimited((mp), \ 50 - "Injecting %ums delay at file %s, line %d, on filesystem \"%s\"", \ 51 - (mp)->m_errortag[(tag)], __FILE__, __LINE__, \ 52 - (mp)->m_super->s_id); \ 53 - mdelay((mp)->m_errortag[(tag)]); \ 54 - } while (0) 55 - 46 + xfs_errortag_delay((mp), __FILE__, __LINE__, (tag)) 56 47 int xfs_errortag_add(struct xfs_mount *mp, unsigned int error_tag); 48 + int xfs_errortag_add_name(struct xfs_mount *mp, const char *tag_name); 49 + void xfs_errortag_copy(struct xfs_mount *dst_mp, struct xfs_mount *src_mp); 57 50 int xfs_errortag_clearall(struct xfs_mount *mp); 58 51 #else 59 52 #define xfs_errortag_init(mp) (0) 60 53 #define xfs_errortag_del(mp) 61 54 #define XFS_TEST_ERROR(mp, tag) (false) 62 55 #define XFS_ERRORTAG_DELAY(mp, tag) ((void)0) 63 - #define xfs_errortag_add(mp, tag) (ENOSYS) 64 - #define xfs_errortag_clearall(mp) (ENOSYS) 56 + #define xfs_errortag_add(mp, tag) (-ENOSYS) 57 + #define xfs_errortag_copy(dst_mp, src_mp) ((void)0) 58 + #define xfs_errortag_add_name(mp, tag_name) (-ENOSYS) 59 + #define xfs_errortag_clearall(mp) (-ENOSYS) 65 60 #endif /* DEBUG */ 66 61 67 62 /*
+5 -8
fs/xfs/xfs_exchmaps_item.c
··· 3 3 * Copyright (c) 2020-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_format.h" 9 9 #include "xfs_log_format.h" ··· 83 83 STATIC void 84 84 xfs_xmi_item_format( 85 85 struct xfs_log_item *lip, 86 - struct xfs_log_vec *lv) 86 + struct xlog_format_buf *lfb) 87 87 { 88 88 struct xfs_xmi_log_item *xmi_lip = XMI_ITEM(lip); 89 - struct xfs_log_iovec *vecp = NULL; 90 89 91 90 xmi_lip->xmi_format.xmi_type = XFS_LI_XMI; 92 91 xmi_lip->xmi_format.xmi_size = 1; 93 92 94 - xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_XMI_FORMAT, 95 - &xmi_lip->xmi_format, 93 + xlog_format_copy(lfb, XLOG_REG_TYPE_XMI_FORMAT, &xmi_lip->xmi_format, 96 94 sizeof(struct xfs_xmi_log_format)); 97 95 } 98 96 ··· 164 166 STATIC void 165 167 xfs_xmd_item_format( 166 168 struct xfs_log_item *lip, 167 - struct xfs_log_vec *lv) 169 + struct xlog_format_buf *lfb) 168 170 { 169 171 struct xfs_xmd_log_item *xmd_lip = XMD_ITEM(lip); 170 - struct xfs_log_iovec *vecp = NULL; 171 172 172 173 xmd_lip->xmd_format.xmd_type = XFS_LI_XMD; 173 174 xmd_lip->xmd_format.xmd_size = 1; 174 175 175 - xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_XMD_FORMAT, &xmd_lip->xmd_format, 176 + xlog_format_copy(lfb, XLOG_REG_TYPE_XMD_FORMAT, &xmd_lip->xmd_format, 176 177 sizeof(struct xfs_xmd_log_format)); 177 178 } 178 179
+1 -1
fs/xfs/xfs_exchrange.c
··· 3 3 * Copyright (c) 2020-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_shared.h" 8 8 #include "xfs_format.h" 9 9 #include "xfs_log_format.h"
+1 -1
fs/xfs/xfs_export.c
··· 3 3 * Copyright (c) 2004-2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_shared.h" 8 8 #include "xfs_format.h" 9 9 #include "xfs_log_format.h"
+1 -1
fs/xfs/xfs_extent_busy.c
··· 5 5 * Copyright (c) 2011 Christoph Hellwig. 6 6 * All Rights Reserved. 7 7 */ 8 - #include "xfs.h" 8 + #include "xfs_platform.h" 9 9 #include "xfs_fs.h" 10 10 #include "xfs_format.h" 11 11 #include "xfs_log_format.h"
+5 -7
fs/xfs/xfs_extfree_item.c
··· 3 3 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_format.h" 9 9 #include "xfs_log_format.h" ··· 98 98 STATIC void 99 99 xfs_efi_item_format( 100 100 struct xfs_log_item *lip, 101 - struct xfs_log_vec *lv) 101 + struct xlog_format_buf *lfb) 102 102 { 103 103 struct xfs_efi_log_item *efip = EFI_ITEM(lip); 104 - struct xfs_log_iovec *vecp = NULL; 105 104 106 105 ASSERT(atomic_read(&efip->efi_next_extent) == 107 106 efip->efi_format.efi_nextents); ··· 109 110 efip->efi_format.efi_type = lip->li_type; 110 111 efip->efi_format.efi_size = 1; 111 112 112 - xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_EFI_FORMAT, &efip->efi_format, 113 + xlog_format_copy(lfb, XLOG_REG_TYPE_EFI_FORMAT, &efip->efi_format, 113 114 xfs_efi_log_format_sizeof(efip->efi_format.efi_nextents)); 114 115 } 115 116 ··· 276 277 STATIC void 277 278 xfs_efd_item_format( 278 279 struct xfs_log_item *lip, 279 - struct xfs_log_vec *lv) 280 + struct xlog_format_buf *lfb) 280 281 { 281 282 struct xfs_efd_log_item *efdp = EFD_ITEM(lip); 282 - struct xfs_log_iovec *vecp = NULL; 283 283 284 284 ASSERT(efdp->efd_next_extent == efdp->efd_format.efd_nextents); 285 285 ASSERT(lip->li_type == XFS_LI_EFD || lip->li_type == XFS_LI_EFD_RT); ··· 286 288 efdp->efd_format.efd_type = lip->li_type; 287 289 efdp->efd_format.efd_size = 1; 288 290 289 - xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_EFD_FORMAT, &efdp->efd_format, 291 + xlog_format_copy(lfb, XLOG_REG_TYPE_EFD_FORMAT, &efdp->efd_format, 290 292 xfs_efd_log_format_sizeof(efdp->efd_format.efd_nextents)); 291 293 } 292 294
+1 -1
fs/xfs/xfs_file.c
··· 3 3 * Copyright (c) 2000-2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/xfs_filestream.c
··· 4 4 * Copyright (c) 2014 Christoph Hellwig. 5 5 * All Rights Reserved. 6 6 */ 7 - #include "xfs.h" 7 + #include "xfs_platform.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" 10 10 #include "xfs_log_format.h"
+1 -1
fs/xfs/xfs_fsmap.c
··· 3 3 * Copyright (C) 2017 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <darrick.wong@oracle.com> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+3 -1
fs/xfs/xfs_fsops.c
··· 3 3 * Copyright (c) 2000-2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 25 25 #include "xfs_rtrmap_btree.h" 26 26 #include "xfs_rtrefcount_btree.h" 27 27 #include "xfs_metafile.h" 28 + #include "xfs_healthmon.h" 28 29 29 30 #include <linux/fserror.h> 30 31 ··· 545 544 xfs_stack_trace(); 546 545 547 546 fserror_report_shutdown(mp->m_super, GFP_KERNEL); 547 + xfs_healthmon_report_shutdown(mp, flags); 548 548 } 549 549 550 550 /*
+1 -1
fs/xfs/xfs_globals.c
··· 3 3 * Copyright (c) 2000-2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_error.h" 8 8 9 9 /*
+1 -1
fs/xfs/xfs_handle.c
··· 4 4 * Copyright (c) 2022-2024 Oracle. 5 5 * All rights reserved. 6 6 */ 7 - #include "xfs.h" 7 + #include "xfs_platform.h" 8 8 #include "xfs_fs.h" 9 9 #include "xfs_format.h" 10 10 #include "xfs_log_format.h"
+125 -1
fs/xfs/xfs_health.c
··· 3 3 * Copyright (C) 2019 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <darrick.wong@oracle.com> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 19 19 #include "xfs_da_btree.h" 20 20 #include "xfs_quota_defs.h" 21 21 #include "xfs_rtgroup.h" 22 + #include "xfs_healthmon.h" 22 23 23 24 #include <linux/fserror.h> 24 25 ··· 108 107 struct xfs_mount *mp, 109 108 unsigned int mask) 110 109 { 110 + unsigned int old_mask; 111 + 111 112 ASSERT(!(mask & ~XFS_SICK_FS_ALL)); 112 113 trace_xfs_fs_mark_sick(mp, mask); 113 114 114 115 spin_lock(&mp->m_sb_lock); 116 + old_mask = mp->m_fs_sick; 115 117 mp->m_fs_sick |= mask; 116 118 spin_unlock(&mp->m_sb_lock); 117 119 118 120 fserror_report_metadata(mp->m_super, -EFSCORRUPTED, GFP_NOFS); 121 + if (mask) 122 + xfs_healthmon_report_fs(mp, XFS_HEALTHMON_SICK, old_mask, mask); 119 123 } 120 124 121 125 /* Mark per-fs metadata as having been checked and found unhealthy by fsck. */ ··· 129 123 struct xfs_mount *mp, 130 124 unsigned int mask) 131 125 { 126 + unsigned int old_mask; 127 + 132 128 ASSERT(!(mask & ~XFS_SICK_FS_ALL)); 133 129 trace_xfs_fs_mark_corrupt(mp, mask); 134 130 135 131 spin_lock(&mp->m_sb_lock); 132 + old_mask = mp->m_fs_sick; 136 133 mp->m_fs_sick |= mask; 137 134 mp->m_fs_checked |= mask; 138 135 spin_unlock(&mp->m_sb_lock); 139 136 140 137 fserror_report_metadata(mp->m_super, -EFSCORRUPTED, GFP_NOFS); 138 + if (mask) 139 + xfs_healthmon_report_fs(mp, XFS_HEALTHMON_CORRUPT, old_mask, 140 + mask); 141 141 } 142 142 143 143 /* Mark a per-fs metadata healed. */ ··· 152 140 struct xfs_mount *mp, 153 141 unsigned int mask) 154 142 { 143 + unsigned int old_mask; 144 + 155 145 ASSERT(!(mask & ~XFS_SICK_FS_ALL)); 156 146 trace_xfs_fs_mark_healthy(mp, mask); 157 147 158 148 spin_lock(&mp->m_sb_lock); 149 + old_mask = mp->m_fs_sick; 159 150 mp->m_fs_sick &= ~mask; 160 151 if (!(mp->m_fs_sick & XFS_SICK_FS_PRIMARY)) 161 152 mp->m_fs_sick &= ~XFS_SICK_FS_SECONDARY; 162 153 mp->m_fs_checked |= mask; 163 154 spin_unlock(&mp->m_sb_lock); 155 + 156 + if (mask) 157 + xfs_healthmon_report_fs(mp, XFS_HEALTHMON_HEALTHY, old_mask, 158 + mask); 164 159 } 165 160 166 161 /* Sample which per-fs metadata are unhealthy. */ ··· 217 198 struct xfs_group *xg, 218 199 unsigned int mask) 219 200 { 201 + unsigned int old_mask; 202 + 220 203 xfs_group_check_mask(xg, mask); 221 204 trace_xfs_group_mark_sick(xg, mask); 222 205 223 206 spin_lock(&xg->xg_state_lock); 207 + old_mask = xg->xg_sick; 224 208 xg->xg_sick |= mask; 225 209 spin_unlock(&xg->xg_state_lock); 226 210 227 211 fserror_report_metadata(xg->xg_mount->m_super, -EFSCORRUPTED, GFP_NOFS); 212 + if (mask) 213 + xfs_healthmon_report_group(xg, XFS_HEALTHMON_SICK, old_mask, 214 + mask); 228 215 } 229 216 230 217 /* ··· 241 216 struct xfs_group *xg, 242 217 unsigned int mask) 243 218 { 219 + unsigned int old_mask; 220 + 244 221 xfs_group_check_mask(xg, mask); 245 222 trace_xfs_group_mark_corrupt(xg, mask); 246 223 247 224 spin_lock(&xg->xg_state_lock); 225 + old_mask = xg->xg_sick; 248 226 xg->xg_sick |= mask; 249 227 xg->xg_checked |= mask; 250 228 spin_unlock(&xg->xg_state_lock); 251 229 252 230 fserror_report_metadata(xg->xg_mount->m_super, -EFSCORRUPTED, GFP_NOFS); 231 + if (mask) 232 + xfs_healthmon_report_group(xg, XFS_HEALTHMON_CORRUPT, old_mask, 233 + mask); 253 234 } 254 235 255 236 /* ··· 266 235 struct xfs_group *xg, 267 236 unsigned int mask) 268 237 { 238 + unsigned int old_mask; 239 + 269 240 xfs_group_check_mask(xg, mask); 270 241 trace_xfs_group_mark_healthy(xg, mask); 271 242 272 243 spin_lock(&xg->xg_state_lock); 244 + old_mask = xg->xg_sick; 273 245 xg->xg_sick &= ~mask; 274 246 if (!(xg->xg_sick & XFS_SICK_AG_PRIMARY)) 275 247 xg->xg_sick &= ~XFS_SICK_AG_SECONDARY; 276 248 xg->xg_checked |= mask; 277 249 spin_unlock(&xg->xg_state_lock); 250 + 251 + if (mask) 252 + xfs_healthmon_report_group(xg, XFS_HEALTHMON_HEALTHY, old_mask, 253 + mask); 278 254 } 279 255 280 256 /* Sample which per-ag metadata are unhealthy. */ ··· 320 282 struct xfs_inode *ip, 321 283 unsigned int mask) 322 284 { 285 + unsigned int old_mask; 286 + 323 287 ASSERT(!(mask & ~XFS_SICK_INO_ALL)); 324 288 trace_xfs_inode_mark_sick(ip, mask); 325 289 326 290 spin_lock(&ip->i_flags_lock); 291 + old_mask = ip->i_sick; 327 292 ip->i_sick |= mask; 328 293 spin_unlock(&ip->i_flags_lock); 329 294 ··· 340 299 spin_unlock(&VFS_I(ip)->i_lock); 341 300 342 301 fserror_report_file_metadata(VFS_I(ip), -EFSCORRUPTED, GFP_NOFS); 302 + if (mask) 303 + xfs_healthmon_report_inode(ip, XFS_HEALTHMON_SICK, old_mask, 304 + mask); 343 305 } 344 306 345 307 /* Mark inode metadata as having been checked and found unhealthy by fsck. */ ··· 351 307 struct xfs_inode *ip, 352 308 unsigned int mask) 353 309 { 310 + unsigned int old_mask; 311 + 354 312 ASSERT(!(mask & ~XFS_SICK_INO_ALL)); 355 313 trace_xfs_inode_mark_corrupt(ip, mask); 356 314 357 315 spin_lock(&ip->i_flags_lock); 316 + old_mask = ip->i_sick; 358 317 ip->i_sick |= mask; 359 318 ip->i_checked |= mask; 360 319 spin_unlock(&ip->i_flags_lock); ··· 372 325 spin_unlock(&VFS_I(ip)->i_lock); 373 326 374 327 fserror_report_file_metadata(VFS_I(ip), -EFSCORRUPTED, GFP_NOFS); 328 + if (mask) 329 + xfs_healthmon_report_inode(ip, XFS_HEALTHMON_CORRUPT, old_mask, 330 + mask); 375 331 } 376 332 377 333 /* Mark parts of an inode healed. */ ··· 383 333 struct xfs_inode *ip, 384 334 unsigned int mask) 385 335 { 336 + unsigned int old_mask; 337 + 386 338 ASSERT(!(mask & ~XFS_SICK_INO_ALL)); 387 339 trace_xfs_inode_mark_healthy(ip, mask); 388 340 389 341 spin_lock(&ip->i_flags_lock); 342 + old_mask = ip->i_sick; 390 343 ip->i_sick &= ~mask; 391 344 if (!(ip->i_sick & XFS_SICK_INO_PRIMARY)) 392 345 ip->i_sick &= ~XFS_SICK_INO_SECONDARY; 393 346 ip->i_checked |= mask; 394 347 spin_unlock(&ip->i_flags_lock); 348 + 349 + if (mask) 350 + xfs_healthmon_report_inode(ip, XFS_HEALTHMON_HEALTHY, old_mask, 351 + mask); 395 352 } 396 353 397 354 /* Sample which parts of an inode are unhealthy. */ ··· 478 421 } 479 422 } 480 423 424 + /* 425 + * Translate XFS_SICK_FS_* into XFS_FSOP_GEOM_SICK_* except for the rt free 426 + * space codes, which are sent via the rtgroup events. 427 + */ 428 + unsigned int 429 + xfs_healthmon_fs_mask( 430 + unsigned int sick_mask) 431 + { 432 + const struct ioctl_sick_map *m; 433 + unsigned int ioctl_mask = 0; 434 + 435 + for_each_sick_map(fs_map, m) { 436 + if (sick_mask & m->sick_mask) 437 + ioctl_mask |= m->ioctl_mask; 438 + } 439 + 440 + return ioctl_mask; 441 + } 442 + 481 443 static const struct ioctl_sick_map ag_map[] = { 482 444 { XFS_SICK_AG_SB, XFS_AG_GEOM_SICK_SB }, 483 445 { XFS_SICK_AG_AGF, XFS_AG_GEOM_SICK_AGF }, ··· 533 457 } 534 458 } 535 459 460 + /* Translate XFS_SICK_AG_* into XFS_AG_GEOM_SICK_*. */ 461 + unsigned int 462 + xfs_healthmon_perag_mask( 463 + unsigned int sick_mask) 464 + { 465 + const struct ioctl_sick_map *m; 466 + unsigned int ioctl_mask = 0; 467 + 468 + for_each_sick_map(ag_map, m) { 469 + if (sick_mask & m->sick_mask) 470 + ioctl_mask |= m->ioctl_mask; 471 + } 472 + 473 + return ioctl_mask; 474 + } 475 + 536 476 static const struct ioctl_sick_map rtgroup_map[] = { 537 477 { XFS_SICK_RG_SUPER, XFS_RTGROUP_GEOM_SICK_SUPER }, 538 478 { XFS_SICK_RG_BITMAP, XFS_RTGROUP_GEOM_SICK_BITMAP }, ··· 577 485 if (sick & m->sick_mask) 578 486 rgeo->rg_sick |= m->ioctl_mask; 579 487 } 488 + } 489 + 490 + /* Translate XFS_SICK_RG_* into XFS_RTGROUP_GEOM_SICK_*. */ 491 + unsigned int 492 + xfs_healthmon_rtgroup_mask( 493 + unsigned int sick_mask) 494 + { 495 + const struct ioctl_sick_map *m; 496 + unsigned int ioctl_mask = 0; 497 + 498 + for_each_sick_map(rtgroup_map, m) { 499 + if (sick_mask & m->sick_mask) 500 + ioctl_mask |= m->ioctl_mask; 501 + } 502 + 503 + return ioctl_mask; 580 504 } 581 505 582 506 static const struct ioctl_sick_map ino_map[] = { ··· 631 523 if (sick & m->sick_mask) 632 524 bs->bs_sick |= m->ioctl_mask; 633 525 } 526 + } 527 + 528 + /* Translate XFS_SICK_INO_* into XFS_BS_SICK_*. */ 529 + unsigned int 530 + xfs_healthmon_inode_mask( 531 + unsigned int sick_mask) 532 + { 533 + const struct ioctl_sick_map *m; 534 + unsigned int ioctl_mask = 0; 535 + 536 + for_each_sick_map(ino_map, m) { 537 + if (sick_mask & m->sick_mask) 538 + ioctl_mask |= m->ioctl_mask; 539 + } 540 + 541 + return ioctl_mask; 634 542 } 635 543 636 544 /* Mark a block mapping sick. */
+1255
fs/xfs/xfs_healthmon.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Copyright (c) 2024-2026 Oracle. All Rights Reserved. 4 + * Author: Darrick J. Wong <djwong@kernel.org> 5 + */ 6 + #include "xfs_platform.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_inode.h" 14 + #include "xfs_trace.h" 15 + #include "xfs_ag.h" 16 + #include "xfs_btree.h" 17 + #include "xfs_da_format.h" 18 + #include "xfs_da_btree.h" 19 + #include "xfs_quota_defs.h" 20 + #include "xfs_rtgroup.h" 21 + #include "xfs_health.h" 22 + #include "xfs_healthmon.h" 23 + #include "xfs_fsops.h" 24 + #include "xfs_notify_failure.h" 25 + #include "xfs_file.h" 26 + #include "xfs_ioctl.h" 27 + 28 + #include <linux/anon_inodes.h> 29 + #include <linux/eventpoll.h> 30 + #include <linux/poll.h> 31 + #include <linux/fserror.h> 32 + 33 + /* 34 + * Live Health Monitoring 35 + * ====================== 36 + * 37 + * Autonomous self-healing of XFS filesystems requires a means for the kernel 38 + * to send filesystem health events to a monitoring daemon in userspace. To 39 + * accomplish this, we establish a thread_with_file kthread object to handle 40 + * translating internal events about filesystem health into a format that can 41 + * be parsed easily by userspace. When those internal events occur, the core 42 + * filesystem code calls this health monitor to convey the events to userspace. 43 + * Userspace reads events from the file descriptor returned by the ioctl. 44 + * 45 + * The healthmon abstraction has a weak reference to the host filesystem mount 46 + * so that the queueing and processing of the events do not pin the mount and 47 + * cannot slow down the main filesystem. The healthmon object can exist past 48 + * the end of the filesystem mount. 49 + */ 50 + 51 + /* sign of a detached health monitor */ 52 + #define DETACHED_MOUNT_COOKIE ((uintptr_t)0) 53 + 54 + /* Constrain the number of event objects that can build up in memory. */ 55 + #define XFS_HEALTHMON_MAX_EVENTS (SZ_32K / \ 56 + sizeof(struct xfs_healthmon_event)) 57 + 58 + /* Constrain the size of the output buffer for read_iter. */ 59 + #define XFS_HEALTHMON_MAX_OUTBUF SZ_64K 60 + 61 + /* spinlock for atomically updating xfs_mount <-> xfs_healthmon pointers */ 62 + static DEFINE_SPINLOCK(xfs_healthmon_lock); 63 + 64 + /* Grab a reference to the healthmon object for a given mount, if any. */ 65 + static struct xfs_healthmon * 66 + xfs_healthmon_get( 67 + struct xfs_mount *mp) 68 + { 69 + struct xfs_healthmon *hm; 70 + 71 + rcu_read_lock(); 72 + hm = mp->m_healthmon; 73 + if (hm && !refcount_inc_not_zero(&hm->ref)) 74 + hm = NULL; 75 + rcu_read_unlock(); 76 + 77 + return hm; 78 + } 79 + 80 + /* 81 + * Release the reference to a healthmon object. If there are no more holders, 82 + * free the health monitor after an RCU grace period to eliminate possibility 83 + * of races with xfs_healthmon_get. 84 + */ 85 + static void 86 + xfs_healthmon_put( 87 + struct xfs_healthmon *hm) 88 + { 89 + if (refcount_dec_and_test(&hm->ref)) { 90 + struct xfs_healthmon_event *event; 91 + struct xfs_healthmon_event *next = hm->first_event; 92 + 93 + while ((event = next) != NULL) { 94 + trace_xfs_healthmon_drop(hm, event); 95 + next = event->next; 96 + kfree(event); 97 + } 98 + 99 + kfree(hm->unmount_event); 100 + kfree(hm->buffer); 101 + mutex_destroy(&hm->lock); 102 + kfree_rcu_mightsleep(hm); 103 + } 104 + } 105 + 106 + /* Attach a health monitor to an xfs_mount. Only one allowed at a time. */ 107 + STATIC int 108 + xfs_healthmon_attach( 109 + struct xfs_mount *mp, 110 + struct xfs_healthmon *hm) 111 + { 112 + spin_lock(&xfs_healthmon_lock); 113 + if (mp->m_healthmon != NULL) { 114 + spin_unlock(&xfs_healthmon_lock); 115 + return -EEXIST; 116 + } 117 + 118 + refcount_inc(&hm->ref); 119 + mp->m_healthmon = hm; 120 + hm->mount_cookie = (uintptr_t)mp->m_super; 121 + spin_unlock(&xfs_healthmon_lock); 122 + 123 + return 0; 124 + } 125 + 126 + /* Detach a xfs mount from a specific healthmon instance. */ 127 + STATIC void 128 + xfs_healthmon_detach( 129 + struct xfs_healthmon *hm) 130 + { 131 + spin_lock(&xfs_healthmon_lock); 132 + if (hm->mount_cookie == DETACHED_MOUNT_COOKIE) { 133 + spin_unlock(&xfs_healthmon_lock); 134 + return; 135 + } 136 + 137 + XFS_M((struct super_block *)hm->mount_cookie)->m_healthmon = NULL; 138 + hm->mount_cookie = DETACHED_MOUNT_COOKIE; 139 + spin_unlock(&xfs_healthmon_lock); 140 + 141 + trace_xfs_healthmon_detach(hm); 142 + xfs_healthmon_put(hm); 143 + } 144 + 145 + static inline void xfs_healthmon_bump_events(struct xfs_healthmon *hm) 146 + { 147 + hm->events++; 148 + hm->total_events++; 149 + } 150 + 151 + static inline void xfs_healthmon_bump_lost(struct xfs_healthmon *hm) 152 + { 153 + hm->lost_prev_event++; 154 + hm->total_lost++; 155 + } 156 + 157 + /* 158 + * If possible, merge a new event into an existing event. Returns whether or 159 + * not it merged anything. 160 + */ 161 + static bool 162 + xfs_healthmon_merge_events( 163 + struct xfs_healthmon_event *existing, 164 + const struct xfs_healthmon_event *new) 165 + { 166 + if (!existing) 167 + return false; 168 + 169 + /* type and domain must match to merge events */ 170 + if (existing->type != new->type || 171 + existing->domain != new->domain) 172 + return false; 173 + 174 + switch (existing->type) { 175 + case XFS_HEALTHMON_RUNNING: 176 + case XFS_HEALTHMON_UNMOUNT: 177 + /* should only ever be one of these events anyway */ 178 + return false; 179 + 180 + case XFS_HEALTHMON_LOST: 181 + existing->lostcount += new->lostcount; 182 + return true; 183 + 184 + case XFS_HEALTHMON_SICK: 185 + case XFS_HEALTHMON_CORRUPT: 186 + case XFS_HEALTHMON_HEALTHY: 187 + switch (existing->domain) { 188 + case XFS_HEALTHMON_FS: 189 + existing->fsmask |= new->fsmask; 190 + return true; 191 + case XFS_HEALTHMON_AG: 192 + case XFS_HEALTHMON_RTGROUP: 193 + if (existing->group == new->group){ 194 + existing->grpmask |= new->grpmask; 195 + return true; 196 + } 197 + return false; 198 + case XFS_HEALTHMON_INODE: 199 + if (existing->ino == new->ino && 200 + existing->gen == new->gen) { 201 + existing->imask |= new->imask; 202 + return true; 203 + } 204 + return false; 205 + default: 206 + ASSERT(0); 207 + return false; 208 + } 209 + return false; 210 + 211 + case XFS_HEALTHMON_SHUTDOWN: 212 + /* yes, we can race to shutdown */ 213 + existing->flags |= new->flags; 214 + return true; 215 + 216 + case XFS_HEALTHMON_MEDIA_ERROR: 217 + /* physically adjacent errors can merge */ 218 + if (existing->daddr + existing->bbcount == new->daddr) { 219 + existing->bbcount += new->bbcount; 220 + return true; 221 + } 222 + if (new->daddr + new->bbcount == existing->daddr) { 223 + existing->daddr = new->daddr; 224 + existing->bbcount += new->bbcount; 225 + return true; 226 + } 227 + return false; 228 + 229 + case XFS_HEALTHMON_BUFREAD: 230 + case XFS_HEALTHMON_BUFWRITE: 231 + case XFS_HEALTHMON_DIOREAD: 232 + case XFS_HEALTHMON_DIOWRITE: 233 + case XFS_HEALTHMON_DATALOST: 234 + /* logically adjacent file ranges can merge */ 235 + if (existing->fino != new->fino || existing->fgen != new->fgen) 236 + return false; 237 + 238 + if (existing->fpos + existing->flen == new->fpos) { 239 + existing->flen += new->flen; 240 + return true; 241 + } 242 + 243 + if (new->fpos + new->flen == existing->fpos) { 244 + existing->fpos = new->fpos; 245 + existing->flen += new->flen; 246 + return true; 247 + } 248 + return false; 249 + } 250 + 251 + return false; 252 + } 253 + 254 + /* Insert an event onto the start of the queue. */ 255 + static inline void 256 + __xfs_healthmon_insert( 257 + struct xfs_healthmon *hm, 258 + struct xfs_healthmon_event *event) 259 + { 260 + struct timespec64 now; 261 + 262 + ktime_get_coarse_real_ts64(&now); 263 + event->time_ns = (now.tv_sec * NSEC_PER_SEC) + now.tv_nsec; 264 + 265 + event->next = hm->first_event; 266 + if (!hm->first_event) 267 + hm->first_event = event; 268 + if (!hm->last_event) 269 + hm->last_event = event; 270 + xfs_healthmon_bump_events(hm); 271 + wake_up(&hm->wait); 272 + 273 + trace_xfs_healthmon_insert(hm, event); 274 + } 275 + 276 + /* Push an event onto the end of the queue. */ 277 + static inline void 278 + __xfs_healthmon_push( 279 + struct xfs_healthmon *hm, 280 + struct xfs_healthmon_event *event) 281 + { 282 + struct timespec64 now; 283 + 284 + ktime_get_coarse_real_ts64(&now); 285 + event->time_ns = (now.tv_sec * NSEC_PER_SEC) + now.tv_nsec; 286 + 287 + if (!hm->first_event) 288 + hm->first_event = event; 289 + if (hm->last_event) 290 + hm->last_event->next = event; 291 + hm->last_event = event; 292 + event->next = NULL; 293 + xfs_healthmon_bump_events(hm); 294 + wake_up(&hm->wait); 295 + 296 + trace_xfs_healthmon_push(hm, event); 297 + } 298 + 299 + /* Deal with any previously lost events */ 300 + static int 301 + xfs_healthmon_clear_lost_prev( 302 + struct xfs_healthmon *hm) 303 + { 304 + struct xfs_healthmon_event lost_event = { 305 + .type = XFS_HEALTHMON_LOST, 306 + .domain = XFS_HEALTHMON_MOUNT, 307 + .lostcount = hm->lost_prev_event, 308 + }; 309 + struct xfs_healthmon_event *event = NULL; 310 + 311 + if (xfs_healthmon_merge_events(hm->last_event, &lost_event)) { 312 + trace_xfs_healthmon_merge(hm, hm->last_event); 313 + wake_up(&hm->wait); 314 + goto cleared; 315 + } 316 + 317 + if (hm->events < XFS_HEALTHMON_MAX_EVENTS) 318 + event = kmemdup(&lost_event, sizeof(struct xfs_healthmon_event), 319 + GFP_NOFS); 320 + if (!event) 321 + return -ENOMEM; 322 + 323 + __xfs_healthmon_push(hm, event); 324 + cleared: 325 + hm->lost_prev_event = 0; 326 + return 0; 327 + } 328 + 329 + /* 330 + * Push an event onto the end of the list after dealing with lost events and 331 + * possibly full queues. 332 + */ 333 + STATIC int 334 + xfs_healthmon_push( 335 + struct xfs_healthmon *hm, 336 + const struct xfs_healthmon_event *template) 337 + { 338 + struct xfs_healthmon_event *event = NULL; 339 + int error = 0; 340 + 341 + /* 342 + * Locklessly check if the health monitor has already detached from the 343 + * mount. If so, ignore the event. If we race with deactivation, 344 + * we'll queue the event but never send it. 345 + */ 346 + if (hm->mount_cookie == DETACHED_MOUNT_COOKIE) 347 + return -ESHUTDOWN; 348 + 349 + mutex_lock(&hm->lock); 350 + 351 + /* Report previously lost events before we do anything else */ 352 + if (hm->lost_prev_event) { 353 + error = xfs_healthmon_clear_lost_prev(hm); 354 + if (error) 355 + goto out_unlock; 356 + } 357 + 358 + /* Try to merge with the newest event */ 359 + if (xfs_healthmon_merge_events(hm->last_event, template)) { 360 + trace_xfs_healthmon_merge(hm, hm->last_event); 361 + wake_up(&hm->wait); 362 + goto out_unlock; 363 + } 364 + 365 + /* Only create a heap event object if we're not already at capacity. */ 366 + if (hm->events < XFS_HEALTHMON_MAX_EVENTS) 367 + event = kmemdup(template, sizeof(struct xfs_healthmon_event), 368 + GFP_NOFS); 369 + if (!event) { 370 + /* No memory means we lose the event */ 371 + trace_xfs_healthmon_lost_event(hm); 372 + xfs_healthmon_bump_lost(hm); 373 + error = -ENOMEM; 374 + goto out_unlock; 375 + } 376 + 377 + __xfs_healthmon_push(hm, event); 378 + 379 + out_unlock: 380 + mutex_unlock(&hm->lock); 381 + return error; 382 + } 383 + 384 + /* 385 + * Report that the filesystem is being unmounted, then detach the xfs mount 386 + * from this healthmon instance. 387 + */ 388 + void 389 + xfs_healthmon_unmount( 390 + struct xfs_mount *mp) 391 + { 392 + struct xfs_healthmon *hm = xfs_healthmon_get(mp); 393 + 394 + if (!hm) 395 + return; 396 + 397 + trace_xfs_healthmon_report_unmount(hm); 398 + 399 + /* 400 + * Insert the unmount notification at the start of the event queue so 401 + * that userspace knows the filesystem went away as soon as possible. 402 + * There's nothing actionable for userspace after an unmount. Once 403 + * we've inserted the unmount event, hm no longer owns that event. 404 + */ 405 + __xfs_healthmon_insert(hm, hm->unmount_event); 406 + hm->unmount_event = NULL; 407 + 408 + xfs_healthmon_detach(hm); 409 + xfs_healthmon_put(hm); 410 + } 411 + 412 + /* Compute the reporting mask for non-unmount metadata health events. */ 413 + static inline unsigned int 414 + metadata_event_mask( 415 + struct xfs_healthmon *hm, 416 + enum xfs_healthmon_type type, 417 + unsigned int old_mask, 418 + unsigned int new_mask) 419 + { 420 + /* If we want all events, return all events. */ 421 + if (hm->verbose) 422 + return new_mask; 423 + 424 + switch (type) { 425 + case XFS_HEALTHMON_SICK: 426 + /* Always report runtime corruptions */ 427 + return new_mask; 428 + case XFS_HEALTHMON_CORRUPT: 429 + /* Only report new fsck errors */ 430 + return new_mask & ~old_mask; 431 + case XFS_HEALTHMON_HEALTHY: 432 + /* Only report healthy metadata that got fixed */ 433 + return new_mask & old_mask; 434 + default: 435 + ASSERT(0); 436 + break; 437 + } 438 + 439 + return 0; 440 + } 441 + 442 + /* Report XFS_FS_SICK_* events to healthmon */ 443 + void 444 + xfs_healthmon_report_fs( 445 + struct xfs_mount *mp, 446 + enum xfs_healthmon_type type, 447 + unsigned int old_mask, 448 + unsigned int new_mask) 449 + { 450 + struct xfs_healthmon_event event = { 451 + .type = type, 452 + .domain = XFS_HEALTHMON_FS, 453 + }; 454 + struct xfs_healthmon *hm = xfs_healthmon_get(mp); 455 + 456 + if (!hm) 457 + return; 458 + 459 + event.fsmask = metadata_event_mask(hm, type, old_mask, new_mask) & 460 + ~XFS_SICK_FS_SECONDARY; 461 + trace_xfs_healthmon_report_fs(hm, old_mask, new_mask, &event); 462 + 463 + if (event.fsmask) 464 + xfs_healthmon_push(hm, &event); 465 + 466 + xfs_healthmon_put(hm); 467 + } 468 + 469 + /* Report XFS_SICK_(AG|RG)* flags to healthmon */ 470 + void 471 + xfs_healthmon_report_group( 472 + struct xfs_group *xg, 473 + enum xfs_healthmon_type type, 474 + unsigned int old_mask, 475 + unsigned int new_mask) 476 + { 477 + struct xfs_healthmon_event event = { 478 + .type = type, 479 + .group = xg->xg_gno, 480 + }; 481 + struct xfs_healthmon *hm = xfs_healthmon_get(xg->xg_mount); 482 + 483 + if (!hm) 484 + return; 485 + 486 + switch (xg->xg_type) { 487 + case XG_TYPE_RTG: 488 + event.domain = XFS_HEALTHMON_RTGROUP; 489 + event.grpmask = metadata_event_mask(hm, type, old_mask, 490 + new_mask) & 491 + ~XFS_SICK_RG_SECONDARY; 492 + break; 493 + case XG_TYPE_AG: 494 + event.domain = XFS_HEALTHMON_AG; 495 + event.grpmask = metadata_event_mask(hm, type, old_mask, 496 + new_mask) & 497 + ~XFS_SICK_AG_SECONDARY; 498 + break; 499 + default: 500 + ASSERT(0); 501 + break; 502 + } 503 + 504 + trace_xfs_healthmon_report_group(hm, old_mask, new_mask, &event); 505 + 506 + if (event.grpmask) 507 + xfs_healthmon_push(hm, &event); 508 + 509 + xfs_healthmon_put(hm); 510 + } 511 + 512 + /* Report XFS_SICK_INO_* flags to healthmon */ 513 + void 514 + xfs_healthmon_report_inode( 515 + struct xfs_inode *ip, 516 + enum xfs_healthmon_type type, 517 + unsigned int old_mask, 518 + unsigned int new_mask) 519 + { 520 + struct xfs_healthmon_event event = { 521 + .type = type, 522 + .domain = XFS_HEALTHMON_INODE, 523 + .ino = ip->i_ino, 524 + .gen = VFS_I(ip)->i_generation, 525 + }; 526 + struct xfs_healthmon *hm = xfs_healthmon_get(ip->i_mount); 527 + 528 + if (!hm) 529 + return; 530 + 531 + event.imask = metadata_event_mask(hm, type, old_mask, new_mask) & 532 + ~XFS_SICK_INO_SECONDARY; 533 + trace_xfs_healthmon_report_inode(hm, old_mask, event.imask, &event); 534 + 535 + if (event.imask) 536 + xfs_healthmon_push(hm, &event); 537 + 538 + xfs_healthmon_put(hm); 539 + } 540 + 541 + /* Add a shutdown event to the reporting queue. */ 542 + void 543 + xfs_healthmon_report_shutdown( 544 + struct xfs_mount *mp, 545 + uint32_t flags) 546 + { 547 + struct xfs_healthmon_event event = { 548 + .type = XFS_HEALTHMON_SHUTDOWN, 549 + .domain = XFS_HEALTHMON_MOUNT, 550 + .flags = flags, 551 + }; 552 + struct xfs_healthmon *hm = xfs_healthmon_get(mp); 553 + 554 + if (!hm) 555 + return; 556 + 557 + trace_xfs_healthmon_report_shutdown(hm, flags); 558 + 559 + xfs_healthmon_push(hm, &event); 560 + xfs_healthmon_put(hm); 561 + } 562 + 563 + static inline enum xfs_healthmon_domain 564 + media_error_domain( 565 + enum xfs_device fdev) 566 + { 567 + switch (fdev) { 568 + case XFS_DEV_DATA: 569 + return XFS_HEALTHMON_DATADEV; 570 + case XFS_DEV_LOG: 571 + return XFS_HEALTHMON_LOGDEV; 572 + case XFS_DEV_RT: 573 + return XFS_HEALTHMON_RTDEV; 574 + } 575 + 576 + ASSERT(0); 577 + return 0; 578 + } 579 + 580 + /* Add a media error event to the reporting queue. */ 581 + void 582 + xfs_healthmon_report_media( 583 + struct xfs_mount *mp, 584 + enum xfs_device fdev, 585 + xfs_daddr_t daddr, 586 + uint64_t bbcount) 587 + { 588 + struct xfs_healthmon_event event = { 589 + .type = XFS_HEALTHMON_MEDIA_ERROR, 590 + .domain = media_error_domain(fdev), 591 + .daddr = daddr, 592 + .bbcount = bbcount, 593 + }; 594 + struct xfs_healthmon *hm = xfs_healthmon_get(mp); 595 + 596 + if (!hm) 597 + return; 598 + 599 + trace_xfs_healthmon_report_media(hm, fdev, &event); 600 + 601 + xfs_healthmon_push(hm, &event); 602 + xfs_healthmon_put(hm); 603 + } 604 + 605 + static inline enum xfs_healthmon_type file_ioerr_type(enum fserror_type action) 606 + { 607 + switch (action) { 608 + case FSERR_BUFFERED_READ: 609 + return XFS_HEALTHMON_BUFREAD; 610 + case FSERR_BUFFERED_WRITE: 611 + return XFS_HEALTHMON_BUFWRITE; 612 + case FSERR_DIRECTIO_READ: 613 + return XFS_HEALTHMON_DIOREAD; 614 + case FSERR_DIRECTIO_WRITE: 615 + return XFS_HEALTHMON_DIOWRITE; 616 + case FSERR_DATA_LOST: 617 + return XFS_HEALTHMON_DATALOST; 618 + case FSERR_METADATA: 619 + /* filtered out by xfs_fs_report_error */ 620 + break; 621 + } 622 + 623 + ASSERT(0); 624 + return -1; 625 + } 626 + 627 + /* Add a file io error event to the reporting queue. */ 628 + void 629 + xfs_healthmon_report_file_ioerror( 630 + struct xfs_inode *ip, 631 + const struct fserror_event *p) 632 + { 633 + struct xfs_healthmon_event event = { 634 + .type = file_ioerr_type(p->type), 635 + .domain = XFS_HEALTHMON_FILERANGE, 636 + .fino = ip->i_ino, 637 + .fgen = VFS_I(ip)->i_generation, 638 + .fpos = p->pos, 639 + .flen = p->len, 640 + /* send positive error number to userspace */ 641 + .error = -p->error, 642 + }; 643 + struct xfs_healthmon *hm = xfs_healthmon_get(ip->i_mount); 644 + 645 + if (!hm) 646 + return; 647 + 648 + trace_xfs_healthmon_report_file_ioerror(hm, p); 649 + 650 + xfs_healthmon_push(hm, &event); 651 + xfs_healthmon_put(hm); 652 + } 653 + 654 + static inline void 655 + xfs_healthmon_reset_outbuf( 656 + struct xfs_healthmon *hm) 657 + { 658 + hm->buftail = 0; 659 + hm->bufhead = 0; 660 + } 661 + 662 + struct flags_map { 663 + unsigned int in_mask; 664 + unsigned int out_mask; 665 + }; 666 + 667 + static const struct flags_map shutdown_map[] = { 668 + { SHUTDOWN_META_IO_ERROR, XFS_HEALTH_SHUTDOWN_META_IO_ERROR }, 669 + { SHUTDOWN_LOG_IO_ERROR, XFS_HEALTH_SHUTDOWN_LOG_IO_ERROR }, 670 + { SHUTDOWN_FORCE_UMOUNT, XFS_HEALTH_SHUTDOWN_FORCE_UMOUNT }, 671 + { SHUTDOWN_CORRUPT_INCORE, XFS_HEALTH_SHUTDOWN_CORRUPT_INCORE }, 672 + { SHUTDOWN_CORRUPT_ONDISK, XFS_HEALTH_SHUTDOWN_CORRUPT_ONDISK }, 673 + { SHUTDOWN_DEVICE_REMOVED, XFS_HEALTH_SHUTDOWN_DEVICE_REMOVED }, 674 + }; 675 + 676 + static inline unsigned int 677 + __map_flags( 678 + const struct flags_map *map, 679 + size_t array_len, 680 + unsigned int flags) 681 + { 682 + const struct flags_map *m; 683 + unsigned int ret = 0; 684 + 685 + for (m = map; m < map + array_len; m++) { 686 + if (flags & m->in_mask) 687 + ret |= m->out_mask; 688 + } 689 + 690 + return ret; 691 + } 692 + 693 + #define map_flags(map, flags) __map_flags((map), ARRAY_SIZE(map), (flags)) 694 + 695 + static inline unsigned int shutdown_mask(unsigned int in) 696 + { 697 + return map_flags(shutdown_map, in); 698 + } 699 + 700 + static const unsigned int domain_map[] = { 701 + [XFS_HEALTHMON_MOUNT] = XFS_HEALTH_MONITOR_DOMAIN_MOUNT, 702 + [XFS_HEALTHMON_FS] = XFS_HEALTH_MONITOR_DOMAIN_FS, 703 + [XFS_HEALTHMON_AG] = XFS_HEALTH_MONITOR_DOMAIN_AG, 704 + [XFS_HEALTHMON_INODE] = XFS_HEALTH_MONITOR_DOMAIN_INODE, 705 + [XFS_HEALTHMON_RTGROUP] = XFS_HEALTH_MONITOR_DOMAIN_RTGROUP, 706 + [XFS_HEALTHMON_DATADEV] = XFS_HEALTH_MONITOR_DOMAIN_DATADEV, 707 + [XFS_HEALTHMON_RTDEV] = XFS_HEALTH_MONITOR_DOMAIN_RTDEV, 708 + [XFS_HEALTHMON_LOGDEV] = XFS_HEALTH_MONITOR_DOMAIN_LOGDEV, 709 + [XFS_HEALTHMON_FILERANGE] = XFS_HEALTH_MONITOR_DOMAIN_FILERANGE, 710 + }; 711 + 712 + static const unsigned int type_map[] = { 713 + [XFS_HEALTHMON_RUNNING] = XFS_HEALTH_MONITOR_TYPE_RUNNING, 714 + [XFS_HEALTHMON_LOST] = XFS_HEALTH_MONITOR_TYPE_LOST, 715 + [XFS_HEALTHMON_SICK] = XFS_HEALTH_MONITOR_TYPE_SICK, 716 + [XFS_HEALTHMON_CORRUPT] = XFS_HEALTH_MONITOR_TYPE_CORRUPT, 717 + [XFS_HEALTHMON_HEALTHY] = XFS_HEALTH_MONITOR_TYPE_HEALTHY, 718 + [XFS_HEALTHMON_UNMOUNT] = XFS_HEALTH_MONITOR_TYPE_UNMOUNT, 719 + [XFS_HEALTHMON_SHUTDOWN] = XFS_HEALTH_MONITOR_TYPE_SHUTDOWN, 720 + [XFS_HEALTHMON_MEDIA_ERROR] = XFS_HEALTH_MONITOR_TYPE_MEDIA_ERROR, 721 + [XFS_HEALTHMON_BUFREAD] = XFS_HEALTH_MONITOR_TYPE_BUFREAD, 722 + [XFS_HEALTHMON_BUFWRITE] = XFS_HEALTH_MONITOR_TYPE_BUFWRITE, 723 + [XFS_HEALTHMON_DIOREAD] = XFS_HEALTH_MONITOR_TYPE_DIOREAD, 724 + [XFS_HEALTHMON_DIOWRITE] = XFS_HEALTH_MONITOR_TYPE_DIOWRITE, 725 + [XFS_HEALTHMON_DATALOST] = XFS_HEALTH_MONITOR_TYPE_DATALOST, 726 + }; 727 + 728 + /* Render event as a V0 structure */ 729 + STATIC int 730 + xfs_healthmon_format_v0( 731 + struct xfs_healthmon *hm, 732 + const struct xfs_healthmon_event *event) 733 + { 734 + struct xfs_health_monitor_event hme = { 735 + .time_ns = event->time_ns, 736 + }; 737 + 738 + trace_xfs_healthmon_format(hm, event); 739 + 740 + if (event->domain < 0 || event->domain >= ARRAY_SIZE(domain_map) || 741 + event->type < 0 || event->type >= ARRAY_SIZE(type_map)) 742 + return -EFSCORRUPTED; 743 + 744 + hme.domain = domain_map[event->domain]; 745 + hme.type = type_map[event->type]; 746 + 747 + /* fill in the event-specific details */ 748 + switch (event->domain) { 749 + case XFS_HEALTHMON_MOUNT: 750 + switch (event->type) { 751 + case XFS_HEALTHMON_LOST: 752 + hme.e.lost.count = event->lostcount; 753 + break; 754 + case XFS_HEALTHMON_SHUTDOWN: 755 + hme.e.shutdown.reasons = shutdown_mask(event->flags); 756 + break; 757 + default: 758 + break; 759 + } 760 + break; 761 + case XFS_HEALTHMON_FS: 762 + hme.e.fs.mask = xfs_healthmon_fs_mask(event->fsmask); 763 + break; 764 + case XFS_HEALTHMON_RTGROUP: 765 + hme.e.group.mask = xfs_healthmon_rtgroup_mask(event->grpmask); 766 + hme.e.group.gno = event->group; 767 + break; 768 + case XFS_HEALTHMON_AG: 769 + hme.e.group.mask = xfs_healthmon_perag_mask(event->grpmask); 770 + hme.e.group.gno = event->group; 771 + break; 772 + case XFS_HEALTHMON_INODE: 773 + hme.e.inode.mask = xfs_healthmon_inode_mask(event->imask); 774 + hme.e.inode.ino = event->ino; 775 + hme.e.inode.gen = event->gen; 776 + break; 777 + case XFS_HEALTHMON_DATADEV: 778 + case XFS_HEALTHMON_LOGDEV: 779 + case XFS_HEALTHMON_RTDEV: 780 + hme.e.media.daddr = event->daddr; 781 + hme.e.media.bbcount = event->bbcount; 782 + break; 783 + case XFS_HEALTHMON_FILERANGE: 784 + hme.e.filerange.ino = event->fino; 785 + hme.e.filerange.gen = event->fgen; 786 + hme.e.filerange.pos = event->fpos; 787 + hme.e.filerange.len = event->flen; 788 + hme.e.filerange.error = abs(event->error); 789 + break; 790 + default: 791 + break; 792 + } 793 + 794 + ASSERT(hm->bufhead + sizeof(hme) <= hm->bufsize); 795 + 796 + /* copy formatted object to the outbuf */ 797 + if (hm->bufhead + sizeof(hme) <= hm->bufsize) { 798 + memcpy(hm->buffer + hm->bufhead, &hme, sizeof(hme)); 799 + hm->bufhead += sizeof(hme); 800 + } 801 + 802 + return 0; 803 + } 804 + 805 + /* How many bytes are waiting in the outbuf to be copied? */ 806 + static inline size_t 807 + xfs_healthmon_outbuf_bytes( 808 + struct xfs_healthmon *hm) 809 + { 810 + if (hm->bufhead > hm->buftail) 811 + return hm->bufhead - hm->buftail; 812 + return 0; 813 + } 814 + 815 + /* 816 + * Do we have something for userspace to read? This can mean unmount events, 817 + * events pending in the queue, or pending bytes in the outbuf. 818 + */ 819 + static inline bool 820 + xfs_healthmon_has_eventdata( 821 + struct xfs_healthmon *hm) 822 + { 823 + /* 824 + * If the health monitor is already detached from the xfs_mount, we 825 + * want reads to return 0 bytes even if there are no events, because 826 + * userspace interprets that as EOF. If we race with deactivation, 827 + * read_iter will take the necessary locks to discover that there are 828 + * no events to send. 829 + */ 830 + if (hm->mount_cookie == DETACHED_MOUNT_COOKIE) 831 + return true; 832 + 833 + /* 834 + * Either there are events waiting to be formatted into the buffer, or 835 + * there's unread bytes in the buffer. 836 + */ 837 + return hm->events > 0 || xfs_healthmon_outbuf_bytes(hm) > 0; 838 + } 839 + 840 + /* Try to copy the rest of the outbuf to the iov iter. */ 841 + STATIC ssize_t 842 + xfs_healthmon_copybuf( 843 + struct xfs_healthmon *hm, 844 + struct iov_iter *to) 845 + { 846 + size_t to_copy; 847 + size_t w = 0; 848 + 849 + trace_xfs_healthmon_copybuf(hm, to); 850 + 851 + to_copy = xfs_healthmon_outbuf_bytes(hm); 852 + if (to_copy) { 853 + w = copy_to_iter(hm->buffer + hm->buftail, to_copy, to); 854 + if (!w) 855 + return -EFAULT; 856 + 857 + hm->buftail += w; 858 + } 859 + 860 + /* 861 + * Nothing left to copy? Reset the output buffer cursors to the start 862 + * since there's no live data in the buffer. 863 + */ 864 + if (xfs_healthmon_outbuf_bytes(hm) == 0) 865 + xfs_healthmon_reset_outbuf(hm); 866 + return w; 867 + } 868 + 869 + /* 870 + * Return a health monitoring event for formatting into the output buffer if 871 + * there's enough space in the outbuf and an event waiting for us. Caller 872 + * must hold i_rwsem on the healthmon file. 873 + */ 874 + static inline struct xfs_healthmon_event * 875 + xfs_healthmon_format_pop( 876 + struct xfs_healthmon *hm) 877 + { 878 + struct xfs_healthmon_event *event; 879 + 880 + if (hm->bufhead + sizeof(*event) > hm->bufsize) 881 + return NULL; 882 + 883 + mutex_lock(&hm->lock); 884 + event = hm->first_event; 885 + if (event) { 886 + if (hm->last_event == event) 887 + hm->last_event = NULL; 888 + hm->first_event = event->next; 889 + hm->events--; 890 + 891 + trace_xfs_healthmon_pop(hm, event); 892 + } 893 + mutex_unlock(&hm->lock); 894 + return event; 895 + } 896 + 897 + /* Allocate formatting buffer */ 898 + STATIC int 899 + xfs_healthmon_alloc_outbuf( 900 + struct xfs_healthmon *hm, 901 + size_t user_bufsize) 902 + { 903 + void *outbuf; 904 + size_t bufsize = 905 + min(XFS_HEALTHMON_MAX_OUTBUF, max(PAGE_SIZE, user_bufsize)); 906 + 907 + outbuf = kzalloc(bufsize, GFP_KERNEL); 908 + if (!outbuf) { 909 + if (bufsize == PAGE_SIZE) 910 + return -ENOMEM; 911 + 912 + bufsize = PAGE_SIZE; 913 + outbuf = kzalloc(bufsize, GFP_KERNEL); 914 + if (!outbuf) 915 + return -ENOMEM; 916 + } 917 + 918 + hm->buffer = outbuf; 919 + hm->bufsize = bufsize; 920 + hm->bufhead = 0; 921 + hm->buftail = 0; 922 + 923 + return 0; 924 + } 925 + 926 + /* 927 + * Convey queued event data to userspace. First copy any remaining bytes in 928 + * the outbuf, then format the oldest event into the outbuf and copy that too. 929 + */ 930 + STATIC ssize_t 931 + xfs_healthmon_read_iter( 932 + struct kiocb *iocb, 933 + struct iov_iter *to) 934 + { 935 + struct file *file = iocb->ki_filp; 936 + struct inode *inode = file_inode(file); 937 + struct xfs_healthmon *hm = file->private_data; 938 + struct xfs_healthmon_event *event; 939 + size_t copied = 0; 940 + ssize_t ret = 0; 941 + 942 + if (file->f_flags & O_NONBLOCK) { 943 + if (!xfs_healthmon_has_eventdata(hm) || !inode_trylock(inode)) 944 + return -EAGAIN; 945 + } else { 946 + ret = wait_event_interruptible(hm->wait, 947 + xfs_healthmon_has_eventdata(hm)); 948 + if (ret) 949 + return ret; 950 + 951 + inode_lock(inode); 952 + } 953 + 954 + if (hm->bufsize == 0) { 955 + ret = xfs_healthmon_alloc_outbuf(hm, iov_iter_count(to)); 956 + if (ret) 957 + goto out_unlock; 958 + } 959 + 960 + trace_xfs_healthmon_read_start(hm); 961 + 962 + /* 963 + * If there's anything left in the output buffer, copy that before 964 + * formatting more events. 965 + */ 966 + ret = xfs_healthmon_copybuf(hm, to); 967 + if (ret < 0) 968 + goto out_unlock; 969 + copied += ret; 970 + 971 + while (iov_iter_count(to) > 0) { 972 + /* Format the next events into the outbuf until it's full. */ 973 + while ((event = xfs_healthmon_format_pop(hm)) != NULL) { 974 + ret = xfs_healthmon_format_v0(hm, event); 975 + kfree(event); 976 + if (ret) 977 + goto out_unlock; 978 + } 979 + 980 + /* Copy anything formatted into outbuf to userspace */ 981 + ret = xfs_healthmon_copybuf(hm, to); 982 + if (ret <= 0) 983 + break; 984 + 985 + copied += ret; 986 + } 987 + 988 + out_unlock: 989 + trace_xfs_healthmon_read_finish(hm); 990 + inode_unlock(inode); 991 + return copied ?: ret; 992 + } 993 + 994 + /* Poll for available events. */ 995 + STATIC __poll_t 996 + xfs_healthmon_poll( 997 + struct file *file, 998 + struct poll_table_struct *wait) 999 + { 1000 + struct xfs_healthmon *hm = file->private_data; 1001 + __poll_t mask = 0; 1002 + 1003 + poll_wait(file, &hm->wait, wait); 1004 + 1005 + if (xfs_healthmon_has_eventdata(hm)) 1006 + mask |= EPOLLIN; 1007 + return mask; 1008 + } 1009 + 1010 + /* Free the health monitoring information. */ 1011 + STATIC int 1012 + xfs_healthmon_release( 1013 + struct inode *inode, 1014 + struct file *file) 1015 + { 1016 + struct xfs_healthmon *hm = file->private_data; 1017 + 1018 + trace_xfs_healthmon_release(hm); 1019 + 1020 + /* 1021 + * We might be closing the healthmon file before the filesystem 1022 + * unmounts, because userspace processes can terminate at any time and 1023 + * for any reason. Null out xfs_mount::m_healthmon so that another 1024 + * process can create another health monitor file. 1025 + */ 1026 + xfs_healthmon_detach(hm); 1027 + 1028 + /* 1029 + * Wake up any readers that might be left. There shouldn't be any 1030 + * because the only users of the waiter are read and poll. 1031 + */ 1032 + wake_up_all(&hm->wait); 1033 + 1034 + xfs_healthmon_put(hm); 1035 + return 0; 1036 + } 1037 + 1038 + /* Validate ioctl parameters. */ 1039 + static inline bool 1040 + xfs_healthmon_validate( 1041 + const struct xfs_health_monitor *hmo) 1042 + { 1043 + if (hmo->flags & ~XFS_HEALTH_MONITOR_ALL) 1044 + return false; 1045 + if (hmo->format != XFS_HEALTH_MONITOR_FMT_V0) 1046 + return false; 1047 + if (memchr_inv(&hmo->pad, 0, sizeof(hmo->pad))) 1048 + return false; 1049 + return true; 1050 + } 1051 + 1052 + /* Emit some data about the health monitoring fd. */ 1053 + static void 1054 + xfs_healthmon_show_fdinfo( 1055 + struct seq_file *m, 1056 + struct file *file) 1057 + { 1058 + struct xfs_healthmon *hm = file->private_data; 1059 + 1060 + mutex_lock(&hm->lock); 1061 + seq_printf(m, "state:\t%s\ndev:\t%d:%d\nformat:\tv0\nevents:\t%llu\nlost:\t%llu\n", 1062 + hm->mount_cookie == DETACHED_MOUNT_COOKIE ? 1063 + "dead" : "alive", 1064 + MAJOR(hm->dev), MINOR(hm->dev), 1065 + hm->total_events, 1066 + hm->total_lost); 1067 + mutex_unlock(&hm->lock); 1068 + } 1069 + 1070 + /* Reconfigure the health monitor. */ 1071 + STATIC long 1072 + xfs_healthmon_reconfigure( 1073 + struct file *file, 1074 + unsigned int cmd, 1075 + void __user *arg) 1076 + { 1077 + struct xfs_health_monitor hmo; 1078 + struct xfs_healthmon *hm = file->private_data; 1079 + 1080 + if (copy_from_user(&hmo, arg, sizeof(hmo))) 1081 + return -EFAULT; 1082 + 1083 + if (!xfs_healthmon_validate(&hmo)) 1084 + return -EINVAL; 1085 + 1086 + mutex_lock(&hm->lock); 1087 + hm->verbose = !!(hmo.flags & XFS_HEALTH_MONITOR_VERBOSE); 1088 + mutex_unlock(&hm->lock); 1089 + 1090 + return 0; 1091 + } 1092 + 1093 + /* Does the fd point to the same filesystem as the one we're monitoring? */ 1094 + STATIC long 1095 + xfs_healthmon_file_on_monitored_fs( 1096 + struct file *file, 1097 + unsigned int cmd, 1098 + void __user *arg) 1099 + { 1100 + struct xfs_health_file_on_monitored_fs hms; 1101 + struct xfs_healthmon *hm = file->private_data; 1102 + struct inode *hms_inode; 1103 + 1104 + if (copy_from_user(&hms, arg, sizeof(hms))) 1105 + return -EFAULT; 1106 + 1107 + if (hms.flags) 1108 + return -EINVAL; 1109 + 1110 + CLASS(fd, hms_fd)(hms.fd); 1111 + if (fd_empty(hms_fd)) 1112 + return -EBADF; 1113 + 1114 + hms_inode = file_inode(fd_file(hms_fd)); 1115 + mutex_lock(&hm->lock); 1116 + if (hm->mount_cookie != (uintptr_t)hms_inode->i_sb) { 1117 + mutex_unlock(&hm->lock); 1118 + return -ESTALE; 1119 + } 1120 + 1121 + mutex_unlock(&hm->lock); 1122 + return 0; 1123 + } 1124 + 1125 + /* Handle ioctls for the health monitoring thread. */ 1126 + STATIC long 1127 + xfs_healthmon_ioctl( 1128 + struct file *file, 1129 + unsigned int cmd, 1130 + unsigned long p) 1131 + { 1132 + void __user *arg = (void __user *)p; 1133 + 1134 + switch (cmd) { 1135 + case XFS_IOC_HEALTH_MONITOR: 1136 + return xfs_healthmon_reconfigure(file, cmd, arg); 1137 + case XFS_IOC_HEALTH_FD_ON_MONITORED_FS: 1138 + return xfs_healthmon_file_on_monitored_fs(file, cmd, arg); 1139 + default: 1140 + break; 1141 + } 1142 + 1143 + return -ENOTTY; 1144 + } 1145 + 1146 + static const struct file_operations xfs_healthmon_fops = { 1147 + .owner = THIS_MODULE, 1148 + .show_fdinfo = xfs_healthmon_show_fdinfo, 1149 + .read_iter = xfs_healthmon_read_iter, 1150 + .poll = xfs_healthmon_poll, 1151 + .release = xfs_healthmon_release, 1152 + .unlocked_ioctl = xfs_healthmon_ioctl, 1153 + }; 1154 + 1155 + /* 1156 + * Create a health monitoring file. Returns an index to the fd table or a 1157 + * negative errno. 1158 + */ 1159 + long 1160 + xfs_ioc_health_monitor( 1161 + struct file *file, 1162 + struct xfs_health_monitor __user *arg) 1163 + { 1164 + struct xfs_health_monitor hmo; 1165 + struct xfs_healthmon_event *running_event; 1166 + struct xfs_healthmon *hm; 1167 + struct xfs_inode *ip = XFS_I(file_inode(file)); 1168 + struct xfs_mount *mp = ip->i_mount; 1169 + int ret; 1170 + 1171 + /* 1172 + * The only intended user of the health monitoring system should be the 1173 + * xfs_healer daemon running on behalf of the whole filesystem in the 1174 + * initial user namespace. IOWs, we don't allow unprivileged userspace 1175 + * (they can use fsnotify) nor do we allow containers. 1176 + */ 1177 + if (!capable(CAP_SYS_ADMIN)) 1178 + return -EPERM; 1179 + if (ip->i_ino != mp->m_sb.sb_rootino) 1180 + return -EPERM; 1181 + if (current_user_ns() != &init_user_ns) 1182 + return -EPERM; 1183 + 1184 + if (copy_from_user(&hmo, arg, sizeof(hmo))) 1185 + return -EFAULT; 1186 + 1187 + if (!xfs_healthmon_validate(&hmo)) 1188 + return -EINVAL; 1189 + 1190 + hm = kzalloc(sizeof(*hm), GFP_KERNEL); 1191 + if (!hm) 1192 + return -ENOMEM; 1193 + hm->dev = mp->m_super->s_dev; 1194 + refcount_set(&hm->ref, 1); 1195 + 1196 + mutex_init(&hm->lock); 1197 + init_waitqueue_head(&hm->wait); 1198 + 1199 + if (hmo.flags & XFS_HEALTH_MONITOR_VERBOSE) 1200 + hm->verbose = true; 1201 + 1202 + /* Queue up the first event that lets the client know we're running. */ 1203 + running_event = kzalloc(sizeof(struct xfs_healthmon_event), GFP_NOFS); 1204 + if (!running_event) { 1205 + ret = -ENOMEM; 1206 + goto out_hm; 1207 + } 1208 + running_event->type = XFS_HEALTHMON_RUNNING; 1209 + running_event->domain = XFS_HEALTHMON_MOUNT; 1210 + __xfs_healthmon_insert(hm, running_event); 1211 + 1212 + /* 1213 + * Preallocate the unmount event so that we can't fail to notify the 1214 + * filesystem later. This is key for triggering fast exit of the 1215 + * xfs_healer daemon. 1216 + */ 1217 + hm->unmount_event = kzalloc(sizeof(struct xfs_healthmon_event), 1218 + GFP_NOFS); 1219 + if (!hm->unmount_event) { 1220 + ret = -ENOMEM; 1221 + goto out_hm; 1222 + } 1223 + hm->unmount_event->type = XFS_HEALTHMON_UNMOUNT; 1224 + hm->unmount_event->domain = XFS_HEALTHMON_MOUNT; 1225 + 1226 + /* 1227 + * Try to attach this health monitor to the xfs_mount. The monitor is 1228 + * considered live and will receive events if this succeeds. 1229 + */ 1230 + ret = xfs_healthmon_attach(mp, hm); 1231 + if (ret) 1232 + goto out_hm; 1233 + 1234 + /* 1235 + * Create the anonymous file and install a fd for it. If it succeeds, 1236 + * the file owns hm and can go away at any time, so we must not access 1237 + * it again. This must go last because we can't undo a fd table 1238 + * installation. 1239 + */ 1240 + ret = anon_inode_getfd("xfs_healthmon", &xfs_healthmon_fops, hm, 1241 + O_CLOEXEC | O_RDONLY); 1242 + if (ret < 0) 1243 + goto out_mp; 1244 + 1245 + trace_xfs_healthmon_create(mp->m_super->s_dev, hmo.flags, hmo.format); 1246 + 1247 + return ret; 1248 + 1249 + out_mp: 1250 + xfs_healthmon_detach(hm); 1251 + out_hm: 1252 + ASSERT(refcount_read(&hm->ref) == 1); 1253 + xfs_healthmon_put(hm); 1254 + return ret; 1255 + }
+184
fs/xfs/xfs_healthmon.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + /* 3 + * Copyright (c) 2024-2026 Oracle. All Rights Reserved. 4 + * Author: Darrick J. Wong <djwong@kernel.org> 5 + */ 6 + #ifndef __XFS_HEALTHMON_H__ 7 + #define __XFS_HEALTHMON_H__ 8 + 9 + struct xfs_healthmon { 10 + /* 11 + * Weak reference to the xfs filesystem that is being monitored. It 12 + * will be set to zero when the filesystem detaches from the monitor. 13 + * Do not dereference this pointer. 14 + */ 15 + uintptr_t mount_cookie; 16 + 17 + /* 18 + * Device number of the filesystem being monitored. This is for 19 + * consistent tracing even after unmount. 20 + */ 21 + dev_t dev; 22 + 23 + /* 24 + * Reference count of this structure. The open healthmon fd holds one 25 + * ref, the xfs_mount holds another ref if it points to this object, 26 + * and running event handlers hold their own refs. 27 + */ 28 + refcount_t ref; 29 + 30 + /* lock for event list and event counters */ 31 + struct mutex lock; 32 + 33 + /* list of event objects */ 34 + struct xfs_healthmon_event *first_event; 35 + struct xfs_healthmon_event *last_event; 36 + 37 + /* preallocated event for unmount */ 38 + struct xfs_healthmon_event *unmount_event; 39 + 40 + /* number of events in the list */ 41 + unsigned int events; 42 + 43 + /* do we want all events? */ 44 + bool verbose:1; 45 + 46 + /* waiter so read/poll can sleep until the arrival of events */ 47 + struct wait_queue_head wait; 48 + 49 + /* 50 + * Buffer for formatting events for a read_iter call. Events are 51 + * formatted into the buffer at bufhead, and buftail determines where 52 + * to start a copy_iter to get those events to userspace. All buffer 53 + * fields are protected by inode_lock. 54 + */ 55 + char *buffer; 56 + size_t bufsize; 57 + size_t bufhead; 58 + size_t buftail; 59 + 60 + /* did we lose previous events? */ 61 + unsigned long long lost_prev_event; 62 + 63 + /* total counts of events observed and lost events */ 64 + unsigned long long total_events; 65 + unsigned long long total_lost; 66 + }; 67 + 68 + void xfs_healthmon_unmount(struct xfs_mount *mp); 69 + 70 + enum xfs_healthmon_type { 71 + XFS_HEALTHMON_RUNNING, /* monitor running */ 72 + XFS_HEALTHMON_LOST, /* message lost */ 73 + XFS_HEALTHMON_UNMOUNT, /* filesystem is unmounting */ 74 + 75 + /* filesystem shutdown */ 76 + XFS_HEALTHMON_SHUTDOWN, 77 + 78 + /* metadata health events */ 79 + XFS_HEALTHMON_SICK, /* runtime corruption observed */ 80 + XFS_HEALTHMON_CORRUPT, /* fsck reported corruption */ 81 + XFS_HEALTHMON_HEALTHY, /* fsck reported healthy structure */ 82 + 83 + /* media errors */ 84 + XFS_HEALTHMON_MEDIA_ERROR, 85 + 86 + /* file range events */ 87 + XFS_HEALTHMON_BUFREAD, 88 + XFS_HEALTHMON_BUFWRITE, 89 + XFS_HEALTHMON_DIOREAD, 90 + XFS_HEALTHMON_DIOWRITE, 91 + XFS_HEALTHMON_DATALOST, 92 + }; 93 + 94 + enum xfs_healthmon_domain { 95 + XFS_HEALTHMON_MOUNT, /* affects the whole fs */ 96 + 97 + /* metadata health events */ 98 + XFS_HEALTHMON_FS, /* main filesystem metadata */ 99 + XFS_HEALTHMON_AG, /* allocation group metadata */ 100 + XFS_HEALTHMON_INODE, /* inode metadata */ 101 + XFS_HEALTHMON_RTGROUP, /* realtime group metadata */ 102 + 103 + /* media errors */ 104 + XFS_HEALTHMON_DATADEV, 105 + XFS_HEALTHMON_RTDEV, 106 + XFS_HEALTHMON_LOGDEV, 107 + 108 + /* file range events */ 109 + XFS_HEALTHMON_FILERANGE, 110 + }; 111 + 112 + struct xfs_healthmon_event { 113 + struct xfs_healthmon_event *next; 114 + 115 + enum xfs_healthmon_type type; 116 + enum xfs_healthmon_domain domain; 117 + 118 + uint64_t time_ns; 119 + 120 + union { 121 + /* lost events */ 122 + struct { 123 + uint64_t lostcount; 124 + }; 125 + /* fs/rt metadata */ 126 + struct { 127 + /* XFS_SICK_* flags */ 128 + unsigned int fsmask; 129 + }; 130 + /* ag/rtgroup metadata */ 131 + struct { 132 + /* XFS_SICK_(AG|RG)* flags */ 133 + unsigned int grpmask; 134 + unsigned int group; 135 + }; 136 + /* inode metadata */ 137 + struct { 138 + /* XFS_SICK_INO_* flags */ 139 + unsigned int imask; 140 + uint32_t gen; 141 + xfs_ino_t ino; 142 + }; 143 + /* shutdown */ 144 + struct { 145 + unsigned int flags; 146 + }; 147 + /* media errors */ 148 + struct { 149 + xfs_daddr_t daddr; 150 + uint64_t bbcount; 151 + }; 152 + /* file range events */ 153 + struct { 154 + xfs_ino_t fino; 155 + loff_t fpos; 156 + uint64_t flen; 157 + uint32_t fgen; 158 + int error; 159 + }; 160 + }; 161 + }; 162 + 163 + void xfs_healthmon_report_fs(struct xfs_mount *mp, 164 + enum xfs_healthmon_type type, unsigned int old_mask, 165 + unsigned int new_mask); 166 + void xfs_healthmon_report_group(struct xfs_group *xg, 167 + enum xfs_healthmon_type type, unsigned int old_mask, 168 + unsigned int new_mask); 169 + void xfs_healthmon_report_inode(struct xfs_inode *ip, 170 + enum xfs_healthmon_type type, unsigned int old_mask, 171 + unsigned int new_mask); 172 + 173 + void xfs_healthmon_report_shutdown(struct xfs_mount *mp, uint32_t flags); 174 + 175 + void xfs_healthmon_report_media(struct xfs_mount *mp, enum xfs_device fdev, 176 + xfs_daddr_t daddr, uint64_t bbcount); 177 + 178 + void xfs_healthmon_report_file_ioerror(struct xfs_inode *ip, 179 + const struct fserror_event *p); 180 + 181 + long xfs_ioc_health_monitor(struct file *file, 182 + struct xfs_health_monitor __user *arg); 183 + 184 + #endif /* __XFS_HEALTHMON_H__ */
+1 -1
fs/xfs/xfs_hooks.c
··· 3 3 * Copyright (c) 2022-2024 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <djwong@kernel.org> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/xfs_icache.c
··· 3 3 * Copyright (c) 2000-2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+3 -5
fs/xfs/xfs_icreate_item.c
··· 3 3 * Copyright (c) 2008-2010, 2013 Dave Chinner 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 49 49 STATIC void 50 50 xfs_icreate_item_format( 51 51 struct xfs_log_item *lip, 52 - struct xfs_log_vec *lv) 52 + struct xlog_format_buf *lfb) 53 53 { 54 54 struct xfs_icreate_item *icp = ICR_ITEM(lip); 55 - struct xfs_log_iovec *vecp = NULL; 56 55 57 - xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ICREATE, 58 - &icp->ic_format, 56 + xlog_format_copy(lfb, XLOG_REG_TYPE_ICREATE, &icp->ic_format, 59 57 sizeof(struct xfs_icreate_log)); 60 58 } 61 59
+1 -1
fs/xfs/xfs_inode.c
··· 5 5 */ 6 6 #include <linux/iversion.h> 7 7 8 - #include "xfs.h" 8 + #include "xfs_platform.h" 9 9 #include "xfs_fs.h" 10 10 #include "xfs_shared.h" 11 11 #include "xfs_format.h"
+24 -27
fs/xfs/xfs_inode_item.c
··· 3 3 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 336 336 xfs_inode_item_format_data_fork( 337 337 struct xfs_inode_log_item *iip, 338 338 struct xfs_inode_log_format *ilf, 339 - struct xfs_log_vec *lv, 340 - struct xfs_log_iovec **vecp) 339 + struct xlog_format_buf *lfb) 341 340 { 342 341 struct xfs_inode *ip = iip->ili_inode; 343 342 size_t data_bytes; ··· 353 354 354 355 ASSERT(xfs_iext_count(&ip->i_df) > 0); 355 356 356 - p = xlog_prepare_iovec(lv, vecp, XLOG_REG_TYPE_IEXT); 357 + p = xlog_format_start(lfb, XLOG_REG_TYPE_IEXT); 357 358 data_bytes = xfs_iextents_copy(ip, p, XFS_DATA_FORK); 358 - xlog_finish_iovec(lv, *vecp, data_bytes); 359 + xlog_format_commit(lfb, data_bytes); 359 360 360 361 ASSERT(data_bytes <= ip->i_df.if_bytes); 361 362 ··· 373 374 if ((iip->ili_fields & XFS_ILOG_DBROOT) && 374 375 ip->i_df.if_broot_bytes > 0) { 375 376 ASSERT(ip->i_df.if_broot != NULL); 376 - xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_IBROOT, 377 + xlog_format_copy(lfb, XLOG_REG_TYPE_IBROOT, 377 378 ip->i_df.if_broot, 378 379 ip->i_df.if_broot_bytes); 379 380 ilf->ilf_dsize = ip->i_df.if_broot_bytes; ··· 391 392 ip->i_df.if_bytes > 0) { 392 393 ASSERT(ip->i_df.if_data != NULL); 393 394 ASSERT(ip->i_disk_size > 0); 394 - xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_ILOCAL, 395 - ip->i_df.if_data, ip->i_df.if_bytes); 395 + xlog_format_copy(lfb, XLOG_REG_TYPE_ILOCAL, 396 + ip->i_df.if_data, 397 + ip->i_df.if_bytes); 396 398 ilf->ilf_dsize = (unsigned)ip->i_df.if_bytes; 397 399 ilf->ilf_size++; 398 400 } else { ··· 416 416 xfs_inode_item_format_attr_fork( 417 417 struct xfs_inode_log_item *iip, 418 418 struct xfs_inode_log_format *ilf, 419 - struct xfs_log_vec *lv, 420 - struct xfs_log_iovec **vecp) 419 + struct xlog_format_buf *lfb) 421 420 { 422 421 struct xfs_inode *ip = iip->ili_inode; 423 422 size_t data_bytes; ··· 434 435 ASSERT(xfs_iext_count(&ip->i_af) == 435 436 ip->i_af.if_nextents); 436 437 437 - p = xlog_prepare_iovec(lv, vecp, XLOG_REG_TYPE_IATTR_EXT); 438 + p = xlog_format_start(lfb, XLOG_REG_TYPE_IATTR_EXT); 438 439 data_bytes = xfs_iextents_copy(ip, p, XFS_ATTR_FORK); 439 - xlog_finish_iovec(lv, *vecp, data_bytes); 440 + xlog_format_commit(lfb, data_bytes); 440 441 441 442 ilf->ilf_asize = data_bytes; 442 443 ilf->ilf_size++; ··· 452 453 ip->i_af.if_broot_bytes > 0) { 453 454 ASSERT(ip->i_af.if_broot != NULL); 454 455 455 - xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_IATTR_BROOT, 456 + xlog_format_copy(lfb, XLOG_REG_TYPE_IATTR_BROOT, 456 457 ip->i_af.if_broot, 457 458 ip->i_af.if_broot_bytes); 458 459 ilf->ilf_asize = ip->i_af.if_broot_bytes; ··· 468 469 if ((iip->ili_fields & XFS_ILOG_ADATA) && 469 470 ip->i_af.if_bytes > 0) { 470 471 ASSERT(ip->i_af.if_data != NULL); 471 - xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_IATTR_LOCAL, 472 - ip->i_af.if_data, ip->i_af.if_bytes); 472 + xlog_format_copy(lfb, XLOG_REG_TYPE_IATTR_LOCAL, 473 + ip->i_af.if_data, 474 + ip->i_af.if_bytes); 473 475 ilf->ilf_asize = (unsigned)ip->i_af.if_bytes; 474 476 ilf->ilf_size++; 475 477 } else { ··· 619 619 static void 620 620 xfs_inode_item_format_core( 621 621 struct xfs_inode *ip, 622 - struct xfs_log_vec *lv, 623 - struct xfs_log_iovec **vecp) 622 + struct xlog_format_buf *lfb) 624 623 { 625 624 struct xfs_log_dinode *dic; 626 625 627 - dic = xlog_prepare_iovec(lv, vecp, XLOG_REG_TYPE_ICORE); 626 + dic = xlog_format_start(lfb, XLOG_REG_TYPE_ICORE); 628 627 xfs_inode_to_log_dinode(ip, dic, ip->i_itemp->ili_item.li_lsn); 629 - xlog_finish_iovec(lv, *vecp, xfs_log_dinode_size(ip->i_mount)); 628 + xlog_format_commit(lfb, xfs_log_dinode_size(ip->i_mount)); 630 629 } 631 630 632 631 /* ··· 643 644 STATIC void 644 645 xfs_inode_item_format( 645 646 struct xfs_log_item *lip, 646 - struct xfs_log_vec *lv) 647 + struct xlog_format_buf *lfb) 647 648 { 648 649 struct xfs_inode_log_item *iip = INODE_ITEM(lip); 649 650 struct xfs_inode *ip = iip->ili_inode; 650 - struct xfs_log_iovec *vecp = NULL; 651 651 struct xfs_inode_log_format *ilf; 652 652 653 - ilf = xlog_prepare_iovec(lv, &vecp, XLOG_REG_TYPE_IFORMAT); 653 + ilf = xlog_format_start(lfb, XLOG_REG_TYPE_IFORMAT); 654 654 ilf->ilf_type = XFS_LI_INODE; 655 655 ilf->ilf_ino = ip->i_ino; 656 656 ilf->ilf_blkno = ip->i_imap.im_blkno; ··· 666 668 ilf->ilf_asize = 0; 667 669 ilf->ilf_pad = 0; 668 670 memset(&ilf->ilf_u, 0, sizeof(ilf->ilf_u)); 671 + xlog_format_commit(lfb, sizeof(*ilf)); 669 672 670 - xlog_finish_iovec(lv, vecp, sizeof(*ilf)); 671 - 672 - xfs_inode_item_format_core(ip, lv, &vecp); 673 - xfs_inode_item_format_data_fork(iip, ilf, lv, &vecp); 673 + xfs_inode_item_format_core(ip, lfb); 674 + xfs_inode_item_format_data_fork(iip, ilf, lfb); 674 675 if (xfs_inode_has_attr_fork(ip)) { 675 - xfs_inode_item_format_attr_fork(iip, ilf, lv, &vecp); 676 + xfs_inode_item_format_attr_fork(iip, ilf, lfb); 676 677 } else { 677 678 iip->ili_fields &= 678 679 ~(XFS_ILOG_ADATA | XFS_ILOG_ABROOT | XFS_ILOG_AEXT);
+1 -1
fs/xfs/xfs_inode_item_recover.c
··· 3 3 * Copyright (c) 2000-2006 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+8 -1
fs/xfs/xfs_ioctl.c
··· 3 3 * Copyright (c) 2000-2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 41 41 #include "xfs_exchrange.h" 42 42 #include "xfs_handle.h" 43 43 #include "xfs_rtgroup.h" 44 + #include "xfs_healthmon.h" 45 + #include "xfs_verify_media.h" 44 46 45 47 #include <linux/mount.h> 46 48 #include <linux/fileattr.h> ··· 1420 1418 return xfs_ioc_start_commit(filp, arg); 1421 1419 case XFS_IOC_COMMIT_RANGE: 1422 1420 return xfs_ioc_commit_range(filp, arg); 1421 + 1422 + case XFS_IOC_HEALTH_MONITOR: 1423 + return xfs_ioc_health_monitor(filp, arg); 1424 + case XFS_IOC_VERIFY_MEDIA: 1425 + return xfs_ioc_verify_media(filp, arg); 1423 1426 1424 1427 default: 1425 1428 return -ENOTTY;
+1 -1
fs/xfs/xfs_ioctl32.c
··· 5 5 */ 6 6 #include <linux/mount.h> 7 7 #include <linux/fsmap.h> 8 - #include "xfs.h" 8 + #include "xfs_platform.h" 9 9 #include "xfs_fs.h" 10 10 #include "xfs_shared.h" 11 11 #include "xfs_format.h"
+1 -1
fs/xfs/xfs_iomap.c
··· 4 4 * Copyright (c) 2016-2018 Christoph Hellwig. 5 5 * All Rights Reserved. 6 6 */ 7 - #include "xfs.h" 7 + #include "xfs_platform.h" 8 8 #include "xfs_fs.h" 9 9 #include "xfs_shared.h" 10 10 #include "xfs_format.h"
+1 -1
fs/xfs/xfs_iops.c
··· 3 3 * Copyright (c) 2000-2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/xfs_itable.c
··· 3 3 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/xfs_iwalk.c
··· 3 3 * Copyright (C) 2019 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <darrick.wong@oracle.com> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+29 -17
fs/xfs/xfs_linux.h fs/xfs/xfs_platform.h
··· 3 3 * Copyright (c) 2000-2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #ifndef __XFS_LINUX__ 7 - #define __XFS_LINUX__ 6 + #ifndef _XFS_PLATFORM_H 7 + #define _XFS_PLATFORM_H 8 8 9 9 #include <linux/types.h> 10 10 #include <linux/uuid.h> 11 - 12 - /* 13 - * Kernel specific type declarations for XFS 14 - */ 15 - 16 - typedef __s64 xfs_off_t; /* <file offset> type */ 17 - typedef unsigned long long xfs_ino_t; /* <inode> type */ 18 - typedef __s64 xfs_daddr_t; /* <disk address> type */ 19 - typedef __u32 xfs_dev_t; 20 - typedef __u32 xfs_nlink_t; 21 - 22 - #include "xfs_types.h" 23 - 24 11 #include <linux/semaphore.h> 25 12 #include <linux/mm.h> 26 13 #include <linux/sched/mm.h> ··· 50 63 #include <linux/xattr.h> 51 64 #include <linux/mnt_idmapping.h> 52 65 #include <linux/debugfs.h> 53 - 54 66 #include <asm/page.h> 55 67 #include <asm/div64.h> 56 68 #include <asm/param.h> ··· 57 71 #include <asm/byteorder.h> 58 72 #include <linux/unaligned.h> 59 73 74 + #ifdef CONFIG_XFS_DEBUG 75 + #define DEBUG 1 76 + #endif 77 + 78 + #ifdef CONFIG_XFS_DEBUG_EXPENSIVE 79 + #define DEBUG_EXPENSIVE 1 80 + #endif 81 + 82 + #ifdef CONFIG_XFS_ASSERT_FATAL 83 + #define XFS_ASSERT_FATAL 1 84 + #endif 85 + 86 + #ifdef CONFIG_XFS_WARN 87 + #define XFS_WARN 1 88 + #endif 89 + 90 + /* 91 + * Kernel specific type declarations for XFS 92 + */ 93 + typedef __s64 xfs_off_t; /* <file offset> type */ 94 + typedef unsigned long long xfs_ino_t; /* <inode> type */ 95 + typedef __s64 xfs_daddr_t; /* <disk address> type */ 96 + typedef __u32 xfs_dev_t; 97 + typedef __u32 xfs_nlink_t; 98 + 99 + #include "xfs_types.h" 60 100 #include "xfs_fs.h" 61 101 #include "xfs_stats.h" 62 102 #include "xfs_sysctl.h" ··· 291 279 return virt_to_page(addr); 292 280 } 293 281 294 - #endif /* __XFS_LINUX__ */ 282 + #endif /* _XFS_PLATFORM_H */
+113 -181
fs/xfs/xfs_log.c
··· 3 3 * Copyright (c) 2000-2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 21 21 #include "xfs_sb.h" 22 22 #include "xfs_health.h" 23 23 #include "xfs_zone_alloc.h" 24 + 25 + struct xlog_write_data { 26 + struct xlog_ticket *ticket; 27 + struct xlog_in_core *iclog; 28 + uint32_t bytes_left; 29 + uint32_t record_cnt; 30 + uint32_t data_cnt; 31 + int log_offset; 32 + }; 24 33 25 34 struct kmem_cache *xfs_log_ticket_cache; 26 35 ··· 52 43 STATIC int 53 44 xlog_state_get_iclog_space( 54 45 struct xlog *log, 55 - int len, 56 - struct xlog_in_core **iclog, 57 - struct xlog_ticket *ticket, 58 - int *logoffsetp); 46 + struct xlog_write_data *data); 59 47 STATIC void 60 48 xlog_sync( 61 49 struct xlog *log, ··· 79 73 80 74 static int 81 75 xfs_log_cover(struct xfs_mount *); 82 - 83 - /* 84 - * We need to make sure the buffer pointer returned is naturally aligned for the 85 - * biggest basic data type we put into it. We have already accounted for this 86 - * padding when sizing the buffer. 87 - * 88 - * However, this padding does not get written into the log, and hence we have to 89 - * track the space used by the log vectors separately to prevent log space hangs 90 - * due to inaccurate accounting (i.e. a leak) of the used log space through the 91 - * CIL context ticket. 92 - * 93 - * We also add space for the xlog_op_header that describes this region in the 94 - * log. This prepends the data region we return to the caller to copy their data 95 - * into, so do all the static initialisation of the ophdr now. Because the ophdr 96 - * is not 8 byte aligned, we have to be careful to ensure that we align the 97 - * start of the buffer such that the region we return to the call is 8 byte 98 - * aligned and packed against the tail of the ophdr. 99 - */ 100 - void * 101 - xlog_prepare_iovec( 102 - struct xfs_log_vec *lv, 103 - struct xfs_log_iovec **vecp, 104 - uint type) 105 - { 106 - struct xfs_log_iovec *vec = *vecp; 107 - struct xlog_op_header *oph; 108 - uint32_t len; 109 - void *buf; 110 - 111 - if (vec) { 112 - ASSERT(vec - lv->lv_iovecp < lv->lv_niovecs); 113 - vec++; 114 - } else { 115 - vec = &lv->lv_iovecp[0]; 116 - } 117 - 118 - len = lv->lv_buf_used + sizeof(struct xlog_op_header); 119 - if (!IS_ALIGNED(len, sizeof(uint64_t))) { 120 - lv->lv_buf_used = round_up(len, sizeof(uint64_t)) - 121 - sizeof(struct xlog_op_header); 122 - } 123 - 124 - vec->i_type = type; 125 - vec->i_addr = lv->lv_buf + lv->lv_buf_used; 126 - 127 - oph = vec->i_addr; 128 - oph->oh_clientid = XFS_TRANSACTION; 129 - oph->oh_res2 = 0; 130 - oph->oh_flags = 0; 131 - 132 - buf = vec->i_addr + sizeof(struct xlog_op_header); 133 - ASSERT(IS_ALIGNED((unsigned long)buf, sizeof(uint64_t))); 134 - 135 - *vecp = vec; 136 - return buf; 137 - } 138 76 139 77 static inline void 140 78 xlog_grant_sub_space( ··· 798 848 return 0; 799 849 } 800 850 851 + int 852 + xlog_write_one_vec( 853 + struct xlog *log, 854 + struct xfs_cil_ctx *ctx, 855 + struct xfs_log_iovec *reg, 856 + struct xlog_ticket *ticket) 857 + { 858 + struct xfs_log_vec lv = { 859 + .lv_niovecs = 1, 860 + .lv_iovecp = reg, 861 + .lv_bytes = reg->i_len, 862 + }; 863 + LIST_HEAD (lv_chain); 864 + 865 + /* account for space used by record data */ 866 + ticket->t_curr_res -= lv.lv_bytes; 867 + 868 + list_add(&lv.lv_list, &lv_chain); 869 + return xlog_write(log, ctx, &lv_chain, ticket, lv.lv_bytes); 870 + } 871 + 801 872 /* 802 873 * Write out an unmount record using the ticket provided. We have to account for 803 874 * the data space used in the unmount ticket as this write is not done from a ··· 847 876 .i_len = sizeof(unmount_rec), 848 877 .i_type = XLOG_REG_TYPE_UNMOUNT, 849 878 }; 850 - struct xfs_log_vec vec = { 851 - .lv_niovecs = 1, 852 - .lv_iovecp = &reg, 853 - }; 854 - LIST_HEAD(lv_chain); 855 - list_add(&vec.lv_list, &lv_chain); 856 879 857 - BUILD_BUG_ON((sizeof(struct xlog_op_header) + 858 - sizeof(struct xfs_unmount_log_format)) != 859 - sizeof(unmount_rec)); 860 - 861 - /* account for space used by record data */ 862 - ticket->t_curr_res -= sizeof(unmount_rec); 863 - 864 - return xlog_write(log, NULL, &lv_chain, ticket, reg.i_len); 880 + return xlog_write_one_vec(log, NULL, &reg, ticket); 865 881 } 866 882 867 883 /* ··· 1880 1922 } 1881 1923 } 1882 1924 1925 + static inline uint32_t xlog_write_space_left(struct xlog_write_data *data) 1926 + { 1927 + return data->iclog->ic_size - data->log_offset; 1928 + } 1929 + 1930 + static void * 1931 + xlog_write_space_advance( 1932 + struct xlog_write_data *data, 1933 + unsigned int len) 1934 + { 1935 + void *p = data->iclog->ic_datap + data->log_offset; 1936 + 1937 + ASSERT(xlog_write_space_left(data) >= len); 1938 + ASSERT(data->log_offset % sizeof(int32_t) == 0); 1939 + ASSERT(len % sizeof(int32_t) == 0); 1940 + 1941 + data->data_cnt += len; 1942 + data->log_offset += len; 1943 + data->bytes_left -= len; 1944 + return p; 1945 + } 1946 + 1883 1947 static inline void 1884 1948 xlog_write_iovec( 1885 - struct xlog_in_core *iclog, 1886 - uint32_t *log_offset, 1887 - void *data, 1888 - uint32_t write_len, 1889 - int *bytes_left, 1890 - uint32_t *record_cnt, 1891 - uint32_t *data_cnt) 1949 + struct xlog_write_data *data, 1950 + void *buf, 1951 + uint32_t buf_len) 1892 1952 { 1893 - ASSERT(*log_offset < iclog->ic_log->l_iclog_size); 1894 - ASSERT(*log_offset % sizeof(int32_t) == 0); 1895 - ASSERT(write_len % sizeof(int32_t) == 0); 1896 - 1897 - memcpy(iclog->ic_datap + *log_offset, data, write_len); 1898 - *log_offset += write_len; 1899 - *bytes_left -= write_len; 1900 - (*record_cnt)++; 1901 - *data_cnt += write_len; 1953 + memcpy(xlog_write_space_advance(data, buf_len), buf, buf_len); 1954 + data->record_cnt++; 1902 1955 } 1903 1956 1904 1957 /* ··· 1919 1950 static void 1920 1951 xlog_write_full( 1921 1952 struct xfs_log_vec *lv, 1922 - struct xlog_ticket *ticket, 1923 - struct xlog_in_core *iclog, 1924 - uint32_t *log_offset, 1925 - uint32_t *len, 1926 - uint32_t *record_cnt, 1927 - uint32_t *data_cnt) 1953 + struct xlog_write_data *data) 1928 1954 { 1929 1955 int index; 1930 1956 1931 - ASSERT(*log_offset + *len <= iclog->ic_size || 1932 - iclog->ic_state == XLOG_STATE_WANT_SYNC); 1957 + ASSERT(data->bytes_left <= xlog_write_space_left(data) || 1958 + data->iclog->ic_state == XLOG_STATE_WANT_SYNC); 1933 1959 1934 1960 /* 1935 1961 * Ordered log vectors have no regions to write so this ··· 1934 1970 struct xfs_log_iovec *reg = &lv->lv_iovecp[index]; 1935 1971 struct xlog_op_header *ophdr = reg->i_addr; 1936 1972 1937 - ophdr->oh_tid = cpu_to_be32(ticket->t_tid); 1938 - xlog_write_iovec(iclog, log_offset, reg->i_addr, 1939 - reg->i_len, len, record_cnt, data_cnt); 1973 + ophdr->oh_tid = cpu_to_be32(data->ticket->t_tid); 1974 + xlog_write_iovec(data, reg->i_addr, reg->i_len); 1940 1975 } 1941 1976 } 1942 1977 1943 1978 static int 1944 1979 xlog_write_get_more_iclog_space( 1945 - struct xlog_ticket *ticket, 1946 - struct xlog_in_core **iclogp, 1947 - uint32_t *log_offset, 1948 - uint32_t len, 1949 - uint32_t *record_cnt, 1950 - uint32_t *data_cnt) 1980 + struct xlog_write_data *data) 1951 1981 { 1952 - struct xlog_in_core *iclog = *iclogp; 1953 - struct xlog *log = iclog->ic_log; 1982 + struct xlog *log = data->iclog->ic_log; 1954 1983 int error; 1955 1984 1956 1985 spin_lock(&log->l_icloglock); 1957 - ASSERT(iclog->ic_state == XLOG_STATE_WANT_SYNC); 1958 - xlog_state_finish_copy(log, iclog, *record_cnt, *data_cnt); 1959 - error = xlog_state_release_iclog(log, iclog, ticket); 1986 + ASSERT(data->iclog->ic_state == XLOG_STATE_WANT_SYNC); 1987 + xlog_state_finish_copy(log, data->iclog, data->record_cnt, 1988 + data->data_cnt); 1989 + error = xlog_state_release_iclog(log, data->iclog, data->ticket); 1960 1990 spin_unlock(&log->l_icloglock); 1961 1991 if (error) 1962 1992 return error; 1963 1993 1964 - error = xlog_state_get_iclog_space(log, len, &iclog, ticket, 1965 - log_offset); 1994 + error = xlog_state_get_iclog_space(log, data); 1966 1995 if (error) 1967 1996 return error; 1968 - *record_cnt = 0; 1969 - *data_cnt = 0; 1970 - *iclogp = iclog; 1997 + data->record_cnt = 0; 1998 + data->data_cnt = 0; 1971 1999 return 0; 1972 2000 } 1973 2001 ··· 1972 2016 static int 1973 2017 xlog_write_partial( 1974 2018 struct xfs_log_vec *lv, 1975 - struct xlog_ticket *ticket, 1976 - struct xlog_in_core **iclogp, 1977 - uint32_t *log_offset, 1978 - uint32_t *len, 1979 - uint32_t *record_cnt, 1980 - uint32_t *data_cnt) 2019 + struct xlog_write_data *data) 1981 2020 { 1982 - struct xlog_in_core *iclog = *iclogp; 1983 2021 struct xlog_op_header *ophdr; 1984 2022 int index = 0; 1985 2023 uint32_t rlen; ··· 1995 2045 * Hence if there isn't space for region data after the 1996 2046 * opheader, then we need to start afresh with a new iclog. 1997 2047 */ 1998 - if (iclog->ic_size - *log_offset <= 2048 + if (xlog_write_space_left(data) <= 1999 2049 sizeof(struct xlog_op_header)) { 2000 - error = xlog_write_get_more_iclog_space(ticket, 2001 - &iclog, log_offset, *len, record_cnt, 2002 - data_cnt); 2050 + error = xlog_write_get_more_iclog_space(data); 2003 2051 if (error) 2004 2052 return error; 2005 2053 } 2006 2054 2007 2055 ophdr = reg->i_addr; 2008 - rlen = min_t(uint32_t, reg->i_len, iclog->ic_size - *log_offset); 2056 + rlen = min_t(uint32_t, reg->i_len, xlog_write_space_left(data)); 2009 2057 2010 - ophdr->oh_tid = cpu_to_be32(ticket->t_tid); 2058 + ophdr->oh_tid = cpu_to_be32(data->ticket->t_tid); 2011 2059 ophdr->oh_len = cpu_to_be32(rlen - sizeof(struct xlog_op_header)); 2012 2060 if (rlen != reg->i_len) 2013 2061 ophdr->oh_flags |= XLOG_CONTINUE_TRANS; 2014 2062 2015 - xlog_write_iovec(iclog, log_offset, reg->i_addr, 2016 - rlen, len, record_cnt, data_cnt); 2063 + xlog_write_iovec(data, reg->i_addr, rlen); 2017 2064 2018 2065 /* If we wrote the whole region, move to the next. */ 2019 2066 if (rlen == reg->i_len) ··· 2045 2098 * consumes hasn't been accounted to the lv we are 2046 2099 * writing. 2047 2100 */ 2048 - error = xlog_write_get_more_iclog_space(ticket, 2049 - &iclog, log_offset, 2050 - *len + sizeof(struct xlog_op_header), 2051 - record_cnt, data_cnt); 2101 + data->bytes_left += sizeof(struct xlog_op_header); 2102 + error = xlog_write_get_more_iclog_space(data); 2052 2103 if (error) 2053 2104 return error; 2054 2105 2055 - ophdr = iclog->ic_datap + *log_offset; 2056 - ophdr->oh_tid = cpu_to_be32(ticket->t_tid); 2106 + ophdr = xlog_write_space_advance(data, 2107 + sizeof(struct xlog_op_header)); 2108 + ophdr->oh_tid = cpu_to_be32(data->ticket->t_tid); 2057 2109 ophdr->oh_clientid = XFS_TRANSACTION; 2058 2110 ophdr->oh_res2 = 0; 2059 2111 ophdr->oh_flags = XLOG_WAS_CONT_TRANS; 2060 2112 2061 - ticket->t_curr_res -= sizeof(struct xlog_op_header); 2062 - *log_offset += sizeof(struct xlog_op_header); 2063 - *data_cnt += sizeof(struct xlog_op_header); 2113 + data->ticket->t_curr_res -= 2114 + sizeof(struct xlog_op_header); 2064 2115 2065 2116 /* 2066 2117 * If rlen fits in the iclog, then end the region ··· 2066 2121 */ 2067 2122 reg_offset += rlen; 2068 2123 rlen = reg->i_len - reg_offset; 2069 - if (rlen <= iclog->ic_size - *log_offset) 2124 + if (rlen <= xlog_write_space_left(data)) 2070 2125 ophdr->oh_flags |= XLOG_END_TRANS; 2071 2126 else 2072 2127 ophdr->oh_flags |= XLOG_CONTINUE_TRANS; 2073 2128 2074 - rlen = min_t(uint32_t, rlen, iclog->ic_size - *log_offset); 2129 + rlen = min_t(uint32_t, rlen, 2130 + xlog_write_space_left(data)); 2075 2131 ophdr->oh_len = cpu_to_be32(rlen); 2076 2132 2077 - xlog_write_iovec(iclog, log_offset, 2078 - reg->i_addr + reg_offset, 2079 - rlen, len, record_cnt, data_cnt); 2080 - 2133 + xlog_write_iovec(data, reg->i_addr + reg_offset, rlen); 2081 2134 } while (ophdr->oh_flags & XLOG_CONTINUE_TRANS); 2082 2135 } 2083 2136 2084 - /* 2085 - * No more iovecs remain in this logvec so return the next log vec to 2086 - * the caller so it can go back to fast path copying. 2087 - */ 2088 - *iclogp = iclog; 2089 2137 return 0; 2090 2138 } 2091 2139 ··· 2131 2193 uint32_t len) 2132 2194 2133 2195 { 2134 - struct xlog_in_core *iclog = NULL; 2135 2196 struct xfs_log_vec *lv; 2136 - uint32_t record_cnt = 0; 2137 - uint32_t data_cnt = 0; 2138 - int error = 0; 2139 - int log_offset; 2197 + struct xlog_write_data data = { 2198 + .ticket = ticket, 2199 + .bytes_left = len, 2200 + }; 2201 + int error; 2140 2202 2141 2203 if (ticket->t_curr_res < 0) { 2142 2204 xfs_alert_tag(log->l_mp, XFS_PTAG_LOGRES, ··· 2145 2207 xlog_force_shutdown(log, SHUTDOWN_LOG_IO_ERROR); 2146 2208 } 2147 2209 2148 - error = xlog_state_get_iclog_space(log, len, &iclog, ticket, 2149 - &log_offset); 2210 + error = xlog_state_get_iclog_space(log, &data); 2150 2211 if (error) 2151 2212 return error; 2152 2213 2153 - ASSERT(log_offset <= iclog->ic_size - 1); 2214 + ASSERT(xlog_write_space_left(&data) > 0); 2154 2215 2155 2216 /* 2156 2217 * If we have a context pointer, pass it the first iclog we are ··· 2157 2220 * ordering. 2158 2221 */ 2159 2222 if (ctx) 2160 - xlog_cil_set_ctx_write_state(ctx, iclog); 2223 + xlog_cil_set_ctx_write_state(ctx, data.iclog); 2161 2224 2162 2225 list_for_each_entry(lv, lv_chain, lv_list) { 2163 2226 /* ··· 2165 2228 * the partial copy loop which can handle this case. 2166 2229 */ 2167 2230 if (lv->lv_niovecs && 2168 - lv->lv_bytes > iclog->ic_size - log_offset) { 2169 - error = xlog_write_partial(lv, ticket, &iclog, 2170 - &log_offset, &len, &record_cnt, 2171 - &data_cnt); 2231 + lv->lv_bytes > xlog_write_space_left(&data)) { 2232 + error = xlog_write_partial(lv, &data); 2172 2233 if (error) { 2173 2234 /* 2174 2235 * We have no iclog to release, so just return ··· 2175 2240 return error; 2176 2241 } 2177 2242 } else { 2178 - xlog_write_full(lv, ticket, iclog, &log_offset, 2179 - &len, &record_cnt, &data_cnt); 2243 + xlog_write_full(lv, &data); 2180 2244 } 2181 2245 } 2182 - ASSERT(len == 0); 2246 + ASSERT(data.bytes_left == 0); 2183 2247 2184 2248 /* 2185 2249 * We've already been guaranteed that the last writes will fit inside ··· 2187 2253 * iclog with the number of bytes written here. 2188 2254 */ 2189 2255 spin_lock(&log->l_icloglock); 2190 - xlog_state_finish_copy(log, iclog, record_cnt, 0); 2191 - error = xlog_state_release_iclog(log, iclog, ticket); 2256 + xlog_state_finish_copy(log, data.iclog, data.record_cnt, 0); 2257 + error = xlog_state_release_iclog(log, data.iclog, ticket); 2192 2258 spin_unlock(&log->l_icloglock); 2193 2259 2194 2260 return error; ··· 2510 2576 STATIC int 2511 2577 xlog_state_get_iclog_space( 2512 2578 struct xlog *log, 2513 - int len, 2514 - struct xlog_in_core **iclogp, 2515 - struct xlog_ticket *ticket, 2516 - int *logoffsetp) 2579 + struct xlog_write_data *data) 2517 2580 { 2518 2581 int log_offset; 2519 2582 struct xlog_rec_header *head; ··· 2545 2614 * must be written. 2546 2615 */ 2547 2616 if (log_offset == 0) { 2548 - ticket->t_curr_res -= log->l_iclog_hsize; 2617 + data->ticket->t_curr_res -= log->l_iclog_hsize; 2549 2618 head->h_cycle = cpu_to_be32(log->l_curr_cycle); 2550 2619 head->h_lsn = cpu_to_be64( 2551 2620 xlog_assign_lsn(log->l_curr_cycle, log->l_curr_block)); ··· 2575 2644 * reference to the iclog. 2576 2645 */ 2577 2646 if (!atomic_add_unless(&iclog->ic_refcnt, -1, 1)) 2578 - error = xlog_state_release_iclog(log, iclog, ticket); 2647 + error = xlog_state_release_iclog(log, iclog, 2648 + data->ticket); 2579 2649 spin_unlock(&log->l_icloglock); 2580 2650 if (error) 2581 2651 return error; ··· 2589 2657 * iclogs (to mark it taken), this particular iclog will release/sync 2590 2658 * to disk in xlog_write(). 2591 2659 */ 2592 - if (len <= iclog->ic_size - iclog->ic_offset) 2593 - iclog->ic_offset += len; 2660 + if (data->bytes_left <= iclog->ic_size - iclog->ic_offset) 2661 + iclog->ic_offset += data->bytes_left; 2594 2662 else 2595 2663 xlog_state_switch_iclogs(log, iclog, iclog->ic_size); 2596 - *iclogp = iclog; 2664 + data->iclog = iclog; 2597 2665 2598 2666 ASSERT(iclog->ic_offset <= iclog->ic_size); 2599 2667 spin_unlock(&log->l_icloglock); 2600 2668 2601 - *logoffsetp = log_offset; 2669 + data->log_offset = log_offset; 2602 2670 return 0; 2603 2671 } 2604 2672
+10 -55
fs/xfs/xfs_log.h
··· 6 6 #ifndef __XFS_LOG_H__ 7 7 #define __XFS_LOG_H__ 8 8 9 + struct xlog_format_buf; 9 10 struct xfs_cil_ctx; 10 - 11 - struct xfs_log_vec { 12 - struct list_head lv_list; /* CIL lv chain ptrs */ 13 - uint32_t lv_order_id; /* chain ordering info */ 14 - int lv_niovecs; /* number of iovecs in lv */ 15 - struct xfs_log_iovec *lv_iovecp; /* iovec array */ 16 - struct xfs_log_item *lv_item; /* owner */ 17 - char *lv_buf; /* formatted buffer */ 18 - int lv_bytes; /* accounted space in buffer */ 19 - int lv_buf_used; /* buffer space used so far */ 20 - int lv_alloc_size; /* size of allocated lv */ 21 - }; 22 11 23 12 /* Region types for iovec's i_type */ 24 13 #define XLOG_REG_TYPE_BFORMAT 1 ··· 59 70 return roundup(len, sizeof(uint32_t)); 60 71 } 61 72 62 - void *xlog_prepare_iovec(struct xfs_log_vec *lv, struct xfs_log_iovec **vecp, 63 - uint type); 64 - 65 - static inline void 66 - xlog_finish_iovec(struct xfs_log_vec *lv, struct xfs_log_iovec *vec, 67 - int data_len) 68 - { 69 - struct xlog_op_header *oph = vec->i_addr; 70 - int len; 71 - 72 - /* 73 - * Always round up the length to the correct alignment so callers don't 74 - * need to know anything about this log vec layout requirement. This 75 - * means we have to zero the area the data to be written does not cover. 76 - * This is complicated by fact the payload region is offset into the 77 - * logvec region by the opheader that tracks the payload. 78 - */ 79 - len = xlog_calc_iovec_len(data_len); 80 - if (len - data_len != 0) { 81 - char *buf = vec->i_addr + sizeof(struct xlog_op_header); 82 - 83 - memset(buf + data_len, 0, len - data_len); 84 - } 85 - 86 - /* 87 - * The opheader tracks aligned payload length, whilst the logvec tracks 88 - * the overall region length. 89 - */ 90 - oph->oh_len = cpu_to_be32(len); 91 - 92 - len += sizeof(struct xlog_op_header); 93 - lv->lv_buf_used += len; 94 - lv->lv_bytes += len; 95 - vec->i_len = len; 96 - 97 - /* Catch buffer overruns */ 98 - ASSERT((void *)lv->lv_buf + lv->lv_bytes <= 99 - (void *)lv + lv->lv_alloc_size); 100 - } 73 + void *xlog_format_start(struct xlog_format_buf *lfb, uint16_t type); 74 + void xlog_format_commit(struct xlog_format_buf *lfb, unsigned int data_len); 101 75 102 76 /* 103 77 * Copy the amount of data requested by the caller into a new log iovec. 104 78 */ 105 79 static inline void * 106 - xlog_copy_iovec(struct xfs_log_vec *lv, struct xfs_log_iovec **vecp, 107 - uint type, void *data, int len) 80 + xlog_format_copy( 81 + struct xlog_format_buf *lfb, 82 + uint16_t type, 83 + void *data, 84 + unsigned int len) 108 85 { 109 86 void *buf; 110 87 111 - buf = xlog_prepare_iovec(lv, vecp, type); 88 + buf = xlog_format_start(lfb, type); 112 89 memcpy(buf, data, len); 113 - xlog_finish_iovec(lv, *vecp, len); 90 + xlog_format_commit(lfb, len); 114 91 return buf; 115 92 } 116 93
+101 -12
fs/xfs/xfs_log_cil.c
··· 3 3 * Copyright (c) 2010 Red Hat, Inc. All Rights Reserved. 4 4 */ 5 5 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_format.h" 9 9 #include "xfs_log_format.h" ··· 409 409 lv->lv_item->li_seq = log->l_cilp->xc_ctx->sequence; 410 410 } 411 411 412 + struct xlog_format_buf { 413 + struct xfs_log_vec *lv; 414 + unsigned int idx; 415 + }; 416 + 417 + /* 418 + * We need to make sure the buffer pointer returned is naturally aligned for the 419 + * biggest basic data type we put into it. We have already accounted for this 420 + * padding when sizing the buffer. 421 + * 422 + * However, this padding does not get written into the log, and hence we have to 423 + * track the space used by the log vectors separately to prevent log space hangs 424 + * due to inaccurate accounting (i.e. a leak) of the used log space through the 425 + * CIL context ticket. 426 + * 427 + * We also add space for the xlog_op_header that describes this region in the 428 + * log. This prepends the data region we return to the caller to copy their data 429 + * into, so do all the static initialisation of the ophdr now. Because the ophdr 430 + * is not 8 byte aligned, we have to be careful to ensure that we align the 431 + * start of the buffer such that the region we return to the call is 8 byte 432 + * aligned and packed against the tail of the ophdr. 433 + */ 434 + void * 435 + xlog_format_start( 436 + struct xlog_format_buf *lfb, 437 + uint16_t type) 438 + { 439 + struct xfs_log_vec *lv = lfb->lv; 440 + struct xfs_log_iovec *vec = &lv->lv_iovecp[lfb->idx]; 441 + struct xlog_op_header *oph; 442 + uint32_t len; 443 + void *buf; 444 + 445 + ASSERT(lfb->idx < lv->lv_niovecs); 446 + 447 + len = lv->lv_buf_used + sizeof(struct xlog_op_header); 448 + if (!IS_ALIGNED(len, sizeof(uint64_t))) { 449 + lv->lv_buf_used = round_up(len, sizeof(uint64_t)) - 450 + sizeof(struct xlog_op_header); 451 + } 452 + 453 + vec->i_type = type; 454 + vec->i_addr = lv->lv_buf + lv->lv_buf_used; 455 + 456 + oph = vec->i_addr; 457 + oph->oh_clientid = XFS_TRANSACTION; 458 + oph->oh_res2 = 0; 459 + oph->oh_flags = 0; 460 + 461 + buf = vec->i_addr + sizeof(struct xlog_op_header); 462 + ASSERT(IS_ALIGNED((unsigned long)buf, sizeof(uint64_t))); 463 + return buf; 464 + } 465 + 466 + void 467 + xlog_format_commit( 468 + struct xlog_format_buf *lfb, 469 + unsigned int data_len) 470 + { 471 + struct xfs_log_vec *lv = lfb->lv; 472 + struct xfs_log_iovec *vec = &lv->lv_iovecp[lfb->idx]; 473 + struct xlog_op_header *oph = vec->i_addr; 474 + int len; 475 + 476 + /* 477 + * Always round up the length to the correct alignment so callers don't 478 + * need to know anything about this log vec layout requirement. This 479 + * means we have to zero the area the data to be written does not cover. 480 + * This is complicated by fact the payload region is offset into the 481 + * logvec region by the opheader that tracks the payload. 482 + */ 483 + len = xlog_calc_iovec_len(data_len); 484 + if (len - data_len != 0) { 485 + char *buf = vec->i_addr + sizeof(struct xlog_op_header); 486 + 487 + memset(buf + data_len, 0, len - data_len); 488 + } 489 + 490 + /* 491 + * The opheader tracks aligned payload length, whilst the logvec tracks 492 + * the overall region length. 493 + */ 494 + oph->oh_len = cpu_to_be32(len); 495 + 496 + len += sizeof(struct xlog_op_header); 497 + lv->lv_buf_used += len; 498 + lv->lv_bytes += len; 499 + vec->i_len = len; 500 + 501 + /* Catch buffer overruns */ 502 + ASSERT((void *)lv->lv_buf + lv->lv_bytes <= 503 + (void *)lv + lv->lv_alloc_size); 504 + 505 + lfb->idx++; 506 + } 507 + 412 508 /* 413 509 * Format log item into a flat buffers 414 510 * ··· 550 454 list_for_each_entry(lip, &tp->t_items, li_trans) { 551 455 struct xfs_log_vec *lv = lip->li_lv; 552 456 struct xfs_log_vec *shadow = lip->li_lv_shadow; 457 + struct xlog_format_buf lfb = { }; 553 458 554 459 /* Skip items which aren't dirty in this transaction. */ 555 460 if (!test_bit(XFS_LI_DIRTY, &lip->li_flags)) ··· 598 501 lv->lv_item = lip; 599 502 } 600 503 504 + lfb.lv = lv; 601 505 ASSERT(IS_ALIGNED((unsigned long)lv->lv_buf, sizeof(uint64_t))); 602 - lip->li_ops->iop_format(lip, lv); 506 + lip->li_ops->iop_format(lip, &lfb); 603 507 xfs_cil_prepare_item(log, lip, lv, diff_len); 604 508 } 605 509 } ··· 1196 1098 .i_len = sizeof(struct xlog_op_header), 1197 1099 .i_type = XLOG_REG_TYPE_COMMIT, 1198 1100 }; 1199 - struct xfs_log_vec vec = { 1200 - .lv_niovecs = 1, 1201 - .lv_iovecp = &reg, 1202 - }; 1203 1101 int error; 1204 - LIST_HEAD(lv_chain); 1205 - list_add(&vec.lv_list, &lv_chain); 1206 1102 1207 1103 if (xlog_is_shutdown(log)) 1208 1104 return -EIO; ··· 1204 1112 error = xlog_cil_order_write(ctx->cil, ctx->sequence, _COMMIT_RECORD); 1205 1113 if (error) 1206 1114 return error; 1207 - 1208 - /* account for space used by record data */ 1209 - ctx->ticket->t_curr_res -= reg.i_len; 1210 - error = xlog_write(log, ctx, &lv_chain, ctx->ticket, reg.i_len); 1115 + error = xlog_write_one_vec(log, ctx, &reg, ctx->ticket); 1211 1116 if (error) 1212 1117 xlog_force_shutdown(log, SHUTDOWN_LOG_IO_ERROR); 1213 1118 return error;
+20
fs/xfs/xfs_log_priv.h
··· 13 13 struct xlog_ticket; 14 14 struct xfs_mount; 15 15 16 + struct xfs_log_iovec { 17 + void *i_addr;/* beginning address of region */ 18 + int i_len; /* length in bytes of region */ 19 + uint i_type; /* type of region */ 20 + }; 21 + 22 + struct xfs_log_vec { 23 + struct list_head lv_list; /* CIL lv chain ptrs */ 24 + uint32_t lv_order_id; /* chain ordering info */ 25 + int lv_niovecs; /* number of iovecs in lv */ 26 + struct xfs_log_iovec *lv_iovecp; /* iovec array */ 27 + struct xfs_log_item *lv_item; /* owner */ 28 + char *lv_buf; /* formatted buffer */ 29 + int lv_bytes; /* accounted space in buffer */ 30 + int lv_buf_used; /* buffer space used so far */ 31 + int lv_alloc_size; /* size of allocated lv */ 32 + }; 33 + 16 34 /* 17 35 * get client id from packed copy. 18 36 * ··· 525 507 int xlog_write(struct xlog *log, struct xfs_cil_ctx *ctx, 526 508 struct list_head *lv_chain, struct xlog_ticket *tic, 527 509 uint32_t len); 510 + int xlog_write_one_vec(struct xlog *log, struct xfs_cil_ctx *ctx, 511 + struct xfs_log_iovec *reg, struct xlog_ticket *ticket); 528 512 void xfs_log_ticket_ungrant(struct xlog *log, struct xlog_ticket *ticket); 529 513 void xfs_log_ticket_regrant(struct xlog *log, struct xlog_ticket *ticket); 530 514
+17 -12
fs/xfs/xfs_log_recover.c
··· 3 3 * Copyright (c) 2000-2006 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 2953 2953 xfs_daddr_t blkno, 2954 2954 int bufsize) 2955 2955 { 2956 + struct xfs_mount *mp = log->l_mp; 2957 + u32 h_version = be32_to_cpu(rhead->h_version); 2956 2958 int hlen; 2957 2959 2958 - if (XFS_IS_CORRUPT(log->l_mp, 2960 + if (XFS_IS_CORRUPT(mp, 2959 2961 rhead->h_magicno != cpu_to_be32(XLOG_HEADER_MAGIC_NUM))) 2960 2962 return -EFSCORRUPTED; 2961 - if (XFS_IS_CORRUPT(log->l_mp, 2962 - (!rhead->h_version || 2963 - (be32_to_cpu(rhead->h_version) & 2964 - (~XLOG_VERSION_OKBITS))))) { 2965 - xfs_warn(log->l_mp, "%s: unrecognised log version (%d).", 2966 - __func__, be32_to_cpu(rhead->h_version)); 2967 - return -EFSCORRUPTED; 2963 + 2964 + /* 2965 + * The log version must match the superblock 2966 + */ 2967 + if (xfs_has_logv2(mp)) { 2968 + if (XFS_IS_CORRUPT(mp, h_version != XLOG_VERSION_2)) 2969 + return -EFSCORRUPTED; 2970 + } else { 2971 + if (XFS_IS_CORRUPT(mp, h_version != XLOG_VERSION_1)) 2972 + return -EFSCORRUPTED; 2968 2973 } 2969 2974 2970 2975 /* ··· 2977 2972 * and h_len must not be greater than LR buffer size. 2978 2973 */ 2979 2974 hlen = be32_to_cpu(rhead->h_len); 2980 - if (XFS_IS_CORRUPT(log->l_mp, hlen <= 0 || hlen > bufsize)) 2975 + if (XFS_IS_CORRUPT(mp, hlen <= 0 || hlen > bufsize)) 2981 2976 return -EFSCORRUPTED; 2982 2977 2983 - if (XFS_IS_CORRUPT(log->l_mp, 2984 - blkno > log->l_logBBsize || blkno > INT_MAX)) 2978 + if (XFS_IS_CORRUPT(mp, blkno > log->l_logBBsize || blkno > INT_MAX)) 2985 2979 return -EFSCORRUPTED; 2980 + 2986 2981 return 0; 2987 2982 } 2988 2983
+1 -9
fs/xfs/xfs_message.c
··· 3 3 * Copyright (c) 2011 Red Hat, Inc. All Rights Reserved. 4 4 */ 5 5 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_error.h" 9 9 #include "xfs_shared.h" ··· 148 148 [XFS_EXPERIMENTAL_LARP] = { 149 149 .opstate = XFS_OPSTATE_WARNED_LARP, 150 150 .name = "logged extended attributes", 151 - }, 152 - [XFS_EXPERIMENTAL_LBS] = { 153 - .opstate = XFS_OPSTATE_WARNED_LBS, 154 - .name = "large block size", 155 - }, 156 - [XFS_EXPERIMENTAL_METADIR] = { 157 - .opstate = XFS_OPSTATE_WARNED_METADIR, 158 - .name = "metadata directory tree", 159 151 }, 160 152 [XFS_EXPERIMENTAL_ZONED] = { 161 153 .opstate = XFS_OPSTATE_WARNED_ZONED,
-2
fs/xfs/xfs_message.h
··· 93 93 enum xfs_experimental_feat { 94 94 XFS_EXPERIMENTAL_SHRINK, 95 95 XFS_EXPERIMENTAL_LARP, 96 - XFS_EXPERIMENTAL_LBS, 97 - XFS_EXPERIMENTAL_METADIR, 98 96 XFS_EXPERIMENTAL_ZONED, 99 97 100 98 XFS_EXPERIMENTAL_MAX,
+3 -1
fs/xfs/xfs_mount.c
··· 3 3 * Copyright (c) 2000-2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" ··· 41 41 #include "xfs_rtrefcount_btree.h" 42 42 #include "scrub/stats.h" 43 43 #include "xfs_zone_alloc.h" 44 + #include "xfs_healthmon.h" 44 45 45 46 static DEFINE_MUTEX(xfs_uuid_table_mutex); 46 47 static int xfs_uuid_table_size; ··· 626 625 cancel_delayed_work_sync(&mp->m_reclaim_work); 627 626 xfs_reclaim_inodes(mp); 628 627 xfs_health_unmount(mp); 628 + xfs_healthmon_unmount(mp); 629 629 } 630 630 631 631 static void
+4
fs/xfs/xfs_mount.h
··· 13 13 struct xfs_quotainfo; 14 14 struct xfs_da_geometry; 15 15 struct xfs_perag; 16 + struct xfs_healthmon; 16 17 17 18 /* dynamic preallocation free space thresholds, 5% down to 1% */ 18 19 enum { ··· 343 342 344 343 /* Hook to feed dirent updates to an active online repair. */ 345 344 struct xfs_hooks m_dir_update_hooks; 345 + 346 + /* Private data referring to a health monitor object. */ 347 + struct xfs_healthmon *m_healthmon; 346 348 } xfs_mount_t; 347 349 348 350 #define M_IGEO(mp) (&(mp)->m_ino_geo)
+1 -1
fs/xfs/xfs_mru_cache.c
··· 3 3 * Copyright (c) 2006-2007 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_mru_cache.h" 8 8 9 9 /*
+13 -6
fs/xfs/xfs_notify_failure.c
··· 3 3 * Copyright (c) 2022 Fujitsu. All Rights Reserved. 4 4 */ 5 5 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_shared.h" 8 8 #include "xfs_format.h" 9 9 #include "xfs_log_format.h" ··· 22 22 #include "xfs_notify_failure.h" 23 23 #include "xfs_rtgroup.h" 24 24 #include "xfs_rtrmap_btree.h" 25 + #include "xfs_healthmon.h" 25 26 26 27 #include <linux/mm.h> 27 28 #include <linux/dax.h> ··· 220 219 if (error) 221 220 return error; 222 221 222 + xfs_healthmon_report_media(mp, XFS_DEV_LOG, daddr, bblen); 223 + 223 224 /* 224 225 * In the pre-remove case the failure notification is attempting to 225 226 * trigger a force unmount. The expectation is that the device is ··· 255 252 uint64_t bblen; 256 253 struct xfs_group *xg = NULL; 257 254 258 - if (!xfs_has_rmapbt(mp)) { 259 - xfs_debug(mp, "notify_failure() needs rmapbt enabled!"); 260 - return -EOPNOTSUPP; 261 - } 262 - 263 255 error = xfs_dax_translate_range(xfs_group_type_buftarg(mp, type), 264 256 offset, len, &daddr, &bblen); 265 257 if (error) 266 258 return error; 259 + 260 + xfs_healthmon_report_media(mp, 261 + type == XG_TYPE_RTG ? XFS_DEV_RT : XFS_DEV_DATA, 262 + daddr, bblen); 263 + 264 + if (!xfs_has_rmapbt(mp)) { 265 + xfs_debug(mp, "notify_failure() needs rmapbt enabled!"); 266 + return -EOPNOTSUPP; 267 + } 267 268 268 269 if (type == XG_TYPE_RTG) { 269 270 start_bno = xfs_daddr_to_rtb(mp, daddr);
+1 -1
fs/xfs/xfs_pnfs.c
··· 2 2 /* 3 3 * Copyright (c) 2014 Christoph Hellwig. 4 4 */ 5 - #include "xfs.h" 5 + #include "xfs_platform.h" 6 6 #include "xfs_shared.h" 7 7 #include "xfs_format.h" 8 8 #include "xfs_log_format.h"
+1 -1
fs/xfs/xfs_pwork.c
··· 3 3 * Copyright (C) 2019 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <darrick.wong@oracle.com> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/xfs_qm.c
··· 3 3 * Copyright (c) 2000-2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/xfs_qm_bhv.c
··· 3 3 * Copyright (c) 2000-2006 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/xfs_qm_syscalls.c
··· 5 5 */ 6 6 7 7 8 - #include "xfs.h" 8 + #include "xfs_platform.h" 9 9 #include "xfs_fs.h" 10 10 #include "xfs_shared.h" 11 11 #include "xfs_format.h"
+1 -1
fs/xfs/xfs_quotaops.c
··· 3 3 * Copyright (c) 2008, Christoph Hellwig 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_shared.h" 8 8 #include "xfs_format.h" 9 9 #include "xfs_log_format.h"
+5 -7
fs/xfs/xfs_refcount_item.c
··· 3 3 * Copyright (C) 2016 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <darrick.wong@oracle.com> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_format.h" 9 9 #include "xfs_log_format.h" ··· 93 93 STATIC void 94 94 xfs_cui_item_format( 95 95 struct xfs_log_item *lip, 96 - struct xfs_log_vec *lv) 96 + struct xlog_format_buf *lfb) 97 97 { 98 98 struct xfs_cui_log_item *cuip = CUI_ITEM(lip); 99 - struct xfs_log_iovec *vecp = NULL; 100 99 101 100 ASSERT(atomic_read(&cuip->cui_next_extent) == 102 101 cuip->cui_format.cui_nextents); ··· 104 105 cuip->cui_format.cui_type = lip->li_type; 105 106 cuip->cui_format.cui_size = 1; 106 107 107 - xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_CUI_FORMAT, &cuip->cui_format, 108 + xlog_format_copy(lfb, XLOG_REG_TYPE_CUI_FORMAT, &cuip->cui_format, 108 109 xfs_cui_log_format_sizeof(cuip->cui_format.cui_nextents)); 109 110 } 110 111 ··· 198 199 STATIC void 199 200 xfs_cud_item_format( 200 201 struct xfs_log_item *lip, 201 - struct xfs_log_vec *lv) 202 + struct xlog_format_buf *lfb) 202 203 { 203 204 struct xfs_cud_log_item *cudp = CUD_ITEM(lip); 204 - struct xfs_log_iovec *vecp = NULL; 205 205 206 206 ASSERT(lip->li_type == XFS_LI_CUD || lip->li_type == XFS_LI_CUD_RT); 207 207 208 208 cudp->cud_format.cud_type = lip->li_type; 209 209 cudp->cud_format.cud_size = 1; 210 210 211 - xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_CUD_FORMAT, &cudp->cud_format, 211 + xlog_format_copy(lfb, XLOG_REG_TYPE_CUD_FORMAT, &cudp->cud_format, 212 212 sizeof(struct xfs_cud_log_format)); 213 213 } 214 214
+1 -1
fs/xfs/xfs_reflink.c
··· 3 3 * Copyright (C) 2016 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <darrick.wong@oracle.com> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+5 -7
fs/xfs/xfs_rmap_item.c
··· 3 3 * Copyright (C) 2016 Oracle. All Rights Reserved. 4 4 * Author: Darrick J. Wong <darrick.wong@oracle.com> 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_format.h" 9 9 #include "xfs_log_format.h" ··· 92 92 STATIC void 93 93 xfs_rui_item_format( 94 94 struct xfs_log_item *lip, 95 - struct xfs_log_vec *lv) 95 + struct xlog_format_buf *lfb) 96 96 { 97 97 struct xfs_rui_log_item *ruip = RUI_ITEM(lip); 98 - struct xfs_log_iovec *vecp = NULL; 99 98 100 99 ASSERT(atomic_read(&ruip->rui_next_extent) == 101 100 ruip->rui_format.rui_nextents); ··· 104 105 ruip->rui_format.rui_type = lip->li_type; 105 106 ruip->rui_format.rui_size = 1; 106 107 107 - xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_RUI_FORMAT, &ruip->rui_format, 108 + xlog_format_copy(lfb, XLOG_REG_TYPE_RUI_FORMAT, &ruip->rui_format, 108 109 xfs_rui_log_format_sizeof(ruip->rui_format.rui_nextents)); 109 110 } 110 111 ··· 199 200 STATIC void 200 201 xfs_rud_item_format( 201 202 struct xfs_log_item *lip, 202 - struct xfs_log_vec *lv) 203 + struct xlog_format_buf *lfb) 203 204 { 204 205 struct xfs_rud_log_item *rudp = RUD_ITEM(lip); 205 - struct xfs_log_iovec *vecp = NULL; 206 206 207 207 ASSERT(lip->li_type == XFS_LI_RUD || lip->li_type == XFS_LI_RUD_RT); 208 208 209 209 rudp->rud_format.rud_type = lip->li_type; 210 210 rudp->rud_format.rud_size = 1; 211 211 212 - xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_RUD_FORMAT, &rudp->rud_format, 212 + xlog_format_copy(lfb, XLOG_REG_TYPE_RUD_FORMAT, &rudp->rud_format, 213 213 sizeof(struct xfs_rud_log_format)); 214 214 } 215 215
+1 -1
fs/xfs/xfs_rtalloc.c
··· 3 3 * Copyright (c) 2000-2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+9 -5
fs/xfs/xfs_stats.c
··· 3 3 * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 8 8 struct xstats xfsstats; 9 9 ··· 23 23 uint64_t xs_xstrat_bytes = 0; 24 24 uint64_t xs_write_bytes = 0; 25 25 uint64_t xs_read_bytes = 0; 26 - uint64_t defer_relog = 0; 26 + uint64_t xs_defer_relog = 0; 27 + uint64_t xs_gc_bytes = 0; 27 28 28 29 static const struct xstats_entry { 29 30 char *desc; ··· 58 57 { "rtrmapbt_mem", xfsstats_offset(xs_rtrefcbt_2) }, 59 58 { "rtrefcntbt", xfsstats_offset(xs_qm_dqreclaims)}, 60 59 /* we print both series of quota information together */ 61 - { "qm", xfsstats_offset(xs_xstrat_bytes)}, 60 + { "qm", xfsstats_offset(xs_gc_read_calls)}, 61 + { "zoned", xfsstats_offset(__pad1)}, 62 62 }; 63 63 64 64 /* Loop over all stats groups */ ··· 78 76 xs_xstrat_bytes += per_cpu_ptr(stats, i)->s.xs_xstrat_bytes; 79 77 xs_write_bytes += per_cpu_ptr(stats, i)->s.xs_write_bytes; 80 78 xs_read_bytes += per_cpu_ptr(stats, i)->s.xs_read_bytes; 81 - defer_relog += per_cpu_ptr(stats, i)->s.defer_relog; 79 + xs_defer_relog += per_cpu_ptr(stats, i)->s.xs_defer_relog; 80 + xs_gc_bytes += per_cpu_ptr(stats, i)->s.xs_gc_bytes; 82 81 } 83 82 84 83 len += scnprintf(buf + len, PATH_MAX-len, "xpc %llu %llu %llu\n", 85 84 xs_xstrat_bytes, xs_write_bytes, xs_read_bytes); 86 85 len += scnprintf(buf + len, PATH_MAX-len, "defer_relog %llu\n", 87 - defer_relog); 86 + xs_defer_relog); 88 87 len += scnprintf(buf + len, PATH_MAX-len, "debug %u\n", 89 88 #if defined(DEBUG) 90 89 1); 91 90 #else 92 91 0); 93 92 #endif 93 + len += scnprintf(buf + len, PATH_MAX-len, "gc xpc %llu\n", xs_gc_bytes); 94 94 95 95 return len; 96 96 }
+7 -1
fs/xfs/xfs_stats.h
··· 138 138 uint32_t xs_qm_dqwants; 139 139 uint32_t xs_qm_dquot; 140 140 uint32_t xs_qm_dquot_unused; 141 + /* Zone GC counters */ 142 + uint32_t xs_gc_read_calls; 143 + uint32_t xs_gc_write_calls; 144 + uint32_t xs_gc_zone_reset_calls; 145 + uint32_t __pad1; 141 146 /* Extra precision counters */ 142 147 uint64_t xs_xstrat_bytes; 143 148 uint64_t xs_write_bytes; 144 149 uint64_t xs_read_bytes; 145 - uint64_t defer_relog; 150 + uint64_t xs_defer_relog; 151 + uint64_t xs_gc_bytes; 146 152 }; 147 153 148 154 #define xfsstats_offset(f) (offsetof(struct __xfsstats, f)/sizeof(uint32_t))
+32 -6
fs/xfs/xfs_super.c
··· 4 4 * All Rights Reserved. 5 5 */ 6 6 7 - #include "xfs.h" 7 + #include "xfs_platform.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" 10 10 #include "xfs_log_format.h" ··· 40 40 #include "xfs_defer.h" 41 41 #include "xfs_attr_item.h" 42 42 #include "xfs_xattr.h" 43 + #include "xfs_error.h" 44 + #include "xfs_errortag.h" 43 45 #include "xfs_iunlink_item.h" 44 46 #include "xfs_dahash_test.h" 45 47 #include "xfs_rtbitmap.h" ··· 49 47 #include "xfs_parent.h" 50 48 #include "xfs_rtalloc.h" 51 49 #include "xfs_zone_alloc.h" 50 + #include "xfs_healthmon.h" 52 51 #include "scrub/stats.h" 53 52 #include "scrub/rcbag_btree.h" 54 53 55 54 #include <linux/magic.h> 56 55 #include <linux/fs_context.h> 57 56 #include <linux/fs_parser.h> 57 + #include <linux/fserror.h> 58 58 59 59 static const struct super_operations xfs_super_operations; 60 60 ··· 115 111 Opt_prjquota, Opt_uquota, Opt_gquota, Opt_pquota, 116 112 Opt_uqnoenforce, Opt_gqnoenforce, Opt_pqnoenforce, Opt_qnoenforce, 117 113 Opt_discard, Opt_nodiscard, Opt_dax, Opt_dax_enum, Opt_max_open_zones, 118 - Opt_lifetime, Opt_nolifetime, Opt_max_atomic_write, 114 + Opt_lifetime, Opt_nolifetime, Opt_max_atomic_write, Opt_errortag, 119 115 }; 120 116 121 117 #define fsparam_dead(NAME) \ ··· 174 170 fsparam_flag("lifetime", Opt_lifetime), 175 171 fsparam_flag("nolifetime", Opt_nolifetime), 176 172 fsparam_string("max_atomic_write", Opt_max_atomic_write), 173 + fsparam_string("errortag", Opt_errortag), 177 174 {} 178 175 }; 179 176 ··· 799 794 debugfs_remove(mp->m_debugfs); 800 795 kfree(mp->m_rtname); 801 796 kfree(mp->m_logname); 797 + #ifdef DEBUG 798 + kfree(mp->m_errortag); 799 + #endif 802 800 kfree(mp); 803 801 } 804 802 ··· 1281 1273 return 0; 1282 1274 } 1283 1275 1276 + static void 1277 + xfs_fs_report_error( 1278 + const struct fserror_event *event) 1279 + { 1280 + /* healthmon already knows about non-inode and metadata errors */ 1281 + if (event->inode && event->type != FSERR_METADATA) 1282 + xfs_healthmon_report_file_ioerror(XFS_I(event->inode), event); 1283 + } 1284 + 1284 1285 static const struct super_operations xfs_super_operations = { 1285 1286 .alloc_inode = xfs_fs_alloc_inode, 1286 1287 .destroy_inode = xfs_fs_destroy_inode, ··· 1305 1288 .free_cached_objects = xfs_fs_free_cached_objects, 1306 1289 .shutdown = xfs_fs_shutdown, 1307 1290 .show_stats = xfs_fs_show_stats, 1291 + .report_error = xfs_fs_report_error, 1308 1292 }; 1309 1293 1310 1294 static int ··· 1566 1548 return -EINVAL; 1567 1549 } 1568 1550 return 0; 1551 + case Opt_errortag: 1552 + return xfs_errortag_add_name(parsing_mp, param->string); 1569 1553 default: 1570 1554 xfs_warn(parsing_mp, "unknown mount option [%s].", param->key); 1571 1555 return -EINVAL; ··· 1826 1806 error = -ENOSYS; 1827 1807 goto out_free_sb; 1828 1808 } 1829 - 1830 - xfs_warn_experimental(mp, XFS_EXPERIMENTAL_LBS); 1831 1809 } 1832 1810 1833 1811 /* Ensure this filesystem fits in the page cache limits */ ··· 1911 1893 goto out_filestream_unmount; 1912 1894 } 1913 1895 xfs_warn_experimental(mp, XFS_EXPERIMENTAL_ZONED); 1914 - } else if (xfs_has_metadir(mp)) { 1915 - xfs_warn_experimental(mp, XFS_EXPERIMENTAL_METADIR); 1916 1896 } 1917 1897 1918 1898 if (xfs_has_reflink(mp)) { ··· 2159 2143 if (error) 2160 2144 return error; 2161 2145 2146 + xfs_errortag_copy(mp, new_mp); 2147 + 2162 2148 /* Validate new max_atomic_write option before making other changes */ 2163 2149 if (mp->m_awu_max_bytes != new_mp->m_awu_max_bytes) { 2164 2150 error = xfs_set_max_atomic_write_opt(mp, ··· 2247 2229 mp = kzalloc(sizeof(struct xfs_mount), GFP_KERNEL); 2248 2230 if (!mp) 2249 2231 return -ENOMEM; 2232 + #ifdef DEBUG 2233 + mp->m_errortag = kcalloc(XFS_ERRTAG_MAX, sizeof(*mp->m_errortag), 2234 + GFP_KERNEL); 2235 + if (!mp->m_errortag) { 2236 + kfree(mp); 2237 + return -ENOMEM; 2238 + } 2239 + #endif 2250 2240 2251 2241 spin_lock_init(&mp->m_sb_lock); 2252 2242 for (i = 0; i < XG_TYPE_MAX; i++)
+1 -1
fs/xfs/xfs_symlink.c
··· 4 4 * Copyright (c) 2012-2013 Red Hat, Inc. 5 5 * All rights reserved. 6 6 */ 7 - #include "xfs.h" 7 + #include "xfs_platform.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_fs.h" 10 10 #include "xfs_format.h"
+1 -1
fs/xfs/xfs_sysctl.c
··· 3 3 * Copyright (c) 2001-2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_error.h" 8 8 9 9 static struct ctl_table_header *xfs_table_header;
+1 -1
fs/xfs/xfs_sysfs.c
··· 4 4 * All Rights Reserved. 5 5 */ 6 6 7 - #include "xfs.h" 7 + #include "xfs_platform.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" 10 10 #include "xfs_log_format.h"
+6 -1
fs/xfs/xfs_trace.c
··· 3 3 * Copyright (c) 2009, Christoph Hellwig 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_bit.h" ··· 51 51 #include "xfs_rtgroup.h" 52 52 #include "xfs_zone_alloc.h" 53 53 #include "xfs_zone_priv.h" 54 + #include "xfs_health.h" 55 + #include "xfs_healthmon.h" 56 + #include "xfs_notify_failure.h" 57 + #include "xfs_file.h" 58 + #include <linux/fserror.h> 54 59 55 60 /* 56 61 * We include this last to have the helpers above available for the trace
+513
fs/xfs/xfs_trace.h
··· 103 103 struct xfs_metadir_update; 104 104 struct xfs_rtgroup; 105 105 struct xfs_open_zone; 106 + struct xfs_healthmon_event; 107 + struct xfs_healthmon; 108 + struct fserror_event; 106 109 107 110 #define XFS_ATTR_FILTER_FLAGS \ 108 111 { XFS_ATTR_ROOT, "ROOT" }, \ ··· 2413 2410 DEFINE_ATTR_EVENT(xfs_attr_sf_create); 2414 2411 DEFINE_ATTR_EVENT(xfs_attr_sf_lookup); 2415 2412 DEFINE_ATTR_EVENT(xfs_attr_sf_remove); 2413 + DEFINE_ATTR_EVENT(xfs_attr_sf_replace); 2416 2414 DEFINE_ATTR_EVENT(xfs_attr_sf_to_leaf); 2417 2415 2418 2416 DEFINE_ATTR_EVENT(xfs_attr_leaf_add); ··· 5909 5905 TP_ARGS(mp, ctr, delta, caller_ip)) 5910 5906 DEFINE_FREEBLOCKS_RESV_EVENT(xfs_freecounter_reserved); 5911 5907 DEFINE_FREEBLOCKS_RESV_EVENT(xfs_freecounter_enospc); 5908 + 5909 + TRACE_EVENT(xfs_healthmon_lost_event, 5910 + TP_PROTO(const struct xfs_healthmon *hm), 5911 + TP_ARGS(hm), 5912 + TP_STRUCT__entry( 5913 + __field(dev_t, dev) 5914 + __field(unsigned long long, lost_prev) 5915 + ), 5916 + TP_fast_assign( 5917 + __entry->dev = hm->dev; 5918 + __entry->lost_prev = hm->lost_prev_event; 5919 + ), 5920 + TP_printk("dev %d:%d lost_prev %llu", 5921 + MAJOR(__entry->dev), MINOR(__entry->dev), 5922 + __entry->lost_prev) 5923 + ); 5924 + 5925 + #define XFS_HEALTHMON_FLAGS_STRINGS \ 5926 + { XFS_HEALTH_MONITOR_VERBOSE, "verbose" } 5927 + #define XFS_HEALTHMON_FMT_STRINGS \ 5928 + { XFS_HEALTH_MONITOR_FMT_V0, "v0" } 5929 + 5930 + TRACE_EVENT(xfs_healthmon_create, 5931 + TP_PROTO(dev_t dev, u64 flags, u8 format), 5932 + TP_ARGS(dev, flags, format), 5933 + TP_STRUCT__entry( 5934 + __field(dev_t, dev) 5935 + __field(u64, flags) 5936 + __field(u8, format) 5937 + ), 5938 + TP_fast_assign( 5939 + __entry->dev = dev; 5940 + __entry->flags = flags; 5941 + __entry->format = format; 5942 + ), 5943 + TP_printk("dev %d:%d flags %s format %s", 5944 + MAJOR(__entry->dev), MINOR(__entry->dev), 5945 + __print_flags(__entry->flags, "|", XFS_HEALTHMON_FLAGS_STRINGS), 5946 + __print_symbolic(__entry->format, XFS_HEALTHMON_FMT_STRINGS)) 5947 + ); 5948 + 5949 + TRACE_EVENT(xfs_healthmon_copybuf, 5950 + TP_PROTO(const struct xfs_healthmon *hm, const struct iov_iter *iov), 5951 + TP_ARGS(hm, iov), 5952 + TP_STRUCT__entry( 5953 + __field(dev_t, dev) 5954 + __field(size_t, bufsize) 5955 + __field(size_t, inpos) 5956 + __field(size_t, outpos) 5957 + __field(size_t, to_copy) 5958 + __field(size_t, iter_count) 5959 + ), 5960 + TP_fast_assign( 5961 + __entry->dev = hm->dev; 5962 + __entry->bufsize = hm->bufsize; 5963 + __entry->inpos = hm->bufhead; 5964 + __entry->outpos = hm->buftail; 5965 + if (hm->bufhead > hm->buftail) 5966 + __entry->to_copy = hm->bufhead - hm->buftail; 5967 + else 5968 + __entry->to_copy = 0; 5969 + __entry->iter_count = iov_iter_count(iov); 5970 + ), 5971 + TP_printk("dev %d:%d bufsize %zu in_pos %zu out_pos %zu to_copy %zu iter_count %zu", 5972 + MAJOR(__entry->dev), MINOR(__entry->dev), 5973 + __entry->bufsize, 5974 + __entry->inpos, 5975 + __entry->outpos, 5976 + __entry->to_copy, 5977 + __entry->iter_count) 5978 + ); 5979 + 5980 + DECLARE_EVENT_CLASS(xfs_healthmon_class, 5981 + TP_PROTO(const struct xfs_healthmon *hm), 5982 + TP_ARGS(hm), 5983 + TP_STRUCT__entry( 5984 + __field(dev_t, dev) 5985 + __field(unsigned int, events) 5986 + __field(unsigned long long, lost_prev) 5987 + ), 5988 + TP_fast_assign( 5989 + __entry->dev = hm->dev; 5990 + __entry->events = hm->events; 5991 + __entry->lost_prev = hm->lost_prev_event; 5992 + ), 5993 + TP_printk("dev %d:%d events %u lost_prev? %llu", 5994 + MAJOR(__entry->dev), MINOR(__entry->dev), 5995 + __entry->events, 5996 + __entry->lost_prev) 5997 + ); 5998 + #define DEFINE_HEALTHMON_EVENT(name) \ 5999 + DEFINE_EVENT(xfs_healthmon_class, name, \ 6000 + TP_PROTO(const struct xfs_healthmon *hm), \ 6001 + TP_ARGS(hm)) 6002 + DEFINE_HEALTHMON_EVENT(xfs_healthmon_read_start); 6003 + DEFINE_HEALTHMON_EVENT(xfs_healthmon_read_finish); 6004 + DEFINE_HEALTHMON_EVENT(xfs_healthmon_release); 6005 + DEFINE_HEALTHMON_EVENT(xfs_healthmon_detach); 6006 + DEFINE_HEALTHMON_EVENT(xfs_healthmon_report_unmount); 6007 + 6008 + #define XFS_HEALTHMON_TYPE_STRINGS \ 6009 + { XFS_HEALTHMON_LOST, "lost" }, \ 6010 + { XFS_HEALTHMON_UNMOUNT, "unmount" }, \ 6011 + { XFS_HEALTHMON_SICK, "sick" }, \ 6012 + { XFS_HEALTHMON_CORRUPT, "corrupt" }, \ 6013 + { XFS_HEALTHMON_HEALTHY, "healthy" }, \ 6014 + { XFS_HEALTHMON_SHUTDOWN, "shutdown" } 6015 + 6016 + #define XFS_HEALTHMON_DOMAIN_STRINGS \ 6017 + { XFS_HEALTHMON_MOUNT, "mount" }, \ 6018 + { XFS_HEALTHMON_FS, "fs" }, \ 6019 + { XFS_HEALTHMON_AG, "ag" }, \ 6020 + { XFS_HEALTHMON_INODE, "inode" }, \ 6021 + { XFS_HEALTHMON_RTGROUP, "rtgroup" } 6022 + 6023 + TRACE_DEFINE_ENUM(XFS_HEALTHMON_LOST); 6024 + TRACE_DEFINE_ENUM(XFS_HEALTHMON_SHUTDOWN); 6025 + TRACE_DEFINE_ENUM(XFS_HEALTHMON_UNMOUNT); 6026 + TRACE_DEFINE_ENUM(XFS_HEALTHMON_SICK); 6027 + TRACE_DEFINE_ENUM(XFS_HEALTHMON_CORRUPT); 6028 + TRACE_DEFINE_ENUM(XFS_HEALTHMON_HEALTHY); 6029 + 6030 + TRACE_DEFINE_ENUM(XFS_HEALTHMON_MOUNT); 6031 + TRACE_DEFINE_ENUM(XFS_HEALTHMON_FS); 6032 + TRACE_DEFINE_ENUM(XFS_HEALTHMON_AG); 6033 + TRACE_DEFINE_ENUM(XFS_HEALTHMON_INODE); 6034 + TRACE_DEFINE_ENUM(XFS_HEALTHMON_RTGROUP); 6035 + 6036 + DECLARE_EVENT_CLASS(xfs_healthmon_event_class, 6037 + TP_PROTO(const struct xfs_healthmon *hm, 6038 + const struct xfs_healthmon_event *event), 6039 + TP_ARGS(hm, event), 6040 + TP_STRUCT__entry( 6041 + __field(dev_t, dev) 6042 + __field(unsigned int, type) 6043 + __field(unsigned int, domain) 6044 + __field(unsigned int, mask) 6045 + __field(unsigned long long, ino) 6046 + __field(unsigned int, gen) 6047 + __field(unsigned int, group) 6048 + __field(unsigned long long, offset) 6049 + __field(unsigned long long, length) 6050 + __field(unsigned long long, lostcount) 6051 + ), 6052 + TP_fast_assign( 6053 + __entry->dev = hm->dev; 6054 + __entry->type = event->type; 6055 + __entry->domain = event->domain; 6056 + __entry->mask = 0; 6057 + __entry->group = 0; 6058 + __entry->ino = 0; 6059 + __entry->gen = 0; 6060 + __entry->offset = 0; 6061 + __entry->length = 0; 6062 + __entry->lostcount = 0; 6063 + switch (__entry->domain) { 6064 + case XFS_HEALTHMON_MOUNT: 6065 + switch (__entry->type) { 6066 + case XFS_HEALTHMON_SHUTDOWN: 6067 + __entry->mask = event->flags; 6068 + break; 6069 + case XFS_HEALTHMON_LOST: 6070 + __entry->lostcount = event->lostcount; 6071 + break; 6072 + } 6073 + break; 6074 + case XFS_HEALTHMON_FS: 6075 + __entry->mask = event->fsmask; 6076 + break; 6077 + case XFS_HEALTHMON_AG: 6078 + case XFS_HEALTHMON_RTGROUP: 6079 + __entry->mask = event->grpmask; 6080 + __entry->group = event->group; 6081 + break; 6082 + case XFS_HEALTHMON_INODE: 6083 + __entry->mask = event->imask; 6084 + __entry->ino = event->ino; 6085 + __entry->gen = event->gen; 6086 + break; 6087 + case XFS_HEALTHMON_DATADEV: 6088 + case XFS_HEALTHMON_LOGDEV: 6089 + case XFS_HEALTHMON_RTDEV: 6090 + __entry->offset = event->daddr; 6091 + __entry->length = event->bbcount; 6092 + break; 6093 + case XFS_HEALTHMON_FILERANGE: 6094 + __entry->ino = event->fino; 6095 + __entry->gen = event->fgen; 6096 + __entry->offset = event->fpos; 6097 + __entry->length = event->flen; 6098 + break; 6099 + } 6100 + ), 6101 + TP_printk("dev %d:%d type %s domain %s mask 0x%x ino 0x%llx gen 0x%x offset 0x%llx len 0x%llx group 0x%x lost %llu", 6102 + MAJOR(__entry->dev), MINOR(__entry->dev), 6103 + __print_symbolic(__entry->type, XFS_HEALTHMON_TYPE_STRINGS), 6104 + __print_symbolic(__entry->domain, XFS_HEALTHMON_DOMAIN_STRINGS), 6105 + __entry->mask, 6106 + __entry->ino, 6107 + __entry->gen, 6108 + __entry->offset, 6109 + __entry->length, 6110 + __entry->group, 6111 + __entry->lostcount) 6112 + ); 6113 + #define DEFINE_HEALTHMONEVENT_EVENT(name) \ 6114 + DEFINE_EVENT(xfs_healthmon_event_class, name, \ 6115 + TP_PROTO(const struct xfs_healthmon *hm, \ 6116 + const struct xfs_healthmon_event *event), \ 6117 + TP_ARGS(hm, event)) 6118 + DEFINE_HEALTHMONEVENT_EVENT(xfs_healthmon_insert); 6119 + DEFINE_HEALTHMONEVENT_EVENT(xfs_healthmon_push); 6120 + DEFINE_HEALTHMONEVENT_EVENT(xfs_healthmon_pop); 6121 + DEFINE_HEALTHMONEVENT_EVENT(xfs_healthmon_format); 6122 + DEFINE_HEALTHMONEVENT_EVENT(xfs_healthmon_format_overflow); 6123 + DEFINE_HEALTHMONEVENT_EVENT(xfs_healthmon_drop); 6124 + DEFINE_HEALTHMONEVENT_EVENT(xfs_healthmon_merge); 6125 + 6126 + TRACE_EVENT(xfs_healthmon_report_fs, 6127 + TP_PROTO(const struct xfs_healthmon *hm, 6128 + unsigned int old_mask, unsigned int new_mask, 6129 + const struct xfs_healthmon_event *event), 6130 + TP_ARGS(hm, old_mask, new_mask, event), 6131 + TP_STRUCT__entry( 6132 + __field(dev_t, dev) 6133 + __field(unsigned int, type) 6134 + __field(unsigned int, domain) 6135 + __field(unsigned int, old_mask) 6136 + __field(unsigned int, new_mask) 6137 + __field(unsigned int, fsmask) 6138 + ), 6139 + TP_fast_assign( 6140 + __entry->dev = hm->dev; 6141 + __entry->type = event->type; 6142 + __entry->domain = event->domain; 6143 + __entry->old_mask = old_mask; 6144 + __entry->new_mask = new_mask; 6145 + __entry->fsmask = event->fsmask; 6146 + ), 6147 + TP_printk("dev %d:%d type %s domain %s oldmask 0x%x newmask 0x%x fsmask 0x%x", 6148 + MAJOR(__entry->dev), MINOR(__entry->dev), 6149 + __print_symbolic(__entry->type, XFS_HEALTHMON_TYPE_STRINGS), 6150 + __print_symbolic(__entry->domain, XFS_HEALTHMON_DOMAIN_STRINGS), 6151 + __entry->old_mask, 6152 + __entry->new_mask, 6153 + __entry->fsmask) 6154 + ); 6155 + 6156 + TRACE_EVENT(xfs_healthmon_report_group, 6157 + TP_PROTO(const struct xfs_healthmon *hm, 6158 + unsigned int old_mask, unsigned int new_mask, 6159 + const struct xfs_healthmon_event *event), 6160 + TP_ARGS(hm, old_mask, new_mask, event), 6161 + TP_STRUCT__entry( 6162 + __field(dev_t, dev) 6163 + __field(unsigned int, type) 6164 + __field(unsigned int, domain) 6165 + __field(unsigned int, old_mask) 6166 + __field(unsigned int, new_mask) 6167 + __field(unsigned int, grpmask) 6168 + __field(unsigned int, group) 6169 + ), 6170 + TP_fast_assign( 6171 + __entry->dev = hm->dev; 6172 + __entry->type = event->type; 6173 + __entry->domain = event->domain; 6174 + __entry->old_mask = old_mask; 6175 + __entry->new_mask = new_mask; 6176 + __entry->grpmask = event->grpmask; 6177 + __entry->group = event->group; 6178 + ), 6179 + TP_printk("dev %d:%d type %s domain %s oldmask 0x%x newmask 0x%x grpmask 0x%x group 0x%x", 6180 + MAJOR(__entry->dev), MINOR(__entry->dev), 6181 + __print_symbolic(__entry->type, XFS_HEALTHMON_TYPE_STRINGS), 6182 + __print_symbolic(__entry->domain, XFS_HEALTHMON_DOMAIN_STRINGS), 6183 + __entry->old_mask, 6184 + __entry->new_mask, 6185 + __entry->grpmask, 6186 + __entry->group) 6187 + ); 6188 + 6189 + TRACE_EVENT(xfs_healthmon_report_inode, 6190 + TP_PROTO(const struct xfs_healthmon *hm, 6191 + unsigned int old_mask, unsigned int new_mask, 6192 + const struct xfs_healthmon_event *event), 6193 + TP_ARGS(hm, old_mask, new_mask, event), 6194 + TP_STRUCT__entry( 6195 + __field(dev_t, dev) 6196 + __field(unsigned int, type) 6197 + __field(unsigned int, domain) 6198 + __field(unsigned int, old_mask) 6199 + __field(unsigned int, new_mask) 6200 + __field(unsigned int, imask) 6201 + __field(unsigned long long, ino) 6202 + __field(unsigned int, gen) 6203 + ), 6204 + TP_fast_assign( 6205 + __entry->dev = hm->dev; 6206 + __entry->type = event->type; 6207 + __entry->domain = event->domain; 6208 + __entry->old_mask = old_mask; 6209 + __entry->new_mask = new_mask; 6210 + __entry->imask = event->imask; 6211 + __entry->ino = event->ino; 6212 + __entry->gen = event->gen; 6213 + ), 6214 + TP_printk("dev %d:%d type %s domain %s oldmask 0x%x newmask 0x%x imask 0x%x ino 0x%llx gen 0x%x", 6215 + MAJOR(__entry->dev), MINOR(__entry->dev), 6216 + __print_symbolic(__entry->type, XFS_HEALTHMON_TYPE_STRINGS), 6217 + __print_symbolic(__entry->domain, XFS_HEALTHMON_DOMAIN_STRINGS), 6218 + __entry->old_mask, 6219 + __entry->new_mask, 6220 + __entry->imask, 6221 + __entry->ino, 6222 + __entry->gen) 6223 + ); 6224 + 6225 + TRACE_EVENT(xfs_healthmon_report_shutdown, 6226 + TP_PROTO(const struct xfs_healthmon *hm, uint32_t shutdown_flags), 6227 + TP_ARGS(hm, shutdown_flags), 6228 + TP_STRUCT__entry( 6229 + __field(dev_t, dev) 6230 + __field(uint32_t, shutdown_flags) 6231 + ), 6232 + TP_fast_assign( 6233 + __entry->dev = hm->dev; 6234 + __entry->shutdown_flags = shutdown_flags; 6235 + ), 6236 + TP_printk("dev %d:%d shutdown_flags %s", 6237 + MAJOR(__entry->dev), MINOR(__entry->dev), 6238 + __print_flags(__entry->shutdown_flags, "|", XFS_SHUTDOWN_STRINGS)) 6239 + ); 6240 + 6241 + #define XFS_DEVICE_STRINGS \ 6242 + { XFS_DEV_DATA, "datadev" }, \ 6243 + { XFS_DEV_RT, "rtdev" }, \ 6244 + { XFS_DEV_LOG, "logdev" } 6245 + 6246 + TRACE_DEFINE_ENUM(XFS_DEV_DATA); 6247 + TRACE_DEFINE_ENUM(XFS_DEV_RT); 6248 + TRACE_DEFINE_ENUM(XFS_DEV_LOG); 6249 + 6250 + TRACE_EVENT(xfs_healthmon_report_media, 6251 + TP_PROTO(const struct xfs_healthmon *hm, enum xfs_device fdev, 6252 + const struct xfs_healthmon_event *event), 6253 + TP_ARGS(hm, fdev, event), 6254 + TP_STRUCT__entry( 6255 + __field(dev_t, dev) 6256 + __field(unsigned int, error_dev) 6257 + __field(uint64_t, daddr) 6258 + __field(uint64_t, bbcount) 6259 + ), 6260 + TP_fast_assign( 6261 + __entry->dev = hm->dev; 6262 + __entry->error_dev = fdev; 6263 + __entry->daddr = event->daddr; 6264 + __entry->bbcount = event->bbcount; 6265 + ), 6266 + TP_printk("dev %d:%d %s daddr 0x%llx bbcount 0x%llx", 6267 + MAJOR(__entry->dev), MINOR(__entry->dev), 6268 + __print_symbolic(__entry->error_dev, XFS_DEVICE_STRINGS), 6269 + __entry->daddr, 6270 + __entry->bbcount) 6271 + ); 6272 + 6273 + #define FS_ERROR_STRINGS \ 6274 + { FSERR_BUFFERED_READ, "buffered_read" }, \ 6275 + { FSERR_BUFFERED_WRITE, "buffered_write" }, \ 6276 + { FSERR_DIRECTIO_READ, "directio_read" }, \ 6277 + { FSERR_DIRECTIO_WRITE, "directio_write" }, \ 6278 + { FSERR_DATA_LOST, "data_lost" }, \ 6279 + { FSERR_METADATA, "metadata" } 6280 + 6281 + TRACE_DEFINE_ENUM(FSERR_BUFFERED_READ); 6282 + TRACE_DEFINE_ENUM(FSERR_BUFFERED_WRITE); 6283 + TRACE_DEFINE_ENUM(FSERR_DIRECTIO_READ); 6284 + TRACE_DEFINE_ENUM(FSERR_DIRECTIO_WRITE); 6285 + TRACE_DEFINE_ENUM(FSERR_DATA_LOST); 6286 + TRACE_DEFINE_ENUM(FSERR_METADATA); 6287 + 6288 + TRACE_EVENT(xfs_healthmon_report_file_ioerror, 6289 + TP_PROTO(const struct xfs_healthmon *hm, 6290 + const struct fserror_event *p), 6291 + TP_ARGS(hm, p), 6292 + TP_STRUCT__entry( 6293 + __field(dev_t, dev) 6294 + __field(unsigned int, type) 6295 + __field(unsigned long long, ino) 6296 + __field(unsigned int, gen) 6297 + __field(long long, pos) 6298 + __field(unsigned long long, len) 6299 + __field(int, error) 6300 + ), 6301 + TP_fast_assign( 6302 + __entry->dev = hm->dev; 6303 + __entry->type = p->type; 6304 + __entry->ino = XFS_I(p->inode)->i_ino; 6305 + __entry->gen = p->inode->i_generation; 6306 + __entry->pos = p->pos; 6307 + __entry->len = p->len; 6308 + __entry->error = p->error; 6309 + ), 6310 + TP_printk("dev %d:%d ino 0x%llx gen 0x%x op %s pos 0x%llx bytecount 0x%llx error %d", 6311 + MAJOR(__entry->dev), MINOR(__entry->dev), 6312 + __entry->ino, 6313 + __entry->gen, 6314 + __print_symbolic(__entry->type, FS_ERROR_STRINGS), 6315 + __entry->pos, 6316 + __entry->len, 6317 + __entry->error) 6318 + ); 6319 + 6320 + TRACE_EVENT(xfs_verify_media, 6321 + TP_PROTO(const struct xfs_mount *mp, const struct xfs_verify_media *me, 6322 + dev_t fdev, xfs_daddr_t daddr, uint64_t bbcount, 6323 + const struct folio *folio), 6324 + TP_ARGS(mp, me, fdev, daddr, bbcount, folio), 6325 + TP_STRUCT__entry( 6326 + __field(dev_t, dev) 6327 + __field(dev_t, fdev) 6328 + __field(xfs_daddr_t, start_daddr) 6329 + __field(xfs_daddr_t, end_daddr) 6330 + __field(unsigned int, flags) 6331 + __field(xfs_daddr_t, daddr) 6332 + __field(uint64_t, bbcount) 6333 + __field(unsigned int, bufsize) 6334 + ), 6335 + TP_fast_assign( 6336 + __entry->dev = mp->m_ddev_targp->bt_dev; 6337 + __entry->fdev = fdev; 6338 + __entry->start_daddr = me->me_start_daddr; 6339 + __entry->end_daddr = me->me_end_daddr; 6340 + __entry->flags = me->me_flags; 6341 + __entry->daddr = daddr; 6342 + __entry->bbcount = bbcount; 6343 + __entry->bufsize = folio_size(folio); 6344 + ), 6345 + TP_printk("dev %d:%d fdev %d:%d start_daddr 0x%llx end_daddr 0x%llx flags 0x%x daddr 0x%llx bbcount 0x%llx bufsize 0x%x", 6346 + MAJOR(__entry->dev), MINOR(__entry->dev), 6347 + MAJOR(__entry->fdev), MINOR(__entry->fdev), 6348 + __entry->start_daddr, 6349 + __entry->end_daddr, 6350 + __entry->flags, 6351 + __entry->daddr, 6352 + __entry->bbcount, 6353 + __entry->bufsize) 6354 + ); 6355 + 6356 + TRACE_EVENT(xfs_verify_media_end, 6357 + TP_PROTO(const struct xfs_mount *mp, const struct xfs_verify_media *me, 6358 + dev_t fdev), 6359 + TP_ARGS(mp, me, fdev), 6360 + TP_STRUCT__entry( 6361 + __field(dev_t, dev) 6362 + __field(dev_t, fdev) 6363 + __field(xfs_daddr_t, start_daddr) 6364 + __field(xfs_daddr_t, end_daddr) 6365 + __field(int, ioerror) 6366 + ), 6367 + TP_fast_assign( 6368 + __entry->dev = mp->m_ddev_targp->bt_dev; 6369 + __entry->fdev = fdev; 6370 + __entry->start_daddr = me->me_start_daddr; 6371 + __entry->end_daddr = me->me_end_daddr; 6372 + __entry->ioerror = me->me_ioerror; 6373 + ), 6374 + TP_printk("dev %d:%d fdev %d:%d start_daddr 0x%llx end_daddr 0x%llx ioerror %d", 6375 + MAJOR(__entry->dev), MINOR(__entry->dev), 6376 + MAJOR(__entry->fdev), MINOR(__entry->fdev), 6377 + __entry->start_daddr, 6378 + __entry->end_daddr, 6379 + __entry->ioerror) 6380 + ); 6381 + 6382 + TRACE_EVENT(xfs_verify_media_error, 6383 + TP_PROTO(const struct xfs_mount *mp, const struct xfs_verify_media *me, 6384 + dev_t fdev, xfs_daddr_t daddr, uint64_t bbcount, 6385 + blk_status_t status), 6386 + TP_ARGS(mp, me, fdev, daddr, bbcount, status), 6387 + TP_STRUCT__entry( 6388 + __field(dev_t, dev) 6389 + __field(dev_t, fdev) 6390 + __field(xfs_daddr_t, start_daddr) 6391 + __field(xfs_daddr_t, end_daddr) 6392 + __field(unsigned int, flags) 6393 + __field(xfs_daddr_t, daddr) 6394 + __field(uint64_t, bbcount) 6395 + __field(int, error) 6396 + ), 6397 + TP_fast_assign( 6398 + __entry->dev = mp->m_ddev_targp->bt_dev; 6399 + __entry->fdev = fdev; 6400 + __entry->start_daddr = me->me_start_daddr; 6401 + __entry->end_daddr = me->me_end_daddr; 6402 + __entry->flags = me->me_flags; 6403 + __entry->daddr = daddr; 6404 + __entry->bbcount = bbcount; 6405 + __entry->error = blk_status_to_errno(status); 6406 + ), 6407 + TP_printk("dev %d:%d fdev %d:%d start_daddr 0x%llx end_daddr 0x%llx flags 0x%x daddr 0x%llx bbcount 0x%llx error %d", 6408 + MAJOR(__entry->dev), MINOR(__entry->dev), 6409 + MAJOR(__entry->fdev), MINOR(__entry->fdev), 6410 + __entry->start_daddr, 6411 + __entry->end_daddr, 6412 + __entry->flags, 6413 + __entry->daddr, 6414 + __entry->bbcount, 6415 + __entry->error) 6416 + ); 5912 6417 5913 6418 #endif /* _TRACE_XFS_H */ 5914 6419
+7 -3
fs/xfs/xfs_trans.c
··· 4 4 * Copyright (C) 2010 Red Hat, Inc. 5 5 * All Rights Reserved. 6 6 */ 7 - #include "xfs.h" 7 + #include "xfs_platform.h" 8 8 #include "xfs_fs.h" 9 9 #include "xfs_shared.h" 10 10 #include "xfs_format.h" ··· 123 123 124 124 ntp->t_rtx_res = tp->t_rtx_res - tp->t_rtx_res_used; 125 125 tp->t_rtx_res = tp->t_rtx_res_used; 126 - 127 - xfs_trans_switch_context(tp, ntp); 128 126 129 127 /* move deferred ops over to the new tp */ 130 128 xfs_defer_move(ntp, tp); ··· 1041 1043 * locked be logged in the prior and the next transactions. 1042 1044 */ 1043 1045 tp = *tpp; 1046 + /* 1047 + * __xfs_trans_commit cleared the NOFS flag by calling into 1048 + * xfs_trans_free. Set it again here before doing memory 1049 + * allocations. 1050 + */ 1051 + xfs_trans_set_context(tp); 1044 1052 error = xfs_log_regrant(tp->t_mountp, tp->t_ticket); 1045 1053 if (error) 1046 1054 return error;
+3 -10
fs/xfs/xfs_trans.h
··· 9 9 /* kernel only transaction subsystem defines */ 10 10 11 11 struct xlog; 12 + struct xlog_format_buf; 12 13 struct xfs_buf; 13 14 struct xfs_buftarg; 14 15 struct xfs_efd_log_item; ··· 71 70 struct xfs_item_ops { 72 71 unsigned flags; 73 72 void (*iop_size)(struct xfs_log_item *, int *, int *); 74 - void (*iop_format)(struct xfs_log_item *, struct xfs_log_vec *); 73 + void (*iop_format)(struct xfs_log_item *lip, 74 + struct xlog_format_buf *lfb); 75 75 void (*iop_pin)(struct xfs_log_item *); 76 76 void (*iop_unpin)(struct xfs_log_item *, int remove); 77 77 uint64_t (*iop_sort)(struct xfs_log_item *lip); ··· 278 276 struct xfs_trans *tp) 279 277 { 280 278 memalloc_nofs_restore(tp->t_pflags); 281 - } 282 - 283 - static inline void 284 - xfs_trans_switch_context( 285 - struct xfs_trans *old_tp, 286 - struct xfs_trans *new_tp) 287 - { 288 - new_tp->t_pflags = old_tp->t_pflags; 289 - old_tp->t_pflags = 0; 290 279 } 291 280 292 281 #endif /* __XFS_TRANS_H__ */
+1 -1
fs/xfs/xfs_trans_ail.c
··· 4 4 * Copyright (c) 2008 Dave Chinner 5 5 * All Rights Reserved. 6 6 */ 7 - #include "xfs.h" 7 + #include "xfs_platform.h" 8 8 #include "xfs_fs.h" 9 9 #include "xfs_shared.h" 10 10 #include "xfs_format.h"
+1 -1
fs/xfs/xfs_trans_buf.c
··· 3 3 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+1 -1
fs/xfs/xfs_trans_dquot.c
··· 3 3 * Copyright (c) 2000-2002 Silicon Graphics, Inc. 4 4 * All Rights Reserved. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_fs.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h"
+445
fs/xfs/xfs_verify_media.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Copyright (c) 2026 Oracle. All Rights Reserved. 4 + * Author: Darrick J. Wong <djwong@kernel.org> 5 + */ 6 + #include "xfs_platform.h" 7 + #include "xfs_shared.h" 8 + #include "xfs_format.h" 9 + #include "xfs_log_format.h" 10 + #include "xfs_trans_resv.h" 11 + #include "xfs_mount.h" 12 + #include "xfs_bit.h" 13 + #include "xfs_btree.h" 14 + #include "xfs_inode.h" 15 + #include "xfs_icache.h" 16 + #include "xfs_trans.h" 17 + #include "xfs_alloc.h" 18 + #include "xfs_ag.h" 19 + #include "xfs_rmap.h" 20 + #include "xfs_rmap_btree.h" 21 + #include "xfs_rtgroup.h" 22 + #include "xfs_rtrmap_btree.h" 23 + #include "xfs_health.h" 24 + #include "xfs_healthmon.h" 25 + #include "xfs_trace.h" 26 + #include "xfs_verify_media.h" 27 + 28 + #include <linux/fserror.h> 29 + 30 + struct xfs_group_data_lost { 31 + xfs_agblock_t startblock; 32 + xfs_extlen_t blockcount; 33 + }; 34 + 35 + /* Report lost file data from rmap records */ 36 + static int 37 + xfs_verify_report_data_lost( 38 + struct xfs_btree_cur *cur, 39 + const struct xfs_rmap_irec *rec, 40 + void *data) 41 + { 42 + struct xfs_mount *mp = cur->bc_mp; 43 + struct xfs_inode *ip; 44 + struct xfs_group_data_lost *lost = data; 45 + xfs_fileoff_t fileoff = rec->rm_offset; 46 + xfs_extlen_t blocks = rec->rm_blockcount; 47 + const bool is_attr = 48 + (rec->rm_flags & XFS_RMAP_ATTR_FORK); 49 + const xfs_agblock_t lost_end = 50 + lost->startblock + lost->blockcount; 51 + const xfs_agblock_t rmap_end = 52 + rec->rm_startblock + rec->rm_blockcount; 53 + int error = 0; 54 + 55 + if (XFS_RMAP_NON_INODE_OWNER(rec->rm_owner)) 56 + return 0; 57 + 58 + error = xfs_iget(mp, cur->bc_tp, rec->rm_owner, 0, 0, &ip); 59 + if (error) 60 + return 0; 61 + 62 + if (rec->rm_flags & XFS_RMAP_BMBT_BLOCK) { 63 + xfs_bmap_mark_sick(ip, is_attr ? XFS_ATTR_FORK : XFS_DATA_FORK); 64 + goto out_rele; 65 + } 66 + 67 + if (is_attr) { 68 + xfs_inode_mark_sick(ip, XFS_SICK_INO_XATTR); 69 + goto out_rele; 70 + } 71 + 72 + if (lost->startblock > rec->rm_startblock) { 73 + fileoff += lost->startblock - rec->rm_startblock; 74 + blocks -= lost->startblock - rec->rm_startblock; 75 + } 76 + if (rmap_end > lost_end) 77 + blocks -= rmap_end - lost_end; 78 + 79 + fserror_report_data_lost(VFS_I(ip), XFS_FSB_TO_B(mp, fileoff), 80 + XFS_FSB_TO_B(mp, blocks), GFP_NOFS); 81 + 82 + out_rele: 83 + xfs_irele(ip); 84 + return 0; 85 + } 86 + 87 + /* Walk reverse mappings to look for all file data loss */ 88 + static int 89 + xfs_verify_report_losses( 90 + struct xfs_mount *mp, 91 + enum xfs_group_type type, 92 + xfs_daddr_t daddr, 93 + u64 bblen) 94 + { 95 + struct xfs_group *xg = NULL; 96 + struct xfs_trans *tp; 97 + xfs_fsblock_t start_bno, end_bno; 98 + uint32_t start_gno, end_gno; 99 + int error; 100 + 101 + if (type == XG_TYPE_RTG) { 102 + start_bno = xfs_daddr_to_rtb(mp, daddr); 103 + end_bno = xfs_daddr_to_rtb(mp, daddr + bblen - 1); 104 + } else { 105 + start_bno = XFS_DADDR_TO_FSB(mp, daddr); 106 + end_bno = XFS_DADDR_TO_FSB(mp, daddr + bblen - 1); 107 + } 108 + 109 + tp = xfs_trans_alloc_empty(mp); 110 + start_gno = xfs_fsb_to_gno(mp, start_bno, type); 111 + end_gno = xfs_fsb_to_gno(mp, end_bno, type); 112 + while ((xg = xfs_group_next_range(mp, xg, start_gno, end_gno, type))) { 113 + struct xfs_buf *agf_bp = NULL; 114 + struct xfs_rtgroup *rtg = NULL; 115 + struct xfs_btree_cur *cur; 116 + struct xfs_rmap_irec ri_low = { }; 117 + struct xfs_rmap_irec ri_high; 118 + struct xfs_group_data_lost lost; 119 + 120 + if (type == XG_TYPE_AG) { 121 + struct xfs_perag *pag = to_perag(xg); 122 + 123 + error = xfs_alloc_read_agf(pag, tp, 0, &agf_bp); 124 + if (error) { 125 + xfs_perag_put(pag); 126 + break; 127 + } 128 + 129 + cur = xfs_rmapbt_init_cursor(mp, tp, agf_bp, pag); 130 + } else { 131 + rtg = to_rtg(xg); 132 + xfs_rtgroup_lock(rtg, XFS_RTGLOCK_RMAP); 133 + cur = xfs_rtrmapbt_init_cursor(tp, rtg); 134 + } 135 + 136 + /* 137 + * Set the rmap range from ri_low to ri_high, which represents 138 + * a [start, end] where we looking for the files or metadata. 139 + */ 140 + memset(&ri_high, 0xFF, sizeof(ri_high)); 141 + if (xg->xg_gno == start_gno) 142 + ri_low.rm_startblock = 143 + xfs_fsb_to_gbno(mp, start_bno, type); 144 + if (xg->xg_gno == end_gno) 145 + ri_high.rm_startblock = 146 + xfs_fsb_to_gbno(mp, end_bno, type); 147 + 148 + lost.startblock = ri_low.rm_startblock; 149 + lost.blockcount = min(xg->xg_block_count, 150 + ri_high.rm_startblock + 1) - 151 + ri_low.rm_startblock; 152 + 153 + error = xfs_rmap_query_range(cur, &ri_low, &ri_high, 154 + xfs_verify_report_data_lost, &lost); 155 + xfs_btree_del_cursor(cur, error); 156 + if (agf_bp) 157 + xfs_trans_brelse(tp, agf_bp); 158 + if (rtg) 159 + xfs_rtgroup_unlock(rtg, XFS_RTGLOCK_RMAP); 160 + if (error) { 161 + xfs_group_put(xg); 162 + break; 163 + } 164 + } 165 + 166 + xfs_trans_cancel(tp); 167 + return 0; 168 + } 169 + 170 + /* 171 + * Compute the desired verify IO size. 172 + * 173 + * To minimize command overhead, we'd like to create bios that are 1MB, though 174 + * we allow the user to ask for a smaller size. 175 + */ 176 + static unsigned int 177 + xfs_verify_iosize( 178 + const struct xfs_verify_media *me, 179 + struct xfs_buftarg *btp, 180 + uint64_t bbcount) 181 + { 182 + unsigned int iosize = 183 + min_not_zero(SZ_1M, me->me_max_io_size); 184 + 185 + BUILD_BUG_ON(BBSHIFT != SECTOR_SHIFT); 186 + ASSERT(BBTOB(bbcount) >= bdev_logical_block_size(btp->bt_bdev)); 187 + 188 + return clamp(iosize, bdev_logical_block_size(btp->bt_bdev), 189 + BBTOB(bbcount)); 190 + } 191 + 192 + /* Allocate as much memory as we can get for verification buffer. */ 193 + static struct folio * 194 + xfs_verify_alloc_folio( 195 + const unsigned int iosize) 196 + { 197 + unsigned int order = get_order(iosize); 198 + 199 + while (order > 0) { 200 + struct folio *folio = 201 + folio_alloc(GFP_KERNEL | __GFP_NORETRY, order); 202 + 203 + if (folio) 204 + return folio; 205 + order--; 206 + } 207 + 208 + return folio_alloc(GFP_KERNEL, 0); 209 + } 210 + 211 + /* Report any kind of problem verifying media */ 212 + static void 213 + xfs_verify_media_error( 214 + struct xfs_mount *mp, 215 + struct xfs_verify_media *me, 216 + struct xfs_buftarg *btp, 217 + xfs_daddr_t daddr, 218 + unsigned int bio_bbcount, 219 + blk_status_t bio_status) 220 + { 221 + trace_xfs_verify_media_error(mp, me, btp->bt_bdev->bd_dev, daddr, 222 + bio_bbcount, bio_status); 223 + 224 + /* 225 + * Pass any error, I/O or otherwise, up to the caller if we didn't 226 + * successfully verify any bytes at all. 227 + */ 228 + if (me->me_start_daddr == daddr) 229 + me->me_ioerror = -blk_status_to_errno(bio_status); 230 + 231 + /* 232 + * PI validation failures, medium errors, or general IO errors are 233 + * treated as indicators of data loss. Everything else are (hopefully) 234 + * transient errors and are not reported to healthmon or fsnotify. 235 + */ 236 + switch (bio_status) { 237 + case BLK_STS_PROTECTION: 238 + case BLK_STS_IOERR: 239 + case BLK_STS_MEDIUM: 240 + break; 241 + default: 242 + return; 243 + } 244 + 245 + if (!(me->me_flags & XFS_VERIFY_MEDIA_REPORT)) 246 + return; 247 + 248 + xfs_healthmon_report_media(mp, me->me_dev, daddr, bio_bbcount); 249 + 250 + if (!xfs_has_rmapbt(mp)) 251 + return; 252 + 253 + switch (me->me_dev) { 254 + case XFS_DEV_DATA: 255 + xfs_verify_report_losses(mp, XG_TYPE_AG, daddr, bio_bbcount); 256 + break; 257 + case XFS_DEV_RT: 258 + xfs_verify_report_losses(mp, XG_TYPE_RTG, daddr, bio_bbcount); 259 + break; 260 + } 261 + } 262 + 263 + /* Verify the media of an xfs device by submitting read requests to the disk. */ 264 + static int 265 + xfs_verify_media( 266 + struct xfs_mount *mp, 267 + struct xfs_verify_media *me) 268 + { 269 + struct xfs_buftarg *btp = NULL; 270 + struct bio *bio; 271 + struct folio *folio; 272 + xfs_daddr_t daddr; 273 + uint64_t bbcount; 274 + int error = 0; 275 + 276 + me->me_ioerror = 0; 277 + 278 + switch (me->me_dev) { 279 + case XFS_DEV_DATA: 280 + btp = mp->m_ddev_targp; 281 + break; 282 + case XFS_DEV_LOG: 283 + if (mp->m_logdev_targp->bt_bdev != mp->m_ddev_targp->bt_bdev) 284 + btp = mp->m_logdev_targp; 285 + break; 286 + case XFS_DEV_RT: 287 + btp = mp->m_rtdev_targp; 288 + break; 289 + } 290 + if (!btp) 291 + return -ENODEV; 292 + 293 + /* 294 + * If the caller told us to verify beyond the end of the disk, tell the 295 + * user exactly where that was. 296 + */ 297 + if (me->me_end_daddr > btp->bt_nr_sectors) 298 + me->me_end_daddr = btp->bt_nr_sectors; 299 + 300 + /* start and end have to be aligned to the lba size */ 301 + if (!IS_ALIGNED(BBTOB(me->me_start_daddr | me->me_end_daddr), 302 + bdev_logical_block_size(btp->bt_bdev))) 303 + return -EINVAL; 304 + 305 + /* 306 + * end_daddr is the exclusive end of the range, so if start_daddr 307 + * reaches there (or beyond), there's no work to be done. 308 + */ 309 + if (me->me_start_daddr >= me->me_end_daddr) 310 + return 0; 311 + 312 + /* 313 + * There are three ranges involved here: 314 + * 315 + * - [me->me_start_daddr, me->me_end_daddr) is the range that the 316 + * user wants to verify. end_daddr can be beyond the end of the 317 + * disk; we'll constrain it to the end if necessary. 318 + * 319 + * - [daddr, me->me_end_daddr) is the range that we have not yet 320 + * verified. We update daddr after each successful read. 321 + * me->me_start_daddr is set to daddr before returning. 322 + * 323 + * - [daddr, daddr + bio_bbcount) is the range that we're currently 324 + * verifying. 325 + */ 326 + daddr = me->me_start_daddr; 327 + bbcount = min_t(sector_t, me->me_end_daddr, btp->bt_nr_sectors) - 328 + me->me_start_daddr; 329 + 330 + folio = xfs_verify_alloc_folio(xfs_verify_iosize(me, btp, bbcount)); 331 + if (!folio) 332 + return -ENOMEM; 333 + 334 + trace_xfs_verify_media(mp, me, btp->bt_bdev->bd_dev, daddr, bbcount, 335 + folio); 336 + 337 + bio = bio_alloc(btp->bt_bdev, 1, REQ_OP_READ, GFP_KERNEL); 338 + if (!bio) { 339 + error = -ENOMEM; 340 + goto out_folio; 341 + } 342 + 343 + while (bbcount > 0) { 344 + unsigned int bio_bbcount; 345 + blk_status_t bio_status; 346 + 347 + bio_reset(bio, btp->bt_bdev, REQ_OP_READ); 348 + bio->bi_iter.bi_sector = daddr; 349 + bio_add_folio_nofail(bio, folio, 350 + min(bbcount << SECTOR_SHIFT, folio_size(folio)), 351 + 0); 352 + 353 + /* 354 + * Save the length of the bio before we submit it, because we 355 + * need the original daddr and length for reporting IO errors 356 + * if the bio fails. 357 + */ 358 + bio_bbcount = bio->bi_iter.bi_size >> SECTOR_SHIFT; 359 + submit_bio_wait(bio); 360 + bio_status = bio->bi_status; 361 + if (bio_status != BLK_STS_OK) { 362 + xfs_verify_media_error(mp, me, btp, daddr, bio_bbcount, 363 + bio_status); 364 + error = 0; 365 + break; 366 + } 367 + 368 + daddr += bio_bbcount; 369 + bbcount -= bio_bbcount; 370 + 371 + if (bbcount == 0) 372 + break; 373 + 374 + if (me->me_rest_us) { 375 + ktime_t expires; 376 + 377 + expires = ktime_add_ns(ktime_get(), 378 + me->me_rest_us * 1000); 379 + set_current_state(TASK_KILLABLE); 380 + schedule_hrtimeout(&expires, HRTIMER_MODE_ABS); 381 + } 382 + 383 + if (fatal_signal_pending(current)) { 384 + error = -EINTR; 385 + break; 386 + } 387 + 388 + cond_resched(); 389 + } 390 + 391 + bio_put(bio); 392 + out_folio: 393 + folio_put(folio); 394 + 395 + if (error) 396 + return error; 397 + 398 + /* 399 + * Advance start_daddr to the end of what we verified if there wasn't 400 + * an operational error. 401 + */ 402 + me->me_start_daddr = daddr; 403 + trace_xfs_verify_media_end(mp, me, btp->bt_bdev->bd_dev); 404 + return 0; 405 + } 406 + 407 + int 408 + xfs_ioc_verify_media( 409 + struct file *file, 410 + struct xfs_verify_media __user *arg) 411 + { 412 + struct xfs_verify_media me; 413 + struct xfs_inode *ip = XFS_I(file_inode(file)); 414 + struct xfs_mount *mp = ip->i_mount; 415 + int error; 416 + 417 + if (!capable(CAP_SYS_ADMIN)) 418 + return -EPERM; 419 + 420 + if (copy_from_user(&me, arg, sizeof(me))) 421 + return -EFAULT; 422 + 423 + if (me.me_pad) 424 + return -EINVAL; 425 + if (me.me_flags & ~XFS_VERIFY_MEDIA_FLAGS) 426 + return -EINVAL; 427 + 428 + switch (me.me_dev) { 429 + case XFS_DEV_DATA: 430 + case XFS_DEV_LOG: 431 + case XFS_DEV_RT: 432 + break; 433 + default: 434 + return -EINVAL; 435 + } 436 + 437 + error = xfs_verify_media(mp, &me); 438 + if (error) 439 + return error; 440 + 441 + if (copy_to_user(arg, &me, sizeof(me))) 442 + return -EFAULT; 443 + 444 + return 0; 445 + }
+13
fs/xfs/xfs_verify_media.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + /* 3 + * Copyright (c) 2026 Oracle. All Rights Reserved. 4 + * Author: Darrick J. Wong <djwong@kernel.org> 5 + */ 6 + #ifndef __XFS_VERIFY_MEDIA_H__ 7 + #define __XFS_VERIFY_MEDIA_H__ 8 + 9 + struct xfs_verify_media; 10 + int xfs_ioc_verify_media(struct file *file, 11 + struct xfs_verify_media __user *arg); 12 + 13 + #endif /* __XFS_VERIFY_MEDIA_H__ */
+1 -1
fs/xfs/xfs_xattr.c
··· 4 4 * Portions Copyright (C) 2000-2008 Silicon Graphics, Inc. 5 5 */ 6 6 7 - #include "xfs.h" 7 + #include "xfs_platform.h" 8 8 #include "xfs_shared.h" 9 9 #include "xfs_format.h" 10 10 #include "xfs_log_format.h"
+116 -104
fs/xfs/xfs_zone_alloc.c
··· 3 3 * Copyright (c) 2023-2025 Christoph Hellwig. 4 4 * Copyright (c) 2024-2025, Western Digital Corporation or its affiliates. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_shared.h" 8 8 #include "xfs_format.h" 9 9 #include "xfs_log_format.h" ··· 408 408 return 0; 409 409 } 410 410 411 - static struct xfs_group * 412 - xfs_find_free_zone( 413 - struct xfs_mount *mp, 414 - unsigned long start, 415 - unsigned long end) 416 - { 417 - struct xfs_zone_info *zi = mp->m_zone_info; 418 - XA_STATE (xas, &mp->m_groups[XG_TYPE_RTG].xa, start); 419 - struct xfs_group *xg; 420 - 421 - xas_lock(&xas); 422 - xas_for_each_marked(&xas, xg, end, XFS_RTG_FREE) 423 - if (atomic_inc_not_zero(&xg->xg_active_ref)) 424 - goto found; 425 - xas_unlock(&xas); 426 - return NULL; 427 - 428 - found: 429 - xas_clear_mark(&xas, XFS_RTG_FREE); 430 - atomic_dec(&zi->zi_nr_free_zones); 431 - zi->zi_free_zone_cursor = xg->xg_gno; 432 - xas_unlock(&xas); 433 - return xg; 434 - } 435 - 436 411 static struct xfs_open_zone * 437 412 xfs_init_open_zone( 438 413 struct xfs_rtgroup *rtg, ··· 447 472 bool is_gc) 448 473 { 449 474 struct xfs_zone_info *zi = mp->m_zone_info; 475 + XA_STATE (xas, &mp->m_groups[XG_TYPE_RTG].xa, 0); 450 476 struct xfs_group *xg; 451 477 452 - xg = xfs_find_free_zone(mp, zi->zi_free_zone_cursor, ULONG_MAX); 453 - if (!xg) 454 - xg = xfs_find_free_zone(mp, 0, zi->zi_free_zone_cursor); 455 - if (!xg) 456 - return NULL; 478 + /* 479 + * Pick the free zone with lowest index. Zones in the beginning of the 480 + * address space typically provides higher bandwidth than those at the 481 + * end of the address space on HDDs. 482 + */ 483 + xas_lock(&xas); 484 + xas_for_each_marked(&xas, xg, ULONG_MAX, XFS_RTG_FREE) 485 + if (atomic_inc_not_zero(&xg->xg_active_ref)) 486 + goto found; 487 + xas_unlock(&xas); 488 + return NULL; 489 + 490 + found: 491 + xas_clear_mark(&xas, XFS_RTG_FREE); 492 + atomic_dec(&zi->zi_nr_free_zones); 493 + xas_unlock(&xas); 457 494 458 495 set_current_state(TASK_RUNNING); 459 496 return xfs_init_open_zone(to_rtg(xg), 0, write_hint, is_gc); ··· 963 976 } 964 977 965 978 struct xfs_init_zones { 966 - struct xfs_mount *mp; 979 + uint32_t zone_size; 980 + uint32_t zone_capacity; 967 981 uint64_t available; 968 982 uint64_t reclaimable; 969 983 }; 984 + 985 + /* 986 + * For sequential write required zones, we restart writing at the hardware write 987 + * pointer returned by xfs_validate_blk_zone(). 988 + * 989 + * For conventional zones or conventional devices we have to query the rmap to 990 + * find the highest recorded block and set the write pointer to the block after 991 + * that. In case of a power loss this misses blocks where the data I/O has 992 + * completed but not recorded in the rmap yet, and it also rewrites blocks if 993 + * the most recently written ones got deleted again before unmount, but this is 994 + * the best we can do without hardware support. 995 + */ 996 + static int 997 + xfs_query_write_pointer( 998 + struct xfs_init_zones *iz, 999 + struct xfs_rtgroup *rtg, 1000 + xfs_rgblock_t *write_pointer) 1001 + { 1002 + struct xfs_mount *mp = rtg_mount(rtg); 1003 + struct block_device *bdev = mp->m_rtdev_targp->bt_bdev; 1004 + sector_t start = xfs_gbno_to_daddr(&rtg->rtg_group, 0); 1005 + xfs_rgblock_t highest_rgbno; 1006 + struct blk_zone zone = {}; 1007 + int error; 1008 + 1009 + if (bdev_is_zoned(bdev)) { 1010 + error = blkdev_get_zone_info(bdev, start, &zone); 1011 + if (error) 1012 + return error; 1013 + if (zone.start != start) { 1014 + xfs_warn(mp, "mismatched zone start: 0x%llx/0x%llx.", 1015 + zone.start, start); 1016 + return -EFSCORRUPTED; 1017 + } 1018 + 1019 + if (!xfs_validate_blk_zone(mp, &zone, rtg_rgno(rtg), 1020 + iz->zone_size, iz->zone_capacity, 1021 + write_pointer)) 1022 + return -EFSCORRUPTED; 1023 + 1024 + /* 1025 + * Use the hardware write pointer returned by 1026 + * xfs_validate_blk_zone for sequential write required zones, 1027 + * else fall through to the rmap-based estimation below. 1028 + */ 1029 + if (zone.cond != BLK_ZONE_COND_NOT_WP) 1030 + return 0; 1031 + } 1032 + 1033 + xfs_rtgroup_lock(rtg, XFS_RTGLOCK_RMAP); 1034 + highest_rgbno = xfs_rtrmap_highest_rgbno(rtg); 1035 + xfs_rtgroup_unlock(rtg, XFS_RTGLOCK_RMAP); 1036 + 1037 + if (highest_rgbno == NULLRGBLOCK) 1038 + *write_pointer = 0; 1039 + else 1040 + *write_pointer = highest_rgbno + 1; 1041 + return 0; 1042 + } 970 1043 971 1044 static int 972 1045 xfs_init_zone( 973 1046 struct xfs_init_zones *iz, 974 1047 struct xfs_rtgroup *rtg, 975 - struct blk_zone *zone) 1048 + xfs_rgblock_t write_pointer) 976 1049 { 977 1050 struct xfs_mount *mp = rtg_mount(rtg); 978 1051 struct xfs_zone_info *zi = mp->m_zone_info; 979 1052 uint32_t used = rtg_rmap(rtg)->i_used_blocks; 980 - xfs_rgblock_t write_pointer, highest_rgbno; 981 1053 int error; 982 1054 983 - if (zone && !xfs_zone_validate(zone, rtg, &write_pointer)) 1055 + if (write_pointer > rtg->rtg_extents) { 1056 + xfs_warn(mp, "zone %u has invalid write pointer (0x%x).", 1057 + rtg_rgno(rtg), write_pointer); 984 1058 return -EFSCORRUPTED; 1059 + } 985 1060 986 - /* 987 - * For sequential write required zones we retrieved the hardware write 988 - * pointer above. 989 - * 990 - * For conventional zones or conventional devices we don't have that 991 - * luxury. Instead query the rmap to find the highest recorded block 992 - * and set the write pointer to the block after that. In case of a 993 - * power loss this misses blocks where the data I/O has completed but 994 - * not recorded in the rmap yet, and it also rewrites blocks if the most 995 - * recently written ones got deleted again before unmount, but this is 996 - * the best we can do without hardware support. 997 - */ 998 - if (!zone || zone->cond == BLK_ZONE_COND_NOT_WP) { 999 - xfs_rtgroup_lock(rtg, XFS_RTGLOCK_RMAP); 1000 - highest_rgbno = xfs_rtrmap_highest_rgbno(rtg); 1001 - if (highest_rgbno == NULLRGBLOCK) 1002 - write_pointer = 0; 1003 - else 1004 - write_pointer = highest_rgbno + 1; 1005 - xfs_rtgroup_unlock(rtg, XFS_RTGLOCK_RMAP); 1061 + if (used > rtg->rtg_extents) { 1062 + xfs_warn(mp, 1063 + "zone %u has used counter (0x%x) larger than zone capacity (0x%llx).", 1064 + rtg_rgno(rtg), used, rtg->rtg_extents); 1065 + return -EFSCORRUPTED; 1066 + } 1067 + 1068 + if (used > write_pointer) { 1069 + xfs_warn(mp, 1070 + "zone %u has used counter (0x%x) larger than write pointer (0x%x).", 1071 + rtg_rgno(rtg), used, write_pointer); 1072 + return -EFSCORRUPTED; 1073 + } 1074 + 1075 + if (write_pointer == 0 && used != 0) { 1076 + xfs_warn(mp, "empty zone %u has non-zero used counter (0x%x).", 1077 + rtg_rgno(rtg), used); 1078 + return -EFSCORRUPTED; 1006 1079 } 1007 1080 1008 1081 /* ··· 1101 1054 } 1102 1055 1103 1056 return 0; 1104 - } 1105 - 1106 - static int 1107 - xfs_get_zone_info_cb( 1108 - struct blk_zone *zone, 1109 - unsigned int idx, 1110 - void *data) 1111 - { 1112 - struct xfs_init_zones *iz = data; 1113 - struct xfs_mount *mp = iz->mp; 1114 - xfs_fsblock_t zsbno = xfs_daddr_to_rtb(mp, zone->start); 1115 - xfs_rgnumber_t rgno; 1116 - struct xfs_rtgroup *rtg; 1117 - int error; 1118 - 1119 - if (xfs_rtb_to_rgbno(mp, zsbno) != 0) { 1120 - xfs_warn(mp, "mismatched zone start 0x%llx.", zsbno); 1121 - return -EFSCORRUPTED; 1122 - } 1123 - 1124 - rgno = xfs_rtb_to_rgno(mp, zsbno); 1125 - rtg = xfs_rtgroup_grab(mp, rgno); 1126 - if (!rtg) { 1127 - xfs_warn(mp, "realtime group not found for zone %u.", rgno); 1128 - return -EFSCORRUPTED; 1129 - } 1130 - error = xfs_init_zone(iz, rtg, zone); 1131 - xfs_rtgroup_rele(rtg); 1132 - return error; 1133 1057 } 1134 1058 1135 1059 /* ··· 1237 1219 struct xfs_mount *mp) 1238 1220 { 1239 1221 struct xfs_init_zones iz = { 1240 - .mp = mp, 1222 + .zone_capacity = mp->m_groups[XG_TYPE_RTG].blocks, 1223 + .zone_size = xfs_rtgroup_raw_size(mp), 1241 1224 }; 1242 - struct xfs_buftarg *bt = mp->m_rtdev_targp; 1243 - xfs_extlen_t zone_blocks = mp->m_groups[XG_TYPE_RTG].blocks; 1225 + struct xfs_rtgroup *rtg = NULL; 1244 1226 int error; 1245 1227 1246 - if (!bt) { 1228 + if (!mp->m_rtdev_targp) { 1247 1229 xfs_notice(mp, "RT device missing."); 1248 1230 return -EINVAL; 1249 1231 } ··· 1271 1253 return -ENOMEM; 1272 1254 1273 1255 xfs_info(mp, "%u zones of %u blocks (%u max open zones)", 1274 - mp->m_sb.sb_rgcount, zone_blocks, mp->m_max_open_zones); 1256 + mp->m_sb.sb_rgcount, iz.zone_capacity, mp->m_max_open_zones); 1275 1257 trace_xfs_zones_mount(mp); 1276 1258 1277 1259 /* ··· 1295 1277 * or beneficial. 1296 1278 */ 1297 1279 mp->m_super->s_min_writeback_pages = 1298 - XFS_FSB_TO_B(mp, min(zone_blocks, XFS_MAX_BMBT_EXTLEN)) >> 1280 + XFS_FSB_TO_B(mp, min(iz.zone_capacity, XFS_MAX_BMBT_EXTLEN)) >> 1299 1281 PAGE_SHIFT; 1300 1282 1301 - if (bdev_is_zoned(bt->bt_bdev)) { 1302 - error = blkdev_report_zones_cached(bt->bt_bdev, 1303 - XFS_FSB_TO_BB(mp, mp->m_sb.sb_rtstart), 1304 - mp->m_sb.sb_rgcount, xfs_get_zone_info_cb, &iz); 1305 - if (error < 0) 1306 - goto out_free_zone_info; 1307 - } else { 1308 - struct xfs_rtgroup *rtg = NULL; 1283 + while ((rtg = xfs_rtgroup_next(mp, rtg))) { 1284 + xfs_rgblock_t write_pointer; 1309 1285 1310 - while ((rtg = xfs_rtgroup_next(mp, rtg))) { 1311 - error = xfs_init_zone(&iz, rtg, NULL); 1312 - if (error) { 1313 - xfs_rtgroup_rele(rtg); 1314 - goto out_free_zone_info; 1315 - } 1286 + error = xfs_query_write_pointer(&iz, rtg, &write_pointer); 1287 + if (!error) 1288 + error = xfs_init_zone(&iz, rtg, write_pointer); 1289 + if (error) { 1290 + xfs_rtgroup_rele(rtg); 1291 + goto out_free_zone_info; 1316 1292 } 1317 1293 } 1318 1294
+119 -102
fs/xfs/xfs_zone_gc.c
··· 3 3 * Copyright (c) 2023-2025 Christoph Hellwig. 4 4 * Copyright (c) 2024-2025, Western Digital Corporation or its affiliates. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_shared.h" 8 8 #include "xfs_format.h" 9 9 #include "xfs_log_format.h" ··· 16 16 #include "xfs_rmap.h" 17 17 #include "xfs_rtbitmap.h" 18 18 #include "xfs_rtrmap_btree.h" 19 + #include "xfs_errortag.h" 20 + #include "xfs_error.h" 19 21 #include "xfs_zone_alloc.h" 20 22 #include "xfs_zone_priv.h" 21 23 #include "xfs_zones.h" ··· 52 50 */ 53 51 54 52 /* 55 - * Size of each GC scratch pad. This is also the upper bound for each 56 - * GC I/O, which helps to keep latency down. 53 + * Size of each GC scratch allocation, and the number of buffers. 57 54 */ 58 - #define XFS_GC_CHUNK_SIZE SZ_1M 59 - 60 - /* 61 - * Scratchpad data to read GCed data into. 62 - * 63 - * The offset member tracks where the next allocation starts, and freed tracks 64 - * the amount of space that is not used anymore. 65 - */ 66 - #define XFS_ZONE_GC_NR_SCRATCH 2 67 - struct xfs_zone_scratch { 68 - struct folio *folio; 69 - unsigned int offset; 70 - unsigned int freed; 71 - }; 55 + #define XFS_GC_BUF_SIZE SZ_1M 56 + #define XFS_GC_NR_BUFS 2 57 + static_assert(XFS_GC_NR_BUFS < BIO_MAX_VECS); 72 58 73 59 /* 74 60 * Chunk that is read and written for each GC operation. ··· 131 141 struct bio_set bio_set; 132 142 133 143 /* 134 - * Scratchpad used, and index to indicated which one is used. 144 + * Scratchpad to buffer GC data, organized as a ring buffer over 145 + * discontiguous folios. scratch_head is where the buffer is filled, 146 + * scratch_tail tracks the buffer space freed, and scratch_available 147 + * counts the space available in the ring buffer between the head and 148 + * the tail. 135 149 */ 136 - struct xfs_zone_scratch scratch[XFS_ZONE_GC_NR_SCRATCH]; 137 - unsigned int scratch_idx; 150 + struct folio *scratch_folios[XFS_GC_NR_BUFS]; 151 + unsigned int scratch_size; 152 + unsigned int scratch_available; 153 + unsigned int scratch_head; 154 + unsigned int scratch_tail; 138 155 139 156 /* 140 157 * List of bios currently being read, written and reset. ··· 207 210 if (!data->iter.recs) 208 211 goto out_free_data; 209 212 210 - /* 211 - * We actually only need a single bio_vec. It would be nice to have 212 - * a flag that only allocates the inline bvecs and not the separate 213 - * bvec pool. 214 - */ 215 213 if (bioset_init(&data->bio_set, 16, offsetof(struct xfs_gc_bio, bio), 216 214 BIOSET_NEED_BVECS)) 217 215 goto out_free_recs; 218 - for (i = 0; i < XFS_ZONE_GC_NR_SCRATCH; i++) { 219 - data->scratch[i].folio = 220 - folio_alloc(GFP_KERNEL, get_order(XFS_GC_CHUNK_SIZE)); 221 - if (!data->scratch[i].folio) 216 + for (i = 0; i < XFS_GC_NR_BUFS; i++) { 217 + data->scratch_folios[i] = 218 + folio_alloc(GFP_KERNEL, get_order(XFS_GC_BUF_SIZE)); 219 + if (!data->scratch_folios[i]) 222 220 goto out_free_scratch; 223 221 } 222 + data->scratch_size = XFS_GC_BUF_SIZE * XFS_GC_NR_BUFS; 223 + data->scratch_available = data->scratch_size; 224 224 INIT_LIST_HEAD(&data->reading); 225 225 INIT_LIST_HEAD(&data->writing); 226 226 INIT_LIST_HEAD(&data->resetting); ··· 226 232 227 233 out_free_scratch: 228 234 while (--i >= 0) 229 - folio_put(data->scratch[i].folio); 235 + folio_put(data->scratch_folios[i]); 230 236 bioset_exit(&data->bio_set); 231 237 out_free_recs: 232 238 kfree(data->iter.recs); ··· 241 247 { 242 248 int i; 243 249 244 - for (i = 0; i < XFS_ZONE_GC_NR_SCRATCH; i++) 245 - folio_put(data->scratch[i].folio); 250 + for (i = 0; i < XFS_GC_NR_BUFS; i++) 251 + folio_put(data->scratch_folios[i]); 246 252 bioset_exit(&data->bio_set); 247 253 kfree(data->iter.recs); 248 254 kfree(data); ··· 580 586 return oz; 581 587 } 582 588 583 - static unsigned int 584 - xfs_zone_gc_scratch_available( 585 - struct xfs_zone_gc_data *data) 586 - { 587 - return XFS_GC_CHUNK_SIZE - data->scratch[data->scratch_idx].offset; 588 - } 589 - 590 - static bool 591 - xfs_zone_gc_space_available( 592 - struct xfs_zone_gc_data *data) 593 - { 594 - struct xfs_open_zone *oz; 595 - 596 - oz = xfs_zone_gc_ensure_target(data->mp); 597 - if (!oz) 598 - return false; 599 - return oz->oz_allocated < rtg_blocks(oz->oz_rtg) && 600 - xfs_zone_gc_scratch_available(data); 601 - } 602 - 603 589 static void 604 590 xfs_zone_gc_end_io( 605 591 struct bio *bio) ··· 606 632 if (!oz) 607 633 return NULL; 608 634 609 - *count_fsb = min(*count_fsb, 610 - XFS_B_TO_FSB(mp, xfs_zone_gc_scratch_available(data))); 635 + *count_fsb = min(*count_fsb, XFS_B_TO_FSB(mp, data->scratch_available)); 611 636 612 637 /* 613 638 * Directly allocate GC blocks from the reserved pool. ··· 637 664 return oz; 638 665 } 639 666 667 + static void 668 + xfs_zone_gc_add_data( 669 + struct xfs_gc_bio *chunk) 670 + { 671 + struct xfs_zone_gc_data *data = chunk->data; 672 + unsigned int len = chunk->len; 673 + unsigned int off = data->scratch_head; 674 + 675 + do { 676 + unsigned int this_off = off % XFS_GC_BUF_SIZE; 677 + unsigned int this_len = min(len, XFS_GC_BUF_SIZE - this_off); 678 + 679 + bio_add_folio_nofail(&chunk->bio, 680 + data->scratch_folios[off / XFS_GC_BUF_SIZE], 681 + this_len, this_off); 682 + len -= this_len; 683 + off += this_len; 684 + if (off == data->scratch_size) 685 + off = 0; 686 + } while (len); 687 + } 688 + 640 689 static bool 641 690 xfs_zone_gc_start_chunk( 642 691 struct xfs_zone_gc_data *data) ··· 672 677 struct xfs_inode *ip; 673 678 struct bio *bio; 674 679 xfs_daddr_t daddr; 680 + unsigned int len; 675 681 bool is_seq; 676 682 677 683 if (xfs_is_shutdown(mp)) ··· 687 691 return false; 688 692 } 689 693 690 - bio = bio_alloc_bioset(bdev, 1, REQ_OP_READ, GFP_NOFS, &data->bio_set); 694 + len = XFS_FSB_TO_B(mp, irec.rm_blockcount); 695 + bio = bio_alloc_bioset(bdev, 696 + min(howmany(len, XFS_GC_BUF_SIZE) + 1, XFS_GC_NR_BUFS), 697 + REQ_OP_READ, GFP_NOFS, &data->bio_set); 691 698 692 699 chunk = container_of(bio, struct xfs_gc_bio, bio); 693 700 chunk->ip = ip; 694 701 chunk->offset = XFS_FSB_TO_B(mp, irec.rm_offset); 695 - chunk->len = XFS_FSB_TO_B(mp, irec.rm_blockcount); 702 + chunk->len = len; 696 703 chunk->old_startblock = 697 704 xfs_rgbno_to_rtb(iter->victim_rtg, irec.rm_startblock); 698 705 chunk->new_daddr = daddr; 699 706 chunk->is_seq = is_seq; 700 - chunk->scratch = &data->scratch[data->scratch_idx]; 701 707 chunk->data = data; 702 708 chunk->oz = oz; 703 709 chunk->victim_rtg = iter->victim_rtg; ··· 708 710 709 711 bio->bi_iter.bi_sector = xfs_rtb_to_daddr(mp, chunk->old_startblock); 710 712 bio->bi_end_io = xfs_zone_gc_end_io; 711 - bio_add_folio_nofail(bio, chunk->scratch->folio, chunk->len, 712 - chunk->scratch->offset); 713 - chunk->scratch->offset += chunk->len; 714 - if (chunk->scratch->offset == XFS_GC_CHUNK_SIZE) { 715 - data->scratch_idx = 716 - (data->scratch_idx + 1) % XFS_ZONE_GC_NR_SCRATCH; 717 - } 713 + xfs_zone_gc_add_data(chunk); 714 + data->scratch_head = (data->scratch_head + len) % data->scratch_size; 715 + data->scratch_available -= len; 716 + 717 + XFS_STATS_INC(mp, xs_gc_read_calls); 718 + 718 719 WRITE_ONCE(chunk->state, XFS_GC_BIO_NEW); 719 720 list_add_tail(&chunk->entry, &data->reading); 720 721 xfs_zone_gc_iter_advance(iter, irec.rm_blockcount); ··· 808 811 { 809 812 struct xfs_zone_gc_data *data = chunk->data; 810 813 struct xfs_mount *mp = chunk->ip->i_mount; 811 - phys_addr_t bvec_paddr = 812 - bvec_phys(bio_first_bvec_all(&chunk->bio)); 813 814 struct xfs_gc_bio *split_chunk; 814 815 815 816 if (chunk->bio.bi_status) ··· 817 822 return; 818 823 } 819 824 825 + XFS_STATS_INC(mp, xs_gc_write_calls); 826 + XFS_STATS_ADD(mp, xs_gc_bytes, chunk->len); 827 + 820 828 WRITE_ONCE(chunk->state, XFS_GC_BIO_NEW); 821 829 list_move_tail(&chunk->entry, &data->writing); 822 830 823 - bio_reset(&chunk->bio, mp->m_rtdev_targp->bt_bdev, REQ_OP_WRITE); 824 - bio_add_folio_nofail(&chunk->bio, chunk->scratch->folio, chunk->len, 825 - offset_in_folio(chunk->scratch->folio, bvec_paddr)); 826 - 831 + bio_reuse(&chunk->bio, REQ_OP_WRITE); 827 832 while ((split_chunk = xfs_zone_gc_split_write(data, chunk))) 828 833 xfs_zone_gc_submit_write(data, split_chunk); 829 834 xfs_zone_gc_submit_write(data, chunk); ··· 834 839 struct xfs_gc_bio *chunk) 835 840 { 836 841 uint iolock = XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL; 842 + struct xfs_zone_gc_data *data = chunk->data; 837 843 struct xfs_inode *ip = chunk->ip; 838 844 struct xfs_mount *mp = ip->i_mount; 839 845 int error; ··· 846 850 return; 847 851 } 848 852 849 - chunk->scratch->freed += chunk->len; 850 - if (chunk->scratch->freed == chunk->scratch->offset) { 851 - chunk->scratch->offset = 0; 852 - chunk->scratch->freed = 0; 853 - } 853 + data->scratch_tail = 854 + (data->scratch_tail + chunk->len) % data->scratch_size; 855 + data->scratch_available += chunk->len; 854 856 855 857 /* 856 858 * Cycle through the iolock and wait for direct I/O and layouts to ··· 900 906 bio_put(&chunk->bio); 901 907 } 902 908 903 - static bool 904 - xfs_zone_gc_prepare_reset( 905 - struct bio *bio, 906 - struct xfs_rtgroup *rtg) 909 + static void 910 + xfs_submit_zone_reset_bio( 911 + struct xfs_rtgroup *rtg, 912 + struct bio *bio) 907 913 { 914 + struct xfs_mount *mp = rtg_mount(rtg); 915 + 908 916 trace_xfs_zone_reset(rtg); 909 917 910 918 ASSERT(rtg_rmap(rtg)->i_used_blocks == 0); 911 - bio->bi_iter.bi_sector = xfs_gbno_to_daddr(&rtg->rtg_group, 0); 912 - if (!bdev_zone_is_seq(bio->bi_bdev, bio->bi_iter.bi_sector)) { 913 - if (!bdev_max_discard_sectors(bio->bi_bdev)) 914 - return false; 915 - bio->bi_opf = REQ_OP_DISCARD | REQ_SYNC; 916 - bio->bi_iter.bi_size = 917 - XFS_FSB_TO_B(rtg_mount(rtg), rtg_blocks(rtg)); 919 + 920 + if (XFS_TEST_ERROR(mp, XFS_ERRTAG_ZONE_RESET)) { 921 + bio_io_error(bio); 922 + return; 918 923 } 919 924 920 - return true; 925 + XFS_STATS_INC(mp, xs_gc_zone_reset_calls); 926 + 927 + bio->bi_iter.bi_sector = xfs_gbno_to_daddr(&rtg->rtg_group, 0); 928 + if (!bdev_zone_is_seq(bio->bi_bdev, bio->bi_iter.bi_sector)) { 929 + /* 930 + * Also use the bio to drive the state machine when neither 931 + * zone reset nor discard is supported to keep things simple. 932 + */ 933 + if (!bdev_max_discard_sectors(bio->bi_bdev)) { 934 + bio_endio(bio); 935 + return; 936 + } 937 + bio->bi_opf &= ~REQ_OP_ZONE_RESET; 938 + bio->bi_opf |= REQ_OP_DISCARD; 939 + bio->bi_iter.bi_size = XFS_FSB_TO_B(mp, rtg_blocks(rtg)); 940 + } 941 + 942 + submit_bio(bio); 943 + } 944 + 945 + static void xfs_bio_wait_endio(struct bio *bio) 946 + { 947 + complete(bio->bi_private); 921 948 } 922 949 923 950 int 924 951 xfs_zone_gc_reset_sync( 925 952 struct xfs_rtgroup *rtg) 926 953 { 927 - int error = 0; 954 + DECLARE_COMPLETION_ONSTACK(done); 928 955 struct bio bio; 956 + int error; 929 957 930 958 bio_init(&bio, rtg_mount(rtg)->m_rtdev_targp->bt_bdev, NULL, 0, 931 - REQ_OP_ZONE_RESET); 932 - if (xfs_zone_gc_prepare_reset(&bio, rtg)) 933 - error = submit_bio_wait(&bio); 934 - bio_uninit(&bio); 959 + REQ_OP_ZONE_RESET | REQ_SYNC); 960 + bio.bi_private = &done; 961 + bio.bi_end_io = xfs_bio_wait_endio; 962 + xfs_submit_zone_reset_bio(rtg, &bio); 963 + wait_for_completion_io(&done); 935 964 965 + error = blk_status_to_errno(bio.bi_status); 966 + bio_uninit(&bio); 936 967 return error; 937 968 } 938 969 ··· 992 973 chunk->data = data; 993 974 WRITE_ONCE(chunk->state, XFS_GC_BIO_NEW); 994 975 list_add_tail(&chunk->entry, &data->resetting); 995 - 996 - /* 997 - * Also use the bio to drive the state machine when neither 998 - * zone reset nor discard is supported to keep things simple. 999 - */ 1000 - if (xfs_zone_gc_prepare_reset(bio, rtg)) 1001 - submit_bio(bio); 1002 - else 1003 - bio_endio(bio); 976 + xfs_submit_zone_reset_bio(rtg, bio); 1004 977 } while (next); 1005 978 } 1006 979 ··· 1000 989 xfs_zone_gc_should_start_new_work( 1001 990 struct xfs_zone_gc_data *data) 1002 991 { 992 + struct xfs_open_zone *oz; 993 + 1003 994 if (xfs_is_shutdown(data->mp)) 1004 995 return false; 1005 - if (!xfs_zone_gc_space_available(data)) 996 + if (!data->scratch_available) 997 + return false; 998 + 999 + oz = xfs_zone_gc_ensure_target(data->mp); 1000 + if (!oz || oz->oz_allocated == rtg_blocks(oz->oz_rtg)) 1006 1001 return false; 1007 1002 1008 1003 if (!data->iter.victim_rtg) {
+1 -1
fs/xfs/xfs_zone_info.c
··· 3 3 * Copyright (c) 2023-2025 Christoph Hellwig. 4 4 * Copyright (c) 2024-2025, Western Digital Corporation or its affiliates. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_shared.h" 8 8 #include "xfs_format.h" 9 9 #include "xfs_trans_resv.h"
-1
fs/xfs/xfs_zone_priv.h
··· 72 72 /* 73 73 * Free zone search cursor and number of free zones: 74 74 */ 75 - unsigned long zi_free_zone_cursor; 76 75 atomic_t zi_nr_free_zones; 77 76 78 77 /*
+1 -1
fs/xfs/xfs_zone_space_resv.c
··· 3 3 * Copyright (c) 2023-2025 Christoph Hellwig. 4 4 * Copyright (c) 2024-2025, Western Digital Corporation or its affiliates. 5 5 */ 6 - #include "xfs.h" 6 + #include "xfs_platform.h" 7 7 #include "xfs_shared.h" 8 8 #include "xfs_format.h" 9 9 #include "xfs_trans_resv.h"
+1
include/linux/bio.h
··· 414 414 } 415 415 extern void bio_uninit(struct bio *); 416 416 void bio_reset(struct bio *bio, struct block_device *bdev, blk_opf_t opf); 417 + void bio_reuse(struct bio *bio, blk_opf_t opf); 417 418 void bio_chain(struct bio *, struct bio *); 418 419 419 420 int __must_check bio_add_page(struct bio *bio, struct page *page, unsigned len,