1 /* 2 * Copyright (c) 2000-2003,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_format.h" 21 #include "xfs_log_format.h" 22 #include "xfs_trans_resv.h" 23 #include "xfs_sb.h" 24 #include "xfs_ag.h" 25 #include "xfs_mount.h" 26 #include "xfs_da_format.h" 27 #include "xfs_da_btree.h" 28 #include "xfs_inode.h" 29 #include "xfs_trans.h" 30 #include "xfs_inode_item.h" 31 #include "xfs_error.h" 32 #include "xfs_dir2.h" 33 #include "xfs_dir2_priv.h" 34 #include "xfs_trace.h" 35 #include "xfs_dinode.h" 36 37 /* 38 * Prototypes for internal functions. 39 */ 40 static void xfs_dir2_sf_addname_easy(xfs_da_args_t *args, 41 xfs_dir2_sf_entry_t *sfep, 42 xfs_dir2_data_aoff_t offset, 43 int new_isize); 44 static void xfs_dir2_sf_addname_hard(xfs_da_args_t *args, int objchange, 45 int new_isize); 46 static int xfs_dir2_sf_addname_pick(xfs_da_args_t *args, int objchange, 47 xfs_dir2_sf_entry_t **sfepp, 48 xfs_dir2_data_aoff_t *offsetp); 49 #ifdef DEBUG 50 static void xfs_dir2_sf_check(xfs_da_args_t *args); 51 #else 52 #define xfs_dir2_sf_check(args) 53 #endif /* DEBUG */ 54 55 static void xfs_dir2_sf_toino4(xfs_da_args_t *args); 56 static void xfs_dir2_sf_toino8(xfs_da_args_t *args); 57 58 /* 59 * Given a block directory (dp/block), calculate its size as a shortform (sf) 60 * directory and a header for the sf directory, if it will fit it the 61 * space currently present in the inode. If it won't fit, the output 62 * size is too big (but not accurate). 63 */ 64 int /* size for sf form */ 65 xfs_dir2_block_sfsize( 66 xfs_inode_t *dp, /* incore inode pointer */ 67 xfs_dir2_data_hdr_t *hdr, /* block directory data */ 68 xfs_dir2_sf_hdr_t *sfhp) /* output: header for sf form */ 69 { 70 xfs_dir2_dataptr_t addr; /* data entry address */ 71 xfs_dir2_leaf_entry_t *blp; /* leaf area of the block */ 72 xfs_dir2_block_tail_t *btp; /* tail area of the block */ 73 int count; /* shortform entry count */ 74 xfs_dir2_data_entry_t *dep; /* data entry in the block */ 75 int i; /* block entry index */ 76 int i8count; /* count of big-inode entries */ 77 int isdot; /* entry is "." */ 78 int isdotdot; /* entry is ".." */ 79 xfs_mount_t *mp; /* mount structure pointer */ 80 int namelen; /* total name bytes */ 81 xfs_ino_t parent = 0; /* parent inode number */ 82 int size=0; /* total computed size */ 83 int has_ftype; 84 struct xfs_da_geometry *geo; 85 86 mp = dp->i_mount; 87 geo = mp->m_dir_geo; 88 89 /* 90 * if there is a filetype field, add the extra byte to the namelen 91 * for each entry that we see. 92 */ 93 has_ftype = xfs_sb_version_hasftype(&mp->m_sb) ? 1 : 0; 94 95 count = i8count = namelen = 0; 96 btp = xfs_dir2_block_tail_p(geo, hdr); 97 blp = xfs_dir2_block_leaf_p(btp); 98 99 /* 100 * Iterate over the block's data entries by using the leaf pointers. 101 */ 102 for (i = 0; i < be32_to_cpu(btp->count); i++) { 103 if ((addr = be32_to_cpu(blp[i].address)) == XFS_DIR2_NULL_DATAPTR) 104 continue; 105 /* 106 * Calculate the pointer to the entry at hand. 107 */ 108 dep = (xfs_dir2_data_entry_t *)((char *)hdr + 109 xfs_dir2_dataptr_to_off(geo, addr)); 110 /* 111 * Detect . and .., so we can special-case them. 112 * . is not included in sf directories. 113 * .. is included by just the parent inode number. 114 */ 115 isdot = dep->namelen == 1 && dep->name[0] == '.'; 116 isdotdot = 117 dep->namelen == 2 && 118 dep->name[0] == '.' && dep->name[1] == '.'; 119 120 if (!isdot) 121 i8count += be64_to_cpu(dep->inumber) > XFS_DIR2_MAX_SHORT_INUM; 122 123 /* take into account the file type field */ 124 if (!isdot && !isdotdot) { 125 count++; 126 namelen += dep->namelen + has_ftype; 127 } else if (isdotdot) 128 parent = be64_to_cpu(dep->inumber); 129 /* 130 * Calculate the new size, see if we should give up yet. 131 */ 132 size = xfs_dir2_sf_hdr_size(i8count) + /* header */ 133 count + /* namelen */ 134 count * (uint)sizeof(xfs_dir2_sf_off_t) + /* offset */ 135 namelen + /* name */ 136 (i8count ? /* inumber */ 137 (uint)sizeof(xfs_dir2_ino8_t) * count : 138 (uint)sizeof(xfs_dir2_ino4_t) * count); 139 if (size > XFS_IFORK_DSIZE(dp)) 140 return size; /* size value is a failure */ 141 } 142 /* 143 * Create the output header, if it worked. 144 */ 145 sfhp->count = count; 146 sfhp->i8count = i8count; 147 dp->d_ops->sf_put_parent_ino(sfhp, parent); 148 return size; 149 } 150 151 /* 152 * Convert a block format directory to shortform. 153 * Caller has already checked that it will fit, and built us a header. 154 */ 155 int /* error */ 156 xfs_dir2_block_to_sf( 157 xfs_da_args_t *args, /* operation arguments */ 158 struct xfs_buf *bp, 159 int size, /* shortform directory size */ 160 xfs_dir2_sf_hdr_t *sfhp) /* shortform directory hdr */ 161 { 162 xfs_dir2_data_hdr_t *hdr; /* block header */ 163 xfs_dir2_block_tail_t *btp; /* block tail pointer */ 164 xfs_dir2_data_entry_t *dep; /* data entry pointer */ 165 xfs_inode_t *dp; /* incore directory inode */ 166 xfs_dir2_data_unused_t *dup; /* unused data pointer */ 167 char *endptr; /* end of data entries */ 168 int error; /* error return value */ 169 int logflags; /* inode logging flags */ 170 xfs_mount_t *mp; /* filesystem mount point */ 171 char *ptr; /* current data pointer */ 172 xfs_dir2_sf_entry_t *sfep; /* shortform entry */ 173 xfs_dir2_sf_hdr_t *sfp; /* shortform directory header */ 174 xfs_dir2_sf_hdr_t *dst; /* temporary data buffer */ 175 176 trace_xfs_dir2_block_to_sf(args); 177 178 dp = args->dp; 179 mp = dp->i_mount; 180 181 /* 182 * allocate a temporary destination buffer the size of the inode 183 * to format the data into. Once we have formatted the data, we 184 * can free the block and copy the formatted data into the inode literal 185 * area. 186 */ 187 dst = kmem_alloc(mp->m_sb.sb_inodesize, KM_SLEEP); 188 hdr = bp->b_addr; 189 190 /* 191 * Copy the header into the newly allocate local space. 192 */ 193 sfp = (xfs_dir2_sf_hdr_t *)dst; 194 memcpy(sfp, sfhp, xfs_dir2_sf_hdr_size(sfhp->i8count)); 195 196 /* 197 * Set up to loop over the block's entries. 198 */ 199 btp = xfs_dir2_block_tail_p(args->geo, hdr); 200 ptr = (char *)dp->d_ops->data_entry_p(hdr); 201 endptr = (char *)xfs_dir2_block_leaf_p(btp); 202 sfep = xfs_dir2_sf_firstentry(sfp); 203 /* 204 * Loop over the active and unused entries. 205 * Stop when we reach the leaf/tail portion of the block. 206 */ 207 while (ptr < endptr) { 208 /* 209 * If it's unused, just skip over it. 210 */ 211 dup = (xfs_dir2_data_unused_t *)ptr; 212 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { 213 ptr += be16_to_cpu(dup->length); 214 continue; 215 } 216 dep = (xfs_dir2_data_entry_t *)ptr; 217 /* 218 * Skip . 219 */ 220 if (dep->namelen == 1 && dep->name[0] == '.') 221 ASSERT(be64_to_cpu(dep->inumber) == dp->i_ino); 222 /* 223 * Skip .., but make sure the inode number is right. 224 */ 225 else if (dep->namelen == 2 && 226 dep->name[0] == '.' && dep->name[1] == '.') 227 ASSERT(be64_to_cpu(dep->inumber) == 228 dp->d_ops->sf_get_parent_ino(sfp)); 229 /* 230 * Normal entry, copy it into shortform. 231 */ 232 else { 233 sfep->namelen = dep->namelen; 234 xfs_dir2_sf_put_offset(sfep, 235 (xfs_dir2_data_aoff_t) 236 ((char *)dep - (char *)hdr)); 237 memcpy(sfep->name, dep->name, dep->namelen); 238 dp->d_ops->sf_put_ino(sfp, sfep, 239 be64_to_cpu(dep->inumber)); 240 dp->d_ops->sf_put_ftype(sfep, 241 dp->d_ops->data_get_ftype(dep)); 242 243 sfep = dp->d_ops->sf_nextentry(sfp, sfep); 244 } 245 ptr += dp->d_ops->data_entsize(dep->namelen); 246 } 247 ASSERT((char *)sfep - (char *)sfp == size); 248 249 /* now we are done with the block, we can shrink the inode */ 250 logflags = XFS_ILOG_CORE; 251 error = xfs_dir2_shrink_inode(args, args->geo->datablk, bp); 252 if (error) { 253 ASSERT(error != -ENOSPC); 254 goto out; 255 } 256 257 /* 258 * The buffer is now unconditionally gone, whether 259 * xfs_dir2_shrink_inode worked or not. 260 * 261 * Convert the inode to local format and copy the data in. 262 */ 263 dp->i_df.if_flags &= ~XFS_IFEXTENTS; 264 dp->i_df.if_flags |= XFS_IFINLINE; 265 dp->i_d.di_format = XFS_DINODE_FMT_LOCAL; 266 ASSERT(dp->i_df.if_bytes == 0); 267 xfs_idata_realloc(dp, size, XFS_DATA_FORK); 268 269 logflags |= XFS_ILOG_DDATA; 270 memcpy(dp->i_df.if_u1.if_data, dst, size); 271 dp->i_d.di_size = size; 272 xfs_dir2_sf_check(args); 273 out: 274 xfs_trans_log_inode(args->trans, dp, logflags); 275 kmem_free(dst); 276 return error; 277 } 278 279 /* 280 * Add a name to a shortform directory. 281 * There are two algorithms, "easy" and "hard" which we decide on 282 * before changing anything. 283 * Convert to block form if necessary, if the new entry won't fit. 284 */ 285 int /* error */ 286 xfs_dir2_sf_addname( 287 xfs_da_args_t *args) /* operation arguments */ 288 { 289 xfs_inode_t *dp; /* incore directory inode */ 290 int error; /* error return value */ 291 int incr_isize; /* total change in size */ 292 int new_isize; /* di_size after adding name */ 293 int objchange; /* changing to 8-byte inodes */ 294 xfs_dir2_data_aoff_t offset = 0; /* offset for new entry */ 295 int pick; /* which algorithm to use */ 296 xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ 297 xfs_dir2_sf_entry_t *sfep = NULL; /* shortform entry */ 298 299 trace_xfs_dir2_sf_addname(args); 300 301 ASSERT(xfs_dir2_sf_lookup(args) == -ENOENT); 302 dp = args->dp; 303 ASSERT(dp->i_df.if_flags & XFS_IFINLINE); 304 /* 305 * Make sure the shortform value has some of its header. 306 */ 307 if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { 308 ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); 309 return -EIO; 310 } 311 ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); 312 ASSERT(dp->i_df.if_u1.if_data != NULL); 313 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 314 ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->i8count)); 315 /* 316 * Compute entry (and change in) size. 317 */ 318 incr_isize = dp->d_ops->sf_entsize(sfp, args->namelen); 319 objchange = 0; 320 321 /* 322 * Do we have to change to 8 byte inodes? 323 */ 324 if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->i8count == 0) { 325 /* 326 * Yes, adjust the inode size. old count + (parent + new) 327 */ 328 incr_isize += 329 (sfp->count + 2) * 330 ((uint)sizeof(xfs_dir2_ino8_t) - 331 (uint)sizeof(xfs_dir2_ino4_t)); 332 objchange = 1; 333 } 334 335 new_isize = (int)dp->i_d.di_size + incr_isize; 336 /* 337 * Won't fit as shortform any more (due to size), 338 * or the pick routine says it won't (due to offset values). 339 */ 340 if (new_isize > XFS_IFORK_DSIZE(dp) || 341 (pick = 342 xfs_dir2_sf_addname_pick(args, objchange, &sfep, &offset)) == 0) { 343 /* 344 * Just checking or no space reservation, it doesn't fit. 345 */ 346 if ((args->op_flags & XFS_DA_OP_JUSTCHECK) || args->total == 0) 347 return -ENOSPC; 348 /* 349 * Convert to block form then add the name. 350 */ 351 error = xfs_dir2_sf_to_block(args); 352 if (error) 353 return error; 354 return xfs_dir2_block_addname(args); 355 } 356 /* 357 * Just checking, it fits. 358 */ 359 if (args->op_flags & XFS_DA_OP_JUSTCHECK) 360 return 0; 361 /* 362 * Do it the easy way - just add it at the end. 363 */ 364 if (pick == 1) 365 xfs_dir2_sf_addname_easy(args, sfep, offset, new_isize); 366 /* 367 * Do it the hard way - look for a place to insert the new entry. 368 * Convert to 8 byte inode numbers first if necessary. 369 */ 370 else { 371 ASSERT(pick == 2); 372 if (objchange) 373 xfs_dir2_sf_toino8(args); 374 xfs_dir2_sf_addname_hard(args, objchange, new_isize); 375 } 376 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); 377 return 0; 378 } 379 380 /* 381 * Add the new entry the "easy" way. 382 * This is copying the old directory and adding the new entry at the end. 383 * Since it's sorted by "offset" we need room after the last offset 384 * that's already there, and then room to convert to a block directory. 385 * This is already checked by the pick routine. 386 */ 387 static void 388 xfs_dir2_sf_addname_easy( 389 xfs_da_args_t *args, /* operation arguments */ 390 xfs_dir2_sf_entry_t *sfep, /* pointer to new entry */ 391 xfs_dir2_data_aoff_t offset, /* offset to use for new ent */ 392 int new_isize) /* new directory size */ 393 { 394 int byteoff; /* byte offset in sf dir */ 395 xfs_inode_t *dp; /* incore directory inode */ 396 xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ 397 398 dp = args->dp; 399 400 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 401 byteoff = (int)((char *)sfep - (char *)sfp); 402 /* 403 * Grow the in-inode space. 404 */ 405 xfs_idata_realloc(dp, dp->d_ops->sf_entsize(sfp, args->namelen), 406 XFS_DATA_FORK); 407 /* 408 * Need to set up again due to realloc of the inode data. 409 */ 410 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 411 sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + byteoff); 412 /* 413 * Fill in the new entry. 414 */ 415 sfep->namelen = args->namelen; 416 xfs_dir2_sf_put_offset(sfep, offset); 417 memcpy(sfep->name, args->name, sfep->namelen); 418 dp->d_ops->sf_put_ino(sfp, sfep, args->inumber); 419 dp->d_ops->sf_put_ftype(sfep, args->filetype); 420 421 /* 422 * Update the header and inode. 423 */ 424 sfp->count++; 425 if (args->inumber > XFS_DIR2_MAX_SHORT_INUM) 426 sfp->i8count++; 427 dp->i_d.di_size = new_isize; 428 xfs_dir2_sf_check(args); 429 } 430 431 /* 432 * Add the new entry the "hard" way. 433 * The caller has already converted to 8 byte inode numbers if necessary, 434 * in which case we need to leave the i8count at 1. 435 * Find a hole that the new entry will fit into, and copy 436 * the first part of the entries, the new entry, and the last part of 437 * the entries. 438 */ 439 /* ARGSUSED */ 440 static void 441 xfs_dir2_sf_addname_hard( 442 xfs_da_args_t *args, /* operation arguments */ 443 int objchange, /* changing inode number size */ 444 int new_isize) /* new directory size */ 445 { 446 int add_datasize; /* data size need for new ent */ 447 char *buf; /* buffer for old */ 448 xfs_inode_t *dp; /* incore directory inode */ 449 int eof; /* reached end of old dir */ 450 int nbytes; /* temp for byte copies */ 451 xfs_dir2_data_aoff_t new_offset; /* next offset value */ 452 xfs_dir2_data_aoff_t offset; /* current offset value */ 453 int old_isize; /* previous di_size */ 454 xfs_dir2_sf_entry_t *oldsfep; /* entry in original dir */ 455 xfs_dir2_sf_hdr_t *oldsfp; /* original shortform dir */ 456 xfs_dir2_sf_entry_t *sfep; /* entry in new dir */ 457 xfs_dir2_sf_hdr_t *sfp; /* new shortform dir */ 458 struct xfs_mount *mp; 459 460 /* 461 * Copy the old directory to the stack buffer. 462 */ 463 dp = args->dp; 464 mp = dp->i_mount; 465 466 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 467 old_isize = (int)dp->i_d.di_size; 468 buf = kmem_alloc(old_isize, KM_SLEEP); 469 oldsfp = (xfs_dir2_sf_hdr_t *)buf; 470 memcpy(oldsfp, sfp, old_isize); 471 /* 472 * Loop over the old directory finding the place we're going 473 * to insert the new entry. 474 * If it's going to end up at the end then oldsfep will point there. 475 */ 476 for (offset = dp->d_ops->data_first_offset, 477 oldsfep = xfs_dir2_sf_firstentry(oldsfp), 478 add_datasize = dp->d_ops->data_entsize(args->namelen), 479 eof = (char *)oldsfep == &buf[old_isize]; 480 !eof; 481 offset = new_offset + dp->d_ops->data_entsize(oldsfep->namelen), 482 oldsfep = dp->d_ops->sf_nextentry(oldsfp, oldsfep), 483 eof = (char *)oldsfep == &buf[old_isize]) { 484 new_offset = xfs_dir2_sf_get_offset(oldsfep); 485 if (offset + add_datasize <= new_offset) 486 break; 487 } 488 /* 489 * Get rid of the old directory, then allocate space for 490 * the new one. We do this so xfs_idata_realloc won't copy 491 * the data. 492 */ 493 xfs_idata_realloc(dp, -old_isize, XFS_DATA_FORK); 494 xfs_idata_realloc(dp, new_isize, XFS_DATA_FORK); 495 /* 496 * Reset the pointer since the buffer was reallocated. 497 */ 498 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 499 /* 500 * Copy the first part of the directory, including the header. 501 */ 502 nbytes = (int)((char *)oldsfep - (char *)oldsfp); 503 memcpy(sfp, oldsfp, nbytes); 504 sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + nbytes); 505 /* 506 * Fill in the new entry, and update the header counts. 507 */ 508 sfep->namelen = args->namelen; 509 xfs_dir2_sf_put_offset(sfep, offset); 510 memcpy(sfep->name, args->name, sfep->namelen); 511 dp->d_ops->sf_put_ino(sfp, sfep, args->inumber); 512 dp->d_ops->sf_put_ftype(sfep, args->filetype); 513 sfp->count++; 514 if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && !objchange) 515 sfp->i8count++; 516 /* 517 * If there's more left to copy, do that. 518 */ 519 if (!eof) { 520 sfep = dp->d_ops->sf_nextentry(sfp, sfep); 521 memcpy(sfep, oldsfep, old_isize - nbytes); 522 } 523 kmem_free(buf); 524 dp->i_d.di_size = new_isize; 525 xfs_dir2_sf_check(args); 526 } 527 528 /* 529 * Decide if the new entry will fit at all. 530 * If it will fit, pick between adding the new entry to the end (easy) 531 * or somewhere else (hard). 532 * Return 0 (won't fit), 1 (easy), 2 (hard). 533 */ 534 /*ARGSUSED*/ 535 static int /* pick result */ 536 xfs_dir2_sf_addname_pick( 537 xfs_da_args_t *args, /* operation arguments */ 538 int objchange, /* inode # size changes */ 539 xfs_dir2_sf_entry_t **sfepp, /* out(1): new entry ptr */ 540 xfs_dir2_data_aoff_t *offsetp) /* out(1): new offset */ 541 { 542 xfs_inode_t *dp; /* incore directory inode */ 543 int holefit; /* found hole it will fit in */ 544 int i; /* entry number */ 545 xfs_mount_t *mp; /* filesystem mount point */ 546 xfs_dir2_data_aoff_t offset; /* data block offset */ 547 xfs_dir2_sf_entry_t *sfep; /* shortform entry */ 548 xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ 549 int size; /* entry's data size */ 550 int used; /* data bytes used */ 551 552 dp = args->dp; 553 mp = dp->i_mount; 554 555 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 556 size = dp->d_ops->data_entsize(args->namelen); 557 offset = dp->d_ops->data_first_offset; 558 sfep = xfs_dir2_sf_firstentry(sfp); 559 holefit = 0; 560 /* 561 * Loop over sf entries. 562 * Keep track of data offset and whether we've seen a place 563 * to insert the new entry. 564 */ 565 for (i = 0; i < sfp->count; i++) { 566 if (!holefit) 567 holefit = offset + size <= xfs_dir2_sf_get_offset(sfep); 568 offset = xfs_dir2_sf_get_offset(sfep) + 569 dp->d_ops->data_entsize(sfep->namelen); 570 sfep = dp->d_ops->sf_nextentry(sfp, sfep); 571 } 572 /* 573 * Calculate data bytes used excluding the new entry, if this 574 * was a data block (block form directory). 575 */ 576 used = offset + 577 (sfp->count + 3) * (uint)sizeof(xfs_dir2_leaf_entry_t) + 578 (uint)sizeof(xfs_dir2_block_tail_t); 579 /* 580 * If it won't fit in a block form then we can't insert it, 581 * we'll go back, convert to block, then try the insert and convert 582 * to leaf. 583 */ 584 if (used + (holefit ? 0 : size) > args->geo->blksize) 585 return 0; 586 /* 587 * If changing the inode number size, do it the hard way. 588 */ 589 if (objchange) 590 return 2; 591 /* 592 * If it won't fit at the end then do it the hard way (use the hole). 593 */ 594 if (used + size > args->geo->blksize) 595 return 2; 596 /* 597 * Do it the easy way. 598 */ 599 *sfepp = sfep; 600 *offsetp = offset; 601 return 1; 602 } 603 604 #ifdef DEBUG 605 /* 606 * Check consistency of shortform directory, assert if bad. 607 */ 608 static void 609 xfs_dir2_sf_check( 610 xfs_da_args_t *args) /* operation arguments */ 611 { 612 xfs_inode_t *dp; /* incore directory inode */ 613 int i; /* entry number */ 614 int i8count; /* number of big inode#s */ 615 xfs_ino_t ino; /* entry inode number */ 616 int offset; /* data offset */ 617 xfs_dir2_sf_entry_t *sfep; /* shortform dir entry */ 618 xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ 619 struct xfs_mount *mp; 620 621 dp = args->dp; 622 mp = dp->i_mount; 623 624 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 625 offset = dp->d_ops->data_first_offset; 626 ino = dp->d_ops->sf_get_parent_ino(sfp); 627 i8count = ino > XFS_DIR2_MAX_SHORT_INUM; 628 629 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); 630 i < sfp->count; 631 i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) { 632 ASSERT(xfs_dir2_sf_get_offset(sfep) >= offset); 633 ino = dp->d_ops->sf_get_ino(sfp, sfep); 634 i8count += ino > XFS_DIR2_MAX_SHORT_INUM; 635 offset = 636 xfs_dir2_sf_get_offset(sfep) + 637 dp->d_ops->data_entsize(sfep->namelen); 638 ASSERT(dp->d_ops->sf_get_ftype(sfep) < XFS_DIR3_FT_MAX); 639 } 640 ASSERT(i8count == sfp->i8count); 641 ASSERT((char *)sfep - (char *)sfp == dp->i_d.di_size); 642 ASSERT(offset + 643 (sfp->count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) + 644 (uint)sizeof(xfs_dir2_block_tail_t) <= args->geo->blksize); 645 } 646 #endif /* DEBUG */ 647 648 /* 649 * Create a new (shortform) directory. 650 */ 651 int /* error, always 0 */ 652 xfs_dir2_sf_create( 653 xfs_da_args_t *args, /* operation arguments */ 654 xfs_ino_t pino) /* parent inode number */ 655 { 656 xfs_inode_t *dp; /* incore directory inode */ 657 int i8count; /* parent inode is an 8-byte number */ 658 xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ 659 int size; /* directory size */ 660 661 trace_xfs_dir2_sf_create(args); 662 663 dp = args->dp; 664 665 ASSERT(dp != NULL); 666 ASSERT(dp->i_d.di_size == 0); 667 /* 668 * If it's currently a zero-length extent file, 669 * convert it to local format. 670 */ 671 if (dp->i_d.di_format == XFS_DINODE_FMT_EXTENTS) { 672 dp->i_df.if_flags &= ~XFS_IFEXTENTS; /* just in case */ 673 dp->i_d.di_format = XFS_DINODE_FMT_LOCAL; 674 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE); 675 dp->i_df.if_flags |= XFS_IFINLINE; 676 } 677 ASSERT(dp->i_df.if_flags & XFS_IFINLINE); 678 ASSERT(dp->i_df.if_bytes == 0); 679 i8count = pino > XFS_DIR2_MAX_SHORT_INUM; 680 size = xfs_dir2_sf_hdr_size(i8count); 681 /* 682 * Make a buffer for the data. 683 */ 684 xfs_idata_realloc(dp, size, XFS_DATA_FORK); 685 /* 686 * Fill in the header, 687 */ 688 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 689 sfp->i8count = i8count; 690 /* 691 * Now can put in the inode number, since i8count is set. 692 */ 693 dp->d_ops->sf_put_parent_ino(sfp, pino); 694 sfp->count = 0; 695 dp->i_d.di_size = size; 696 xfs_dir2_sf_check(args); 697 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); 698 return 0; 699 } 700 701 /* 702 * Lookup an entry in a shortform directory. 703 * Returns EEXIST if found, ENOENT if not found. 704 */ 705 int /* error */ 706 xfs_dir2_sf_lookup( 707 xfs_da_args_t *args) /* operation arguments */ 708 { 709 xfs_inode_t *dp; /* incore directory inode */ 710 int i; /* entry index */ 711 int error; 712 xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ 713 xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ 714 enum xfs_dacmp cmp; /* comparison result */ 715 xfs_dir2_sf_entry_t *ci_sfep; /* case-insens. entry */ 716 717 trace_xfs_dir2_sf_lookup(args); 718 719 xfs_dir2_sf_check(args); 720 dp = args->dp; 721 722 ASSERT(dp->i_df.if_flags & XFS_IFINLINE); 723 /* 724 * Bail out if the directory is way too short. 725 */ 726 if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { 727 ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); 728 return -EIO; 729 } 730 ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); 731 ASSERT(dp->i_df.if_u1.if_data != NULL); 732 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 733 ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->i8count)); 734 /* 735 * Special case for . 736 */ 737 if (args->namelen == 1 && args->name[0] == '.') { 738 args->inumber = dp->i_ino; 739 args->cmpresult = XFS_CMP_EXACT; 740 args->filetype = XFS_DIR3_FT_DIR; 741 return -EEXIST; 742 } 743 /* 744 * Special case for .. 745 */ 746 if (args->namelen == 2 && 747 args->name[0] == '.' && args->name[1] == '.') { 748 args->inumber = dp->d_ops->sf_get_parent_ino(sfp); 749 args->cmpresult = XFS_CMP_EXACT; 750 args->filetype = XFS_DIR3_FT_DIR; 751 return -EEXIST; 752 } 753 /* 754 * Loop over all the entries trying to match ours. 755 */ 756 ci_sfep = NULL; 757 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count; 758 i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) { 759 /* 760 * Compare name and if it's an exact match, return the inode 761 * number. If it's the first case-insensitive match, store the 762 * inode number and continue looking for an exact match. 763 */ 764 cmp = dp->i_mount->m_dirnameops->compname(args, sfep->name, 765 sfep->namelen); 766 if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) { 767 args->cmpresult = cmp; 768 args->inumber = dp->d_ops->sf_get_ino(sfp, sfep); 769 args->filetype = dp->d_ops->sf_get_ftype(sfep); 770 if (cmp == XFS_CMP_EXACT) 771 return -EEXIST; 772 ci_sfep = sfep; 773 } 774 } 775 ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); 776 /* 777 * Here, we can only be doing a lookup (not a rename or replace). 778 * If a case-insensitive match was not found, return -ENOENT. 779 */ 780 if (!ci_sfep) 781 return -ENOENT; 782 /* otherwise process the CI match as required by the caller */ 783 error = xfs_dir_cilookup_result(args, ci_sfep->name, ci_sfep->namelen); 784 return error; 785 } 786 787 /* 788 * Remove an entry from a shortform directory. 789 */ 790 int /* error */ 791 xfs_dir2_sf_removename( 792 xfs_da_args_t *args) 793 { 794 int byteoff; /* offset of removed entry */ 795 xfs_inode_t *dp; /* incore directory inode */ 796 int entsize; /* this entry's size */ 797 int i; /* shortform entry index */ 798 int newsize; /* new inode size */ 799 int oldsize; /* old inode size */ 800 xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ 801 xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ 802 803 trace_xfs_dir2_sf_removename(args); 804 805 dp = args->dp; 806 807 ASSERT(dp->i_df.if_flags & XFS_IFINLINE); 808 oldsize = (int)dp->i_d.di_size; 809 /* 810 * Bail out if the directory is way too short. 811 */ 812 if (oldsize < offsetof(xfs_dir2_sf_hdr_t, parent)) { 813 ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); 814 return -EIO; 815 } 816 ASSERT(dp->i_df.if_bytes == oldsize); 817 ASSERT(dp->i_df.if_u1.if_data != NULL); 818 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 819 ASSERT(oldsize >= xfs_dir2_sf_hdr_size(sfp->i8count)); 820 /* 821 * Loop over the old directory entries. 822 * Find the one we're deleting. 823 */ 824 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count; 825 i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) { 826 if (xfs_da_compname(args, sfep->name, sfep->namelen) == 827 XFS_CMP_EXACT) { 828 ASSERT(dp->d_ops->sf_get_ino(sfp, sfep) == 829 args->inumber); 830 break; 831 } 832 } 833 /* 834 * Didn't find it. 835 */ 836 if (i == sfp->count) 837 return -ENOENT; 838 /* 839 * Calculate sizes. 840 */ 841 byteoff = (int)((char *)sfep - (char *)sfp); 842 entsize = dp->d_ops->sf_entsize(sfp, args->namelen); 843 newsize = oldsize - entsize; 844 /* 845 * Copy the part if any after the removed entry, sliding it down. 846 */ 847 if (byteoff + entsize < oldsize) 848 memmove((char *)sfp + byteoff, (char *)sfp + byteoff + entsize, 849 oldsize - (byteoff + entsize)); 850 /* 851 * Fix up the header and file size. 852 */ 853 sfp->count--; 854 dp->i_d.di_size = newsize; 855 /* 856 * Reallocate, making it smaller. 857 */ 858 xfs_idata_realloc(dp, newsize - oldsize, XFS_DATA_FORK); 859 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 860 /* 861 * Are we changing inode number size? 862 */ 863 if (args->inumber > XFS_DIR2_MAX_SHORT_INUM) { 864 if (sfp->i8count == 1) 865 xfs_dir2_sf_toino4(args); 866 else 867 sfp->i8count--; 868 } 869 xfs_dir2_sf_check(args); 870 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); 871 return 0; 872 } 873 874 /* 875 * Replace the inode number of an entry in a shortform directory. 876 */ 877 int /* error */ 878 xfs_dir2_sf_replace( 879 xfs_da_args_t *args) /* operation arguments */ 880 { 881 xfs_inode_t *dp; /* incore directory inode */ 882 int i; /* entry index */ 883 xfs_ino_t ino=0; /* entry old inode number */ 884 int i8elevated; /* sf_toino8 set i8count=1 */ 885 xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ 886 xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ 887 888 trace_xfs_dir2_sf_replace(args); 889 890 dp = args->dp; 891 892 ASSERT(dp->i_df.if_flags & XFS_IFINLINE); 893 /* 894 * Bail out if the shortform directory is way too small. 895 */ 896 if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { 897 ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); 898 return -EIO; 899 } 900 ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); 901 ASSERT(dp->i_df.if_u1.if_data != NULL); 902 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 903 ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->i8count)); 904 905 /* 906 * New inode number is large, and need to convert to 8-byte inodes. 907 */ 908 if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->i8count == 0) { 909 int error; /* error return value */ 910 int newsize; /* new inode size */ 911 912 newsize = 913 dp->i_df.if_bytes + 914 (sfp->count + 1) * 915 ((uint)sizeof(xfs_dir2_ino8_t) - 916 (uint)sizeof(xfs_dir2_ino4_t)); 917 /* 918 * Won't fit as shortform, convert to block then do replace. 919 */ 920 if (newsize > XFS_IFORK_DSIZE(dp)) { 921 error = xfs_dir2_sf_to_block(args); 922 if (error) { 923 return error; 924 } 925 return xfs_dir2_block_replace(args); 926 } 927 /* 928 * Still fits, convert to 8-byte now. 929 */ 930 xfs_dir2_sf_toino8(args); 931 i8elevated = 1; 932 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 933 } else 934 i8elevated = 0; 935 936 ASSERT(args->namelen != 1 || args->name[0] != '.'); 937 /* 938 * Replace ..'s entry. 939 */ 940 if (args->namelen == 2 && 941 args->name[0] == '.' && args->name[1] == '.') { 942 ino = dp->d_ops->sf_get_parent_ino(sfp); 943 ASSERT(args->inumber != ino); 944 dp->d_ops->sf_put_parent_ino(sfp, args->inumber); 945 } 946 /* 947 * Normal entry, look for the name. 948 */ 949 else { 950 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count; 951 i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) { 952 if (xfs_da_compname(args, sfep->name, sfep->namelen) == 953 XFS_CMP_EXACT) { 954 ino = dp->d_ops->sf_get_ino(sfp, sfep); 955 ASSERT(args->inumber != ino); 956 dp->d_ops->sf_put_ino(sfp, sfep, args->inumber); 957 dp->d_ops->sf_put_ftype(sfep, args->filetype); 958 break; 959 } 960 } 961 /* 962 * Didn't find it. 963 */ 964 if (i == sfp->count) { 965 ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); 966 if (i8elevated) 967 xfs_dir2_sf_toino4(args); 968 return -ENOENT; 969 } 970 } 971 /* 972 * See if the old number was large, the new number is small. 973 */ 974 if (ino > XFS_DIR2_MAX_SHORT_INUM && 975 args->inumber <= XFS_DIR2_MAX_SHORT_INUM) { 976 /* 977 * And the old count was one, so need to convert to small. 978 */ 979 if (sfp->i8count == 1) 980 xfs_dir2_sf_toino4(args); 981 else 982 sfp->i8count--; 983 } 984 /* 985 * See if the old number was small, the new number is large. 986 */ 987 if (ino <= XFS_DIR2_MAX_SHORT_INUM && 988 args->inumber > XFS_DIR2_MAX_SHORT_INUM) { 989 /* 990 * add to the i8count unless we just converted to 8-byte 991 * inodes (which does an implied i8count = 1) 992 */ 993 ASSERT(sfp->i8count != 0); 994 if (!i8elevated) 995 sfp->i8count++; 996 } 997 xfs_dir2_sf_check(args); 998 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA); 999 return 0; 1000 } 1001 1002 /* 1003 * Convert from 8-byte inode numbers to 4-byte inode numbers. 1004 * The last 8-byte inode number is gone, but the count is still 1. 1005 */ 1006 static void 1007 xfs_dir2_sf_toino4( 1008 xfs_da_args_t *args) /* operation arguments */ 1009 { 1010 char *buf; /* old dir's buffer */ 1011 xfs_inode_t *dp; /* incore directory inode */ 1012 int i; /* entry index */ 1013 int newsize; /* new inode size */ 1014 xfs_dir2_sf_entry_t *oldsfep; /* old sf entry */ 1015 xfs_dir2_sf_hdr_t *oldsfp; /* old sf directory */ 1016 int oldsize; /* old inode size */ 1017 xfs_dir2_sf_entry_t *sfep; /* new sf entry */ 1018 xfs_dir2_sf_hdr_t *sfp; /* new sf directory */ 1019 struct xfs_mount *mp; 1020 1021 trace_xfs_dir2_sf_toino4(args); 1022 1023 dp = args->dp; 1024 mp = dp->i_mount; 1025 1026 /* 1027 * Copy the old directory to the buffer. 1028 * Then nuke it from the inode, and add the new buffer to the inode. 1029 * Don't want xfs_idata_realloc copying the data here. 1030 */ 1031 oldsize = dp->i_df.if_bytes; 1032 buf = kmem_alloc(oldsize, KM_SLEEP); 1033 oldsfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 1034 ASSERT(oldsfp->i8count == 1); 1035 memcpy(buf, oldsfp, oldsize); 1036 /* 1037 * Compute the new inode size. 1038 */ 1039 newsize = 1040 oldsize - 1041 (oldsfp->count + 1) * 1042 ((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t)); 1043 xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK); 1044 xfs_idata_realloc(dp, newsize, XFS_DATA_FORK); 1045 /* 1046 * Reset our pointers, the data has moved. 1047 */ 1048 oldsfp = (xfs_dir2_sf_hdr_t *)buf; 1049 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 1050 /* 1051 * Fill in the new header. 1052 */ 1053 sfp->count = oldsfp->count; 1054 sfp->i8count = 0; 1055 dp->d_ops->sf_put_parent_ino(sfp, dp->d_ops->sf_get_parent_ino(oldsfp)); 1056 /* 1057 * Copy the entries field by field. 1058 */ 1059 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp), 1060 oldsfep = xfs_dir2_sf_firstentry(oldsfp); 1061 i < sfp->count; 1062 i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep), 1063 oldsfep = dp->d_ops->sf_nextentry(oldsfp, oldsfep)) { 1064 sfep->namelen = oldsfep->namelen; 1065 sfep->offset = oldsfep->offset; 1066 memcpy(sfep->name, oldsfep->name, sfep->namelen); 1067 dp->d_ops->sf_put_ino(sfp, sfep, 1068 dp->d_ops->sf_get_ino(oldsfp, oldsfep)); 1069 dp->d_ops->sf_put_ftype(sfep, dp->d_ops->sf_get_ftype(oldsfep)); 1070 } 1071 /* 1072 * Clean up the inode. 1073 */ 1074 kmem_free(buf); 1075 dp->i_d.di_size = newsize; 1076 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); 1077 } 1078 1079 /* 1080 * Convert existing entries from 4-byte inode numbers to 8-byte inode numbers. 1081 * The new entry w/ an 8-byte inode number is not there yet; we leave with 1082 * i8count set to 1, but no corresponding 8-byte entry. 1083 */ 1084 static void 1085 xfs_dir2_sf_toino8( 1086 xfs_da_args_t *args) /* operation arguments */ 1087 { 1088 char *buf; /* old dir's buffer */ 1089 xfs_inode_t *dp; /* incore directory inode */ 1090 int i; /* entry index */ 1091 int newsize; /* new inode size */ 1092 xfs_dir2_sf_entry_t *oldsfep; /* old sf entry */ 1093 xfs_dir2_sf_hdr_t *oldsfp; /* old sf directory */ 1094 int oldsize; /* old inode size */ 1095 xfs_dir2_sf_entry_t *sfep; /* new sf entry */ 1096 xfs_dir2_sf_hdr_t *sfp; /* new sf directory */ 1097 struct xfs_mount *mp; 1098 1099 trace_xfs_dir2_sf_toino8(args); 1100 1101 dp = args->dp; 1102 mp = dp->i_mount; 1103 1104 /* 1105 * Copy the old directory to the buffer. 1106 * Then nuke it from the inode, and add the new buffer to the inode. 1107 * Don't want xfs_idata_realloc copying the data here. 1108 */ 1109 oldsize = dp->i_df.if_bytes; 1110 buf = kmem_alloc(oldsize, KM_SLEEP); 1111 oldsfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 1112 ASSERT(oldsfp->i8count == 0); 1113 memcpy(buf, oldsfp, oldsize); 1114 /* 1115 * Compute the new inode size (nb: entry count + 1 for parent) 1116 */ 1117 newsize = 1118 oldsize + 1119 (oldsfp->count + 1) * 1120 ((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t)); 1121 xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK); 1122 xfs_idata_realloc(dp, newsize, XFS_DATA_FORK); 1123 /* 1124 * Reset our pointers, the data has moved. 1125 */ 1126 oldsfp = (xfs_dir2_sf_hdr_t *)buf; 1127 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 1128 /* 1129 * Fill in the new header. 1130 */ 1131 sfp->count = oldsfp->count; 1132 sfp->i8count = 1; 1133 dp->d_ops->sf_put_parent_ino(sfp, dp->d_ops->sf_get_parent_ino(oldsfp)); 1134 /* 1135 * Copy the entries field by field. 1136 */ 1137 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp), 1138 oldsfep = xfs_dir2_sf_firstentry(oldsfp); 1139 i < sfp->count; 1140 i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep), 1141 oldsfep = dp->d_ops->sf_nextentry(oldsfp, oldsfep)) { 1142 sfep->namelen = oldsfep->namelen; 1143 sfep->offset = oldsfep->offset; 1144 memcpy(sfep->name, oldsfep->name, sfep->namelen); 1145 dp->d_ops->sf_put_ino(sfp, sfep, 1146 dp->d_ops->sf_get_ino(oldsfp, oldsfep)); 1147 dp->d_ops->sf_put_ftype(sfep, dp->d_ops->sf_get_ftype(oldsfep)); 1148 } 1149 /* 1150 * Clean up the inode. 1151 */ 1152 kmem_free(buf); 1153 dp->i_d.di_size = newsize; 1154 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); 1155 } 1156