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