1/* 2 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. 3 * All Rights Reserved. 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it would be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write the Free Software Foundation, 16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18#include "xfs.h" 19#include "xfs_fs.h" 20#include "xfs_types.h" 21#include "xfs_log.h" 22#include "xfs_inum.h" 23#include "xfs_trans.h" 24#include "xfs_sb.h" 25#include "xfs_dir.h" 26#include "xfs_dir2.h" 27#include "xfs_dmapi.h" 28#include "xfs_mount.h" 29#include "xfs_da_btree.h" 30#include "xfs_bmap_btree.h" 31#include "xfs_alloc_btree.h" 32#include "xfs_ialloc_btree.h" 33#include "xfs_alloc.h" 34#include "xfs_btree.h" 35#include "xfs_dir_sf.h" 36#include "xfs_dir2_sf.h" 37#include "xfs_attr_sf.h" 38#include "xfs_dinode.h" 39#include "xfs_inode.h" 40#include "xfs_bmap.h" 41#include "xfs_dir_leaf.h" 42#include "xfs_error.h" 43 44/* 45 * xfs_dir.c 46 * 47 * Provide the external interfaces to manage directories. 48 */ 49 50/*======================================================================== 51 * Function prototypes for the kernel. 52 *========================================================================*/ 53 54/* 55 * Functions for the dirops interfaces. 56 */ 57static void xfs_dir_mount(struct xfs_mount *mp); 58 59static int xfs_dir_isempty(struct xfs_inode *dp); 60 61static int xfs_dir_init(struct xfs_trans *trans, 62 struct xfs_inode *dir, 63 struct xfs_inode *parent_dir); 64 65static int xfs_dir_createname(struct xfs_trans *trans, 66 struct xfs_inode *dp, 67 char *name_string, 68 int name_len, 69 xfs_ino_t inode_number, 70 xfs_fsblock_t *firstblock, 71 xfs_bmap_free_t *flist, 72 xfs_extlen_t total); 73 74static int xfs_dir_lookup(struct xfs_trans *tp, 75 struct xfs_inode *dp, 76 char *name_string, 77 int name_length, 78 xfs_ino_t *inode_number); 79 80static int xfs_dir_removename(struct xfs_trans *trans, 81 struct xfs_inode *dp, 82 char *name_string, 83 int name_length, 84 xfs_ino_t ino, 85 xfs_fsblock_t *firstblock, 86 xfs_bmap_free_t *flist, 87 xfs_extlen_t total); 88 89static int xfs_dir_getdents(struct xfs_trans *tp, 90 struct xfs_inode *dp, 91 struct uio *uiop, 92 int *eofp); 93 94static int xfs_dir_replace(struct xfs_trans *tp, 95 struct xfs_inode *dp, 96 char *name_string, 97 int name_length, 98 xfs_ino_t inode_number, 99 xfs_fsblock_t *firstblock, 100 xfs_bmap_free_t *flist, 101 xfs_extlen_t total); 102 103static int xfs_dir_canenter(struct xfs_trans *tp, 104 struct xfs_inode *dp, 105 char *name_string, 106 int name_length); 107 108static int xfs_dir_shortform_validate_ondisk(xfs_mount_t *mp, 109 xfs_dinode_t *dip); 110 111xfs_dirops_t xfsv1_dirops = { 112 .xd_mount = xfs_dir_mount, 113 .xd_isempty = xfs_dir_isempty, 114 .xd_init = xfs_dir_init, 115 .xd_createname = xfs_dir_createname, 116 .xd_lookup = xfs_dir_lookup, 117 .xd_removename = xfs_dir_removename, 118 .xd_getdents = xfs_dir_getdents, 119 .xd_replace = xfs_dir_replace, 120 .xd_canenter = xfs_dir_canenter, 121 .xd_shortform_validate_ondisk = xfs_dir_shortform_validate_ondisk, 122 .xd_shortform_to_single = xfs_dir_shortform_to_leaf, 123}; 124 125/* 126 * Internal routines when dirsize == XFS_LBSIZE(mp). 127 */ 128STATIC int xfs_dir_leaf_lookup(xfs_da_args_t *args); 129STATIC int xfs_dir_leaf_removename(xfs_da_args_t *args, int *number_entries, 130 int *total_namebytes); 131STATIC int xfs_dir_leaf_getdents(xfs_trans_t *trans, xfs_inode_t *dp, 132 uio_t *uio, int *eofp, 133 xfs_dirent_t *dbp, 134 xfs_dir_put_t put); 135STATIC int xfs_dir_leaf_replace(xfs_da_args_t *args); 136 137/* 138 * Internal routines when dirsize > XFS_LBSIZE(mp). 139 */ 140STATIC int xfs_dir_node_addname(xfs_da_args_t *args); 141STATIC int xfs_dir_node_lookup(xfs_da_args_t *args); 142STATIC int xfs_dir_node_removename(xfs_da_args_t *args); 143STATIC int xfs_dir_node_getdents(xfs_trans_t *trans, xfs_inode_t *dp, 144 uio_t *uio, int *eofp, 145 xfs_dirent_t *dbp, 146 xfs_dir_put_t put); 147STATIC int xfs_dir_node_replace(xfs_da_args_t *args); 148 149#if defined(XFS_DIR_TRACE) 150ktrace_t *xfs_dir_trace_buf; 151#endif 152 153 154/*======================================================================== 155 * Overall external interface routines. 156 *========================================================================*/ 157 158xfs_dahash_t xfs_dir_hash_dot, xfs_dir_hash_dotdot; 159 160/* 161 * One-time startup routine called from xfs_init(). 162 */ 163void 164xfs_dir_startup(void) 165{ 166 xfs_dir_hash_dot = xfs_da_hashname(".", 1); 167 xfs_dir_hash_dotdot = xfs_da_hashname("..", 2); 168} 169 170/* 171 * Initialize directory-related fields in the mount structure. 172 */ 173static void 174xfs_dir_mount(xfs_mount_t *mp) 175{ 176 uint shortcount, leafcount, count; 177 178 mp->m_dirversion = 1; 179 if (!(mp->m_flags & XFS_MOUNT_ATTR2)) { 180 shortcount = (mp->m_attroffset - 181 (uint)sizeof(xfs_dir_sf_hdr_t)) / 182 (uint)sizeof(xfs_dir_sf_entry_t); 183 leafcount = (XFS_LBSIZE(mp) - 184 (uint)sizeof(xfs_dir_leaf_hdr_t)) / 185 ((uint)sizeof(xfs_dir_leaf_entry_t) + 186 (uint)sizeof(xfs_dir_leaf_name_t)); 187 } else { 188 shortcount = (XFS_BMDR_SPACE_CALC(MINABTPTRS) - 189 (uint)sizeof(xfs_dir_sf_hdr_t)) / 190 (uint)sizeof(xfs_dir_sf_entry_t); 191 leafcount = (XFS_LBSIZE(mp) - 192 (uint)sizeof(xfs_dir_leaf_hdr_t)) / 193 ((uint)sizeof(xfs_dir_leaf_entry_t) + 194 (uint)sizeof(xfs_dir_leaf_name_t)); 195 } 196 count = shortcount > leafcount ? shortcount : leafcount; 197 mp->m_dircook_elog = xfs_da_log2_roundup(count + 1); 198 ASSERT(mp->m_dircook_elog <= mp->m_sb.sb_blocklog); 199 mp->m_dir_node_ents = mp->m_attr_node_ents = 200 (XFS_LBSIZE(mp) - (uint)sizeof(xfs_da_node_hdr_t)) / 201 (uint)sizeof(xfs_da_node_entry_t); 202 mp->m_dir_magicpct = (XFS_LBSIZE(mp) * 37) / 100; 203 mp->m_dirblksize = mp->m_sb.sb_blocksize; 204 mp->m_dirblkfsbs = 1; 205} 206 207/* 208 * Return 1 if directory contains only "." and "..". 209 */ 210static int 211xfs_dir_isempty(xfs_inode_t *dp) 212{ 213 xfs_dir_sf_hdr_t *hdr; 214 215 ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); 216 if (dp->i_d.di_size == 0) 217 return(1); 218 if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp)) 219 return(0); 220 hdr = (xfs_dir_sf_hdr_t *)dp->i_df.if_u1.if_data; 221 return(hdr->count == 0); 222} 223 224/* 225 * Initialize a directory with its "." and ".." entries. 226 */ 227static int 228xfs_dir_init(xfs_trans_t *trans, xfs_inode_t *dir, xfs_inode_t *parent_dir) 229{ 230 xfs_da_args_t args; 231 int error; 232 233 memset((char *)&args, 0, sizeof(args)); 234 args.dp = dir; 235 args.trans = trans; 236 237 ASSERT((dir->i_d.di_mode & S_IFMT) == S_IFDIR); 238 if ((error = xfs_dir_ino_validate(trans->t_mountp, parent_dir->i_ino))) 239 return error; 240 241 return(xfs_dir_shortform_create(&args, parent_dir->i_ino)); 242} 243 244/* 245 * Generic handler routine to add a name to a directory. 246 * Transitions directory from shortform to Btree as necessary. 247 */ 248static int /* error */ 249xfs_dir_createname(xfs_trans_t *trans, xfs_inode_t *dp, char *name, 250 int namelen, xfs_ino_t inum, xfs_fsblock_t *firstblock, 251 xfs_bmap_free_t *flist, xfs_extlen_t total) 252{ 253 xfs_da_args_t args; 254 int retval, newsize, done; 255 256 ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); 257 258 if ((retval = xfs_dir_ino_validate(trans->t_mountp, inum))) 259 return (retval); 260 261 XFS_STATS_INC(xs_dir_create); 262 /* 263 * Fill in the arg structure for this request. 264 */ 265 args.name = name; 266 args.namelen = namelen; 267 args.hashval = xfs_da_hashname(name, namelen); 268 args.inumber = inum; 269 args.dp = dp; 270 args.firstblock = firstblock; 271 args.flist = flist; 272 args.total = total; 273 args.whichfork = XFS_DATA_FORK; 274 args.trans = trans; 275 args.justcheck = 0; 276 args.addname = args.oknoent = 1; 277 278 /* 279 * Decide on what work routines to call based on the inode size. 280 */ 281 done = 0; 282 if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { 283 newsize = XFS_DIR_SF_ENTSIZE_BYNAME(args.namelen); 284 if ((dp->i_d.di_size + newsize) <= XFS_IFORK_DSIZE(dp)) { 285 retval = xfs_dir_shortform_addname(&args); 286 done = 1; 287 } else { 288 if (total == 0) 289 return XFS_ERROR(ENOSPC); 290 retval = xfs_dir_shortform_to_leaf(&args); 291 done = retval != 0; 292 } 293 } 294 if (!done && xfs_bmap_one_block(dp, XFS_DATA_FORK)) { 295 retval = xfs_dir_leaf_addname(&args); 296 done = retval != ENOSPC; 297 if (!done) { 298 if (total == 0) 299 return XFS_ERROR(ENOSPC); 300 retval = xfs_dir_leaf_to_node(&args); 301 done = retval != 0; 302 } 303 } 304 if (!done) { 305 retval = xfs_dir_node_addname(&args); 306 } 307 return(retval); 308} 309 310/* 311 * Generic handler routine to check if a name can be added to a directory, 312 * without adding any blocks to the directory. 313 */ 314static int /* error */ 315xfs_dir_canenter(xfs_trans_t *trans, xfs_inode_t *dp, char *name, int namelen) 316{ 317 xfs_da_args_t args; 318 int retval, newsize; 319 320 ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); 321 /* 322 * Fill in the arg structure for this request. 323 */ 324 args.name = name; 325 args.namelen = namelen; 326 args.hashval = xfs_da_hashname(name, namelen); 327 args.inumber = 0; 328 args.dp = dp; 329 args.firstblock = NULL; 330 args.flist = NULL; 331 args.total = 0; 332 args.whichfork = XFS_DATA_FORK; 333 args.trans = trans; 334 args.justcheck = args.addname = args.oknoent = 1; 335 336 /* 337 * Decide on what work routines to call based on the inode size. 338 */ 339 if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { 340 newsize = XFS_DIR_SF_ENTSIZE_BYNAME(args.namelen); 341 if ((dp->i_d.di_size + newsize) <= XFS_IFORK_DSIZE(dp)) 342 retval = 0; 343 else 344 retval = XFS_ERROR(ENOSPC); 345 } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) { 346 retval = xfs_dir_leaf_addname(&args); 347 } else { 348 retval = xfs_dir_node_addname(&args); 349 } 350 return(retval); 351} 352 353/* 354 * Generic handler routine to remove a name from a directory. 355 * Transitions directory from Btree to shortform as necessary. 356 */ 357static int /* error */ 358xfs_dir_removename(xfs_trans_t *trans, xfs_inode_t *dp, char *name, 359 int namelen, xfs_ino_t ino, xfs_fsblock_t *firstblock, 360 xfs_bmap_free_t *flist, xfs_extlen_t total) 361{ 362 xfs_da_args_t args; 363 int count, totallen, newsize, retval; 364 365 ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); 366 XFS_STATS_INC(xs_dir_remove); 367 /* 368 * Fill in the arg structure for this request. 369 */ 370 args.name = name; 371 args.namelen = namelen; 372 args.hashval = xfs_da_hashname(name, namelen); 373 args.inumber = ino; 374 args.dp = dp; 375 args.firstblock = firstblock; 376 args.flist = flist; 377 args.total = total; 378 args.whichfork = XFS_DATA_FORK; 379 args.trans = trans; 380 args.justcheck = args.addname = args.oknoent = 0; 381 382 /* 383 * Decide on what work routines to call based on the inode size. 384 */ 385 if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { 386 retval = xfs_dir_shortform_removename(&args); 387 } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) { 388 count = totallen = 0; 389 retval = xfs_dir_leaf_removename(&args, &count, &totallen); 390 if (retval == 0) { 391 newsize = XFS_DIR_SF_ALLFIT(count, totallen); 392 if (newsize <= XFS_IFORK_DSIZE(dp)) { 393 retval = xfs_dir_leaf_to_shortform(&args); 394 } 395 } 396 } else { 397 retval = xfs_dir_node_removename(&args); 398 } 399 return(retval); 400} 401 402static int /* error */ 403xfs_dir_lookup(xfs_trans_t *trans, xfs_inode_t *dp, char *name, int namelen, 404 xfs_ino_t *inum) 405{ 406 xfs_da_args_t args; 407 int retval; 408 409 ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); 410 411 XFS_STATS_INC(xs_dir_lookup); 412 /* 413 * Fill in the arg structure for this request. 414 */ 415 args.name = name; 416 args.namelen = namelen; 417 args.hashval = xfs_da_hashname(name, namelen); 418 args.inumber = 0; 419 args.dp = dp; 420 args.firstblock = NULL; 421 args.flist = NULL; 422 args.total = 0; 423 args.whichfork = XFS_DATA_FORK; 424 args.trans = trans; 425 args.justcheck = args.addname = 0; 426 args.oknoent = 1; 427 428 /* 429 * Decide on what work routines to call based on the inode size. 430 */ 431 if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { 432 retval = xfs_dir_shortform_lookup(&args); 433 } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) { 434 retval = xfs_dir_leaf_lookup(&args); 435 } else { 436 retval = xfs_dir_node_lookup(&args); 437 } 438 if (retval == EEXIST) 439 retval = 0; 440 *inum = args.inumber; 441 return(retval); 442} 443 444/* 445 * Implement readdir. 446 */ 447static int /* error */ 448xfs_dir_getdents(xfs_trans_t *trans, xfs_inode_t *dp, uio_t *uio, int *eofp) 449{ 450 xfs_dirent_t *dbp; 451 int alignment, retval; 452 xfs_dir_put_t put; 453 454 XFS_STATS_INC(xs_dir_getdents); 455 ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); 456 457 /* 458 * If our caller has given us a single contiguous memory buffer, 459 * just work directly within that buffer. If it's in user memory, 460 * lock it down first. 461 */ 462 alignment = sizeof(xfs_off_t) - 1; 463 if ((uio->uio_iovcnt == 1) && 464 (((__psint_t)uio->uio_iov[0].iov_base & alignment) == 0) && 465 ((uio->uio_iov[0].iov_len & alignment) == 0)) { 466 dbp = NULL; 467 put = xfs_dir_put_dirent64_direct; 468 } else { 469 dbp = kmem_alloc(sizeof(*dbp) + MAXNAMELEN, KM_SLEEP); 470 put = xfs_dir_put_dirent64_uio; 471 } 472 473 /* 474 * Decide on what work routines to call based on the inode size. 475 */ 476 *eofp = 0; 477 478 if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { 479 retval = xfs_dir_shortform_getdents(dp, uio, eofp, dbp, put); 480 } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) { 481 retval = xfs_dir_leaf_getdents(trans, dp, uio, eofp, dbp, put); 482 } else { 483 retval = xfs_dir_node_getdents(trans, dp, uio, eofp, dbp, put); 484 } 485 if (dbp != NULL) 486 kmem_free(dbp, sizeof(*dbp) + MAXNAMELEN); 487 488 return(retval); 489} 490 491static int /* error */ 492xfs_dir_replace(xfs_trans_t *trans, xfs_inode_t *dp, char *name, int namelen, 493 xfs_ino_t inum, xfs_fsblock_t *firstblock, 494 xfs_bmap_free_t *flist, xfs_extlen_t total) 495{ 496 xfs_da_args_t args; 497 int retval; 498 499 ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); 500 501 if ((retval = xfs_dir_ino_validate(trans->t_mountp, inum))) 502 return retval; 503 504 /* 505 * Fill in the arg structure for this request. 506 */ 507 args.name = name; 508 args.namelen = namelen; 509 args.hashval = xfs_da_hashname(name, namelen); 510 args.inumber = inum; 511 args.dp = dp; 512 args.firstblock = firstblock; 513 args.flist = flist; 514 args.total = total; 515 args.whichfork = XFS_DATA_FORK; 516 args.trans = trans; 517 args.justcheck = args.addname = args.oknoent = 0; 518 519 /* 520 * Decide on what work routines to call based on the inode size. 521 */ 522 if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { 523 retval = xfs_dir_shortform_replace(&args); 524 } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) { 525 retval = xfs_dir_leaf_replace(&args); 526 } else { 527 retval = xfs_dir_node_replace(&args); 528 } 529 530 return(retval); 531} 532 533static int 534xfs_dir_shortform_validate_ondisk(xfs_mount_t *mp, xfs_dinode_t *dp) 535{ 536 xfs_ino_t ino; 537 int namelen_sum; 538 int count; 539 xfs_dir_shortform_t *sf; 540 xfs_dir_sf_entry_t *sfe; 541 int i; 542 543 544 545 if ((INT_GET(dp->di_core.di_mode, ARCH_CONVERT) & S_IFMT) != S_IFDIR) { 546 return 0; 547 } 548 if (INT_GET(dp->di_core.di_format, ARCH_CONVERT) != XFS_DINODE_FMT_LOCAL) { 549 return 0; 550 } 551 if (INT_GET(dp->di_core.di_size, ARCH_CONVERT) < sizeof(sf->hdr)) { 552 xfs_fs_cmn_err(CE_WARN, mp, "Invalid shortform size: dp 0x%p", 553 dp); 554 return 1; 555 } 556 sf = (xfs_dir_shortform_t *)(&dp->di_u.di_dirsf); 557 ino = XFS_GET_DIR_INO8(sf->hdr.parent); 558 if (xfs_dir_ino_validate(mp, ino)) 559 return 1; 560 561 count = sf->hdr.count; 562 if ((count < 0) || ((count * 10) > XFS_LITINO(mp))) { 563 xfs_fs_cmn_err(CE_WARN, mp, 564 "Invalid shortform count: dp 0x%p", dp); 565 return(1); 566 } 567 568 if (count == 0) { 569 return 0; 570 } 571 572 namelen_sum = 0; 573 sfe = &sf->list[0]; 574 for (i = sf->hdr.count - 1; i >= 0; i--) { 575 ino = XFS_GET_DIR_INO8(sfe->inumber); 576 xfs_dir_ino_validate(mp, ino); 577 if (sfe->namelen >= XFS_LITINO(mp)) { 578 xfs_fs_cmn_err(CE_WARN, mp, 579 "Invalid shortform namelen: dp 0x%p", dp); 580 return 1; 581 } 582 namelen_sum += sfe->namelen; 583 sfe = XFS_DIR_SF_NEXTENTRY(sfe); 584 } 585 if (namelen_sum >= XFS_LITINO(mp)) { 586 xfs_fs_cmn_err(CE_WARN, mp, 587 "Invalid shortform namelen: dp 0x%p", dp); 588 return 1; 589 } 590 591 return 0; 592} 593 594/*======================================================================== 595 * External routines when dirsize == XFS_LBSIZE(dp->i_mount). 596 *========================================================================*/ 597 598/* 599 * Add a name to the leaf directory structure 600 * This is the external routine. 601 */ 602int 603xfs_dir_leaf_addname(xfs_da_args_t *args) 604{ 605 int index, retval; 606 xfs_dabuf_t *bp; 607 608 retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp, 609 XFS_DATA_FORK); 610 if (retval) 611 return(retval); 612 ASSERT(bp != NULL); 613 614 retval = xfs_dir_leaf_lookup_int(bp, args, &index); 615 if (retval == ENOENT) 616 retval = xfs_dir_leaf_add(bp, args, index); 617 xfs_da_buf_done(bp); 618 return(retval); 619} 620 621/* 622 * Remove a name from the leaf directory structure 623 * This is the external routine. 624 */ 625STATIC int 626xfs_dir_leaf_removename(xfs_da_args_t *args, int *count, int *totallen) 627{ 628 xfs_dir_leafblock_t *leaf; 629 int index, retval; 630 xfs_dabuf_t *bp; 631 632 retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp, 633 XFS_DATA_FORK); 634 if (retval) 635 return(retval); 636 ASSERT(bp != NULL); 637 leaf = bp->data; 638 ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC); 639 retval = xfs_dir_leaf_lookup_int(bp, args, &index); 640 if (retval == EEXIST) { 641 (void)xfs_dir_leaf_remove(args->trans, bp, index); 642 *count = INT_GET(leaf->hdr.count, ARCH_CONVERT); 643 *totallen = INT_GET(leaf->hdr.namebytes, ARCH_CONVERT); 644 retval = 0; 645 } 646 xfs_da_buf_done(bp); 647 return(retval); 648} 649 650/* 651 * Look up a name in a leaf directory structure. 652 * This is the external routine. 653 */ 654STATIC int 655xfs_dir_leaf_lookup(xfs_da_args_t *args) 656{ 657 int index, retval; 658 xfs_dabuf_t *bp; 659 660 retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp, 661 XFS_DATA_FORK); 662 if (retval) 663 return(retval); 664 ASSERT(bp != NULL); 665 retval = xfs_dir_leaf_lookup_int(bp, args, &index); 666 xfs_da_brelse(args->trans, bp); 667 return(retval); 668} 669 670/* 671 * Copy out directory entries for getdents(), for leaf directories. 672 */ 673STATIC int 674xfs_dir_leaf_getdents(xfs_trans_t *trans, xfs_inode_t *dp, uio_t *uio, 675 int *eofp, xfs_dirent_t *dbp, xfs_dir_put_t put) 676{ 677 xfs_dabuf_t *bp; 678 int retval, eob; 679 680 retval = xfs_da_read_buf(dp->i_transp, dp, 0, -1, &bp, XFS_DATA_FORK); 681 if (retval) 682 return(retval); 683 ASSERT(bp != NULL); 684 retval = xfs_dir_leaf_getdents_int(bp, dp, 0, uio, &eob, dbp, put, -1); 685 xfs_da_brelse(trans, bp); 686 *eofp = (eob == 0); 687 return(retval); 688} 689 690/* 691 * Look up a name in a leaf directory structure, replace the inode number. 692 * This is the external routine. 693 */ 694STATIC int 695xfs_dir_leaf_replace(xfs_da_args_t *args) 696{ 697 int index, retval; 698 xfs_dabuf_t *bp; 699 xfs_ino_t inum; 700 xfs_dir_leafblock_t *leaf; 701 xfs_dir_leaf_entry_t *entry; 702 xfs_dir_leaf_name_t *namest; 703 704 inum = args->inumber; 705 retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp, 706 XFS_DATA_FORK); 707 if (retval) 708 return(retval); 709 ASSERT(bp != NULL); 710 retval = xfs_dir_leaf_lookup_int(bp, args, &index); 711 if (retval == EEXIST) { 712 leaf = bp->data; 713 entry = &leaf->entries[index]; 714 namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); 715 /* XXX - replace assert? */ 716 XFS_DIR_SF_PUT_DIRINO(&inum, &namest->inumber); 717 xfs_da_log_buf(args->trans, bp, 718 XFS_DA_LOGRANGE(leaf, namest, sizeof(namest->inumber))); 719 xfs_da_buf_done(bp); 720 retval = 0; 721 } else 722 xfs_da_brelse(args->trans, bp); 723 return(retval); 724} 725 726 727/*======================================================================== 728 * External routines when dirsize > XFS_LBSIZE(mp). 729 *========================================================================*/ 730 731/* 732 * Add a name to a Btree-format directory. 733 * 734 * This will involve walking down the Btree, and may involve splitting 735 * leaf nodes and even splitting intermediate nodes up to and including 736 * the root node (a special case of an intermediate node). 737 */ 738STATIC int 739xfs_dir_node_addname(xfs_da_args_t *args) 740{ 741 xfs_da_state_t *state; 742 xfs_da_state_blk_t *blk; 743 int retval, error; 744 745 /* 746 * Fill in bucket of arguments/results/context to carry around. 747 */ 748 state = xfs_da_state_alloc(); 749 state->args = args; 750 state->mp = args->dp->i_mount; 751 state->blocksize = state->mp->m_sb.sb_blocksize; 752 state->node_ents = state->mp->m_dir_node_ents; 753 754 /* 755 * Search to see if name already exists, and get back a pointer 756 * to where it should go. 757 */ 758 error = xfs_da_node_lookup_int(state, &retval); 759 if (error) 760 retval = error; 761 if (retval != ENOENT) 762 goto error; 763 blk = &state->path.blk[ state->path.active-1 ]; 764 ASSERT(blk->magic == XFS_DIR_LEAF_MAGIC); 765 retval = xfs_dir_leaf_add(blk->bp, args, blk->index); 766 if (retval == 0) { 767 /* 768 * Addition succeeded, update Btree hashvals. 769 */ 770 if (!args->justcheck) 771 xfs_da_fixhashpath(state, &state->path); 772 } else { 773 /* 774 * Addition failed, split as many Btree elements as required. 775 */ 776 if (args->total == 0) { 777 ASSERT(retval == ENOSPC); 778 goto error; 779 } 780 retval = xfs_da_split(state); 781 } 782error: 783 xfs_da_state_free(state); 784 785 return(retval); 786} 787 788/* 789 * Remove a name from a B-tree directory. 790 * 791 * This will involve walking down the Btree, and may involve joining 792 * leaf nodes and even joining intermediate nodes up to and including 793 * the root node (a special case of an intermediate node). 794 */ 795STATIC int 796xfs_dir_node_removename(xfs_da_args_t *args) 797{ 798 xfs_da_state_t *state; 799 xfs_da_state_blk_t *blk; 800 int retval, error; 801 802 state = xfs_da_state_alloc(); 803 state->args = args; 804 state->mp = args->dp->i_mount; 805 state->blocksize = state->mp->m_sb.sb_blocksize; 806 state->node_ents = state->mp->m_dir_node_ents; 807 808 /* 809 * Search to see if name exists, and get back a pointer to it. 810 */ 811 error = xfs_da_node_lookup_int(state, &retval); 812 if (error) 813 retval = error; 814 if (retval != EEXIST) { 815 xfs_da_state_free(state); 816 return(retval); 817 } 818 819 /* 820 * Remove the name and update the hashvals in the tree. 821 */ 822 blk = &state->path.blk[ state->path.active-1 ]; 823 ASSERT(blk->magic == XFS_DIR_LEAF_MAGIC); 824 retval = xfs_dir_leaf_remove(args->trans, blk->bp, blk->index); 825 xfs_da_fixhashpath(state, &state->path); 826 827 /* 828 * Check to see if the tree needs to be collapsed. 829 */ 830 error = 0; 831 if (retval) { 832 error = xfs_da_join(state); 833 } 834 835 xfs_da_state_free(state); 836 if (error) 837 return(error); 838 return(0); 839} 840 841/* 842 * Look up a filename in a int directory. 843 * Use an internal routine to actually do all the work. 844 */ 845STATIC int 846xfs_dir_node_lookup(xfs_da_args_t *args) 847{ 848 xfs_da_state_t *state; 849 int retval, error, i; 850 851 state = xfs_da_state_alloc(); 852 state->args = args; 853 state->mp = args->dp->i_mount; 854 state->blocksize = state->mp->m_sb.sb_blocksize; 855 state->node_ents = state->mp->m_dir_node_ents; 856 857 /* 858 * Search to see if name exists, 859 * and get back a pointer to it. 860 */ 861 error = xfs_da_node_lookup_int(state, &retval); 862 if (error) { 863 retval = error; 864 } 865 866 /* 867 * If not in a transaction, we have to release all the buffers. 868 */ 869 for (i = 0; i < state->path.active; i++) { 870 xfs_da_brelse(args->trans, state->path.blk[i].bp); 871 state->path.blk[i].bp = NULL; 872 } 873 874 xfs_da_state_free(state); 875 return(retval); 876} 877 878STATIC int 879xfs_dir_node_getdents(xfs_trans_t *trans, xfs_inode_t *dp, uio_t *uio, 880 int *eofp, xfs_dirent_t *dbp, xfs_dir_put_t put) 881{ 882 xfs_da_intnode_t *node; 883 xfs_da_node_entry_t *btree; 884 xfs_dir_leafblock_t *leaf = NULL; 885 xfs_dablk_t bno, nextbno; 886 xfs_dahash_t cookhash; 887 xfs_mount_t *mp; 888 int error, eob, i; 889 xfs_dabuf_t *bp; 890 xfs_daddr_t nextda; 891 892 /* 893 * Pick up our context. 894 */ 895 mp = dp->i_mount; 896 bp = NULL; 897 bno = XFS_DA_COOKIE_BNO(mp, uio->uio_offset); 898 cookhash = XFS_DA_COOKIE_HASH(mp, uio->uio_offset); 899 900 xfs_dir_trace_g_du("node: start", dp, uio); 901 902 /* 903 * Re-find our place, even if we're confused about what our place is. 904 * 905 * First we check the block number from the magic cookie, it is a 906 * cache of where we ended last time. If we find a leaf block, and 907 * the starting hashval in that block is less than our desired 908 * hashval, then we run with it. 909 */ 910 if (bno > 0) { 911 error = xfs_da_read_buf(trans, dp, bno, -2, &bp, XFS_DATA_FORK); 912 if ((error != 0) && (error != EFSCORRUPTED)) 913 return(error); 914 if (bp) 915 leaf = bp->data; 916 if (bp && be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR_LEAF_MAGIC) { 917 xfs_dir_trace_g_dub("node: block not a leaf", 918 dp, uio, bno); 919 xfs_da_brelse(trans, bp); 920 bp = NULL; 921 } 922 if (bp && INT_GET(leaf->entries[0].hashval, ARCH_CONVERT) > cookhash) { 923 xfs_dir_trace_g_dub("node: leaf hash too large", 924 dp, uio, bno); 925 xfs_da_brelse(trans, bp); 926 bp = NULL; 927 } 928 if (bp && 929 cookhash > INT_GET(leaf->entries[INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT)) { 930 xfs_dir_trace_g_dub("node: leaf hash too small", 931 dp, uio, bno); 932 xfs_da_brelse(trans, bp); 933 bp = NULL; 934 } 935 } 936 937 /* 938 * If we did not find a leaf block from the blockno in the cookie, 939 * or we there was no blockno in the cookie (eg: first time thru), 940 * the we start at the top of the Btree and re-find our hashval. 941 */ 942 if (bp == NULL) { 943 xfs_dir_trace_g_du("node: start at root" , dp, uio); 944 bno = 0; 945 for (;;) { 946 error = xfs_da_read_buf(trans, dp, bno, -1, &bp, 947 XFS_DATA_FORK); 948 if (error) 949 return(error); 950 if (bp == NULL) 951 return(XFS_ERROR(EFSCORRUPTED)); 952 node = bp->data; 953 if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC) 954 break; 955 btree = &node->btree[0]; 956 xfs_dir_trace_g_dun("node: node detail", dp, uio, node); 957 for (i = 0; i < be16_to_cpu(node->hdr.count); btree++, i++) { 958 if (be32_to_cpu(btree->hashval) >= cookhash) { 959 bno = be32_to_cpu(btree->before); 960 break; 961 } 962 } 963 if (i == be16_to_cpu(node->hdr.count)) { 964 xfs_da_brelse(trans, bp); 965 xfs_dir_trace_g_du("node: hash beyond EOF", 966 dp, uio); 967 uio->uio_offset = XFS_DA_MAKE_COOKIE(mp, 0, 0, 968 XFS_DA_MAXHASH); 969 *eofp = 1; 970 return(0); 971 } 972 xfs_dir_trace_g_dub("node: going to block", 973 dp, uio, bno); 974 xfs_da_brelse(trans, bp); 975 } 976 } 977 ASSERT(cookhash != XFS_DA_MAXHASH); 978 979 /* 980 * We've dropped down to the (first) leaf block that contains the 981 * hashval we are interested in. Continue rolling upward thru the 982 * leaf blocks until we fill up our buffer. 983 */ 984 for (;;) { 985 leaf = bp->data; 986 if (unlikely(be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR_LEAF_MAGIC)) { 987 xfs_dir_trace_g_dul("node: not a leaf", dp, uio, leaf); 988 xfs_da_brelse(trans, bp); 989 XFS_CORRUPTION_ERROR("xfs_dir_node_getdents(1)", 990 XFS_ERRLEVEL_LOW, mp, leaf); 991 return XFS_ERROR(EFSCORRUPTED); 992 } 993 xfs_dir_trace_g_dul("node: leaf detail", dp, uio, leaf); 994 if ((nextbno = be32_to_cpu(leaf->hdr.info.forw))) { 995 nextda = xfs_da_reada_buf(trans, dp, nextbno, 996 XFS_DATA_FORK); 997 } else 998 nextda = -1; 999 error = xfs_dir_leaf_getdents_int(bp, dp, bno, uio, &eob, dbp, 1000 put, nextda); 1001 xfs_da_brelse(trans, bp); 1002 bno = nextbno; 1003 if (eob) { 1004 xfs_dir_trace_g_dub("node: E-O-B", dp, uio, bno); 1005 *eofp = 0; 1006 return(error); 1007 } 1008 if (bno == 0) 1009 break; 1010 error = xfs_da_read_buf(trans, dp, bno, nextda, &bp, 1011 XFS_DATA_FORK); 1012 if (error) 1013 return(error); 1014 if (unlikely(bp == NULL)) { 1015 XFS_ERROR_REPORT("xfs_dir_node_getdents(2)", 1016 XFS_ERRLEVEL_LOW, mp); 1017 return(XFS_ERROR(EFSCORRUPTED)); 1018 } 1019 } 1020 *eofp = 1; 1021 xfs_dir_trace_g_du("node: E-O-F", dp, uio); 1022 return(0); 1023} 1024 1025/* 1026 * Look up a filename in an int directory, replace the inode number. 1027 * Use an internal routine to actually do the lookup. 1028 */ 1029STATIC int 1030xfs_dir_node_replace(xfs_da_args_t *args) 1031{ 1032 xfs_da_state_t *state; 1033 xfs_da_state_blk_t *blk; 1034 xfs_dir_leafblock_t *leaf; 1035 xfs_dir_leaf_entry_t *entry; 1036 xfs_dir_leaf_name_t *namest; 1037 xfs_ino_t inum; 1038 int retval, error, i; 1039 xfs_dabuf_t *bp; 1040 1041 state = xfs_da_state_alloc(); 1042 state->args = args; 1043 state->mp = args->dp->i_mount; 1044 state->blocksize = state->mp->m_sb.sb_blocksize; 1045 state->node_ents = state->mp->m_dir_node_ents; 1046 inum = args->inumber; 1047 1048 /* 1049 * Search to see if name exists, 1050 * and get back a pointer to it. 1051 */ 1052 error = xfs_da_node_lookup_int(state, &retval); 1053 if (error) { 1054 retval = error; 1055 } 1056 1057 if (retval == EEXIST) { 1058 blk = &state->path.blk[state->path.active - 1]; 1059 ASSERT(blk->magic == XFS_DIR_LEAF_MAGIC); 1060 bp = blk->bp; 1061 leaf = bp->data; 1062 entry = &leaf->entries[blk->index]; 1063 namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); 1064 /* XXX - replace assert ? */ 1065 XFS_DIR_SF_PUT_DIRINO(&inum, &namest->inumber); 1066 xfs_da_log_buf(args->trans, bp, 1067 XFS_DA_LOGRANGE(leaf, namest, sizeof(namest->inumber))); 1068 xfs_da_buf_done(bp); 1069 blk->bp = NULL; 1070 retval = 0; 1071 } else { 1072 i = state->path.active - 1; 1073 xfs_da_brelse(args->trans, state->path.blk[i].bp); 1074 state->path.blk[i].bp = NULL; 1075 } 1076 for (i = 0; i < state->path.active - 1; i++) { 1077 xfs_da_brelse(args->trans, state->path.blk[i].bp); 1078 state->path.blk[i].bp = NULL; 1079 } 1080 1081 xfs_da_state_free(state); 1082 return(retval); 1083} 1084 1085#if defined(XFS_DIR_TRACE) 1086/* 1087 * Add a trace buffer entry for an inode and a uio. 1088 */ 1089void 1090xfs_dir_trace_g_du(char *where, xfs_inode_t *dp, uio_t *uio) 1091{ 1092 xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DU, where, 1093 (void *)dp, (void *)dp->i_mount, 1094 (void *)((unsigned long)(uio->uio_offset >> 32)), 1095 (void *)((unsigned long)(uio->uio_offset & 0xFFFFFFFF)), 1096 (void *)(unsigned long)uio->uio_resid, 1097 NULL, NULL, NULL, NULL, NULL, NULL, NULL); 1098} 1099 1100/* 1101 * Add a trace buffer entry for an inode and a uio. 1102 */ 1103void 1104xfs_dir_trace_g_dub(char *where, xfs_inode_t *dp, uio_t *uio, xfs_dablk_t bno) 1105{ 1106 xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUB, where, 1107 (void *)dp, (void *)dp->i_mount, 1108 (void *)((unsigned long)(uio->uio_offset >> 32)), 1109 (void *)((unsigned long)(uio->uio_offset & 0xFFFFFFFF)), 1110 (void *)(unsigned long)uio->uio_resid, 1111 (void *)(unsigned long)bno, 1112 NULL, NULL, NULL, NULL, NULL, NULL); 1113} 1114 1115/* 1116 * Add a trace buffer entry for an inode and a uio. 1117 */ 1118void 1119xfs_dir_trace_g_dun(char *where, xfs_inode_t *dp, uio_t *uio, 1120 xfs_da_intnode_t *node) 1121{ 1122 int last = be16_to_cpu(node->hdr.count) - 1; 1123 1124 xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUN, where, 1125 (void *)dp, (void *)dp->i_mount, 1126 (void *)((unsigned long)(uio->uio_offset >> 32)), 1127 (void *)((unsigned long)(uio->uio_offset & 0xFFFFFFFF)), 1128 (void *)(unsigned long)uio->uio_resid, 1129 (void *)(unsigned long)be32_to_cpu(node->hdr.info.forw), 1130 (void *)(unsigned long) 1131 be16_to_cpu(node->hdr.count), 1132 (void *)(unsigned long) 1133 be32_to_cpu(node->btree[0].hashval), 1134 (void *)(unsigned long) 1135 be32_to_cpu(node->btree[last].hashval), 1136 NULL, NULL, NULL); 1137} 1138 1139/* 1140 * Add a trace buffer entry for an inode and a uio. 1141 */ 1142void 1143xfs_dir_trace_g_dul(char *where, xfs_inode_t *dp, uio_t *uio, 1144 xfs_dir_leafblock_t *leaf) 1145{ 1146 int last = INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1; 1147 1148 xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUL, where, 1149 (void *)dp, (void *)dp->i_mount, 1150 (void *)((unsigned long)(uio->uio_offset >> 32)), 1151 (void *)((unsigned long)(uio->uio_offset & 0xFFFFFFFF)), 1152 (void *)(unsigned long)uio->uio_resid, 1153 (void *)(unsigned long)be32_to_cpu(leaf->hdr.info.forw), 1154 (void *)(unsigned long) 1155 INT_GET(leaf->hdr.count, ARCH_CONVERT), 1156 (void *)(unsigned long) 1157 INT_GET(leaf->entries[0].hashval, ARCH_CONVERT), 1158 (void *)(unsigned long) 1159 INT_GET(leaf->entries[last].hashval, ARCH_CONVERT), 1160 NULL, NULL, NULL); 1161} 1162 1163/* 1164 * Add a trace buffer entry for an inode and a uio. 1165 */ 1166void 1167xfs_dir_trace_g_due(char *where, xfs_inode_t *dp, uio_t *uio, 1168 xfs_dir_leaf_entry_t *entry) 1169{ 1170 xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUE, where, 1171 (void *)dp, (void *)dp->i_mount, 1172 (void *)((unsigned long)(uio->uio_offset >> 32)), 1173 (void *)((unsigned long)(uio->uio_offset & 0xFFFFFFFF)), 1174 (void *)(unsigned long)uio->uio_resid, 1175 (void *)(unsigned long) 1176 INT_GET(entry->hashval, ARCH_CONVERT), 1177 NULL, NULL, NULL, NULL, NULL, NULL); 1178} 1179 1180/* 1181 * Add a trace buffer entry for an inode and a uio. 1182 */ 1183void 1184xfs_dir_trace_g_duc(char *where, xfs_inode_t *dp, uio_t *uio, xfs_off_t cookie) 1185{ 1186 xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUC, where, 1187 (void *)dp, (void *)dp->i_mount, 1188 (void *)((unsigned long)(uio->uio_offset >> 32)), 1189 (void *)((unsigned long)(uio->uio_offset & 0xFFFFFFFF)), 1190 (void *)(unsigned long)uio->uio_resid, 1191 (void *)((unsigned long)(cookie >> 32)), 1192 (void *)((unsigned long)(cookie & 0xFFFFFFFF)), 1193 NULL, NULL, NULL, NULL, NULL); 1194} 1195 1196/* 1197 * Add a trace buffer entry for the arguments given to the routine, 1198 * generic form. 1199 */ 1200void 1201xfs_dir_trace_enter(int type, char *where, 1202 void * a0, void * a1, 1203 void * a2, void * a3, 1204 void * a4, void * a5, 1205 void * a6, void * a7, 1206 void * a8, void * a9, 1207 void * a10, void * a11) 1208{ 1209 ASSERT(xfs_dir_trace_buf); 1210 ktrace_enter(xfs_dir_trace_buf, (void *)(unsigned long)type, 1211 (void *)where, 1212 (void *)a0, (void *)a1, (void *)a2, 1213 (void *)a3, (void *)a4, (void *)a5, 1214 (void *)a6, (void *)a7, (void *)a8, 1215 (void *)a9, (void *)a10, (void *)a11, 1216 NULL, NULL); 1217} 1218#endif /* XFS_DIR_TRACE */ 1219