xfs_attr_list.c (13580B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (c) 2000-2005 Silicon Graphics, Inc. 4 * Copyright (c) 2013 Red Hat, Inc. 5 * All Rights Reserved. 6 */ 7#include "xfs.h" 8#include "xfs_fs.h" 9#include "xfs_shared.h" 10#include "xfs_format.h" 11#include "xfs_log_format.h" 12#include "xfs_trans_resv.h" 13#include "xfs_mount.h" 14#include "xfs_da_format.h" 15#include "xfs_inode.h" 16#include "xfs_trans.h" 17#include "xfs_bmap.h" 18#include "xfs_da_btree.h" 19#include "xfs_attr.h" 20#include "xfs_attr_sf.h" 21#include "xfs_attr_leaf.h" 22#include "xfs_error.h" 23#include "xfs_trace.h" 24#include "xfs_dir2.h" 25 26STATIC int 27xfs_attr_shortform_compare(const void *a, const void *b) 28{ 29 xfs_attr_sf_sort_t *sa, *sb; 30 31 sa = (xfs_attr_sf_sort_t *)a; 32 sb = (xfs_attr_sf_sort_t *)b; 33 if (sa->hash < sb->hash) { 34 return -1; 35 } else if (sa->hash > sb->hash) { 36 return 1; 37 } else { 38 return sa->entno - sb->entno; 39 } 40} 41 42#define XFS_ISRESET_CURSOR(cursor) \ 43 (!((cursor)->initted) && !((cursor)->hashval) && \ 44 !((cursor)->blkno) && !((cursor)->offset)) 45/* 46 * Copy out entries of shortform attribute lists for attr_list(). 47 * Shortform attribute lists are not stored in hashval sorted order. 48 * If the output buffer is not large enough to hold them all, then 49 * we have to calculate each entries' hashvalue and sort them before 50 * we can begin returning them to the user. 51 */ 52static int 53xfs_attr_shortform_list( 54 struct xfs_attr_list_context *context) 55{ 56 struct xfs_attrlist_cursor_kern *cursor = &context->cursor; 57 struct xfs_inode *dp = context->dp; 58 struct xfs_attr_sf_sort *sbuf, *sbp; 59 struct xfs_attr_shortform *sf; 60 struct xfs_attr_sf_entry *sfe; 61 int sbsize, nsbuf, count, i; 62 int error = 0; 63 64 ASSERT(dp->i_afp != NULL); 65 sf = (struct xfs_attr_shortform *)dp->i_afp->if_u1.if_data; 66 ASSERT(sf != NULL); 67 if (!sf->hdr.count) 68 return 0; 69 70 trace_xfs_attr_list_sf(context); 71 72 /* 73 * If the buffer is large enough and the cursor is at the start, 74 * do not bother with sorting since we will return everything in 75 * one buffer and another call using the cursor won't need to be 76 * made. 77 * Note the generous fudge factor of 16 overhead bytes per entry. 78 * If bufsize is zero then put_listent must be a search function 79 * and can just scan through what we have. 80 */ 81 if (context->bufsize == 0 || 82 (XFS_ISRESET_CURSOR(cursor) && 83 (dp->i_afp->if_bytes + sf->hdr.count * 16) < context->bufsize)) { 84 for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) { 85 if (XFS_IS_CORRUPT(context->dp->i_mount, 86 !xfs_attr_namecheck(sfe->nameval, 87 sfe->namelen))) 88 return -EFSCORRUPTED; 89 context->put_listent(context, 90 sfe->flags, 91 sfe->nameval, 92 (int)sfe->namelen, 93 (int)sfe->valuelen); 94 /* 95 * Either search callback finished early or 96 * didn't fit it all in the buffer after all. 97 */ 98 if (context->seen_enough) 99 break; 100 sfe = xfs_attr_sf_nextentry(sfe); 101 } 102 trace_xfs_attr_list_sf_all(context); 103 return 0; 104 } 105 106 /* do no more for a search callback */ 107 if (context->bufsize == 0) 108 return 0; 109 110 /* 111 * It didn't all fit, so we have to sort everything on hashval. 112 */ 113 sbsize = sf->hdr.count * sizeof(*sbuf); 114 sbp = sbuf = kmem_alloc(sbsize, KM_NOFS); 115 116 /* 117 * Scan the attribute list for the rest of the entries, storing 118 * the relevant info from only those that match into a buffer. 119 */ 120 nsbuf = 0; 121 for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) { 122 if (unlikely( 123 ((char *)sfe < (char *)sf) || 124 ((char *)sfe >= ((char *)sf + dp->i_afp->if_bytes)))) { 125 XFS_CORRUPTION_ERROR("xfs_attr_shortform_list", 126 XFS_ERRLEVEL_LOW, 127 context->dp->i_mount, sfe, 128 sizeof(*sfe)); 129 kmem_free(sbuf); 130 return -EFSCORRUPTED; 131 } 132 133 sbp->entno = i; 134 sbp->hash = xfs_da_hashname(sfe->nameval, sfe->namelen); 135 sbp->name = sfe->nameval; 136 sbp->namelen = sfe->namelen; 137 /* These are bytes, and both on-disk, don't endian-flip */ 138 sbp->valuelen = sfe->valuelen; 139 sbp->flags = sfe->flags; 140 sfe = xfs_attr_sf_nextentry(sfe); 141 sbp++; 142 nsbuf++; 143 } 144 145 /* 146 * Sort the entries on hash then entno. 147 */ 148 xfs_sort(sbuf, nsbuf, sizeof(*sbuf), xfs_attr_shortform_compare); 149 150 /* 151 * Re-find our place IN THE SORTED LIST. 152 */ 153 count = 0; 154 cursor->initted = 1; 155 cursor->blkno = 0; 156 for (sbp = sbuf, i = 0; i < nsbuf; i++, sbp++) { 157 if (sbp->hash == cursor->hashval) { 158 if (cursor->offset == count) { 159 break; 160 } 161 count++; 162 } else if (sbp->hash > cursor->hashval) { 163 break; 164 } 165 } 166 if (i == nsbuf) 167 goto out; 168 169 /* 170 * Loop putting entries into the user buffer. 171 */ 172 for ( ; i < nsbuf; i++, sbp++) { 173 if (cursor->hashval != sbp->hash) { 174 cursor->hashval = sbp->hash; 175 cursor->offset = 0; 176 } 177 if (XFS_IS_CORRUPT(context->dp->i_mount, 178 !xfs_attr_namecheck(sbp->name, 179 sbp->namelen))) { 180 error = -EFSCORRUPTED; 181 goto out; 182 } 183 context->put_listent(context, 184 sbp->flags, 185 sbp->name, 186 sbp->namelen, 187 sbp->valuelen); 188 if (context->seen_enough) 189 break; 190 cursor->offset++; 191 } 192out: 193 kmem_free(sbuf); 194 return error; 195} 196 197/* 198 * We didn't find the block & hash mentioned in the cursor state, so 199 * walk down the attr btree looking for the hash. 200 */ 201STATIC int 202xfs_attr_node_list_lookup( 203 struct xfs_attr_list_context *context, 204 struct xfs_attrlist_cursor_kern *cursor, 205 struct xfs_buf **pbp) 206{ 207 struct xfs_da3_icnode_hdr nodehdr; 208 struct xfs_da_intnode *node; 209 struct xfs_da_node_entry *btree; 210 struct xfs_inode *dp = context->dp; 211 struct xfs_mount *mp = dp->i_mount; 212 struct xfs_trans *tp = context->tp; 213 struct xfs_buf *bp; 214 int i; 215 int error = 0; 216 unsigned int expected_level = 0; 217 uint16_t magic; 218 219 ASSERT(*pbp == NULL); 220 cursor->blkno = 0; 221 for (;;) { 222 error = xfs_da3_node_read(tp, dp, cursor->blkno, &bp, 223 XFS_ATTR_FORK); 224 if (error) 225 return error; 226 node = bp->b_addr; 227 magic = be16_to_cpu(node->hdr.info.magic); 228 if (magic == XFS_ATTR_LEAF_MAGIC || 229 magic == XFS_ATTR3_LEAF_MAGIC) 230 break; 231 if (magic != XFS_DA_NODE_MAGIC && 232 magic != XFS_DA3_NODE_MAGIC) { 233 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, 234 node, sizeof(*node)); 235 goto out_corruptbuf; 236 } 237 238 xfs_da3_node_hdr_from_disk(mp, &nodehdr, node); 239 240 /* Tree taller than we can handle; bail out! */ 241 if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH) 242 goto out_corruptbuf; 243 244 /* Check the level from the root node. */ 245 if (cursor->blkno == 0) 246 expected_level = nodehdr.level - 1; 247 else if (expected_level != nodehdr.level) 248 goto out_corruptbuf; 249 else 250 expected_level--; 251 252 btree = nodehdr.btree; 253 for (i = 0; i < nodehdr.count; btree++, i++) { 254 if (cursor->hashval <= be32_to_cpu(btree->hashval)) { 255 cursor->blkno = be32_to_cpu(btree->before); 256 trace_xfs_attr_list_node_descend(context, 257 btree); 258 break; 259 } 260 } 261 xfs_trans_brelse(tp, bp); 262 263 if (i == nodehdr.count) 264 return 0; 265 266 /* We can't point back to the root. */ 267 if (XFS_IS_CORRUPT(mp, cursor->blkno == 0)) 268 return -EFSCORRUPTED; 269 } 270 271 if (expected_level != 0) 272 goto out_corruptbuf; 273 274 *pbp = bp; 275 return 0; 276 277out_corruptbuf: 278 xfs_buf_mark_corrupt(bp); 279 xfs_trans_brelse(tp, bp); 280 return -EFSCORRUPTED; 281} 282 283STATIC int 284xfs_attr_node_list( 285 struct xfs_attr_list_context *context) 286{ 287 struct xfs_attrlist_cursor_kern *cursor = &context->cursor; 288 struct xfs_attr3_icleaf_hdr leafhdr; 289 struct xfs_attr_leafblock *leaf; 290 struct xfs_da_intnode *node; 291 struct xfs_buf *bp; 292 struct xfs_inode *dp = context->dp; 293 struct xfs_mount *mp = dp->i_mount; 294 int error = 0; 295 296 trace_xfs_attr_node_list(context); 297 298 cursor->initted = 1; 299 300 /* 301 * Do all sorts of validation on the passed-in cursor structure. 302 * If anything is amiss, ignore the cursor and look up the hashval 303 * starting from the btree root. 304 */ 305 bp = NULL; 306 if (cursor->blkno > 0) { 307 error = xfs_da3_node_read(context->tp, dp, cursor->blkno, &bp, 308 XFS_ATTR_FORK); 309 if ((error != 0) && (error != -EFSCORRUPTED)) 310 return error; 311 if (bp) { 312 struct xfs_attr_leaf_entry *entries; 313 314 node = bp->b_addr; 315 switch (be16_to_cpu(node->hdr.info.magic)) { 316 case XFS_DA_NODE_MAGIC: 317 case XFS_DA3_NODE_MAGIC: 318 trace_xfs_attr_list_wrong_blk(context); 319 xfs_trans_brelse(context->tp, bp); 320 bp = NULL; 321 break; 322 case XFS_ATTR_LEAF_MAGIC: 323 case XFS_ATTR3_LEAF_MAGIC: 324 leaf = bp->b_addr; 325 xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, 326 &leafhdr, leaf); 327 entries = xfs_attr3_leaf_entryp(leaf); 328 if (cursor->hashval > be32_to_cpu( 329 entries[leafhdr.count - 1].hashval)) { 330 trace_xfs_attr_list_wrong_blk(context); 331 xfs_trans_brelse(context->tp, bp); 332 bp = NULL; 333 } else if (cursor->hashval <= be32_to_cpu( 334 entries[0].hashval)) { 335 trace_xfs_attr_list_wrong_blk(context); 336 xfs_trans_brelse(context->tp, bp); 337 bp = NULL; 338 } 339 break; 340 default: 341 trace_xfs_attr_list_wrong_blk(context); 342 xfs_trans_brelse(context->tp, bp); 343 bp = NULL; 344 } 345 } 346 } 347 348 /* 349 * We did not find what we expected given the cursor's contents, 350 * so we start from the top and work down based on the hash value. 351 * Note that start of node block is same as start of leaf block. 352 */ 353 if (bp == NULL) { 354 error = xfs_attr_node_list_lookup(context, cursor, &bp); 355 if (error || !bp) 356 return error; 357 } 358 ASSERT(bp != NULL); 359 360 /* 361 * Roll upward through the blocks, processing each leaf block in 362 * order. As long as there is space in the result buffer, keep 363 * adding the information. 364 */ 365 for (;;) { 366 leaf = bp->b_addr; 367 error = xfs_attr3_leaf_list_int(bp, context); 368 if (error) 369 break; 370 xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf); 371 if (context->seen_enough || leafhdr.forw == 0) 372 break; 373 cursor->blkno = leafhdr.forw; 374 xfs_trans_brelse(context->tp, bp); 375 error = xfs_attr3_leaf_read(context->tp, dp, cursor->blkno, 376 &bp); 377 if (error) 378 return error; 379 } 380 xfs_trans_brelse(context->tp, bp); 381 return error; 382} 383 384/* 385 * Copy out attribute list entries for attr_list(), for leaf attribute lists. 386 */ 387int 388xfs_attr3_leaf_list_int( 389 struct xfs_buf *bp, 390 struct xfs_attr_list_context *context) 391{ 392 struct xfs_attrlist_cursor_kern *cursor = &context->cursor; 393 struct xfs_attr_leafblock *leaf; 394 struct xfs_attr3_icleaf_hdr ichdr; 395 struct xfs_attr_leaf_entry *entries; 396 struct xfs_attr_leaf_entry *entry; 397 int i; 398 struct xfs_mount *mp = context->dp->i_mount; 399 400 trace_xfs_attr_list_leaf(context); 401 402 leaf = bp->b_addr; 403 xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, leaf); 404 entries = xfs_attr3_leaf_entryp(leaf); 405 406 cursor->initted = 1; 407 408 /* 409 * Re-find our place in the leaf block if this is a new syscall. 410 */ 411 if (context->resynch) { 412 entry = &entries[0]; 413 for (i = 0; i < ichdr.count; entry++, i++) { 414 if (be32_to_cpu(entry->hashval) == cursor->hashval) { 415 if (cursor->offset == context->dupcnt) { 416 context->dupcnt = 0; 417 break; 418 } 419 context->dupcnt++; 420 } else if (be32_to_cpu(entry->hashval) > 421 cursor->hashval) { 422 context->dupcnt = 0; 423 break; 424 } 425 } 426 if (i == ichdr.count) { 427 trace_xfs_attr_list_notfound(context); 428 return 0; 429 } 430 } else { 431 entry = &entries[0]; 432 i = 0; 433 } 434 context->resynch = 0; 435 436 /* 437 * We have found our place, start copying out the new attributes. 438 */ 439 for (; i < ichdr.count; entry++, i++) { 440 char *name; 441 int namelen, valuelen; 442 443 if (be32_to_cpu(entry->hashval) != cursor->hashval) { 444 cursor->hashval = be32_to_cpu(entry->hashval); 445 cursor->offset = 0; 446 } 447 448 if ((entry->flags & XFS_ATTR_INCOMPLETE) && 449 !context->allow_incomplete) 450 continue; 451 452 if (entry->flags & XFS_ATTR_LOCAL) { 453 xfs_attr_leaf_name_local_t *name_loc; 454 455 name_loc = xfs_attr3_leaf_name_local(leaf, i); 456 name = name_loc->nameval; 457 namelen = name_loc->namelen; 458 valuelen = be16_to_cpu(name_loc->valuelen); 459 } else { 460 xfs_attr_leaf_name_remote_t *name_rmt; 461 462 name_rmt = xfs_attr3_leaf_name_remote(leaf, i); 463 name = name_rmt->name; 464 namelen = name_rmt->namelen; 465 valuelen = be32_to_cpu(name_rmt->valuelen); 466 } 467 468 if (XFS_IS_CORRUPT(context->dp->i_mount, 469 !xfs_attr_namecheck(name, namelen))) 470 return -EFSCORRUPTED; 471 context->put_listent(context, entry->flags, 472 name, namelen, valuelen); 473 if (context->seen_enough) 474 break; 475 cursor->offset++; 476 } 477 trace_xfs_attr_list_leaf_end(context); 478 return 0; 479} 480 481/* 482 * Copy out attribute entries for attr_list(), for leaf attribute lists. 483 */ 484STATIC int 485xfs_attr_leaf_list( 486 struct xfs_attr_list_context *context) 487{ 488 struct xfs_buf *bp; 489 int error; 490 491 trace_xfs_attr_leaf_list(context); 492 493 context->cursor.blkno = 0; 494 error = xfs_attr3_leaf_read(context->tp, context->dp, 0, &bp); 495 if (error) 496 return error; 497 498 error = xfs_attr3_leaf_list_int(bp, context); 499 xfs_trans_brelse(context->tp, bp); 500 return error; 501} 502 503int 504xfs_attr_list_ilocked( 505 struct xfs_attr_list_context *context) 506{ 507 struct xfs_inode *dp = context->dp; 508 509 ASSERT(xfs_isilocked(dp, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)); 510 511 /* 512 * Decide on what work routines to call based on the inode size. 513 */ 514 if (!xfs_inode_hasattr(dp)) 515 return 0; 516 if (dp->i_afp->if_format == XFS_DINODE_FMT_LOCAL) 517 return xfs_attr_shortform_list(context); 518 if (xfs_attr_is_leaf(dp)) 519 return xfs_attr_leaf_list(context); 520 return xfs_attr_node_list(context); 521} 522 523int 524xfs_attr_list( 525 struct xfs_attr_list_context *context) 526{ 527 struct xfs_inode *dp = context->dp; 528 uint lock_mode; 529 int error; 530 531 XFS_STATS_INC(dp->i_mount, xs_attr_list); 532 533 if (xfs_is_shutdown(dp->i_mount)) 534 return -EIO; 535 536 lock_mode = xfs_ilock_attr_map_shared(dp); 537 error = xfs_attr_list_ilocked(context); 538 xfs_iunlock(dp, lock_mode); 539 return error; 540}