Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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