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