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