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