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.

at v2.6.14-rc2 3066 lines 91 kB view raw
1/* 2 * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms of version 2 of the GNU General Public License as 6 * published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it would be useful, but 9 * WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 * 12 * Further, this software is distributed without any warranty that it is 13 * free of the rightful claim of any third person regarding infringement 14 * or the like. Any license provided herein, whether implied or 15 * otherwise, applies only to this software file. Patent licenses, if 16 * any, provided herein do not apply to combinations of this program with 17 * other software, or any other product whatsoever. 18 * 19 * You should have received a copy of the GNU General Public License along 20 * with this program; if not, write the Free Software Foundation, Inc., 59 21 * Temple Place - Suite 330, Boston MA 02111-1307, USA. 22 * 23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, 24 * Mountain View, CA 94043, or: 25 * 26 * http://www.sgi.com 27 * 28 * For further information regarding this notice, see: 29 * 30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ 31 */ 32/* 33 * xfs_attr_leaf.c 34 * 35 * GROT: figure out how to recover gracefully when bmap returns ENOSPC. 36 */ 37 38#include "xfs.h" 39 40#include "xfs_macros.h" 41#include "xfs_types.h" 42#include "xfs_inum.h" 43#include "xfs_log.h" 44#include "xfs_trans.h" 45#include "xfs_sb.h" 46#include "xfs_ag.h" 47#include "xfs_dir.h" 48#include "xfs_dir2.h" 49#include "xfs_dmapi.h" 50#include "xfs_mount.h" 51#include "xfs_alloc_btree.h" 52#include "xfs_bmap_btree.h" 53#include "xfs_ialloc_btree.h" 54#include "xfs_alloc.h" 55#include "xfs_btree.h" 56#include "xfs_attr_sf.h" 57#include "xfs_dir_sf.h" 58#include "xfs_dir2_sf.h" 59#include "xfs_dinode.h" 60#include "xfs_inode_item.h" 61#include "xfs_inode.h" 62#include "xfs_bmap.h" 63#include "xfs_da_btree.h" 64#include "xfs_attr.h" 65#include "xfs_attr_leaf.h" 66#include "xfs_error.h" 67#include "xfs_bit.h" 68 69/* 70 * xfs_attr_leaf.c 71 * 72 * Routines to implement leaf blocks of attributes as Btrees of hashed names. 73 */ 74 75/*======================================================================== 76 * Function prototypes for the kernel. 77 *========================================================================*/ 78 79/* 80 * Routines used for growing the Btree. 81 */ 82STATIC int xfs_attr_leaf_create(xfs_da_args_t *args, xfs_dablk_t which_block, 83 xfs_dabuf_t **bpp); 84STATIC int xfs_attr_leaf_add_work(xfs_dabuf_t *leaf_buffer, xfs_da_args_t *args, 85 int freemap_index); 86STATIC void xfs_attr_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *leaf_buffer); 87STATIC void xfs_attr_leaf_rebalance(xfs_da_state_t *state, 88 xfs_da_state_blk_t *blk1, 89 xfs_da_state_blk_t *blk2); 90STATIC int xfs_attr_leaf_figure_balance(xfs_da_state_t *state, 91 xfs_da_state_blk_t *leaf_blk_1, 92 xfs_da_state_blk_t *leaf_blk_2, 93 int *number_entries_in_blk1, 94 int *number_usedbytes_in_blk1); 95 96/* 97 * Routines used for shrinking the Btree. 98 */ 99STATIC int xfs_attr_node_inactive(xfs_trans_t **trans, xfs_inode_t *dp, 100 xfs_dabuf_t *bp, int level); 101STATIC int xfs_attr_leaf_inactive(xfs_trans_t **trans, xfs_inode_t *dp, 102 xfs_dabuf_t *bp); 103STATIC int xfs_attr_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp, 104 xfs_dablk_t blkno, int blkcnt); 105 106/* 107 * Utility routines. 108 */ 109STATIC void xfs_attr_leaf_moveents(xfs_attr_leafblock_t *src_leaf, 110 int src_start, 111 xfs_attr_leafblock_t *dst_leaf, 112 int dst_start, int move_count, 113 xfs_mount_t *mp); 114STATIC int xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index); 115STATIC int xfs_attr_put_listent(xfs_attr_list_context_t *context, 116 attrnames_t *, char *name, int namelen, 117 int valuelen); 118 119 120/*======================================================================== 121 * External routines when dirsize < XFS_LITINO(mp). 122 *========================================================================*/ 123 124/* 125 * Create the initial contents of a shortform attribute list. 126 */ 127int 128xfs_attr_shortform_create(xfs_da_args_t *args) 129{ 130 xfs_attr_sf_hdr_t *hdr; 131 xfs_inode_t *dp; 132 xfs_ifork_t *ifp; 133 134 dp = args->dp; 135 ASSERT(dp != NULL); 136 ifp = dp->i_afp; 137 ASSERT(ifp != NULL); 138 ASSERT(ifp->if_bytes == 0); 139 if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) { 140 ifp->if_flags &= ~XFS_IFEXTENTS; /* just in case */ 141 dp->i_d.di_aformat = XFS_DINODE_FMT_LOCAL; 142 ifp->if_flags |= XFS_IFINLINE; 143 } else { 144 ASSERT(ifp->if_flags & XFS_IFINLINE); 145 } 146 xfs_idata_realloc(dp, sizeof(*hdr), XFS_ATTR_FORK); 147 hdr = (xfs_attr_sf_hdr_t *)ifp->if_u1.if_data; 148 hdr->count = 0; 149 INT_SET(hdr->totsize, ARCH_CONVERT, sizeof(*hdr)); 150 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA); 151 return(0); 152} 153 154/* 155 * Add a name/value pair to the shortform attribute list. 156 * Overflow from the inode has already been checked for. 157 */ 158int 159xfs_attr_shortform_add(xfs_da_args_t *args) 160{ 161 xfs_attr_shortform_t *sf; 162 xfs_attr_sf_entry_t *sfe; 163 int i, offset, size; 164 xfs_inode_t *dp; 165 xfs_ifork_t *ifp; 166 167 dp = args->dp; 168 ifp = dp->i_afp; 169 ASSERT(ifp->if_flags & XFS_IFINLINE); 170 sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data; 171 sfe = &sf->list[0]; 172 for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT); 173 sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) { 174 if (sfe->namelen != args->namelen) 175 continue; 176 if (memcmp(args->name, sfe->nameval, args->namelen) != 0) 177 continue; 178 if (((args->flags & ATTR_SECURE) != 0) != 179 ((sfe->flags & XFS_ATTR_SECURE) != 0)) 180 continue; 181 if (((args->flags & ATTR_ROOT) != 0) != 182 ((sfe->flags & XFS_ATTR_ROOT) != 0)) 183 continue; 184 return(XFS_ERROR(EEXIST)); 185 } 186 187 offset = (char *)sfe - (char *)sf; 188 size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen); 189 xfs_idata_realloc(dp, size, XFS_ATTR_FORK); 190 sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data; 191 sfe = (xfs_attr_sf_entry_t *)((char *)sf + offset); 192 193 sfe->namelen = args->namelen; 194 INT_SET(sfe->valuelen, ARCH_CONVERT, args->valuelen); 195 sfe->flags = (args->flags & ATTR_SECURE) ? XFS_ATTR_SECURE : 196 ((args->flags & ATTR_ROOT) ? XFS_ATTR_ROOT : 0); 197 memcpy(sfe->nameval, args->name, args->namelen); 198 memcpy(&sfe->nameval[args->namelen], args->value, args->valuelen); 199 INT_MOD(sf->hdr.count, ARCH_CONVERT, 1); 200 INT_MOD(sf->hdr.totsize, ARCH_CONVERT, size); 201 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA); 202 203 return(0); 204} 205 206/* 207 * Remove a name from the shortform attribute list structure. 208 */ 209int 210xfs_attr_shortform_remove(xfs_da_args_t *args) 211{ 212 xfs_attr_shortform_t *sf; 213 xfs_attr_sf_entry_t *sfe; 214 int base, size=0, end, totsize, i; 215 xfs_inode_t *dp; 216 217 /* 218 * Remove the attribute. 219 */ 220 dp = args->dp; 221 base = sizeof(xfs_attr_sf_hdr_t); 222 sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data; 223 sfe = &sf->list[0]; 224 for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT); 225 sfe = XFS_ATTR_SF_NEXTENTRY(sfe), 226 base += size, i++) { 227 size = XFS_ATTR_SF_ENTSIZE(sfe); 228 if (sfe->namelen != args->namelen) 229 continue; 230 if (memcmp(sfe->nameval, args->name, args->namelen) != 0) 231 continue; 232 if (((args->flags & ATTR_SECURE) != 0) != 233 ((sfe->flags & XFS_ATTR_SECURE) != 0)) 234 continue; 235 if (((args->flags & ATTR_ROOT) != 0) != 236 ((sfe->flags & XFS_ATTR_ROOT) != 0)) 237 continue; 238 break; 239 } 240 if (i == INT_GET(sf->hdr.count, ARCH_CONVERT)) 241 return(XFS_ERROR(ENOATTR)); 242 243 end = base + size; 244 totsize = INT_GET(sf->hdr.totsize, ARCH_CONVERT); 245 if (end != totsize) { 246 memmove(&((char *)sf)[base], &((char *)sf)[end], 247 totsize - end); 248 } 249 INT_MOD(sf->hdr.count, ARCH_CONVERT, -1); 250 INT_MOD(sf->hdr.totsize, ARCH_CONVERT, -size); 251 xfs_idata_realloc(dp, -size, XFS_ATTR_FORK); 252 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA); 253 254 return(0); 255} 256 257/* 258 * Look up a name in a shortform attribute list structure. 259 */ 260/*ARGSUSED*/ 261int 262xfs_attr_shortform_lookup(xfs_da_args_t *args) 263{ 264 xfs_attr_shortform_t *sf; 265 xfs_attr_sf_entry_t *sfe; 266 int i; 267 xfs_ifork_t *ifp; 268 269 ifp = args->dp->i_afp; 270 ASSERT(ifp->if_flags & XFS_IFINLINE); 271 sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data; 272 sfe = &sf->list[0]; 273 for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT); 274 sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) { 275 if (sfe->namelen != args->namelen) 276 continue; 277 if (memcmp(args->name, sfe->nameval, args->namelen) != 0) 278 continue; 279 if (((args->flags & ATTR_SECURE) != 0) != 280 ((sfe->flags & XFS_ATTR_SECURE) != 0)) 281 continue; 282 if (((args->flags & ATTR_ROOT) != 0) != 283 ((sfe->flags & XFS_ATTR_ROOT) != 0)) 284 continue; 285 return(XFS_ERROR(EEXIST)); 286 } 287 return(XFS_ERROR(ENOATTR)); 288} 289 290/* 291 * Look up a name in a shortform attribute list structure. 292 */ 293/*ARGSUSED*/ 294int 295xfs_attr_shortform_getvalue(xfs_da_args_t *args) 296{ 297 xfs_attr_shortform_t *sf; 298 xfs_attr_sf_entry_t *sfe; 299 int i; 300 301 ASSERT(args->dp->i_d.di_aformat == XFS_IFINLINE); 302 sf = (xfs_attr_shortform_t *)args->dp->i_afp->if_u1.if_data; 303 sfe = &sf->list[0]; 304 for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT); 305 sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) { 306 if (sfe->namelen != args->namelen) 307 continue; 308 if (memcmp(args->name, sfe->nameval, args->namelen) != 0) 309 continue; 310 if (((args->flags & ATTR_SECURE) != 0) != 311 ((sfe->flags & XFS_ATTR_SECURE) != 0)) 312 continue; 313 if (((args->flags & ATTR_ROOT) != 0) != 314 ((sfe->flags & XFS_ATTR_ROOT) != 0)) 315 continue; 316 if (args->flags & ATTR_KERNOVAL) { 317 args->valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT); 318 return(XFS_ERROR(EEXIST)); 319 } 320 if (args->valuelen < INT_GET(sfe->valuelen, ARCH_CONVERT)) { 321 args->valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT); 322 return(XFS_ERROR(ERANGE)); 323 } 324 args->valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT); 325 memcpy(args->value, &sfe->nameval[args->namelen], 326 args->valuelen); 327 return(XFS_ERROR(EEXIST)); 328 } 329 return(XFS_ERROR(ENOATTR)); 330} 331 332/* 333 * Convert from using the shortform to the leaf. 334 */ 335int 336xfs_attr_shortform_to_leaf(xfs_da_args_t *args) 337{ 338 xfs_inode_t *dp; 339 xfs_attr_shortform_t *sf; 340 xfs_attr_sf_entry_t *sfe; 341 xfs_da_args_t nargs; 342 char *tmpbuffer; 343 int error, i, size; 344 xfs_dablk_t blkno; 345 xfs_dabuf_t *bp; 346 xfs_ifork_t *ifp; 347 348 dp = args->dp; 349 ifp = dp->i_afp; 350 sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data; 351 size = INT_GET(sf->hdr.totsize, ARCH_CONVERT); 352 tmpbuffer = kmem_alloc(size, KM_SLEEP); 353 ASSERT(tmpbuffer != NULL); 354 memcpy(tmpbuffer, ifp->if_u1.if_data, size); 355 sf = (xfs_attr_shortform_t *)tmpbuffer; 356 357 xfs_idata_realloc(dp, -size, XFS_ATTR_FORK); 358 bp = NULL; 359 error = xfs_da_grow_inode(args, &blkno); 360 if (error) { 361 /* 362 * If we hit an IO error middle of the transaction inside 363 * grow_inode(), we may have inconsistent data. Bail out. 364 */ 365 if (error == EIO) 366 goto out; 367 xfs_idata_realloc(dp, size, XFS_ATTR_FORK); /* try to put */ 368 memcpy(ifp->if_u1.if_data, tmpbuffer, size); /* it back */ 369 goto out; 370 } 371 372 ASSERT(blkno == 0); 373 error = xfs_attr_leaf_create(args, blkno, &bp); 374 if (error) { 375 error = xfs_da_shrink_inode(args, 0, bp); 376 bp = NULL; 377 if (error) 378 goto out; 379 xfs_idata_realloc(dp, size, XFS_ATTR_FORK); /* try to put */ 380 memcpy(ifp->if_u1.if_data, tmpbuffer, size); /* it back */ 381 goto out; 382 } 383 384 memset((char *)&nargs, 0, sizeof(nargs)); 385 nargs.dp = dp; 386 nargs.firstblock = args->firstblock; 387 nargs.flist = args->flist; 388 nargs.total = args->total; 389 nargs.whichfork = XFS_ATTR_FORK; 390 nargs.trans = args->trans; 391 nargs.oknoent = 1; 392 393 sfe = &sf->list[0]; 394 for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) { 395 nargs.name = (char *)sfe->nameval; 396 nargs.namelen = sfe->namelen; 397 nargs.value = (char *)&sfe->nameval[nargs.namelen]; 398 nargs.valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT); 399 nargs.hashval = xfs_da_hashname((char *)sfe->nameval, 400 sfe->namelen); 401 nargs.flags = (sfe->flags & XFS_ATTR_SECURE) ? ATTR_SECURE : 402 ((sfe->flags & XFS_ATTR_ROOT) ? ATTR_ROOT : 0); 403 error = xfs_attr_leaf_lookup_int(bp, &nargs); /* set a->index */ 404 ASSERT(error == ENOATTR); 405 error = xfs_attr_leaf_add(bp, &nargs); 406 ASSERT(error != ENOSPC); 407 if (error) 408 goto out; 409 sfe = XFS_ATTR_SF_NEXTENTRY(sfe); 410 } 411 error = 0; 412 413out: 414 if(bp) 415 xfs_da_buf_done(bp); 416 kmem_free(tmpbuffer, size); 417 return(error); 418} 419 420STATIC int 421xfs_attr_shortform_compare(const void *a, const void *b) 422{ 423 xfs_attr_sf_sort_t *sa, *sb; 424 425 sa = (xfs_attr_sf_sort_t *)a; 426 sb = (xfs_attr_sf_sort_t *)b; 427 if (INT_GET(sa->hash, ARCH_CONVERT) 428 < INT_GET(sb->hash, ARCH_CONVERT)) { 429 return(-1); 430 } else if (INT_GET(sa->hash, ARCH_CONVERT) 431 > INT_GET(sb->hash, ARCH_CONVERT)) { 432 return(1); 433 } else { 434 return(sa->entno - sb->entno); 435 } 436} 437 438/* 439 * Copy out entries of shortform attribute lists for attr_list(). 440 * Shortform atrtribute lists are not stored in hashval sorted order. 441 * If the output buffer is not large enough to hold them all, then we 442 * we have to calculate each entries' hashvalue and sort them before 443 * we can begin returning them to the user. 444 */ 445/*ARGSUSED*/ 446int 447xfs_attr_shortform_list(xfs_attr_list_context_t *context) 448{ 449 attrlist_cursor_kern_t *cursor; 450 xfs_attr_sf_sort_t *sbuf, *sbp; 451 xfs_attr_shortform_t *sf; 452 xfs_attr_sf_entry_t *sfe; 453 xfs_inode_t *dp; 454 int sbsize, nsbuf, count, i; 455 456 ASSERT(context != NULL); 457 dp = context->dp; 458 ASSERT(dp != NULL); 459 ASSERT(dp->i_afp != NULL); 460 sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data; 461 ASSERT(sf != NULL); 462 if (!sf->hdr.count) 463 return(0); 464 cursor = context->cursor; 465 ASSERT(cursor != NULL); 466 467 xfs_attr_trace_l_c("sf start", context); 468 469 /* 470 * If the buffer is large enough, do not bother with sorting. 471 * Note the generous fudge factor of 16 overhead bytes per entry. 472 */ 473 if ((dp->i_afp->if_bytes + INT_GET(sf->hdr.count, ARCH_CONVERT) * 16) 474 < context->bufsize) { 475 for (i = 0, sfe = &sf->list[0]; 476 i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) { 477 attrnames_t *namesp; 478 479 if (((context->flags & ATTR_SECURE) != 0) != 480 ((sfe->flags & XFS_ATTR_SECURE) != 0) && 481 !(context->flags & ATTR_KERNORMALS)) { 482 sfe = XFS_ATTR_SF_NEXTENTRY(sfe); 483 continue; 484 } 485 if (((context->flags & ATTR_ROOT) != 0) != 486 ((sfe->flags & XFS_ATTR_ROOT) != 0) && 487 !(context->flags & ATTR_KERNROOTLS)) { 488 sfe = XFS_ATTR_SF_NEXTENTRY(sfe); 489 continue; 490 } 491 namesp = (sfe->flags & XFS_ATTR_SECURE) ? &attr_secure: 492 ((sfe->flags & XFS_ATTR_ROOT) ? &attr_trusted : 493 &attr_user); 494 if (context->flags & ATTR_KERNOVAL) { 495 ASSERT(context->flags & ATTR_KERNAMELS); 496 context->count += namesp->attr_namelen + 497 INT_GET(sfe->namelen, ARCH_CONVERT) + 1; 498 } 499 else { 500 if (xfs_attr_put_listent(context, namesp, 501 (char *)sfe->nameval, 502 (int)sfe->namelen, 503 (int)INT_GET(sfe->valuelen, 504 ARCH_CONVERT))) 505 break; 506 } 507 sfe = XFS_ATTR_SF_NEXTENTRY(sfe); 508 } 509 xfs_attr_trace_l_c("sf big-gulp", context); 510 return(0); 511 } 512 513 /* 514 * It didn't all fit, so we have to sort everything on hashval. 515 */ 516 sbsize = INT_GET(sf->hdr.count, ARCH_CONVERT) * sizeof(*sbuf); 517 sbp = sbuf = kmem_alloc(sbsize, KM_SLEEP); 518 519 /* 520 * Scan the attribute list for the rest of the entries, storing 521 * the relevant info from only those that match into a buffer. 522 */ 523 nsbuf = 0; 524 for (i = 0, sfe = &sf->list[0]; 525 i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) { 526 if (unlikely( 527 ((char *)sfe < (char *)sf) || 528 ((char *)sfe >= ((char *)sf + dp->i_afp->if_bytes)))) { 529 XFS_CORRUPTION_ERROR("xfs_attr_shortform_list", 530 XFS_ERRLEVEL_LOW, 531 context->dp->i_mount, sfe); 532 xfs_attr_trace_l_c("sf corrupted", context); 533 kmem_free(sbuf, sbsize); 534 return XFS_ERROR(EFSCORRUPTED); 535 } 536 if (((context->flags & ATTR_SECURE) != 0) != 537 ((sfe->flags & XFS_ATTR_SECURE) != 0) && 538 !(context->flags & ATTR_KERNORMALS)) { 539 sfe = XFS_ATTR_SF_NEXTENTRY(sfe); 540 continue; 541 } 542 if (((context->flags & ATTR_ROOT) != 0) != 543 ((sfe->flags & XFS_ATTR_ROOT) != 0) && 544 !(context->flags & ATTR_KERNROOTLS)) { 545 sfe = XFS_ATTR_SF_NEXTENTRY(sfe); 546 continue; 547 } 548 sbp->entno = i; 549 INT_SET(sbp->hash, ARCH_CONVERT, 550 xfs_da_hashname((char *)sfe->nameval, sfe->namelen)); 551 sbp->name = (char *)sfe->nameval; 552 sbp->namelen = sfe->namelen; 553 /* These are bytes, and both on-disk, don't endian-flip */ 554 sbp->valuelen = sfe->valuelen; 555 sbp->flags = sfe->flags; 556 sfe = XFS_ATTR_SF_NEXTENTRY(sfe); 557 sbp++; 558 nsbuf++; 559 } 560 561 /* 562 * Sort the entries on hash then entno. 563 */ 564 qsort(sbuf, nsbuf, sizeof(*sbuf), xfs_attr_shortform_compare); 565 566 /* 567 * Re-find our place IN THE SORTED LIST. 568 */ 569 count = 0; 570 cursor->initted = 1; 571 cursor->blkno = 0; 572 for (sbp = sbuf, i = 0; i < nsbuf; i++, sbp++) { 573 if (INT_GET(sbp->hash, ARCH_CONVERT) == cursor->hashval) { 574 if (cursor->offset == count) { 575 break; 576 } 577 count++; 578 } else if (INT_GET(sbp->hash, ARCH_CONVERT) > cursor->hashval) { 579 break; 580 } 581 } 582 if (i == nsbuf) { 583 kmem_free(sbuf, sbsize); 584 xfs_attr_trace_l_c("blk end", context); 585 return(0); 586 } 587 588 /* 589 * Loop putting entries into the user buffer. 590 */ 591 for ( ; i < nsbuf; i++, sbp++) { 592 attrnames_t *namesp; 593 594 namesp = (sbp->flags & XFS_ATTR_SECURE) ? &attr_secure : 595 ((sbp->flags & XFS_ATTR_ROOT) ? &attr_trusted : 596 &attr_user); 597 598 if (cursor->hashval != INT_GET(sbp->hash, ARCH_CONVERT)) { 599 cursor->hashval = INT_GET(sbp->hash, ARCH_CONVERT); 600 cursor->offset = 0; 601 } 602 if (context->flags & ATTR_KERNOVAL) { 603 ASSERT(context->flags & ATTR_KERNAMELS); 604 context->count += namesp->attr_namelen + 605 sbp->namelen + 1; 606 } else { 607 if (xfs_attr_put_listent(context, namesp, 608 sbp->name, sbp->namelen, 609 INT_GET(sbp->valuelen, ARCH_CONVERT))) 610 break; 611 } 612 cursor->offset++; 613 } 614 615 kmem_free(sbuf, sbsize); 616 xfs_attr_trace_l_c("sf E-O-F", context); 617 return(0); 618} 619 620/* 621 * Check a leaf attribute block to see if all the entries would fit into 622 * a shortform attribute list. 623 */ 624int 625xfs_attr_shortform_allfit(xfs_dabuf_t *bp, xfs_inode_t *dp) 626{ 627 xfs_attr_leafblock_t *leaf; 628 xfs_attr_leaf_entry_t *entry; 629 xfs_attr_leaf_name_local_t *name_loc; 630 int bytes, i; 631 632 leaf = bp->data; 633 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) 634 == XFS_ATTR_LEAF_MAGIC); 635 636 entry = &leaf->entries[0]; 637 bytes = sizeof(struct xfs_attr_sf_hdr); 638 for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) { 639 if (entry->flags & XFS_ATTR_INCOMPLETE) 640 continue; /* don't copy partial entries */ 641 if (!(entry->flags & XFS_ATTR_LOCAL)) 642 return(0); 643 name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i); 644 if (name_loc->namelen >= XFS_ATTR_SF_ENTSIZE_MAX) 645 return(0); 646 if (INT_GET(name_loc->valuelen, ARCH_CONVERT) >= XFS_ATTR_SF_ENTSIZE_MAX) 647 return(0); 648 bytes += sizeof(struct xfs_attr_sf_entry)-1 649 + name_loc->namelen 650 + INT_GET(name_loc->valuelen, ARCH_CONVERT); 651 } 652 return( bytes < XFS_IFORK_ASIZE(dp) ); 653} 654 655/* 656 * Convert a leaf attribute list to shortform attribute list 657 */ 658int 659xfs_attr_leaf_to_shortform(xfs_dabuf_t *bp, xfs_da_args_t *args) 660{ 661 xfs_attr_leafblock_t *leaf; 662 xfs_attr_leaf_entry_t *entry; 663 xfs_attr_leaf_name_local_t *name_loc; 664 xfs_da_args_t nargs; 665 xfs_inode_t *dp; 666 char *tmpbuffer; 667 int error, i; 668 669 dp = args->dp; 670 tmpbuffer = kmem_alloc(XFS_LBSIZE(dp->i_mount), KM_SLEEP); 671 ASSERT(tmpbuffer != NULL); 672 673 ASSERT(bp != NULL); 674 memcpy(tmpbuffer, bp->data, XFS_LBSIZE(dp->i_mount)); 675 leaf = (xfs_attr_leafblock_t *)tmpbuffer; 676 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) 677 == XFS_ATTR_LEAF_MAGIC); 678 memset(bp->data, 0, XFS_LBSIZE(dp->i_mount)); 679 680 /* 681 * Clean out the prior contents of the attribute list. 682 */ 683 error = xfs_da_shrink_inode(args, 0, bp); 684 if (error) 685 goto out; 686 error = xfs_attr_shortform_create(args); 687 if (error) 688 goto out; 689 690 /* 691 * Copy the attributes 692 */ 693 memset((char *)&nargs, 0, sizeof(nargs)); 694 nargs.dp = dp; 695 nargs.firstblock = args->firstblock; 696 nargs.flist = args->flist; 697 nargs.total = args->total; 698 nargs.whichfork = XFS_ATTR_FORK; 699 nargs.trans = args->trans; 700 nargs.oknoent = 1; 701 entry = &leaf->entries[0]; 702 for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) { 703 if (entry->flags & XFS_ATTR_INCOMPLETE) 704 continue; /* don't copy partial entries */ 705 if (!entry->nameidx) 706 continue; 707 ASSERT(entry->flags & XFS_ATTR_LOCAL); 708 name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i); 709 nargs.name = (char *)name_loc->nameval; 710 nargs.namelen = name_loc->namelen; 711 nargs.value = (char *)&name_loc->nameval[nargs.namelen]; 712 nargs.valuelen = INT_GET(name_loc->valuelen, ARCH_CONVERT); 713 nargs.hashval = INT_GET(entry->hashval, ARCH_CONVERT); 714 nargs.flags = (entry->flags & XFS_ATTR_SECURE) ? ATTR_SECURE : 715 ((entry->flags & XFS_ATTR_ROOT) ? ATTR_ROOT : 0); 716 xfs_attr_shortform_add(&nargs); 717 } 718 error = 0; 719 720out: 721 kmem_free(tmpbuffer, XFS_LBSIZE(dp->i_mount)); 722 return(error); 723} 724 725/* 726 * Convert from using a single leaf to a root node and a leaf. 727 */ 728int 729xfs_attr_leaf_to_node(xfs_da_args_t *args) 730{ 731 xfs_attr_leafblock_t *leaf; 732 xfs_da_intnode_t *node; 733 xfs_inode_t *dp; 734 xfs_dabuf_t *bp1, *bp2; 735 xfs_dablk_t blkno; 736 int error; 737 738 dp = args->dp; 739 bp1 = bp2 = NULL; 740 error = xfs_da_grow_inode(args, &blkno); 741 if (error) 742 goto out; 743 error = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp1, 744 XFS_ATTR_FORK); 745 if (error) 746 goto out; 747 ASSERT(bp1 != NULL); 748 bp2 = NULL; 749 error = xfs_da_get_buf(args->trans, args->dp, blkno, -1, &bp2, 750 XFS_ATTR_FORK); 751 if (error) 752 goto out; 753 ASSERT(bp2 != NULL); 754 memcpy(bp2->data, bp1->data, XFS_LBSIZE(dp->i_mount)); 755 xfs_da_buf_done(bp1); 756 bp1 = NULL; 757 xfs_da_log_buf(args->trans, bp2, 0, XFS_LBSIZE(dp->i_mount) - 1); 758 759 /* 760 * Set up the new root node. 761 */ 762 error = xfs_da_node_create(args, 0, 1, &bp1, XFS_ATTR_FORK); 763 if (error) 764 goto out; 765 node = bp1->data; 766 leaf = bp2->data; 767 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) 768 == XFS_ATTR_LEAF_MAGIC); 769 /* both on-disk, don't endian-flip twice */ 770 node->btree[0].hashval = 771 leaf->entries[INT_GET(leaf->hdr.count, ARCH_CONVERT)-1 ].hashval; 772 INT_SET(node->btree[0].before, ARCH_CONVERT, blkno); 773 INT_SET(node->hdr.count, ARCH_CONVERT, 1); 774 xfs_da_log_buf(args->trans, bp1, 0, XFS_LBSIZE(dp->i_mount) - 1); 775 error = 0; 776out: 777 if (bp1) 778 xfs_da_buf_done(bp1); 779 if (bp2) 780 xfs_da_buf_done(bp2); 781 return(error); 782} 783 784 785/*======================================================================== 786 * Routines used for growing the Btree. 787 *========================================================================*/ 788 789/* 790 * Create the initial contents of a leaf attribute list 791 * or a leaf in a node attribute list. 792 */ 793STATIC int 794xfs_attr_leaf_create(xfs_da_args_t *args, xfs_dablk_t blkno, xfs_dabuf_t **bpp) 795{ 796 xfs_attr_leafblock_t *leaf; 797 xfs_attr_leaf_hdr_t *hdr; 798 xfs_inode_t *dp; 799 xfs_dabuf_t *bp; 800 int error; 801 802 dp = args->dp; 803 ASSERT(dp != NULL); 804 error = xfs_da_get_buf(args->trans, args->dp, blkno, -1, &bp, 805 XFS_ATTR_FORK); 806 if (error) 807 return(error); 808 ASSERT(bp != NULL); 809 leaf = bp->data; 810 memset((char *)leaf, 0, XFS_LBSIZE(dp->i_mount)); 811 hdr = &leaf->hdr; 812 INT_SET(hdr->info.magic, ARCH_CONVERT, XFS_ATTR_LEAF_MAGIC); 813 INT_SET(hdr->firstused, ARCH_CONVERT, XFS_LBSIZE(dp->i_mount)); 814 if (!hdr->firstused) { 815 INT_SET(hdr->firstused, ARCH_CONVERT, 816 XFS_LBSIZE(dp->i_mount) - XFS_ATTR_LEAF_NAME_ALIGN); 817 } 818 819 INT_SET(hdr->freemap[0].base, ARCH_CONVERT, 820 sizeof(xfs_attr_leaf_hdr_t)); 821 INT_SET(hdr->freemap[0].size, ARCH_CONVERT, 822 INT_GET(hdr->firstused, ARCH_CONVERT) 823 - INT_GET(hdr->freemap[0].base, 824 ARCH_CONVERT)); 825 826 xfs_da_log_buf(args->trans, bp, 0, XFS_LBSIZE(dp->i_mount) - 1); 827 828 *bpp = bp; 829 return(0); 830} 831 832/* 833 * Split the leaf node, rebalance, then add the new entry. 834 */ 835int 836xfs_attr_leaf_split(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk, 837 xfs_da_state_blk_t *newblk) 838{ 839 xfs_dablk_t blkno; 840 int error; 841 842 /* 843 * Allocate space for a new leaf node. 844 */ 845 ASSERT(oldblk->magic == XFS_ATTR_LEAF_MAGIC); 846 error = xfs_da_grow_inode(state->args, &blkno); 847 if (error) 848 return(error); 849 error = xfs_attr_leaf_create(state->args, blkno, &newblk->bp); 850 if (error) 851 return(error); 852 newblk->blkno = blkno; 853 newblk->magic = XFS_ATTR_LEAF_MAGIC; 854 855 /* 856 * Rebalance the entries across the two leaves. 857 * NOTE: rebalance() currently depends on the 2nd block being empty. 858 */ 859 xfs_attr_leaf_rebalance(state, oldblk, newblk); 860 error = xfs_da_blk_link(state, oldblk, newblk); 861 if (error) 862 return(error); 863 864 /* 865 * Save info on "old" attribute for "atomic rename" ops, leaf_add() 866 * modifies the index/blkno/rmtblk/rmtblkcnt fields to show the 867 * "new" attrs info. Will need the "old" info to remove it later. 868 * 869 * Insert the "new" entry in the correct block. 870 */ 871 if (state->inleaf) 872 error = xfs_attr_leaf_add(oldblk->bp, state->args); 873 else 874 error = xfs_attr_leaf_add(newblk->bp, state->args); 875 876 /* 877 * Update last hashval in each block since we added the name. 878 */ 879 oldblk->hashval = xfs_attr_leaf_lasthash(oldblk->bp, NULL); 880 newblk->hashval = xfs_attr_leaf_lasthash(newblk->bp, NULL); 881 return(error); 882} 883 884/* 885 * Add a name to the leaf attribute list structure. 886 */ 887int 888xfs_attr_leaf_add(xfs_dabuf_t *bp, xfs_da_args_t *args) 889{ 890 xfs_attr_leafblock_t *leaf; 891 xfs_attr_leaf_hdr_t *hdr; 892 xfs_attr_leaf_map_t *map; 893 int tablesize, entsize, sum, tmp, i; 894 895 leaf = bp->data; 896 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) 897 == XFS_ATTR_LEAF_MAGIC); 898 ASSERT((args->index >= 0) 899 && (args->index <= INT_GET(leaf->hdr.count, ARCH_CONVERT))); 900 hdr = &leaf->hdr; 901 entsize = xfs_attr_leaf_newentsize(args, 902 args->trans->t_mountp->m_sb.sb_blocksize, NULL); 903 904 /* 905 * Search through freemap for first-fit on new name length. 906 * (may need to figure in size of entry struct too) 907 */ 908 tablesize = (INT_GET(hdr->count, ARCH_CONVERT) + 1) 909 * sizeof(xfs_attr_leaf_entry_t) 910 + sizeof(xfs_attr_leaf_hdr_t); 911 map = &hdr->freemap[XFS_ATTR_LEAF_MAPSIZE-1]; 912 for (sum = 0, i = XFS_ATTR_LEAF_MAPSIZE-1; i >= 0; map--, i--) { 913 if (tablesize > INT_GET(hdr->firstused, ARCH_CONVERT)) { 914 sum += INT_GET(map->size, ARCH_CONVERT); 915 continue; 916 } 917 if (!map->size) 918 continue; /* no space in this map */ 919 tmp = entsize; 920 if (INT_GET(map->base, ARCH_CONVERT) 921 < INT_GET(hdr->firstused, ARCH_CONVERT)) 922 tmp += sizeof(xfs_attr_leaf_entry_t); 923 if (INT_GET(map->size, ARCH_CONVERT) >= tmp) { 924 tmp = xfs_attr_leaf_add_work(bp, args, i); 925 return(tmp); 926 } 927 sum += INT_GET(map->size, ARCH_CONVERT); 928 } 929 930 /* 931 * If there are no holes in the address space of the block, 932 * and we don't have enough freespace, then compaction will do us 933 * no good and we should just give up. 934 */ 935 if (!hdr->holes && (sum < entsize)) 936 return(XFS_ERROR(ENOSPC)); 937 938 /* 939 * Compact the entries to coalesce free space. 940 * This may change the hdr->count via dropping INCOMPLETE entries. 941 */ 942 xfs_attr_leaf_compact(args->trans, bp); 943 944 /* 945 * After compaction, the block is guaranteed to have only one 946 * free region, in freemap[0]. If it is not big enough, give up. 947 */ 948 if (INT_GET(hdr->freemap[0].size, ARCH_CONVERT) 949 < (entsize + sizeof(xfs_attr_leaf_entry_t))) 950 return(XFS_ERROR(ENOSPC)); 951 952 return(xfs_attr_leaf_add_work(bp, args, 0)); 953} 954 955/* 956 * Add a name to a leaf attribute list structure. 957 */ 958STATIC int 959xfs_attr_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int mapindex) 960{ 961 xfs_attr_leafblock_t *leaf; 962 xfs_attr_leaf_hdr_t *hdr; 963 xfs_attr_leaf_entry_t *entry; 964 xfs_attr_leaf_name_local_t *name_loc; 965 xfs_attr_leaf_name_remote_t *name_rmt; 966 xfs_attr_leaf_map_t *map; 967 xfs_mount_t *mp; 968 int tmp, i; 969 970 leaf = bp->data; 971 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) 972 == XFS_ATTR_LEAF_MAGIC); 973 hdr = &leaf->hdr; 974 ASSERT((mapindex >= 0) && (mapindex < XFS_ATTR_LEAF_MAPSIZE)); 975 ASSERT((args->index >= 0) 976 && (args->index <= INT_GET(hdr->count, ARCH_CONVERT))); 977 978 /* 979 * Force open some space in the entry array and fill it in. 980 */ 981 entry = &leaf->entries[args->index]; 982 if (args->index < INT_GET(hdr->count, ARCH_CONVERT)) { 983 tmp = INT_GET(hdr->count, ARCH_CONVERT) - args->index; 984 tmp *= sizeof(xfs_attr_leaf_entry_t); 985 memmove((char *)(entry+1), (char *)entry, tmp); 986 xfs_da_log_buf(args->trans, bp, 987 XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(*entry))); 988 } 989 INT_MOD(hdr->count, ARCH_CONVERT, 1); 990 991 /* 992 * Allocate space for the new string (at the end of the run). 993 */ 994 map = &hdr->freemap[mapindex]; 995 mp = args->trans->t_mountp; 996 ASSERT(INT_GET(map->base, ARCH_CONVERT) < XFS_LBSIZE(mp)); 997 ASSERT((INT_GET(map->base, ARCH_CONVERT) & 0x3) == 0); 998 ASSERT(INT_GET(map->size, ARCH_CONVERT) 999 >= xfs_attr_leaf_newentsize(args, 1000 mp->m_sb.sb_blocksize, NULL)); 1001 ASSERT(INT_GET(map->size, ARCH_CONVERT) < XFS_LBSIZE(mp)); 1002 ASSERT((INT_GET(map->size, ARCH_CONVERT) & 0x3) == 0); 1003 INT_MOD(map->size, ARCH_CONVERT, 1004 -xfs_attr_leaf_newentsize(args, mp->m_sb.sb_blocksize, &tmp)); 1005 INT_SET(entry->nameidx, ARCH_CONVERT, 1006 INT_GET(map->base, ARCH_CONVERT) 1007 + INT_GET(map->size, ARCH_CONVERT)); 1008 INT_SET(entry->hashval, ARCH_CONVERT, args->hashval); 1009 entry->flags = tmp ? XFS_ATTR_LOCAL : 0; 1010 entry->flags |= (args->flags & ATTR_SECURE) ? XFS_ATTR_SECURE : 1011 ((args->flags & ATTR_ROOT) ? XFS_ATTR_ROOT : 0); 1012 if (args->rename) { 1013 entry->flags |= XFS_ATTR_INCOMPLETE; 1014 if ((args->blkno2 == args->blkno) && 1015 (args->index2 <= args->index)) { 1016 args->index2++; 1017 } 1018 } 1019 xfs_da_log_buf(args->trans, bp, 1020 XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry))); 1021 ASSERT((args->index == 0) || (INT_GET(entry->hashval, ARCH_CONVERT) 1022 >= INT_GET((entry-1)->hashval, 1023 ARCH_CONVERT))); 1024 ASSERT((args->index == INT_GET(hdr->count, ARCH_CONVERT)-1) || 1025 (INT_GET(entry->hashval, ARCH_CONVERT) 1026 <= (INT_GET((entry+1)->hashval, ARCH_CONVERT)))); 1027 1028 /* 1029 * Copy the attribute name and value into the new space. 1030 * 1031 * For "remote" attribute values, simply note that we need to 1032 * allocate space for the "remote" value. We can't actually 1033 * allocate the extents in this transaction, and we can't decide 1034 * which blocks they should be as we might allocate more blocks 1035 * as part of this transaction (a split operation for example). 1036 */ 1037 if (entry->flags & XFS_ATTR_LOCAL) { 1038 name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, args->index); 1039 name_loc->namelen = args->namelen; 1040 INT_SET(name_loc->valuelen, ARCH_CONVERT, args->valuelen); 1041 memcpy((char *)name_loc->nameval, args->name, args->namelen); 1042 memcpy((char *)&name_loc->nameval[args->namelen], args->value, 1043 INT_GET(name_loc->valuelen, ARCH_CONVERT)); 1044 } else { 1045 name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index); 1046 name_rmt->namelen = args->namelen; 1047 memcpy((char *)name_rmt->name, args->name, args->namelen); 1048 entry->flags |= XFS_ATTR_INCOMPLETE; 1049 /* just in case */ 1050 name_rmt->valuelen = 0; 1051 name_rmt->valueblk = 0; 1052 args->rmtblkno = 1; 1053 args->rmtblkcnt = XFS_B_TO_FSB(mp, args->valuelen); 1054 } 1055 xfs_da_log_buf(args->trans, bp, 1056 XFS_DA_LOGRANGE(leaf, XFS_ATTR_LEAF_NAME(leaf, args->index), 1057 xfs_attr_leaf_entsize(leaf, args->index))); 1058 1059 /* 1060 * Update the control info for this leaf node 1061 */ 1062 if (INT_GET(entry->nameidx, ARCH_CONVERT) 1063 < INT_GET(hdr->firstused, ARCH_CONVERT)) { 1064 /* both on-disk, don't endian-flip twice */ 1065 hdr->firstused = entry->nameidx; 1066 } 1067 ASSERT(INT_GET(hdr->firstused, ARCH_CONVERT) 1068 >= ((INT_GET(hdr->count, ARCH_CONVERT) 1069 * sizeof(*entry))+sizeof(*hdr))); 1070 tmp = (INT_GET(hdr->count, ARCH_CONVERT)-1) 1071 * sizeof(xfs_attr_leaf_entry_t) 1072 + sizeof(xfs_attr_leaf_hdr_t); 1073 map = &hdr->freemap[0]; 1074 for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; map++, i++) { 1075 if (INT_GET(map->base, ARCH_CONVERT) == tmp) { 1076 INT_MOD(map->base, ARCH_CONVERT, 1077 sizeof(xfs_attr_leaf_entry_t)); 1078 INT_MOD(map->size, ARCH_CONVERT, 1079 -sizeof(xfs_attr_leaf_entry_t)); 1080 } 1081 } 1082 INT_MOD(hdr->usedbytes, ARCH_CONVERT, 1083 xfs_attr_leaf_entsize(leaf, args->index)); 1084 xfs_da_log_buf(args->trans, bp, 1085 XFS_DA_LOGRANGE(leaf, hdr, sizeof(*hdr))); 1086 return(0); 1087} 1088 1089/* 1090 * Garbage collect a leaf attribute list block by copying it to a new buffer. 1091 */ 1092STATIC void 1093xfs_attr_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *bp) 1094{ 1095 xfs_attr_leafblock_t *leaf_s, *leaf_d; 1096 xfs_attr_leaf_hdr_t *hdr_s, *hdr_d; 1097 xfs_mount_t *mp; 1098 char *tmpbuffer; 1099 1100 mp = trans->t_mountp; 1101 tmpbuffer = kmem_alloc(XFS_LBSIZE(mp), KM_SLEEP); 1102 ASSERT(tmpbuffer != NULL); 1103 memcpy(tmpbuffer, bp->data, XFS_LBSIZE(mp)); 1104 memset(bp->data, 0, XFS_LBSIZE(mp)); 1105 1106 /* 1107 * Copy basic information 1108 */ 1109 leaf_s = (xfs_attr_leafblock_t *)tmpbuffer; 1110 leaf_d = bp->data; 1111 hdr_s = &leaf_s->hdr; 1112 hdr_d = &leaf_d->hdr; 1113 hdr_d->info = hdr_s->info; /* struct copy */ 1114 INT_SET(hdr_d->firstused, ARCH_CONVERT, XFS_LBSIZE(mp)); 1115 /* handle truncation gracefully */ 1116 if (!hdr_d->firstused) { 1117 INT_SET(hdr_d->firstused, ARCH_CONVERT, 1118 XFS_LBSIZE(mp) - XFS_ATTR_LEAF_NAME_ALIGN); 1119 } 1120 hdr_d->usedbytes = 0; 1121 hdr_d->count = 0; 1122 hdr_d->holes = 0; 1123 INT_SET(hdr_d->freemap[0].base, ARCH_CONVERT, 1124 sizeof(xfs_attr_leaf_hdr_t)); 1125 INT_SET(hdr_d->freemap[0].size, ARCH_CONVERT, 1126 INT_GET(hdr_d->firstused, ARCH_CONVERT) 1127 - INT_GET(hdr_d->freemap[0].base, ARCH_CONVERT)); 1128 1129 /* 1130 * Copy all entry's in the same (sorted) order, 1131 * but allocate name/value pairs packed and in sequence. 1132 */ 1133 xfs_attr_leaf_moveents(leaf_s, 0, leaf_d, 0, 1134 (int)INT_GET(hdr_s->count, ARCH_CONVERT), mp); 1135 1136 xfs_da_log_buf(trans, bp, 0, XFS_LBSIZE(mp) - 1); 1137 1138 kmem_free(tmpbuffer, XFS_LBSIZE(mp)); 1139} 1140 1141/* 1142 * Redistribute the attribute list entries between two leaf nodes, 1143 * taking into account the size of the new entry. 1144 * 1145 * NOTE: if new block is empty, then it will get the upper half of the 1146 * old block. At present, all (one) callers pass in an empty second block. 1147 * 1148 * This code adjusts the args->index/blkno and args->index2/blkno2 fields 1149 * to match what it is doing in splitting the attribute leaf block. Those 1150 * values are used in "atomic rename" operations on attributes. Note that 1151 * the "new" and "old" values can end up in different blocks. 1152 */ 1153STATIC void 1154xfs_attr_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, 1155 xfs_da_state_blk_t *blk2) 1156{ 1157 xfs_da_args_t *args; 1158 xfs_da_state_blk_t *tmp_blk; 1159 xfs_attr_leafblock_t *leaf1, *leaf2; 1160 xfs_attr_leaf_hdr_t *hdr1, *hdr2; 1161 int count, totallen, max, space, swap; 1162 1163 /* 1164 * Set up environment. 1165 */ 1166 ASSERT(blk1->magic == XFS_ATTR_LEAF_MAGIC); 1167 ASSERT(blk2->magic == XFS_ATTR_LEAF_MAGIC); 1168 leaf1 = blk1->bp->data; 1169 leaf2 = blk2->bp->data; 1170 ASSERT(INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT) 1171 == XFS_ATTR_LEAF_MAGIC); 1172 ASSERT(INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT) 1173 == XFS_ATTR_LEAF_MAGIC); 1174 args = state->args; 1175 1176 /* 1177 * Check ordering of blocks, reverse if it makes things simpler. 1178 * 1179 * NOTE: Given that all (current) callers pass in an empty 1180 * second block, this code should never set "swap". 1181 */ 1182 swap = 0; 1183 if (xfs_attr_leaf_order(blk1->bp, blk2->bp)) { 1184 tmp_blk = blk1; 1185 blk1 = blk2; 1186 blk2 = tmp_blk; 1187 leaf1 = blk1->bp->data; 1188 leaf2 = blk2->bp->data; 1189 swap = 1; 1190 } 1191 hdr1 = &leaf1->hdr; 1192 hdr2 = &leaf2->hdr; 1193 1194 /* 1195 * Examine entries until we reduce the absolute difference in 1196 * byte usage between the two blocks to a minimum. Then get 1197 * the direction to copy and the number of elements to move. 1198 * 1199 * "inleaf" is true if the new entry should be inserted into blk1. 1200 * If "swap" is also true, then reverse the sense of "inleaf". 1201 */ 1202 state->inleaf = xfs_attr_leaf_figure_balance(state, blk1, blk2, 1203 &count, &totallen); 1204 if (swap) 1205 state->inleaf = !state->inleaf; 1206 1207 /* 1208 * Move any entries required from leaf to leaf: 1209 */ 1210 if (count < INT_GET(hdr1->count, ARCH_CONVERT)) { 1211 /* 1212 * Figure the total bytes to be added to the destination leaf. 1213 */ 1214 /* number entries being moved */ 1215 count = INT_GET(hdr1->count, ARCH_CONVERT) - count; 1216 space = INT_GET(hdr1->usedbytes, ARCH_CONVERT) - totallen; 1217 space += count * sizeof(xfs_attr_leaf_entry_t); 1218 1219 /* 1220 * leaf2 is the destination, compact it if it looks tight. 1221 */ 1222 max = INT_GET(hdr2->firstused, ARCH_CONVERT) 1223 - sizeof(xfs_attr_leaf_hdr_t); 1224 max -= INT_GET(hdr2->count, ARCH_CONVERT) 1225 * sizeof(xfs_attr_leaf_entry_t); 1226 if (space > max) { 1227 xfs_attr_leaf_compact(args->trans, blk2->bp); 1228 } 1229 1230 /* 1231 * Move high entries from leaf1 to low end of leaf2. 1232 */ 1233 xfs_attr_leaf_moveents(leaf1, 1234 INT_GET(hdr1->count, ARCH_CONVERT)-count, 1235 leaf2, 0, count, state->mp); 1236 1237 xfs_da_log_buf(args->trans, blk1->bp, 0, state->blocksize-1); 1238 xfs_da_log_buf(args->trans, blk2->bp, 0, state->blocksize-1); 1239 } else if (count > INT_GET(hdr1->count, ARCH_CONVERT)) { 1240 /* 1241 * I assert that since all callers pass in an empty 1242 * second buffer, this code should never execute. 1243 */ 1244 1245 /* 1246 * Figure the total bytes to be added to the destination leaf. 1247 */ 1248 /* number entries being moved */ 1249 count -= INT_GET(hdr1->count, ARCH_CONVERT); 1250 space = totallen - INT_GET(hdr1->usedbytes, ARCH_CONVERT); 1251 space += count * sizeof(xfs_attr_leaf_entry_t); 1252 1253 /* 1254 * leaf1 is the destination, compact it if it looks tight. 1255 */ 1256 max = INT_GET(hdr1->firstused, ARCH_CONVERT) 1257 - sizeof(xfs_attr_leaf_hdr_t); 1258 max -= INT_GET(hdr1->count, ARCH_CONVERT) 1259 * sizeof(xfs_attr_leaf_entry_t); 1260 if (space > max) { 1261 xfs_attr_leaf_compact(args->trans, blk1->bp); 1262 } 1263 1264 /* 1265 * Move low entries from leaf2 to high end of leaf1. 1266 */ 1267 xfs_attr_leaf_moveents(leaf2, 0, leaf1, 1268 (int)INT_GET(hdr1->count, ARCH_CONVERT), count, 1269 state->mp); 1270 1271 xfs_da_log_buf(args->trans, blk1->bp, 0, state->blocksize-1); 1272 xfs_da_log_buf(args->trans, blk2->bp, 0, state->blocksize-1); 1273 } 1274 1275 /* 1276 * Copy out last hashval in each block for B-tree code. 1277 */ 1278 blk1->hashval = 1279 INT_GET(leaf1->entries[INT_GET(leaf1->hdr.count, 1280 ARCH_CONVERT)-1].hashval, ARCH_CONVERT); 1281 blk2->hashval = 1282 INT_GET(leaf2->entries[INT_GET(leaf2->hdr.count, 1283 ARCH_CONVERT)-1].hashval, ARCH_CONVERT); 1284 1285 /* 1286 * Adjust the expected index for insertion. 1287 * NOTE: this code depends on the (current) situation that the 1288 * second block was originally empty. 1289 * 1290 * If the insertion point moved to the 2nd block, we must adjust 1291 * the index. We must also track the entry just following the 1292 * new entry for use in an "atomic rename" operation, that entry 1293 * is always the "old" entry and the "new" entry is what we are 1294 * inserting. The index/blkno fields refer to the "old" entry, 1295 * while the index2/blkno2 fields refer to the "new" entry. 1296 */ 1297 if (blk1->index > INT_GET(leaf1->hdr.count, ARCH_CONVERT)) { 1298 ASSERT(state->inleaf == 0); 1299 blk2->index = blk1->index 1300 - INT_GET(leaf1->hdr.count, ARCH_CONVERT); 1301 args->index = args->index2 = blk2->index; 1302 args->blkno = args->blkno2 = blk2->blkno; 1303 } else if (blk1->index == INT_GET(leaf1->hdr.count, ARCH_CONVERT)) { 1304 if (state->inleaf) { 1305 args->index = blk1->index; 1306 args->blkno = blk1->blkno; 1307 args->index2 = 0; 1308 args->blkno2 = blk2->blkno; 1309 } else { 1310 blk2->index = blk1->index 1311 - INT_GET(leaf1->hdr.count, ARCH_CONVERT); 1312 args->index = args->index2 = blk2->index; 1313 args->blkno = args->blkno2 = blk2->blkno; 1314 } 1315 } else { 1316 ASSERT(state->inleaf == 1); 1317 args->index = args->index2 = blk1->index; 1318 args->blkno = args->blkno2 = blk1->blkno; 1319 } 1320} 1321 1322/* 1323 * Examine entries until we reduce the absolute difference in 1324 * byte usage between the two blocks to a minimum. 1325 * GROT: Is this really necessary? With other than a 512 byte blocksize, 1326 * GROT: there will always be enough room in either block for a new entry. 1327 * GROT: Do a double-split for this case? 1328 */ 1329STATIC int 1330xfs_attr_leaf_figure_balance(xfs_da_state_t *state, 1331 xfs_da_state_blk_t *blk1, 1332 xfs_da_state_blk_t *blk2, 1333 int *countarg, int *usedbytesarg) 1334{ 1335 xfs_attr_leafblock_t *leaf1, *leaf2; 1336 xfs_attr_leaf_hdr_t *hdr1, *hdr2; 1337 xfs_attr_leaf_entry_t *entry; 1338 int count, max, index, totallen, half; 1339 int lastdelta, foundit, tmp; 1340 1341 /* 1342 * Set up environment. 1343 */ 1344 leaf1 = blk1->bp->data; 1345 leaf2 = blk2->bp->data; 1346 hdr1 = &leaf1->hdr; 1347 hdr2 = &leaf2->hdr; 1348 foundit = 0; 1349 totallen = 0; 1350 1351 /* 1352 * Examine entries until we reduce the absolute difference in 1353 * byte usage between the two blocks to a minimum. 1354 */ 1355 max = INT_GET(hdr1->count, ARCH_CONVERT) 1356 + INT_GET(hdr2->count, ARCH_CONVERT); 1357 half = (max+1) * sizeof(*entry); 1358 half += INT_GET(hdr1->usedbytes, ARCH_CONVERT) 1359 + INT_GET(hdr2->usedbytes, ARCH_CONVERT) 1360 + xfs_attr_leaf_newentsize(state->args, 1361 state->blocksize, NULL); 1362 half /= 2; 1363 lastdelta = state->blocksize; 1364 entry = &leaf1->entries[0]; 1365 for (count = index = 0; count < max; entry++, index++, count++) { 1366 1367#define XFS_ATTR_ABS(A) (((A) < 0) ? -(A) : (A)) 1368 /* 1369 * The new entry is in the first block, account for it. 1370 */ 1371 if (count == blk1->index) { 1372 tmp = totallen + sizeof(*entry) + 1373 xfs_attr_leaf_newentsize(state->args, 1374 state->blocksize, 1375 NULL); 1376 if (XFS_ATTR_ABS(half - tmp) > lastdelta) 1377 break; 1378 lastdelta = XFS_ATTR_ABS(half - tmp); 1379 totallen = tmp; 1380 foundit = 1; 1381 } 1382 1383 /* 1384 * Wrap around into the second block if necessary. 1385 */ 1386 if (count == INT_GET(hdr1->count, ARCH_CONVERT)) { 1387 leaf1 = leaf2; 1388 entry = &leaf1->entries[0]; 1389 index = 0; 1390 } 1391 1392 /* 1393 * Figure out if next leaf entry would be too much. 1394 */ 1395 tmp = totallen + sizeof(*entry) + xfs_attr_leaf_entsize(leaf1, 1396 index); 1397 if (XFS_ATTR_ABS(half - tmp) > lastdelta) 1398 break; 1399 lastdelta = XFS_ATTR_ABS(half - tmp); 1400 totallen = tmp; 1401#undef XFS_ATTR_ABS 1402 } 1403 1404 /* 1405 * Calculate the number of usedbytes that will end up in lower block. 1406 * If new entry not in lower block, fix up the count. 1407 */ 1408 totallen -= count * sizeof(*entry); 1409 if (foundit) { 1410 totallen -= sizeof(*entry) + 1411 xfs_attr_leaf_newentsize(state->args, 1412 state->blocksize, 1413 NULL); 1414 } 1415 1416 *countarg = count; 1417 *usedbytesarg = totallen; 1418 return(foundit); 1419} 1420 1421/*======================================================================== 1422 * Routines used for shrinking the Btree. 1423 *========================================================================*/ 1424 1425/* 1426 * Check a leaf block and its neighbors to see if the block should be 1427 * collapsed into one or the other neighbor. Always keep the block 1428 * with the smaller block number. 1429 * If the current block is over 50% full, don't try to join it, return 0. 1430 * If the block is empty, fill in the state structure and return 2. 1431 * If it can be collapsed, fill in the state structure and return 1. 1432 * If nothing can be done, return 0. 1433 * 1434 * GROT: allow for INCOMPLETE entries in calculation. 1435 */ 1436int 1437xfs_attr_leaf_toosmall(xfs_da_state_t *state, int *action) 1438{ 1439 xfs_attr_leafblock_t *leaf; 1440 xfs_da_state_blk_t *blk; 1441 xfs_da_blkinfo_t *info; 1442 int count, bytes, forward, error, retval, i; 1443 xfs_dablk_t blkno; 1444 xfs_dabuf_t *bp; 1445 1446 /* 1447 * Check for the degenerate case of the block being over 50% full. 1448 * If so, it's not worth even looking to see if we might be able 1449 * to coalesce with a sibling. 1450 */ 1451 blk = &state->path.blk[ state->path.active-1 ]; 1452 info = blk->bp->data; 1453 ASSERT(INT_GET(info->magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC); 1454 leaf = (xfs_attr_leafblock_t *)info; 1455 count = INT_GET(leaf->hdr.count, ARCH_CONVERT); 1456 bytes = sizeof(xfs_attr_leaf_hdr_t) + 1457 count * sizeof(xfs_attr_leaf_entry_t) + 1458 INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT); 1459 if (bytes > (state->blocksize >> 1)) { 1460 *action = 0; /* blk over 50%, don't try to join */ 1461 return(0); 1462 } 1463 1464 /* 1465 * Check for the degenerate case of the block being empty. 1466 * If the block is empty, we'll simply delete it, no need to 1467 * coalesce it with a sibling block. We choose (aribtrarily) 1468 * to merge with the forward block unless it is NULL. 1469 */ 1470 if (count == 0) { 1471 /* 1472 * Make altpath point to the block we want to keep and 1473 * path point to the block we want to drop (this one). 1474 */ 1475 forward = info->forw; 1476 memcpy(&state->altpath, &state->path, sizeof(state->path)); 1477 error = xfs_da_path_shift(state, &state->altpath, forward, 1478 0, &retval); 1479 if (error) 1480 return(error); 1481 if (retval) { 1482 *action = 0; 1483 } else { 1484 *action = 2; 1485 } 1486 return(0); 1487 } 1488 1489 /* 1490 * Examine each sibling block to see if we can coalesce with 1491 * at least 25% free space to spare. We need to figure out 1492 * whether to merge with the forward or the backward block. 1493 * We prefer coalescing with the lower numbered sibling so as 1494 * to shrink an attribute list over time. 1495 */ 1496 /* start with smaller blk num */ 1497 forward = (INT_GET(info->forw, ARCH_CONVERT) 1498 < INT_GET(info->back, ARCH_CONVERT)); 1499 for (i = 0; i < 2; forward = !forward, i++) { 1500 if (forward) 1501 blkno = INT_GET(info->forw, ARCH_CONVERT); 1502 else 1503 blkno = INT_GET(info->back, ARCH_CONVERT); 1504 if (blkno == 0) 1505 continue; 1506 error = xfs_da_read_buf(state->args->trans, state->args->dp, 1507 blkno, -1, &bp, XFS_ATTR_FORK); 1508 if (error) 1509 return(error); 1510 ASSERT(bp != NULL); 1511 1512 leaf = (xfs_attr_leafblock_t *)info; 1513 count = INT_GET(leaf->hdr.count, ARCH_CONVERT); 1514 bytes = state->blocksize - (state->blocksize>>2); 1515 bytes -= INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT); 1516 leaf = bp->data; 1517 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) 1518 == XFS_ATTR_LEAF_MAGIC); 1519 count += INT_GET(leaf->hdr.count, ARCH_CONVERT); 1520 bytes -= INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT); 1521 bytes -= count * sizeof(xfs_attr_leaf_entry_t); 1522 bytes -= sizeof(xfs_attr_leaf_hdr_t); 1523 xfs_da_brelse(state->args->trans, bp); 1524 if (bytes >= 0) 1525 break; /* fits with at least 25% to spare */ 1526 } 1527 if (i >= 2) { 1528 *action = 0; 1529 return(0); 1530 } 1531 1532 /* 1533 * Make altpath point to the block we want to keep (the lower 1534 * numbered block) and path point to the block we want to drop. 1535 */ 1536 memcpy(&state->altpath, &state->path, sizeof(state->path)); 1537 if (blkno < blk->blkno) { 1538 error = xfs_da_path_shift(state, &state->altpath, forward, 1539 0, &retval); 1540 } else { 1541 error = xfs_da_path_shift(state, &state->path, forward, 1542 0, &retval); 1543 } 1544 if (error) 1545 return(error); 1546 if (retval) { 1547 *action = 0; 1548 } else { 1549 *action = 1; 1550 } 1551 return(0); 1552} 1553 1554/* 1555 * Remove a name from the leaf attribute list structure. 1556 * 1557 * Return 1 if leaf is less than 37% full, 0 if >= 37% full. 1558 * If two leaves are 37% full, when combined they will leave 25% free. 1559 */ 1560int 1561xfs_attr_leaf_remove(xfs_dabuf_t *bp, xfs_da_args_t *args) 1562{ 1563 xfs_attr_leafblock_t *leaf; 1564 xfs_attr_leaf_hdr_t *hdr; 1565 xfs_attr_leaf_map_t *map; 1566 xfs_attr_leaf_entry_t *entry; 1567 int before, after, smallest, entsize; 1568 int tablesize, tmp, i; 1569 xfs_mount_t *mp; 1570 1571 leaf = bp->data; 1572 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) 1573 == XFS_ATTR_LEAF_MAGIC); 1574 hdr = &leaf->hdr; 1575 mp = args->trans->t_mountp; 1576 ASSERT((INT_GET(hdr->count, ARCH_CONVERT) > 0) 1577 && (INT_GET(hdr->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8))); 1578 ASSERT((args->index >= 0) 1579 && (args->index < INT_GET(hdr->count, ARCH_CONVERT))); 1580 ASSERT(INT_GET(hdr->firstused, ARCH_CONVERT) 1581 >= ((INT_GET(hdr->count, ARCH_CONVERT) 1582 * sizeof(*entry))+sizeof(*hdr))); 1583 entry = &leaf->entries[args->index]; 1584 ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) 1585 >= INT_GET(hdr->firstused, ARCH_CONVERT)); 1586 ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) < XFS_LBSIZE(mp)); 1587 1588 /* 1589 * Scan through free region table: 1590 * check for adjacency of free'd entry with an existing one, 1591 * find smallest free region in case we need to replace it, 1592 * adjust any map that borders the entry table, 1593 */ 1594 tablesize = INT_GET(hdr->count, ARCH_CONVERT) 1595 * sizeof(xfs_attr_leaf_entry_t) 1596 + sizeof(xfs_attr_leaf_hdr_t); 1597 map = &hdr->freemap[0]; 1598 tmp = INT_GET(map->size, ARCH_CONVERT); 1599 before = after = -1; 1600 smallest = XFS_ATTR_LEAF_MAPSIZE - 1; 1601 entsize = xfs_attr_leaf_entsize(leaf, args->index); 1602 for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; map++, i++) { 1603 ASSERT(INT_GET(map->base, ARCH_CONVERT) < XFS_LBSIZE(mp)); 1604 ASSERT(INT_GET(map->size, ARCH_CONVERT) < XFS_LBSIZE(mp)); 1605 if (INT_GET(map->base, ARCH_CONVERT) == tablesize) { 1606 INT_MOD(map->base, ARCH_CONVERT, 1607 -sizeof(xfs_attr_leaf_entry_t)); 1608 INT_MOD(map->size, ARCH_CONVERT, 1609 sizeof(xfs_attr_leaf_entry_t)); 1610 } 1611 1612 if ((INT_GET(map->base, ARCH_CONVERT) 1613 + INT_GET(map->size, ARCH_CONVERT)) 1614 == INT_GET(entry->nameidx, ARCH_CONVERT)) { 1615 before = i; 1616 } else if (INT_GET(map->base, ARCH_CONVERT) 1617 == (INT_GET(entry->nameidx, ARCH_CONVERT) + entsize)) { 1618 after = i; 1619 } else if (INT_GET(map->size, ARCH_CONVERT) < tmp) { 1620 tmp = INT_GET(map->size, ARCH_CONVERT); 1621 smallest = i; 1622 } 1623 } 1624 1625 /* 1626 * Coalesce adjacent freemap regions, 1627 * or replace the smallest region. 1628 */ 1629 if ((before >= 0) || (after >= 0)) { 1630 if ((before >= 0) && (after >= 0)) { 1631 map = &hdr->freemap[before]; 1632 INT_MOD(map->size, ARCH_CONVERT, entsize); 1633 INT_MOD(map->size, ARCH_CONVERT, 1634 INT_GET(hdr->freemap[after].size, 1635 ARCH_CONVERT)); 1636 hdr->freemap[after].base = 0; 1637 hdr->freemap[after].size = 0; 1638 } else if (before >= 0) { 1639 map = &hdr->freemap[before]; 1640 INT_MOD(map->size, ARCH_CONVERT, entsize); 1641 } else { 1642 map = &hdr->freemap[after]; 1643 /* both on-disk, don't endian flip twice */ 1644 map->base = entry->nameidx; 1645 INT_MOD(map->size, ARCH_CONVERT, entsize); 1646 } 1647 } else { 1648 /* 1649 * Replace smallest region (if it is smaller than free'd entry) 1650 */ 1651 map = &hdr->freemap[smallest]; 1652 if (INT_GET(map->size, ARCH_CONVERT) < entsize) { 1653 INT_SET(map->base, ARCH_CONVERT, 1654 INT_GET(entry->nameidx, ARCH_CONVERT)); 1655 INT_SET(map->size, ARCH_CONVERT, entsize); 1656 } 1657 } 1658 1659 /* 1660 * Did we remove the first entry? 1661 */ 1662 if (INT_GET(entry->nameidx, ARCH_CONVERT) 1663 == INT_GET(hdr->firstused, ARCH_CONVERT)) 1664 smallest = 1; 1665 else 1666 smallest = 0; 1667 1668 /* 1669 * Compress the remaining entries and zero out the removed stuff. 1670 */ 1671 memset(XFS_ATTR_LEAF_NAME(leaf, args->index), 0, entsize); 1672 INT_MOD(hdr->usedbytes, ARCH_CONVERT, -entsize); 1673 xfs_da_log_buf(args->trans, bp, 1674 XFS_DA_LOGRANGE(leaf, XFS_ATTR_LEAF_NAME(leaf, args->index), 1675 entsize)); 1676 1677 tmp = (INT_GET(hdr->count, ARCH_CONVERT) - args->index) 1678 * sizeof(xfs_attr_leaf_entry_t); 1679 memmove((char *)entry, (char *)(entry+1), tmp); 1680 INT_MOD(hdr->count, ARCH_CONVERT, -1); 1681 xfs_da_log_buf(args->trans, bp, 1682 XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(*entry))); 1683 entry = &leaf->entries[INT_GET(hdr->count, ARCH_CONVERT)]; 1684 memset((char *)entry, 0, sizeof(xfs_attr_leaf_entry_t)); 1685 1686 /* 1687 * If we removed the first entry, re-find the first used byte 1688 * in the name area. Note that if the entry was the "firstused", 1689 * then we don't have a "hole" in our block resulting from 1690 * removing the name. 1691 */ 1692 if (smallest) { 1693 tmp = XFS_LBSIZE(mp); 1694 entry = &leaf->entries[0]; 1695 for (i = INT_GET(hdr->count, ARCH_CONVERT)-1; 1696 i >= 0; entry++, i--) { 1697 ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) 1698 >= INT_GET(hdr->firstused, ARCH_CONVERT)); 1699 ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) 1700 < XFS_LBSIZE(mp)); 1701 if (INT_GET(entry->nameidx, ARCH_CONVERT) < tmp) 1702 tmp = INT_GET(entry->nameidx, ARCH_CONVERT); 1703 } 1704 INT_SET(hdr->firstused, ARCH_CONVERT, tmp); 1705 if (!hdr->firstused) { 1706 INT_SET(hdr->firstused, ARCH_CONVERT, 1707 tmp - XFS_ATTR_LEAF_NAME_ALIGN); 1708 } 1709 } else { 1710 hdr->holes = 1; /* mark as needing compaction */ 1711 } 1712 xfs_da_log_buf(args->trans, bp, 1713 XFS_DA_LOGRANGE(leaf, hdr, sizeof(*hdr))); 1714 1715 /* 1716 * Check if leaf is less than 50% full, caller may want to 1717 * "join" the leaf with a sibling if so. 1718 */ 1719 tmp = sizeof(xfs_attr_leaf_hdr_t); 1720 tmp += INT_GET(leaf->hdr.count, ARCH_CONVERT) 1721 * sizeof(xfs_attr_leaf_entry_t); 1722 tmp += INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT); 1723 return(tmp < mp->m_attr_magicpct); /* leaf is < 37% full */ 1724} 1725 1726/* 1727 * Move all the attribute list entries from drop_leaf into save_leaf. 1728 */ 1729void 1730xfs_attr_leaf_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk, 1731 xfs_da_state_blk_t *save_blk) 1732{ 1733 xfs_attr_leafblock_t *drop_leaf, *save_leaf, *tmp_leaf; 1734 xfs_attr_leaf_hdr_t *drop_hdr, *save_hdr, *tmp_hdr; 1735 xfs_mount_t *mp; 1736 char *tmpbuffer; 1737 1738 /* 1739 * Set up environment. 1740 */ 1741 mp = state->mp; 1742 ASSERT(drop_blk->magic == XFS_ATTR_LEAF_MAGIC); 1743 ASSERT(save_blk->magic == XFS_ATTR_LEAF_MAGIC); 1744 drop_leaf = drop_blk->bp->data; 1745 save_leaf = save_blk->bp->data; 1746 ASSERT(INT_GET(drop_leaf->hdr.info.magic, ARCH_CONVERT) 1747 == XFS_ATTR_LEAF_MAGIC); 1748 ASSERT(INT_GET(save_leaf->hdr.info.magic, ARCH_CONVERT) 1749 == XFS_ATTR_LEAF_MAGIC); 1750 drop_hdr = &drop_leaf->hdr; 1751 save_hdr = &save_leaf->hdr; 1752 1753 /* 1754 * Save last hashval from dying block for later Btree fixup. 1755 */ 1756 drop_blk->hashval = 1757 INT_GET(drop_leaf->entries[INT_GET(drop_leaf->hdr.count, 1758 ARCH_CONVERT)-1].hashval, 1759 ARCH_CONVERT); 1760 1761 /* 1762 * Check if we need a temp buffer, or can we do it in place. 1763 * Note that we don't check "leaf" for holes because we will 1764 * always be dropping it, toosmall() decided that for us already. 1765 */ 1766 if (save_hdr->holes == 0) { 1767 /* 1768 * dest leaf has no holes, so we add there. May need 1769 * to make some room in the entry array. 1770 */ 1771 if (xfs_attr_leaf_order(save_blk->bp, drop_blk->bp)) { 1772 xfs_attr_leaf_moveents(drop_leaf, 0, save_leaf, 0, 1773 (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp); 1774 } else { 1775 xfs_attr_leaf_moveents(drop_leaf, 0, save_leaf, 1776 INT_GET(save_hdr->count, ARCH_CONVERT), 1777 (int)INT_GET(drop_hdr->count, ARCH_CONVERT), 1778 mp); 1779 } 1780 } else { 1781 /* 1782 * Destination has holes, so we make a temporary copy 1783 * of the leaf and add them both to that. 1784 */ 1785 tmpbuffer = kmem_alloc(state->blocksize, KM_SLEEP); 1786 ASSERT(tmpbuffer != NULL); 1787 memset(tmpbuffer, 0, state->blocksize); 1788 tmp_leaf = (xfs_attr_leafblock_t *)tmpbuffer; 1789 tmp_hdr = &tmp_leaf->hdr; 1790 tmp_hdr->info = save_hdr->info; /* struct copy */ 1791 tmp_hdr->count = 0; 1792 INT_SET(tmp_hdr->firstused, ARCH_CONVERT, state->blocksize); 1793 if (!tmp_hdr->firstused) { 1794 INT_SET(tmp_hdr->firstused, ARCH_CONVERT, 1795 state->blocksize - XFS_ATTR_LEAF_NAME_ALIGN); 1796 } 1797 tmp_hdr->usedbytes = 0; 1798 if (xfs_attr_leaf_order(save_blk->bp, drop_blk->bp)) { 1799 xfs_attr_leaf_moveents(drop_leaf, 0, tmp_leaf, 0, 1800 (int)INT_GET(drop_hdr->count, ARCH_CONVERT), 1801 mp); 1802 xfs_attr_leaf_moveents(save_leaf, 0, tmp_leaf, 1803 INT_GET(tmp_leaf->hdr.count, ARCH_CONVERT), 1804 (int)INT_GET(save_hdr->count, ARCH_CONVERT), 1805 mp); 1806 } else { 1807 xfs_attr_leaf_moveents(save_leaf, 0, tmp_leaf, 0, 1808 (int)INT_GET(save_hdr->count, ARCH_CONVERT), 1809 mp); 1810 xfs_attr_leaf_moveents(drop_leaf, 0, tmp_leaf, 1811 INT_GET(tmp_leaf->hdr.count, ARCH_CONVERT), 1812 (int)INT_GET(drop_hdr->count, ARCH_CONVERT), 1813 mp); 1814 } 1815 memcpy((char *)save_leaf, (char *)tmp_leaf, state->blocksize); 1816 kmem_free(tmpbuffer, state->blocksize); 1817 } 1818 1819 xfs_da_log_buf(state->args->trans, save_blk->bp, 0, 1820 state->blocksize - 1); 1821 1822 /* 1823 * Copy out last hashval in each block for B-tree code. 1824 */ 1825 save_blk->hashval = 1826 INT_GET(save_leaf->entries[INT_GET(save_leaf->hdr.count, 1827 ARCH_CONVERT)-1].hashval, 1828 ARCH_CONVERT); 1829} 1830 1831/*======================================================================== 1832 * Routines used for finding things in the Btree. 1833 *========================================================================*/ 1834 1835/* 1836 * Look up a name in a leaf attribute list structure. 1837 * This is the internal routine, it uses the caller's buffer. 1838 * 1839 * Note that duplicate keys are allowed, but only check within the 1840 * current leaf node. The Btree code must check in adjacent leaf nodes. 1841 * 1842 * Return in args->index the index into the entry[] array of either 1843 * the found entry, or where the entry should have been (insert before 1844 * that entry). 1845 * 1846 * Don't change the args->value unless we find the attribute. 1847 */ 1848int 1849xfs_attr_leaf_lookup_int(xfs_dabuf_t *bp, xfs_da_args_t *args) 1850{ 1851 xfs_attr_leafblock_t *leaf; 1852 xfs_attr_leaf_entry_t *entry; 1853 xfs_attr_leaf_name_local_t *name_loc; 1854 xfs_attr_leaf_name_remote_t *name_rmt; 1855 int probe, span; 1856 xfs_dahash_t hashval; 1857 1858 leaf = bp->data; 1859 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) 1860 == XFS_ATTR_LEAF_MAGIC); 1861 ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) 1862 < (XFS_LBSIZE(args->dp->i_mount)/8)); 1863 1864 /* 1865 * Binary search. (note: small blocks will skip this loop) 1866 */ 1867 hashval = args->hashval; 1868 probe = span = INT_GET(leaf->hdr.count, ARCH_CONVERT) / 2; 1869 for (entry = &leaf->entries[probe]; span > 4; 1870 entry = &leaf->entries[probe]) { 1871 span /= 2; 1872 if (INT_GET(entry->hashval, ARCH_CONVERT) < hashval) 1873 probe += span; 1874 else if (INT_GET(entry->hashval, ARCH_CONVERT) > hashval) 1875 probe -= span; 1876 else 1877 break; 1878 } 1879 ASSERT((probe >= 0) && 1880 (!leaf->hdr.count 1881 || (probe < INT_GET(leaf->hdr.count, ARCH_CONVERT)))); 1882 ASSERT((span <= 4) || (INT_GET(entry->hashval, ARCH_CONVERT) 1883 == hashval)); 1884 1885 /* 1886 * Since we may have duplicate hashval's, find the first matching 1887 * hashval in the leaf. 1888 */ 1889 while ((probe > 0) && (INT_GET(entry->hashval, ARCH_CONVERT) 1890 >= hashval)) { 1891 entry--; 1892 probe--; 1893 } 1894 while ((probe < INT_GET(leaf->hdr.count, ARCH_CONVERT)) 1895 && (INT_GET(entry->hashval, ARCH_CONVERT) < hashval)) { 1896 entry++; 1897 probe++; 1898 } 1899 if ((probe == INT_GET(leaf->hdr.count, ARCH_CONVERT)) 1900 || (INT_GET(entry->hashval, ARCH_CONVERT) != hashval)) { 1901 args->index = probe; 1902 return(XFS_ERROR(ENOATTR)); 1903 } 1904 1905 /* 1906 * Duplicate keys may be present, so search all of them for a match. 1907 */ 1908 for ( ; (probe < INT_GET(leaf->hdr.count, ARCH_CONVERT)) 1909 && (INT_GET(entry->hashval, ARCH_CONVERT) == hashval); 1910 entry++, probe++) { 1911/* 1912 * GROT: Add code to remove incomplete entries. 1913 */ 1914 /* 1915 * If we are looking for INCOMPLETE entries, show only those. 1916 * If we are looking for complete entries, show only those. 1917 */ 1918 if ((args->flags & XFS_ATTR_INCOMPLETE) != 1919 (entry->flags & XFS_ATTR_INCOMPLETE)) { 1920 continue; 1921 } 1922 if (entry->flags & XFS_ATTR_LOCAL) { 1923 name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, probe); 1924 if (name_loc->namelen != args->namelen) 1925 continue; 1926 if (memcmp(args->name, (char *)name_loc->nameval, 1927 args->namelen) != 0) 1928 continue; 1929 if (((args->flags & ATTR_SECURE) != 0) != 1930 ((entry->flags & XFS_ATTR_SECURE) != 0)) 1931 continue; 1932 if (((args->flags & ATTR_ROOT) != 0) != 1933 ((entry->flags & XFS_ATTR_ROOT) != 0)) 1934 continue; 1935 args->index = probe; 1936 return(XFS_ERROR(EEXIST)); 1937 } else { 1938 name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, probe); 1939 if (name_rmt->namelen != args->namelen) 1940 continue; 1941 if (memcmp(args->name, (char *)name_rmt->name, 1942 args->namelen) != 0) 1943 continue; 1944 if (((args->flags & ATTR_SECURE) != 0) != 1945 ((entry->flags & XFS_ATTR_SECURE) != 0)) 1946 continue; 1947 if (((args->flags & ATTR_ROOT) != 0) != 1948 ((entry->flags & XFS_ATTR_ROOT) != 0)) 1949 continue; 1950 args->index = probe; 1951 args->rmtblkno 1952 = INT_GET(name_rmt->valueblk, ARCH_CONVERT); 1953 args->rmtblkcnt = XFS_B_TO_FSB(args->dp->i_mount, 1954 INT_GET(name_rmt->valuelen, 1955 ARCH_CONVERT)); 1956 return(XFS_ERROR(EEXIST)); 1957 } 1958 } 1959 args->index = probe; 1960 return(XFS_ERROR(ENOATTR)); 1961} 1962 1963/* 1964 * Get the value associated with an attribute name from a leaf attribute 1965 * list structure. 1966 */ 1967int 1968xfs_attr_leaf_getvalue(xfs_dabuf_t *bp, xfs_da_args_t *args) 1969{ 1970 int valuelen; 1971 xfs_attr_leafblock_t *leaf; 1972 xfs_attr_leaf_entry_t *entry; 1973 xfs_attr_leaf_name_local_t *name_loc; 1974 xfs_attr_leaf_name_remote_t *name_rmt; 1975 1976 leaf = bp->data; 1977 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) 1978 == XFS_ATTR_LEAF_MAGIC); 1979 ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) 1980 < (XFS_LBSIZE(args->dp->i_mount)/8)); 1981 ASSERT(args->index < ((int)INT_GET(leaf->hdr.count, ARCH_CONVERT))); 1982 1983 entry = &leaf->entries[args->index]; 1984 if (entry->flags & XFS_ATTR_LOCAL) { 1985 name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, args->index); 1986 ASSERT(name_loc->namelen == args->namelen); 1987 ASSERT(memcmp(args->name, name_loc->nameval, args->namelen) == 0); 1988 valuelen = INT_GET(name_loc->valuelen, ARCH_CONVERT); 1989 if (args->flags & ATTR_KERNOVAL) { 1990 args->valuelen = valuelen; 1991 return(0); 1992 } 1993 if (args->valuelen < valuelen) { 1994 args->valuelen = valuelen; 1995 return(XFS_ERROR(ERANGE)); 1996 } 1997 args->valuelen = valuelen; 1998 memcpy(args->value, &name_loc->nameval[args->namelen], valuelen); 1999 } else { 2000 name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index); 2001 ASSERT(name_rmt->namelen == args->namelen); 2002 ASSERT(memcmp(args->name, name_rmt->name, args->namelen) == 0); 2003 valuelen = INT_GET(name_rmt->valuelen, ARCH_CONVERT); 2004 args->rmtblkno = INT_GET(name_rmt->valueblk, ARCH_CONVERT); 2005 args->rmtblkcnt = XFS_B_TO_FSB(args->dp->i_mount, valuelen); 2006 if (args->flags & ATTR_KERNOVAL) { 2007 args->valuelen = valuelen; 2008 return(0); 2009 } 2010 if (args->valuelen < valuelen) { 2011 args->valuelen = valuelen; 2012 return(XFS_ERROR(ERANGE)); 2013 } 2014 args->valuelen = valuelen; 2015 } 2016 return(0); 2017} 2018 2019/*======================================================================== 2020 * Utility routines. 2021 *========================================================================*/ 2022 2023/* 2024 * Move the indicated entries from one leaf to another. 2025 * NOTE: this routine modifies both source and destination leaves. 2026 */ 2027/*ARGSUSED*/ 2028STATIC void 2029xfs_attr_leaf_moveents(xfs_attr_leafblock_t *leaf_s, int start_s, 2030 xfs_attr_leafblock_t *leaf_d, int start_d, 2031 int count, xfs_mount_t *mp) 2032{ 2033 xfs_attr_leaf_hdr_t *hdr_s, *hdr_d; 2034 xfs_attr_leaf_entry_t *entry_s, *entry_d; 2035 int desti, tmp, i; 2036 2037 /* 2038 * Check for nothing to do. 2039 */ 2040 if (count == 0) 2041 return; 2042 2043 /* 2044 * Set up environment. 2045 */ 2046 ASSERT(INT_GET(leaf_s->hdr.info.magic, ARCH_CONVERT) 2047 == XFS_ATTR_LEAF_MAGIC); 2048 ASSERT(INT_GET(leaf_d->hdr.info.magic, ARCH_CONVERT) 2049 == XFS_ATTR_LEAF_MAGIC); 2050 hdr_s = &leaf_s->hdr; 2051 hdr_d = &leaf_d->hdr; 2052 ASSERT((INT_GET(hdr_s->count, ARCH_CONVERT) > 0) 2053 && (INT_GET(hdr_s->count, ARCH_CONVERT) 2054 < (XFS_LBSIZE(mp)/8))); 2055 ASSERT(INT_GET(hdr_s->firstused, ARCH_CONVERT) >= 2056 ((INT_GET(hdr_s->count, ARCH_CONVERT) 2057 * sizeof(*entry_s))+sizeof(*hdr_s))); 2058 ASSERT(INT_GET(hdr_d->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8)); 2059 ASSERT(INT_GET(hdr_d->firstused, ARCH_CONVERT) >= 2060 ((INT_GET(hdr_d->count, ARCH_CONVERT) 2061 * sizeof(*entry_d))+sizeof(*hdr_d))); 2062 2063 ASSERT(start_s < INT_GET(hdr_s->count, ARCH_CONVERT)); 2064 ASSERT(start_d <= INT_GET(hdr_d->count, ARCH_CONVERT)); 2065 ASSERT(count <= INT_GET(hdr_s->count, ARCH_CONVERT)); 2066 2067 /* 2068 * Move the entries in the destination leaf up to make a hole? 2069 */ 2070 if (start_d < INT_GET(hdr_d->count, ARCH_CONVERT)) { 2071 tmp = INT_GET(hdr_d->count, ARCH_CONVERT) - start_d; 2072 tmp *= sizeof(xfs_attr_leaf_entry_t); 2073 entry_s = &leaf_d->entries[start_d]; 2074 entry_d = &leaf_d->entries[start_d + count]; 2075 memmove((char *)entry_d, (char *)entry_s, tmp); 2076 } 2077 2078 /* 2079 * Copy all entry's in the same (sorted) order, 2080 * but allocate attribute info packed and in sequence. 2081 */ 2082 entry_s = &leaf_s->entries[start_s]; 2083 entry_d = &leaf_d->entries[start_d]; 2084 desti = start_d; 2085 for (i = 0; i < count; entry_s++, entry_d++, desti++, i++) { 2086 ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT) 2087 >= INT_GET(hdr_s->firstused, ARCH_CONVERT)); 2088 tmp = xfs_attr_leaf_entsize(leaf_s, start_s + i); 2089#ifdef GROT 2090 /* 2091 * Code to drop INCOMPLETE entries. Difficult to use as we 2092 * may also need to change the insertion index. Code turned 2093 * off for 6.2, should be revisited later. 2094 */ 2095 if (entry_s->flags & XFS_ATTR_INCOMPLETE) { /* skip partials? */ 2096 memset(XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), 0, tmp); 2097 INT_MOD(hdr_s->usedbytes, ARCH_CONVERT, -tmp); 2098 INT_MOD(hdr_s->count, ARCH_CONVERT, -1); 2099 entry_d--; /* to compensate for ++ in loop hdr */ 2100 desti--; 2101 if ((start_s + i) < offset) 2102 result++; /* insertion index adjustment */ 2103 } else { 2104#endif /* GROT */ 2105 INT_MOD(hdr_d->firstused, ARCH_CONVERT, -tmp); 2106 /* both on-disk, don't endian flip twice */ 2107 entry_d->hashval = entry_s->hashval; 2108 /* both on-disk, don't endian flip twice */ 2109 entry_d->nameidx = hdr_d->firstused; 2110 entry_d->flags = entry_s->flags; 2111 ASSERT(INT_GET(entry_d->nameidx, ARCH_CONVERT) + tmp 2112 <= XFS_LBSIZE(mp)); 2113 memmove(XFS_ATTR_LEAF_NAME(leaf_d, desti), 2114 XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), tmp); 2115 ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT) + tmp 2116 <= XFS_LBSIZE(mp)); 2117 memset(XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), 0, tmp); 2118 INT_MOD(hdr_s->usedbytes, ARCH_CONVERT, -tmp); 2119 INT_MOD(hdr_d->usedbytes, ARCH_CONVERT, tmp); 2120 INT_MOD(hdr_s->count, ARCH_CONVERT, -1); 2121 INT_MOD(hdr_d->count, ARCH_CONVERT, 1); 2122 tmp = INT_GET(hdr_d->count, ARCH_CONVERT) 2123 * sizeof(xfs_attr_leaf_entry_t) 2124 + sizeof(xfs_attr_leaf_hdr_t); 2125 ASSERT(INT_GET(hdr_d->firstused, ARCH_CONVERT) >= tmp); 2126#ifdef GROT 2127 } 2128#endif /* GROT */ 2129 } 2130 2131 /* 2132 * Zero out the entries we just copied. 2133 */ 2134 if (start_s == INT_GET(hdr_s->count, ARCH_CONVERT)) { 2135 tmp = count * sizeof(xfs_attr_leaf_entry_t); 2136 entry_s = &leaf_s->entries[start_s]; 2137 ASSERT(((char *)entry_s + tmp) <= 2138 ((char *)leaf_s + XFS_LBSIZE(mp))); 2139 memset((char *)entry_s, 0, tmp); 2140 } else { 2141 /* 2142 * Move the remaining entries down to fill the hole, 2143 * then zero the entries at the top. 2144 */ 2145 tmp = INT_GET(hdr_s->count, ARCH_CONVERT) - count; 2146 tmp *= sizeof(xfs_attr_leaf_entry_t); 2147 entry_s = &leaf_s->entries[start_s + count]; 2148 entry_d = &leaf_s->entries[start_s]; 2149 memmove((char *)entry_d, (char *)entry_s, tmp); 2150 2151 tmp = count * sizeof(xfs_attr_leaf_entry_t); 2152 entry_s = &leaf_s->entries[INT_GET(hdr_s->count, 2153 ARCH_CONVERT)]; 2154 ASSERT(((char *)entry_s + tmp) <= 2155 ((char *)leaf_s + XFS_LBSIZE(mp))); 2156 memset((char *)entry_s, 0, tmp); 2157 } 2158 2159 /* 2160 * Fill in the freemap information 2161 */ 2162 INT_SET(hdr_d->freemap[0].base, ARCH_CONVERT, 2163 sizeof(xfs_attr_leaf_hdr_t)); 2164 INT_MOD(hdr_d->freemap[0].base, ARCH_CONVERT, 2165 INT_GET(hdr_d->count, ARCH_CONVERT) 2166 * sizeof(xfs_attr_leaf_entry_t)); 2167 INT_SET(hdr_d->freemap[0].size, ARCH_CONVERT, 2168 INT_GET(hdr_d->firstused, ARCH_CONVERT) 2169 - INT_GET(hdr_d->freemap[0].base, ARCH_CONVERT)); 2170 hdr_d->freemap[1].base = 0; 2171 hdr_d->freemap[2].base = 0; 2172 hdr_d->freemap[1].size = 0; 2173 hdr_d->freemap[2].size = 0; 2174 hdr_s->holes = 1; /* leaf may not be compact */ 2175} 2176 2177/* 2178 * Compare two leaf blocks "order". 2179 * Return 0 unless leaf2 should go before leaf1. 2180 */ 2181int 2182xfs_attr_leaf_order(xfs_dabuf_t *leaf1_bp, xfs_dabuf_t *leaf2_bp) 2183{ 2184 xfs_attr_leafblock_t *leaf1, *leaf2; 2185 2186 leaf1 = leaf1_bp->data; 2187 leaf2 = leaf2_bp->data; 2188 ASSERT((INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT) 2189 == XFS_ATTR_LEAF_MAGIC) && 2190 (INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT) 2191 == XFS_ATTR_LEAF_MAGIC)); 2192 if ( (INT_GET(leaf1->hdr.count, ARCH_CONVERT) > 0) 2193 && (INT_GET(leaf2->hdr.count, ARCH_CONVERT) > 0) 2194 && ( (INT_GET(leaf2->entries[ 0 ].hashval, ARCH_CONVERT) < 2195 INT_GET(leaf1->entries[ 0 ].hashval, ARCH_CONVERT)) 2196 || (INT_GET(leaf2->entries[INT_GET(leaf2->hdr.count, 2197 ARCH_CONVERT)-1].hashval, ARCH_CONVERT) < 2198 INT_GET(leaf1->entries[INT_GET(leaf1->hdr.count, 2199 ARCH_CONVERT)-1].hashval, ARCH_CONVERT))) ) { 2200 return(1); 2201 } 2202 return(0); 2203} 2204 2205/* 2206 * Pick up the last hashvalue from a leaf block. 2207 */ 2208xfs_dahash_t 2209xfs_attr_leaf_lasthash(xfs_dabuf_t *bp, int *count) 2210{ 2211 xfs_attr_leafblock_t *leaf; 2212 2213 leaf = bp->data; 2214 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) 2215 == XFS_ATTR_LEAF_MAGIC); 2216 if (count) 2217 *count = INT_GET(leaf->hdr.count, ARCH_CONVERT); 2218 if (!leaf->hdr.count) 2219 return(0); 2220 return(INT_GET(leaf->entries[INT_GET(leaf->hdr.count, 2221 ARCH_CONVERT)-1].hashval, ARCH_CONVERT)); 2222} 2223 2224/* 2225 * Calculate the number of bytes used to store the indicated attribute 2226 * (whether local or remote only calculate bytes in this block). 2227 */ 2228STATIC int 2229xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index) 2230{ 2231 xfs_attr_leaf_name_local_t *name_loc; 2232 xfs_attr_leaf_name_remote_t *name_rmt; 2233 int size; 2234 2235 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) 2236 == XFS_ATTR_LEAF_MAGIC); 2237 if (leaf->entries[index].flags & XFS_ATTR_LOCAL) { 2238 name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, index); 2239 size = XFS_ATTR_LEAF_ENTSIZE_LOCAL(name_loc->namelen, 2240 INT_GET(name_loc->valuelen, 2241 ARCH_CONVERT)); 2242 } else { 2243 name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, index); 2244 size = XFS_ATTR_LEAF_ENTSIZE_REMOTE(name_rmt->namelen); 2245 } 2246 return(size); 2247} 2248 2249/* 2250 * Calculate the number of bytes that would be required to store the new 2251 * attribute (whether local or remote only calculate bytes in this block). 2252 * This routine decides as a side effect whether the attribute will be 2253 * a "local" or a "remote" attribute. 2254 */ 2255int 2256xfs_attr_leaf_newentsize(xfs_da_args_t *args, int blocksize, int *local) 2257{ 2258 int size; 2259 2260 size = XFS_ATTR_LEAF_ENTSIZE_LOCAL(args->namelen, args->valuelen); 2261 if (size < XFS_ATTR_LEAF_ENTSIZE_LOCAL_MAX(blocksize)) { 2262 if (local) { 2263 *local = 1; 2264 } 2265 } else { 2266 size = XFS_ATTR_LEAF_ENTSIZE_REMOTE(args->namelen); 2267 if (local) { 2268 *local = 0; 2269 } 2270 } 2271 return(size); 2272} 2273 2274/* 2275 * Copy out attribute list entries for attr_list(), for leaf attribute lists. 2276 */ 2277int 2278xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context) 2279{ 2280 attrlist_cursor_kern_t *cursor; 2281 xfs_attr_leafblock_t *leaf; 2282 xfs_attr_leaf_entry_t *entry; 2283 xfs_attr_leaf_name_local_t *name_loc; 2284 xfs_attr_leaf_name_remote_t *name_rmt; 2285 int retval, i; 2286 2287 ASSERT(bp != NULL); 2288 leaf = bp->data; 2289 cursor = context->cursor; 2290 cursor->initted = 1; 2291 2292 xfs_attr_trace_l_cl("blk start", context, leaf); 2293 2294 /* 2295 * Re-find our place in the leaf block if this is a new syscall. 2296 */ 2297 if (context->resynch) { 2298 entry = &leaf->entries[0]; 2299 for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); 2300 entry++, i++) { 2301 if (INT_GET(entry->hashval, ARCH_CONVERT) 2302 == cursor->hashval) { 2303 if (cursor->offset == context->dupcnt) { 2304 context->dupcnt = 0; 2305 break; 2306 } 2307 context->dupcnt++; 2308 } else if (INT_GET(entry->hashval, ARCH_CONVERT) 2309 > cursor->hashval) { 2310 context->dupcnt = 0; 2311 break; 2312 } 2313 } 2314 if (i == INT_GET(leaf->hdr.count, ARCH_CONVERT)) { 2315 xfs_attr_trace_l_c("not found", context); 2316 return(0); 2317 } 2318 } else { 2319 entry = &leaf->entries[0]; 2320 i = 0; 2321 } 2322 context->resynch = 0; 2323 2324 /* 2325 * We have found our place, start copying out the new attributes. 2326 */ 2327 retval = 0; 2328 for ( ; (i < INT_GET(leaf->hdr.count, ARCH_CONVERT)) 2329 && (retval == 0); entry++, i++) { 2330 attrnames_t *namesp; 2331 2332 if (INT_GET(entry->hashval, ARCH_CONVERT) != cursor->hashval) { 2333 cursor->hashval = INT_GET(entry->hashval, ARCH_CONVERT); 2334 cursor->offset = 0; 2335 } 2336 2337 if (entry->flags & XFS_ATTR_INCOMPLETE) 2338 continue; /* skip incomplete entries */ 2339 if (((context->flags & ATTR_SECURE) != 0) != 2340 ((entry->flags & XFS_ATTR_SECURE) != 0) && 2341 !(context->flags & ATTR_KERNORMALS)) 2342 continue; /* skip non-matching entries */ 2343 if (((context->flags & ATTR_ROOT) != 0) != 2344 ((entry->flags & XFS_ATTR_ROOT) != 0) && 2345 !(context->flags & ATTR_KERNROOTLS)) 2346 continue; /* skip non-matching entries */ 2347 2348 namesp = (entry->flags & XFS_ATTR_SECURE) ? &attr_secure : 2349 ((entry->flags & XFS_ATTR_ROOT) ? &attr_trusted : 2350 &attr_user); 2351 2352 if (entry->flags & XFS_ATTR_LOCAL) { 2353 name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i); 2354 if (context->flags & ATTR_KERNOVAL) { 2355 ASSERT(context->flags & ATTR_KERNAMELS); 2356 context->count += namesp->attr_namelen + 2357 (int)name_loc->namelen + 1; 2358 } else { 2359 retval = xfs_attr_put_listent(context, namesp, 2360 (char *)name_loc->nameval, 2361 (int)name_loc->namelen, 2362 (int)INT_GET(name_loc->valuelen, 2363 ARCH_CONVERT)); 2364 } 2365 } else { 2366 name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i); 2367 if (context->flags & ATTR_KERNOVAL) { 2368 ASSERT(context->flags & ATTR_KERNAMELS); 2369 context->count += namesp->attr_namelen + 2370 (int)name_rmt->namelen + 1; 2371 } else { 2372 retval = xfs_attr_put_listent(context, namesp, 2373 (char *)name_rmt->name, 2374 (int)name_rmt->namelen, 2375 (int)INT_GET(name_rmt->valuelen, 2376 ARCH_CONVERT)); 2377 } 2378 } 2379 if (retval == 0) { 2380 cursor->offset++; 2381 } 2382 } 2383 xfs_attr_trace_l_cl("blk end", context, leaf); 2384 return(retval); 2385} 2386 2387#define ATTR_ENTBASESIZE /* minimum bytes used by an attr */ \ 2388 (((struct attrlist_ent *) 0)->a_name - (char *) 0) 2389#define ATTR_ENTSIZE(namelen) /* actual bytes used by an attr */ \ 2390 ((ATTR_ENTBASESIZE + (namelen) + 1 + sizeof(u_int32_t)-1) \ 2391 & ~(sizeof(u_int32_t)-1)) 2392 2393/* 2394 * Format an attribute and copy it out to the user's buffer. 2395 * Take care to check values and protect against them changing later, 2396 * we may be reading them directly out of a user buffer. 2397 */ 2398/*ARGSUSED*/ 2399STATIC int 2400xfs_attr_put_listent(xfs_attr_list_context_t *context, 2401 attrnames_t *namesp, char *name, int namelen, int valuelen) 2402{ 2403 attrlist_ent_t *aep; 2404 int arraytop; 2405 2406 ASSERT(!(context->flags & ATTR_KERNOVAL)); 2407 if (context->flags & ATTR_KERNAMELS) { 2408 char *offset; 2409 2410 ASSERT(context->count >= 0); 2411 2412 arraytop = context->count + namesp->attr_namelen + namelen + 1; 2413 if (arraytop > context->firstu) { 2414 context->count = -1; /* insufficient space */ 2415 return(1); 2416 } 2417 offset = (char *)context->alist + context->count; 2418 strncpy(offset, namesp->attr_name, namesp->attr_namelen); 2419 offset += namesp->attr_namelen; 2420 strncpy(offset, name, namelen); /* real name */ 2421 offset += namelen; 2422 *offset = '\0'; 2423 context->count += namesp->attr_namelen + namelen + 1; 2424 return(0); 2425 } 2426 2427 ASSERT(context->count >= 0); 2428 ASSERT(context->count < (ATTR_MAX_VALUELEN/8)); 2429 ASSERT(context->firstu >= sizeof(*context->alist)); 2430 ASSERT(context->firstu <= context->bufsize); 2431 2432 arraytop = sizeof(*context->alist) + 2433 context->count * sizeof(context->alist->al_offset[0]); 2434 context->firstu -= ATTR_ENTSIZE(namelen); 2435 if (context->firstu < arraytop) { 2436 xfs_attr_trace_l_c("buffer full", context); 2437 context->alist->al_more = 1; 2438 return(1); 2439 } 2440 2441 aep = (attrlist_ent_t *)&(((char *)context->alist)[ context->firstu ]); 2442 aep->a_valuelen = valuelen; 2443 memcpy(aep->a_name, name, namelen); 2444 aep->a_name[ namelen ] = 0; 2445 context->alist->al_offset[ context->count++ ] = context->firstu; 2446 context->alist->al_count = context->count; 2447 xfs_attr_trace_l_c("add", context); 2448 return(0); 2449} 2450 2451/*======================================================================== 2452 * Manage the INCOMPLETE flag in a leaf entry 2453 *========================================================================*/ 2454 2455/* 2456 * Clear the INCOMPLETE flag on an entry in a leaf block. 2457 */ 2458int 2459xfs_attr_leaf_clearflag(xfs_da_args_t *args) 2460{ 2461 xfs_attr_leafblock_t *leaf; 2462 xfs_attr_leaf_entry_t *entry; 2463 xfs_attr_leaf_name_remote_t *name_rmt; 2464 xfs_dabuf_t *bp; 2465 int error; 2466#ifdef DEBUG 2467 xfs_attr_leaf_name_local_t *name_loc; 2468 int namelen; 2469 char *name; 2470#endif /* DEBUG */ 2471 2472 /* 2473 * Set up the operation. 2474 */ 2475 error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp, 2476 XFS_ATTR_FORK); 2477 if (error) { 2478 return(error); 2479 } 2480 ASSERT(bp != NULL); 2481 2482 leaf = bp->data; 2483 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) 2484 == XFS_ATTR_LEAF_MAGIC); 2485 ASSERT(args->index < INT_GET(leaf->hdr.count, ARCH_CONVERT)); 2486 ASSERT(args->index >= 0); 2487 entry = &leaf->entries[ args->index ]; 2488 ASSERT(entry->flags & XFS_ATTR_INCOMPLETE); 2489 2490#ifdef DEBUG 2491 if (entry->flags & XFS_ATTR_LOCAL) { 2492 name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, args->index); 2493 namelen = name_loc->namelen; 2494 name = (char *)name_loc->nameval; 2495 } else { 2496 name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index); 2497 namelen = name_rmt->namelen; 2498 name = (char *)name_rmt->name; 2499 } 2500 ASSERT(INT_GET(entry->hashval, ARCH_CONVERT) == args->hashval); 2501 ASSERT(namelen == args->namelen); 2502 ASSERT(memcmp(name, args->name, namelen) == 0); 2503#endif /* DEBUG */ 2504 2505 entry->flags &= ~XFS_ATTR_INCOMPLETE; 2506 xfs_da_log_buf(args->trans, bp, 2507 XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry))); 2508 2509 if (args->rmtblkno) { 2510 ASSERT((entry->flags & XFS_ATTR_LOCAL) == 0); 2511 name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index); 2512 INT_SET(name_rmt->valueblk, ARCH_CONVERT, args->rmtblkno); 2513 INT_SET(name_rmt->valuelen, ARCH_CONVERT, args->valuelen); 2514 xfs_da_log_buf(args->trans, bp, 2515 XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt))); 2516 } 2517 xfs_da_buf_done(bp); 2518 2519 /* 2520 * Commit the flag value change and start the next trans in series. 2521 */ 2522 error = xfs_attr_rolltrans(&args->trans, args->dp); 2523 2524 return(error); 2525} 2526 2527/* 2528 * Set the INCOMPLETE flag on an entry in a leaf block. 2529 */ 2530int 2531xfs_attr_leaf_setflag(xfs_da_args_t *args) 2532{ 2533 xfs_attr_leafblock_t *leaf; 2534 xfs_attr_leaf_entry_t *entry; 2535 xfs_attr_leaf_name_remote_t *name_rmt; 2536 xfs_dabuf_t *bp; 2537 int error; 2538 2539 /* 2540 * Set up the operation. 2541 */ 2542 error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp, 2543 XFS_ATTR_FORK); 2544 if (error) { 2545 return(error); 2546 } 2547 ASSERT(bp != NULL); 2548 2549 leaf = bp->data; 2550 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) 2551 == XFS_ATTR_LEAF_MAGIC); 2552 ASSERT(args->index < INT_GET(leaf->hdr.count, ARCH_CONVERT)); 2553 ASSERT(args->index >= 0); 2554 entry = &leaf->entries[ args->index ]; 2555 2556 ASSERT((entry->flags & XFS_ATTR_INCOMPLETE) == 0); 2557 entry->flags |= XFS_ATTR_INCOMPLETE; 2558 xfs_da_log_buf(args->trans, bp, 2559 XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry))); 2560 if ((entry->flags & XFS_ATTR_LOCAL) == 0) { 2561 name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index); 2562 name_rmt->valueblk = 0; 2563 name_rmt->valuelen = 0; 2564 xfs_da_log_buf(args->trans, bp, 2565 XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt))); 2566 } 2567 xfs_da_buf_done(bp); 2568 2569 /* 2570 * Commit the flag value change and start the next trans in series. 2571 */ 2572 error = xfs_attr_rolltrans(&args->trans, args->dp); 2573 2574 return(error); 2575} 2576 2577/* 2578 * In a single transaction, clear the INCOMPLETE flag on the leaf entry 2579 * given by args->blkno/index and set the INCOMPLETE flag on the leaf 2580 * entry given by args->blkno2/index2. 2581 * 2582 * Note that they could be in different blocks, or in the same block. 2583 */ 2584int 2585xfs_attr_leaf_flipflags(xfs_da_args_t *args) 2586{ 2587 xfs_attr_leafblock_t *leaf1, *leaf2; 2588 xfs_attr_leaf_entry_t *entry1, *entry2; 2589 xfs_attr_leaf_name_remote_t *name_rmt; 2590 xfs_dabuf_t *bp1, *bp2; 2591 int error; 2592#ifdef DEBUG 2593 xfs_attr_leaf_name_local_t *name_loc; 2594 int namelen1, namelen2; 2595 char *name1, *name2; 2596#endif /* DEBUG */ 2597 2598 /* 2599 * Read the block containing the "old" attr 2600 */ 2601 error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp1, 2602 XFS_ATTR_FORK); 2603 if (error) { 2604 return(error); 2605 } 2606 ASSERT(bp1 != NULL); 2607 2608 /* 2609 * Read the block containing the "new" attr, if it is different 2610 */ 2611 if (args->blkno2 != args->blkno) { 2612 error = xfs_da_read_buf(args->trans, args->dp, args->blkno2, 2613 -1, &bp2, XFS_ATTR_FORK); 2614 if (error) { 2615 return(error); 2616 } 2617 ASSERT(bp2 != NULL); 2618 } else { 2619 bp2 = bp1; 2620 } 2621 2622 leaf1 = bp1->data; 2623 ASSERT(INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT) 2624 == XFS_ATTR_LEAF_MAGIC); 2625 ASSERT(args->index < INT_GET(leaf1->hdr.count, ARCH_CONVERT)); 2626 ASSERT(args->index >= 0); 2627 entry1 = &leaf1->entries[ args->index ]; 2628 2629 leaf2 = bp2->data; 2630 ASSERT(INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT) 2631 == XFS_ATTR_LEAF_MAGIC); 2632 ASSERT(args->index2 < INT_GET(leaf2->hdr.count, ARCH_CONVERT)); 2633 ASSERT(args->index2 >= 0); 2634 entry2 = &leaf2->entries[ args->index2 ]; 2635 2636#ifdef DEBUG 2637 if (entry1->flags & XFS_ATTR_LOCAL) { 2638 name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf1, args->index); 2639 namelen1 = name_loc->namelen; 2640 name1 = (char *)name_loc->nameval; 2641 } else { 2642 name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf1, args->index); 2643 namelen1 = name_rmt->namelen; 2644 name1 = (char *)name_rmt->name; 2645 } 2646 if (entry2->flags & XFS_ATTR_LOCAL) { 2647 name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf2, args->index2); 2648 namelen2 = name_loc->namelen; 2649 name2 = (char *)name_loc->nameval; 2650 } else { 2651 name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf2, args->index2); 2652 namelen2 = name_rmt->namelen; 2653 name2 = (char *)name_rmt->name; 2654 } 2655 ASSERT(INT_GET(entry1->hashval, ARCH_CONVERT) == INT_GET(entry2->hashval, ARCH_CONVERT)); 2656 ASSERT(namelen1 == namelen2); 2657 ASSERT(memcmp(name1, name2, namelen1) == 0); 2658#endif /* DEBUG */ 2659 2660 ASSERT(entry1->flags & XFS_ATTR_INCOMPLETE); 2661 ASSERT((entry2->flags & XFS_ATTR_INCOMPLETE) == 0); 2662 2663 entry1->flags &= ~XFS_ATTR_INCOMPLETE; 2664 xfs_da_log_buf(args->trans, bp1, 2665 XFS_DA_LOGRANGE(leaf1, entry1, sizeof(*entry1))); 2666 if (args->rmtblkno) { 2667 ASSERT((entry1->flags & XFS_ATTR_LOCAL) == 0); 2668 name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf1, args->index); 2669 INT_SET(name_rmt->valueblk, ARCH_CONVERT, args->rmtblkno); 2670 INT_SET(name_rmt->valuelen, ARCH_CONVERT, args->valuelen); 2671 xfs_da_log_buf(args->trans, bp1, 2672 XFS_DA_LOGRANGE(leaf1, name_rmt, sizeof(*name_rmt))); 2673 } 2674 2675 entry2->flags |= XFS_ATTR_INCOMPLETE; 2676 xfs_da_log_buf(args->trans, bp2, 2677 XFS_DA_LOGRANGE(leaf2, entry2, sizeof(*entry2))); 2678 if ((entry2->flags & XFS_ATTR_LOCAL) == 0) { 2679 name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf2, args->index2); 2680 name_rmt->valueblk = 0; 2681 name_rmt->valuelen = 0; 2682 xfs_da_log_buf(args->trans, bp2, 2683 XFS_DA_LOGRANGE(leaf2, name_rmt, sizeof(*name_rmt))); 2684 } 2685 xfs_da_buf_done(bp1); 2686 if (bp1 != bp2) 2687 xfs_da_buf_done(bp2); 2688 2689 /* 2690 * Commit the flag value change and start the next trans in series. 2691 */ 2692 error = xfs_attr_rolltrans(&args->trans, args->dp); 2693 2694 return(error); 2695} 2696 2697/*======================================================================== 2698 * Indiscriminately delete the entire attribute fork 2699 *========================================================================*/ 2700 2701/* 2702 * Recurse (gasp!) through the attribute nodes until we find leaves. 2703 * We're doing a depth-first traversal in order to invalidate everything. 2704 */ 2705int 2706xfs_attr_root_inactive(xfs_trans_t **trans, xfs_inode_t *dp) 2707{ 2708 xfs_da_blkinfo_t *info; 2709 xfs_daddr_t blkno; 2710 xfs_dabuf_t *bp; 2711 int error; 2712 2713 /* 2714 * Read block 0 to see what we have to work with. 2715 * We only get here if we have extents, since we remove 2716 * the extents in reverse order the extent containing 2717 * block 0 must still be there. 2718 */ 2719 error = xfs_da_read_buf(*trans, dp, 0, -1, &bp, XFS_ATTR_FORK); 2720 if (error) 2721 return(error); 2722 blkno = xfs_da_blkno(bp); 2723 2724 /* 2725 * Invalidate the tree, even if the "tree" is only a single leaf block. 2726 * This is a depth-first traversal! 2727 */ 2728 info = bp->data; 2729 if (INT_GET(info->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC) { 2730 error = xfs_attr_node_inactive(trans, dp, bp, 1); 2731 } else if (INT_GET(info->magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC) { 2732 error = xfs_attr_leaf_inactive(trans, dp, bp); 2733 } else { 2734 error = XFS_ERROR(EIO); 2735 xfs_da_brelse(*trans, bp); 2736 } 2737 if (error) 2738 return(error); 2739 2740 /* 2741 * Invalidate the incore copy of the root block. 2742 */ 2743 error = xfs_da_get_buf(*trans, dp, 0, blkno, &bp, XFS_ATTR_FORK); 2744 if (error) 2745 return(error); 2746 xfs_da_binval(*trans, bp); /* remove from cache */ 2747 /* 2748 * Commit the invalidate and start the next transaction. 2749 */ 2750 error = xfs_attr_rolltrans(trans, dp); 2751 2752 return (error); 2753} 2754 2755/* 2756 * Recurse (gasp!) through the attribute nodes until we find leaves. 2757 * We're doing a depth-first traversal in order to invalidate everything. 2758 */ 2759STATIC int 2760xfs_attr_node_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp, 2761 int level) 2762{ 2763 xfs_da_blkinfo_t *info; 2764 xfs_da_intnode_t *node; 2765 xfs_dablk_t child_fsb; 2766 xfs_daddr_t parent_blkno, child_blkno; 2767 int error, count, i; 2768 xfs_dabuf_t *child_bp; 2769 2770 /* 2771 * Since this code is recursive (gasp!) we must protect ourselves. 2772 */ 2773 if (level > XFS_DA_NODE_MAXDEPTH) { 2774 xfs_da_brelse(*trans, bp); /* no locks for later trans */ 2775 return(XFS_ERROR(EIO)); 2776 } 2777 2778 node = bp->data; 2779 ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT) 2780 == XFS_DA_NODE_MAGIC); 2781 parent_blkno = xfs_da_blkno(bp); /* save for re-read later */ 2782 count = INT_GET(node->hdr.count, ARCH_CONVERT); 2783 if (!count) { 2784 xfs_da_brelse(*trans, bp); 2785 return(0); 2786 } 2787 child_fsb = INT_GET(node->btree[0].before, ARCH_CONVERT); 2788 xfs_da_brelse(*trans, bp); /* no locks for later trans */ 2789 2790 /* 2791 * If this is the node level just above the leaves, simply loop 2792 * over the leaves removing all of them. If this is higher up 2793 * in the tree, recurse downward. 2794 */ 2795 for (i = 0; i < count; i++) { 2796 /* 2797 * Read the subsidiary block to see what we have to work with. 2798 * Don't do this in a transaction. This is a depth-first 2799 * traversal of the tree so we may deal with many blocks 2800 * before we come back to this one. 2801 */ 2802 error = xfs_da_read_buf(*trans, dp, child_fsb, -2, &child_bp, 2803 XFS_ATTR_FORK); 2804 if (error) 2805 return(error); 2806 if (child_bp) { 2807 /* save for re-read later */ 2808 child_blkno = xfs_da_blkno(child_bp); 2809 2810 /* 2811 * Invalidate the subtree, however we have to. 2812 */ 2813 info = child_bp->data; 2814 if (INT_GET(info->magic, ARCH_CONVERT) 2815 == XFS_DA_NODE_MAGIC) { 2816 error = xfs_attr_node_inactive(trans, dp, 2817 child_bp, level+1); 2818 } else if (INT_GET(info->magic, ARCH_CONVERT) 2819 == XFS_ATTR_LEAF_MAGIC) { 2820 error = xfs_attr_leaf_inactive(trans, dp, 2821 child_bp); 2822 } else { 2823 error = XFS_ERROR(EIO); 2824 xfs_da_brelse(*trans, child_bp); 2825 } 2826 if (error) 2827 return(error); 2828 2829 /* 2830 * Remove the subsidiary block from the cache 2831 * and from the log. 2832 */ 2833 error = xfs_da_get_buf(*trans, dp, 0, child_blkno, 2834 &child_bp, XFS_ATTR_FORK); 2835 if (error) 2836 return(error); 2837 xfs_da_binval(*trans, child_bp); 2838 } 2839 2840 /* 2841 * If we're not done, re-read the parent to get the next 2842 * child block number. 2843 */ 2844 if ((i+1) < count) { 2845 error = xfs_da_read_buf(*trans, dp, 0, parent_blkno, 2846 &bp, XFS_ATTR_FORK); 2847 if (error) 2848 return(error); 2849 child_fsb = INT_GET(node->btree[i+1].before, ARCH_CONVERT); 2850 xfs_da_brelse(*trans, bp); 2851 } 2852 /* 2853 * Atomically commit the whole invalidate stuff. 2854 */ 2855 if ((error = xfs_attr_rolltrans(trans, dp))) 2856 return (error); 2857 } 2858 2859 return(0); 2860} 2861 2862/* 2863 * Invalidate all of the "remote" value regions pointed to by a particular 2864 * leaf block. 2865 * Note that we must release the lock on the buffer so that we are not 2866 * caught holding something that the logging code wants to flush to disk. 2867 */ 2868STATIC int 2869xfs_attr_leaf_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp) 2870{ 2871 xfs_attr_leafblock_t *leaf; 2872 xfs_attr_leaf_entry_t *entry; 2873 xfs_attr_leaf_name_remote_t *name_rmt; 2874 xfs_attr_inactive_list_t *list, *lp; 2875 int error, count, size, tmp, i; 2876 2877 leaf = bp->data; 2878 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) 2879 == XFS_ATTR_LEAF_MAGIC); 2880 2881 /* 2882 * Count the number of "remote" value extents. 2883 */ 2884 count = 0; 2885 entry = &leaf->entries[0]; 2886 for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) { 2887 if ( INT_GET(entry->nameidx, ARCH_CONVERT) 2888 && ((entry->flags & XFS_ATTR_LOCAL) == 0)) { 2889 name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i); 2890 if (name_rmt->valueblk) 2891 count++; 2892 } 2893 } 2894 2895 /* 2896 * If there are no "remote" values, we're done. 2897 */ 2898 if (count == 0) { 2899 xfs_da_brelse(*trans, bp); 2900 return(0); 2901 } 2902 2903 /* 2904 * Allocate storage for a list of all the "remote" value extents. 2905 */ 2906 size = count * sizeof(xfs_attr_inactive_list_t); 2907 list = (xfs_attr_inactive_list_t *)kmem_alloc(size, KM_SLEEP); 2908 2909 /* 2910 * Identify each of the "remote" value extents. 2911 */ 2912 lp = list; 2913 entry = &leaf->entries[0]; 2914 for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) { 2915 if ( INT_GET(entry->nameidx, ARCH_CONVERT) 2916 && ((entry->flags & XFS_ATTR_LOCAL) == 0)) { 2917 name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i); 2918 if (name_rmt->valueblk) { 2919 /* both on-disk, don't endian flip twice */ 2920 lp->valueblk = name_rmt->valueblk; 2921 INT_SET(lp->valuelen, ARCH_CONVERT, 2922 XFS_B_TO_FSB(dp->i_mount, 2923 INT_GET(name_rmt->valuelen, 2924 ARCH_CONVERT))); 2925 lp++; 2926 } 2927 } 2928 } 2929 xfs_da_brelse(*trans, bp); /* unlock for trans. in freextent() */ 2930 2931 /* 2932 * Invalidate each of the "remote" value extents. 2933 */ 2934 error = 0; 2935 for (lp = list, i = 0; i < count; i++, lp++) { 2936 tmp = xfs_attr_leaf_freextent(trans, dp, 2937 INT_GET(lp->valueblk, 2938 ARCH_CONVERT), 2939 INT_GET(lp->valuelen, 2940 ARCH_CONVERT)); 2941 if (error == 0) 2942 error = tmp; /* save only the 1st errno */ 2943 } 2944 2945 kmem_free((xfs_caddr_t)list, size); 2946 return(error); 2947} 2948 2949/* 2950 * Look at all the extents for this logical region, 2951 * invalidate any buffers that are incore/in transactions. 2952 */ 2953STATIC int 2954xfs_attr_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp, 2955 xfs_dablk_t blkno, int blkcnt) 2956{ 2957 xfs_bmbt_irec_t map; 2958 xfs_dablk_t tblkno; 2959 int tblkcnt, dblkcnt, nmap, error; 2960 xfs_daddr_t dblkno; 2961 xfs_buf_t *bp; 2962 2963 /* 2964 * Roll through the "value", invalidating the attribute value's 2965 * blocks. 2966 */ 2967 tblkno = blkno; 2968 tblkcnt = blkcnt; 2969 while (tblkcnt > 0) { 2970 /* 2971 * Try to remember where we decided to put the value. 2972 */ 2973 nmap = 1; 2974 error = xfs_bmapi(*trans, dp, (xfs_fileoff_t)tblkno, tblkcnt, 2975 XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, 2976 NULL, 0, &map, &nmap, NULL); 2977 if (error) { 2978 return(error); 2979 } 2980 ASSERT(nmap == 1); 2981 ASSERT(map.br_startblock != DELAYSTARTBLOCK); 2982 2983 /* 2984 * If it's a hole, these are already unmapped 2985 * so there's nothing to invalidate. 2986 */ 2987 if (map.br_startblock != HOLESTARTBLOCK) { 2988 2989 dblkno = XFS_FSB_TO_DADDR(dp->i_mount, 2990 map.br_startblock); 2991 dblkcnt = XFS_FSB_TO_BB(dp->i_mount, 2992 map.br_blockcount); 2993 bp = xfs_trans_get_buf(*trans, 2994 dp->i_mount->m_ddev_targp, 2995 dblkno, dblkcnt, XFS_BUF_LOCK); 2996 xfs_trans_binval(*trans, bp); 2997 /* 2998 * Roll to next transaction. 2999 */ 3000 if ((error = xfs_attr_rolltrans(trans, dp))) 3001 return (error); 3002 } 3003 3004 tblkno += map.br_blockcount; 3005 tblkcnt -= map.br_blockcount; 3006 } 3007 3008 return(0); 3009} 3010 3011 3012/* 3013 * Roll from one trans in the sequence of PERMANENT transactions to the next. 3014 */ 3015int 3016xfs_attr_rolltrans(xfs_trans_t **transp, xfs_inode_t *dp) 3017{ 3018 xfs_trans_t *trans; 3019 unsigned int logres, count; 3020 int error; 3021 3022 /* 3023 * Ensure that the inode is always logged. 3024 */ 3025 trans = *transp; 3026 xfs_trans_log_inode(trans, dp, XFS_ILOG_CORE); 3027 3028 /* 3029 * Copy the critical parameters from one trans to the next. 3030 */ 3031 logres = trans->t_log_res; 3032 count = trans->t_log_count; 3033 *transp = xfs_trans_dup(trans); 3034 3035 /* 3036 * Commit the current transaction. 3037 * If this commit failed, then it'd just unlock those items that 3038 * are not marked ihold. That also means that a filesystem shutdown 3039 * is in progress. The caller takes the responsibility to cancel 3040 * the duplicate transaction that gets returned. 3041 */ 3042 if ((error = xfs_trans_commit(trans, 0, NULL))) 3043 return (error); 3044 3045 trans = *transp; 3046 3047 /* 3048 * Reserve space in the log for th next transaction. 3049 * This also pushes items in the "AIL", the list of logged items, 3050 * out to disk if they are taking up space at the tail of the log 3051 * that we want to use. This requires that either nothing be locked 3052 * across this call, or that anything that is locked be logged in 3053 * the prior and the next transactions. 3054 */ 3055 error = xfs_trans_reserve(trans, 0, logres, 0, 3056 XFS_TRANS_PERM_LOG_RES, count); 3057 /* 3058 * Ensure that the inode is in the new transaction and locked. 3059 */ 3060 if (!error) { 3061 xfs_trans_ijoin(trans, dp, XFS_ILOCK_EXCL); 3062 xfs_trans_ihold(trans, dp); 3063 } 3064 return (error); 3065 3066}