0001
0002
0003
0004
0005
0006 #include "xfs.h"
0007 #include "xfs_fs.h"
0008 #include "xfs_shared.h"
0009 #include "xfs_format.h"
0010 #include "xfs_log_format.h"
0011 #include "xfs_trans_resv.h"
0012 #include "xfs_mount.h"
0013 #include "xfs_inode.h"
0014 #include "xfs_trans.h"
0015 #include "xfs_dir2.h"
0016 #include "xfs_dir2_priv.h"
0017 #include "xfs_trace.h"
0018
0019
0020
0021
0022 static void xfs_dir2_sf_addname_easy(xfs_da_args_t *args,
0023 xfs_dir2_sf_entry_t *sfep,
0024 xfs_dir2_data_aoff_t offset,
0025 int new_isize);
0026 static void xfs_dir2_sf_addname_hard(xfs_da_args_t *args, int objchange,
0027 int new_isize);
0028 static int xfs_dir2_sf_addname_pick(xfs_da_args_t *args, int objchange,
0029 xfs_dir2_sf_entry_t **sfepp,
0030 xfs_dir2_data_aoff_t *offsetp);
0031 #ifdef DEBUG
0032 static void xfs_dir2_sf_check(xfs_da_args_t *args);
0033 #else
0034 #define xfs_dir2_sf_check(args)
0035 #endif
0036
0037 static void xfs_dir2_sf_toino4(xfs_da_args_t *args);
0038 static void xfs_dir2_sf_toino8(xfs_da_args_t *args);
0039
0040 int
0041 xfs_dir2_sf_entsize(
0042 struct xfs_mount *mp,
0043 struct xfs_dir2_sf_hdr *hdr,
0044 int len)
0045 {
0046 int count = len;
0047
0048 count += sizeof(struct xfs_dir2_sf_entry);
0049 count += hdr->i8count ? XFS_INO64_SIZE : XFS_INO32_SIZE;
0050
0051 if (xfs_has_ftype(mp))
0052 count += sizeof(uint8_t);
0053 return count;
0054 }
0055
0056 struct xfs_dir2_sf_entry *
0057 xfs_dir2_sf_nextentry(
0058 struct xfs_mount *mp,
0059 struct xfs_dir2_sf_hdr *hdr,
0060 struct xfs_dir2_sf_entry *sfep)
0061 {
0062 return (void *)sfep + xfs_dir2_sf_entsize(mp, hdr, sfep->namelen);
0063 }
0064
0065
0066
0067
0068
0069
0070
0071 xfs_ino_t
0072 xfs_dir2_sf_get_ino(
0073 struct xfs_mount *mp,
0074 struct xfs_dir2_sf_hdr *hdr,
0075 struct xfs_dir2_sf_entry *sfep)
0076 {
0077 uint8_t *from = sfep->name + sfep->namelen;
0078
0079 if (xfs_has_ftype(mp))
0080 from++;
0081
0082 if (!hdr->i8count)
0083 return get_unaligned_be32(from);
0084 return get_unaligned_be64(from) & XFS_MAXINUMBER;
0085 }
0086
0087 void
0088 xfs_dir2_sf_put_ino(
0089 struct xfs_mount *mp,
0090 struct xfs_dir2_sf_hdr *hdr,
0091 struct xfs_dir2_sf_entry *sfep,
0092 xfs_ino_t ino)
0093 {
0094 uint8_t *to = sfep->name + sfep->namelen;
0095
0096 ASSERT(ino <= XFS_MAXINUMBER);
0097
0098 if (xfs_has_ftype(mp))
0099 to++;
0100
0101 if (hdr->i8count)
0102 put_unaligned_be64(ino, to);
0103 else
0104 put_unaligned_be32(ino, to);
0105 }
0106
0107 xfs_ino_t
0108 xfs_dir2_sf_get_parent_ino(
0109 struct xfs_dir2_sf_hdr *hdr)
0110 {
0111 if (!hdr->i8count)
0112 return get_unaligned_be32(hdr->parent);
0113 return get_unaligned_be64(hdr->parent) & XFS_MAXINUMBER;
0114 }
0115
0116 void
0117 xfs_dir2_sf_put_parent_ino(
0118 struct xfs_dir2_sf_hdr *hdr,
0119 xfs_ino_t ino)
0120 {
0121 ASSERT(ino <= XFS_MAXINUMBER);
0122
0123 if (hdr->i8count)
0124 put_unaligned_be64(ino, hdr->parent);
0125 else
0126 put_unaligned_be32(ino, hdr->parent);
0127 }
0128
0129
0130
0131
0132
0133 uint8_t
0134 xfs_dir2_sf_get_ftype(
0135 struct xfs_mount *mp,
0136 struct xfs_dir2_sf_entry *sfep)
0137 {
0138 if (xfs_has_ftype(mp)) {
0139 uint8_t ftype = sfep->name[sfep->namelen];
0140
0141 if (ftype < XFS_DIR3_FT_MAX)
0142 return ftype;
0143 }
0144
0145 return XFS_DIR3_FT_UNKNOWN;
0146 }
0147
0148 void
0149 xfs_dir2_sf_put_ftype(
0150 struct xfs_mount *mp,
0151 struct xfs_dir2_sf_entry *sfep,
0152 uint8_t ftype)
0153 {
0154 ASSERT(ftype < XFS_DIR3_FT_MAX);
0155
0156 if (xfs_has_ftype(mp))
0157 sfep->name[sfep->namelen] = ftype;
0158 }
0159
0160
0161
0162
0163
0164
0165
0166 int
0167 xfs_dir2_block_sfsize(
0168 xfs_inode_t *dp,
0169 xfs_dir2_data_hdr_t *hdr,
0170 xfs_dir2_sf_hdr_t *sfhp)
0171 {
0172 xfs_dir2_dataptr_t addr;
0173 xfs_dir2_leaf_entry_t *blp;
0174 xfs_dir2_block_tail_t *btp;
0175 int count;
0176 xfs_dir2_data_entry_t *dep;
0177 int i;
0178 int i8count;
0179 int isdot;
0180 int isdotdot;
0181 xfs_mount_t *mp;
0182 int namelen;
0183 xfs_ino_t parent = 0;
0184 int size=0;
0185 int has_ftype;
0186 struct xfs_da_geometry *geo;
0187
0188 mp = dp->i_mount;
0189 geo = mp->m_dir_geo;
0190
0191
0192
0193
0194
0195 has_ftype = xfs_has_ftype(mp) ? 1 : 0;
0196
0197 count = i8count = namelen = 0;
0198 btp = xfs_dir2_block_tail_p(geo, hdr);
0199 blp = xfs_dir2_block_leaf_p(btp);
0200
0201
0202
0203
0204 for (i = 0; i < be32_to_cpu(btp->count); i++) {
0205 if ((addr = be32_to_cpu(blp[i].address)) == XFS_DIR2_NULL_DATAPTR)
0206 continue;
0207
0208
0209
0210 dep = (xfs_dir2_data_entry_t *)((char *)hdr +
0211 xfs_dir2_dataptr_to_off(geo, addr));
0212
0213
0214
0215
0216
0217 isdot = dep->namelen == 1 && dep->name[0] == '.';
0218 isdotdot =
0219 dep->namelen == 2 &&
0220 dep->name[0] == '.' && dep->name[1] == '.';
0221
0222 if (!isdot)
0223 i8count += be64_to_cpu(dep->inumber) > XFS_DIR2_MAX_SHORT_INUM;
0224
0225
0226 if (!isdot && !isdotdot) {
0227 count++;
0228 namelen += dep->namelen + has_ftype;
0229 } else if (isdotdot)
0230 parent = be64_to_cpu(dep->inumber);
0231
0232
0233
0234 size = xfs_dir2_sf_hdr_size(i8count) +
0235 count * 3 * sizeof(u8) +
0236 namelen +
0237 (i8count ?
0238 count * XFS_INO64_SIZE :
0239 count * XFS_INO32_SIZE);
0240 if (size > xfs_inode_data_fork_size(dp))
0241 return size;
0242 }
0243
0244
0245
0246 sfhp->count = count;
0247 sfhp->i8count = i8count;
0248 xfs_dir2_sf_put_parent_ino(sfhp, parent);
0249 return size;
0250 }
0251
0252
0253
0254
0255
0256 int
0257 xfs_dir2_block_to_sf(
0258 struct xfs_da_args *args,
0259 struct xfs_buf *bp,
0260 int size,
0261 struct xfs_dir2_sf_hdr *sfhp)
0262 {
0263 struct xfs_inode *dp = args->dp;
0264 struct xfs_mount *mp = dp->i_mount;
0265 int error;
0266 int logflags;
0267 struct xfs_dir2_sf_entry *sfep;
0268 struct xfs_dir2_sf_hdr *sfp;
0269 unsigned int offset = args->geo->data_entry_offset;
0270 unsigned int end;
0271
0272 trace_xfs_dir2_block_to_sf(args);
0273
0274
0275
0276
0277
0278
0279 sfp = kmem_alloc(mp->m_sb.sb_inodesize, 0);
0280 memcpy(sfp, sfhp, xfs_dir2_sf_hdr_size(sfhp->i8count));
0281
0282
0283
0284
0285
0286 end = xfs_dir3_data_end_offset(args->geo, bp->b_addr);
0287 sfep = xfs_dir2_sf_firstentry(sfp);
0288 while (offset < end) {
0289 struct xfs_dir2_data_unused *dup = bp->b_addr + offset;
0290 struct xfs_dir2_data_entry *dep = bp->b_addr + offset;
0291
0292
0293
0294
0295 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
0296 offset += be16_to_cpu(dup->length);
0297 continue;
0298 }
0299
0300
0301
0302
0303 if (dep->namelen == 1 && dep->name[0] == '.')
0304 ASSERT(be64_to_cpu(dep->inumber) == dp->i_ino);
0305
0306
0307
0308 else if (dep->namelen == 2 &&
0309 dep->name[0] == '.' && dep->name[1] == '.')
0310 ASSERT(be64_to_cpu(dep->inumber) ==
0311 xfs_dir2_sf_get_parent_ino(sfp));
0312
0313
0314
0315 else {
0316 sfep->namelen = dep->namelen;
0317 xfs_dir2_sf_put_offset(sfep, offset);
0318 memcpy(sfep->name, dep->name, dep->namelen);
0319 xfs_dir2_sf_put_ino(mp, sfp, sfep,
0320 be64_to_cpu(dep->inumber));
0321 xfs_dir2_sf_put_ftype(mp, sfep,
0322 xfs_dir2_data_get_ftype(mp, dep));
0323
0324 sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
0325 }
0326 offset += xfs_dir2_data_entsize(mp, dep->namelen);
0327 }
0328 ASSERT((char *)sfep - (char *)sfp == size);
0329
0330
0331 logflags = XFS_ILOG_CORE;
0332 error = xfs_dir2_shrink_inode(args, args->geo->datablk, bp);
0333 if (error) {
0334 ASSERT(error != -ENOSPC);
0335 goto out;
0336 }
0337
0338
0339
0340
0341
0342
0343
0344 ASSERT(dp->i_df.if_bytes == 0);
0345 xfs_init_local_fork(dp, XFS_DATA_FORK, sfp, size);
0346 dp->i_df.if_format = XFS_DINODE_FMT_LOCAL;
0347 dp->i_disk_size = size;
0348
0349 logflags |= XFS_ILOG_DDATA;
0350 xfs_dir2_sf_check(args);
0351 out:
0352 xfs_trans_log_inode(args->trans, dp, logflags);
0353 kmem_free(sfp);
0354 return error;
0355 }
0356
0357
0358
0359
0360
0361
0362
0363 int
0364 xfs_dir2_sf_addname(
0365 xfs_da_args_t *args)
0366 {
0367 xfs_inode_t *dp;
0368 int error;
0369 int incr_isize;
0370 int new_isize;
0371 int objchange;
0372 xfs_dir2_data_aoff_t offset = 0;
0373 int pick;
0374 xfs_dir2_sf_hdr_t *sfp;
0375 xfs_dir2_sf_entry_t *sfep = NULL;
0376
0377 trace_xfs_dir2_sf_addname(args);
0378
0379 ASSERT(xfs_dir2_sf_lookup(args) == -ENOENT);
0380 dp = args->dp;
0381 ASSERT(dp->i_df.if_format == XFS_DINODE_FMT_LOCAL);
0382 ASSERT(dp->i_disk_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
0383 ASSERT(dp->i_df.if_bytes == dp->i_disk_size);
0384 ASSERT(dp->i_df.if_u1.if_data != NULL);
0385 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
0386 ASSERT(dp->i_disk_size >= xfs_dir2_sf_hdr_size(sfp->i8count));
0387
0388
0389
0390 incr_isize = xfs_dir2_sf_entsize(dp->i_mount, sfp, args->namelen);
0391 objchange = 0;
0392
0393
0394
0395
0396 if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->i8count == 0) {
0397
0398
0399
0400 incr_isize += (sfp->count + 2) * XFS_INO64_DIFF;
0401 objchange = 1;
0402 }
0403
0404 new_isize = (int)dp->i_disk_size + incr_isize;
0405
0406
0407
0408
0409 if (new_isize > xfs_inode_data_fork_size(dp) ||
0410 (pick =
0411 xfs_dir2_sf_addname_pick(args, objchange, &sfep, &offset)) == 0) {
0412
0413
0414
0415 if ((args->op_flags & XFS_DA_OP_JUSTCHECK) || args->total == 0)
0416 return -ENOSPC;
0417
0418
0419
0420 error = xfs_dir2_sf_to_block(args);
0421 if (error)
0422 return error;
0423 return xfs_dir2_block_addname(args);
0424 }
0425
0426
0427
0428 if (args->op_flags & XFS_DA_OP_JUSTCHECK)
0429 return 0;
0430
0431
0432
0433 if (pick == 1)
0434 xfs_dir2_sf_addname_easy(args, sfep, offset, new_isize);
0435
0436
0437
0438
0439 else {
0440 ASSERT(pick == 2);
0441 if (objchange)
0442 xfs_dir2_sf_toino8(args);
0443 xfs_dir2_sf_addname_hard(args, objchange, new_isize);
0444 }
0445 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
0446 return 0;
0447 }
0448
0449
0450
0451
0452
0453
0454
0455
0456 static void
0457 xfs_dir2_sf_addname_easy(
0458 xfs_da_args_t *args,
0459 xfs_dir2_sf_entry_t *sfep,
0460 xfs_dir2_data_aoff_t offset,
0461 int new_isize)
0462 {
0463 struct xfs_inode *dp = args->dp;
0464 struct xfs_mount *mp = dp->i_mount;
0465 int byteoff;
0466 xfs_dir2_sf_hdr_t *sfp;
0467
0468 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
0469 byteoff = (int)((char *)sfep - (char *)sfp);
0470
0471
0472
0473 xfs_idata_realloc(dp, xfs_dir2_sf_entsize(mp, sfp, args->namelen),
0474 XFS_DATA_FORK);
0475
0476
0477
0478 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
0479 sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + byteoff);
0480
0481
0482
0483 sfep->namelen = args->namelen;
0484 xfs_dir2_sf_put_offset(sfep, offset);
0485 memcpy(sfep->name, args->name, sfep->namelen);
0486 xfs_dir2_sf_put_ino(mp, sfp, sfep, args->inumber);
0487 xfs_dir2_sf_put_ftype(mp, sfep, args->filetype);
0488
0489
0490
0491
0492 sfp->count++;
0493 if (args->inumber > XFS_DIR2_MAX_SHORT_INUM)
0494 sfp->i8count++;
0495 dp->i_disk_size = new_isize;
0496 xfs_dir2_sf_check(args);
0497 }
0498
0499
0500
0501
0502
0503
0504
0505
0506
0507
0508 static void
0509 xfs_dir2_sf_addname_hard(
0510 xfs_da_args_t *args,
0511 int objchange,
0512 int new_isize)
0513 {
0514 struct xfs_inode *dp = args->dp;
0515 struct xfs_mount *mp = dp->i_mount;
0516 int add_datasize;
0517 char *buf;
0518 int eof;
0519 int nbytes;
0520 xfs_dir2_data_aoff_t new_offset;
0521 xfs_dir2_data_aoff_t offset;
0522 int old_isize;
0523 xfs_dir2_sf_entry_t *oldsfep;
0524 xfs_dir2_sf_hdr_t *oldsfp;
0525 xfs_dir2_sf_entry_t *sfep;
0526 xfs_dir2_sf_hdr_t *sfp;
0527
0528
0529
0530
0531 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
0532 old_isize = (int)dp->i_disk_size;
0533 buf = kmem_alloc(old_isize, 0);
0534 oldsfp = (xfs_dir2_sf_hdr_t *)buf;
0535 memcpy(oldsfp, sfp, old_isize);
0536
0537
0538
0539
0540
0541 for (offset = args->geo->data_first_offset,
0542 oldsfep = xfs_dir2_sf_firstentry(oldsfp),
0543 add_datasize = xfs_dir2_data_entsize(mp, args->namelen),
0544 eof = (char *)oldsfep == &buf[old_isize];
0545 !eof;
0546 offset = new_offset + xfs_dir2_data_entsize(mp, oldsfep->namelen),
0547 oldsfep = xfs_dir2_sf_nextentry(mp, oldsfp, oldsfep),
0548 eof = (char *)oldsfep == &buf[old_isize]) {
0549 new_offset = xfs_dir2_sf_get_offset(oldsfep);
0550 if (offset + add_datasize <= new_offset)
0551 break;
0552 }
0553
0554
0555
0556
0557
0558 xfs_idata_realloc(dp, -old_isize, XFS_DATA_FORK);
0559 xfs_idata_realloc(dp, new_isize, XFS_DATA_FORK);
0560
0561
0562
0563 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
0564
0565
0566
0567 nbytes = (int)((char *)oldsfep - (char *)oldsfp);
0568 memcpy(sfp, oldsfp, nbytes);
0569 sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + nbytes);
0570
0571
0572
0573 sfep->namelen = args->namelen;
0574 xfs_dir2_sf_put_offset(sfep, offset);
0575 memcpy(sfep->name, args->name, sfep->namelen);
0576 xfs_dir2_sf_put_ino(mp, sfp, sfep, args->inumber);
0577 xfs_dir2_sf_put_ftype(mp, sfep, args->filetype);
0578 sfp->count++;
0579 if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && !objchange)
0580 sfp->i8count++;
0581
0582
0583
0584 if (!eof) {
0585 sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
0586 memcpy(sfep, oldsfep, old_isize - nbytes);
0587 }
0588 kmem_free(buf);
0589 dp->i_disk_size = new_isize;
0590 xfs_dir2_sf_check(args);
0591 }
0592
0593
0594
0595
0596
0597
0598
0599
0600 static int
0601 xfs_dir2_sf_addname_pick(
0602 xfs_da_args_t *args,
0603 int objchange,
0604 xfs_dir2_sf_entry_t **sfepp,
0605 xfs_dir2_data_aoff_t *offsetp)
0606 {
0607 struct xfs_inode *dp = args->dp;
0608 struct xfs_mount *mp = dp->i_mount;
0609 int holefit;
0610 int i;
0611 xfs_dir2_data_aoff_t offset;
0612 xfs_dir2_sf_entry_t *sfep;
0613 xfs_dir2_sf_hdr_t *sfp;
0614 int size;
0615 int used;
0616
0617 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
0618 size = xfs_dir2_data_entsize(mp, args->namelen);
0619 offset = args->geo->data_first_offset;
0620 sfep = xfs_dir2_sf_firstentry(sfp);
0621 holefit = 0;
0622
0623
0624
0625
0626
0627 for (i = 0; i < sfp->count; i++) {
0628 if (!holefit)
0629 holefit = offset + size <= xfs_dir2_sf_get_offset(sfep);
0630 offset = xfs_dir2_sf_get_offset(sfep) +
0631 xfs_dir2_data_entsize(mp, sfep->namelen);
0632 sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
0633 }
0634
0635
0636
0637
0638 used = offset +
0639 (sfp->count + 3) * (uint)sizeof(xfs_dir2_leaf_entry_t) +
0640 (uint)sizeof(xfs_dir2_block_tail_t);
0641
0642
0643
0644
0645
0646 if (used + (holefit ? 0 : size) > args->geo->blksize)
0647 return 0;
0648
0649
0650
0651 if (objchange)
0652 return 2;
0653
0654
0655
0656 if (used + size > args->geo->blksize)
0657 return 2;
0658
0659
0660
0661 *sfepp = sfep;
0662 *offsetp = offset;
0663 return 1;
0664 }
0665
0666 #ifdef DEBUG
0667
0668
0669
0670 static void
0671 xfs_dir2_sf_check(
0672 xfs_da_args_t *args)
0673 {
0674 struct xfs_inode *dp = args->dp;
0675 struct xfs_mount *mp = dp->i_mount;
0676 int i;
0677 int i8count;
0678 xfs_ino_t ino;
0679 int offset;
0680 xfs_dir2_sf_entry_t *sfep;
0681 xfs_dir2_sf_hdr_t *sfp;
0682
0683 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
0684 offset = args->geo->data_first_offset;
0685 ino = xfs_dir2_sf_get_parent_ino(sfp);
0686 i8count = ino > XFS_DIR2_MAX_SHORT_INUM;
0687
0688 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
0689 i < sfp->count;
0690 i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep)) {
0691 ASSERT(xfs_dir2_sf_get_offset(sfep) >= offset);
0692 ino = xfs_dir2_sf_get_ino(mp, sfp, sfep);
0693 i8count += ino > XFS_DIR2_MAX_SHORT_INUM;
0694 offset =
0695 xfs_dir2_sf_get_offset(sfep) +
0696 xfs_dir2_data_entsize(mp, sfep->namelen);
0697 ASSERT(xfs_dir2_sf_get_ftype(mp, sfep) < XFS_DIR3_FT_MAX);
0698 }
0699 ASSERT(i8count == sfp->i8count);
0700 ASSERT((char *)sfep - (char *)sfp == dp->i_disk_size);
0701 ASSERT(offset +
0702 (sfp->count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) +
0703 (uint)sizeof(xfs_dir2_block_tail_t) <= args->geo->blksize);
0704 }
0705 #endif
0706
0707
0708 xfs_failaddr_t
0709 xfs_dir2_sf_verify(
0710 struct xfs_inode *ip)
0711 {
0712 struct xfs_mount *mp = ip->i_mount;
0713 struct xfs_ifork *ifp = xfs_ifork_ptr(ip, XFS_DATA_FORK);
0714 struct xfs_dir2_sf_hdr *sfp;
0715 struct xfs_dir2_sf_entry *sfep;
0716 struct xfs_dir2_sf_entry *next_sfep;
0717 char *endp;
0718 xfs_ino_t ino;
0719 int i;
0720 int i8count;
0721 int offset;
0722 int64_t size;
0723 int error;
0724 uint8_t filetype;
0725
0726 ASSERT(ifp->if_format == XFS_DINODE_FMT_LOCAL);
0727
0728 sfp = (struct xfs_dir2_sf_hdr *)ifp->if_u1.if_data;
0729 size = ifp->if_bytes;
0730
0731
0732
0733
0734 if (size <= offsetof(struct xfs_dir2_sf_hdr, parent) ||
0735 size < xfs_dir2_sf_hdr_size(sfp->i8count))
0736 return __this_address;
0737
0738 endp = (char *)sfp + size;
0739
0740
0741 ino = xfs_dir2_sf_get_parent_ino(sfp);
0742 i8count = ino > XFS_DIR2_MAX_SHORT_INUM;
0743 error = xfs_dir_ino_validate(mp, ino);
0744 if (error)
0745 return __this_address;
0746 offset = mp->m_dir_geo->data_first_offset;
0747
0748
0749 sfep = xfs_dir2_sf_firstentry(sfp);
0750 for (i = 0; i < sfp->count; i++) {
0751
0752
0753
0754
0755
0756 if (((char *)sfep + sizeof(*sfep)) >= endp)
0757 return __this_address;
0758
0759
0760 if (sfep->namelen == 0)
0761 return __this_address;
0762
0763
0764
0765
0766
0767
0768 next_sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
0769 if (endp < (char *)next_sfep)
0770 return __this_address;
0771
0772
0773 if (xfs_dir2_sf_get_offset(sfep) < offset)
0774 return __this_address;
0775
0776
0777 ino = xfs_dir2_sf_get_ino(mp, sfp, sfep);
0778 i8count += ino > XFS_DIR2_MAX_SHORT_INUM;
0779 error = xfs_dir_ino_validate(mp, ino);
0780 if (error)
0781 return __this_address;
0782
0783
0784 filetype = xfs_dir2_sf_get_ftype(mp, sfep);
0785 if (filetype >= XFS_DIR3_FT_MAX)
0786 return __this_address;
0787
0788 offset = xfs_dir2_sf_get_offset(sfep) +
0789 xfs_dir2_data_entsize(mp, sfep->namelen);
0790
0791 sfep = next_sfep;
0792 }
0793 if (i8count != sfp->i8count)
0794 return __this_address;
0795 if ((void *)sfep != (void *)endp)
0796 return __this_address;
0797
0798
0799 if (offset + (sfp->count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) +
0800 (uint)sizeof(xfs_dir2_block_tail_t) > mp->m_dir_geo->blksize)
0801 return __this_address;
0802
0803 return NULL;
0804 }
0805
0806
0807
0808
0809 int
0810 xfs_dir2_sf_create(
0811 xfs_da_args_t *args,
0812 xfs_ino_t pino)
0813 {
0814 xfs_inode_t *dp;
0815 int i8count;
0816 xfs_dir2_sf_hdr_t *sfp;
0817 int size;
0818
0819 trace_xfs_dir2_sf_create(args);
0820
0821 dp = args->dp;
0822
0823 ASSERT(dp != NULL);
0824 ASSERT(dp->i_disk_size == 0);
0825
0826
0827
0828
0829 if (dp->i_df.if_format == XFS_DINODE_FMT_EXTENTS) {
0830 dp->i_df.if_format = XFS_DINODE_FMT_LOCAL;
0831 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
0832 }
0833 ASSERT(dp->i_df.if_format == XFS_DINODE_FMT_LOCAL);
0834 ASSERT(dp->i_df.if_bytes == 0);
0835 i8count = pino > XFS_DIR2_MAX_SHORT_INUM;
0836 size = xfs_dir2_sf_hdr_size(i8count);
0837
0838
0839
0840 xfs_idata_realloc(dp, size, XFS_DATA_FORK);
0841
0842
0843
0844 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
0845 sfp->i8count = i8count;
0846
0847
0848
0849 xfs_dir2_sf_put_parent_ino(sfp, pino);
0850 sfp->count = 0;
0851 dp->i_disk_size = size;
0852 xfs_dir2_sf_check(args);
0853 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
0854 return 0;
0855 }
0856
0857
0858
0859
0860
0861 int
0862 xfs_dir2_sf_lookup(
0863 xfs_da_args_t *args)
0864 {
0865 struct xfs_inode *dp = args->dp;
0866 struct xfs_mount *mp = dp->i_mount;
0867 int i;
0868 int error;
0869 xfs_dir2_sf_entry_t *sfep;
0870 xfs_dir2_sf_hdr_t *sfp;
0871 enum xfs_dacmp cmp;
0872 xfs_dir2_sf_entry_t *ci_sfep;
0873
0874 trace_xfs_dir2_sf_lookup(args);
0875
0876 xfs_dir2_sf_check(args);
0877
0878 ASSERT(dp->i_df.if_format == XFS_DINODE_FMT_LOCAL);
0879 ASSERT(dp->i_disk_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
0880 ASSERT(dp->i_df.if_bytes == dp->i_disk_size);
0881 ASSERT(dp->i_df.if_u1.if_data != NULL);
0882 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
0883 ASSERT(dp->i_disk_size >= xfs_dir2_sf_hdr_size(sfp->i8count));
0884
0885
0886
0887 if (args->namelen == 1 && args->name[0] == '.') {
0888 args->inumber = dp->i_ino;
0889 args->cmpresult = XFS_CMP_EXACT;
0890 args->filetype = XFS_DIR3_FT_DIR;
0891 return -EEXIST;
0892 }
0893
0894
0895
0896 if (args->namelen == 2 &&
0897 args->name[0] == '.' && args->name[1] == '.') {
0898 args->inumber = xfs_dir2_sf_get_parent_ino(sfp);
0899 args->cmpresult = XFS_CMP_EXACT;
0900 args->filetype = XFS_DIR3_FT_DIR;
0901 return -EEXIST;
0902 }
0903
0904
0905
0906 ci_sfep = NULL;
0907 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
0908 i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep)) {
0909
0910
0911
0912
0913
0914 cmp = xfs_dir2_compname(args, sfep->name, sfep->namelen);
0915 if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
0916 args->cmpresult = cmp;
0917 args->inumber = xfs_dir2_sf_get_ino(mp, sfp, sfep);
0918 args->filetype = xfs_dir2_sf_get_ftype(mp, sfep);
0919 if (cmp == XFS_CMP_EXACT)
0920 return -EEXIST;
0921 ci_sfep = sfep;
0922 }
0923 }
0924 ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
0925
0926
0927
0928
0929 if (!ci_sfep)
0930 return -ENOENT;
0931
0932 error = xfs_dir_cilookup_result(args, ci_sfep->name, ci_sfep->namelen);
0933 return error;
0934 }
0935
0936
0937
0938
0939 int
0940 xfs_dir2_sf_removename(
0941 xfs_da_args_t *args)
0942 {
0943 struct xfs_inode *dp = args->dp;
0944 struct xfs_mount *mp = dp->i_mount;
0945 int byteoff;
0946 int entsize;
0947 int i;
0948 int newsize;
0949 int oldsize;
0950 xfs_dir2_sf_entry_t *sfep;
0951 xfs_dir2_sf_hdr_t *sfp;
0952
0953 trace_xfs_dir2_sf_removename(args);
0954
0955 ASSERT(dp->i_df.if_format == XFS_DINODE_FMT_LOCAL);
0956 oldsize = (int)dp->i_disk_size;
0957 ASSERT(oldsize >= offsetof(struct xfs_dir2_sf_hdr, parent));
0958 ASSERT(dp->i_df.if_bytes == oldsize);
0959 ASSERT(dp->i_df.if_u1.if_data != NULL);
0960 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
0961 ASSERT(oldsize >= xfs_dir2_sf_hdr_size(sfp->i8count));
0962
0963
0964
0965
0966 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
0967 i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep)) {
0968 if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
0969 XFS_CMP_EXACT) {
0970 ASSERT(xfs_dir2_sf_get_ino(mp, sfp, sfep) ==
0971 args->inumber);
0972 break;
0973 }
0974 }
0975
0976
0977
0978 if (i == sfp->count)
0979 return -ENOENT;
0980
0981
0982
0983 byteoff = (int)((char *)sfep - (char *)sfp);
0984 entsize = xfs_dir2_sf_entsize(mp, sfp, args->namelen);
0985 newsize = oldsize - entsize;
0986
0987
0988
0989 if (byteoff + entsize < oldsize)
0990 memmove((char *)sfp + byteoff, (char *)sfp + byteoff + entsize,
0991 oldsize - (byteoff + entsize));
0992
0993
0994
0995 sfp->count--;
0996 dp->i_disk_size = newsize;
0997
0998
0999
1000 xfs_idata_realloc(dp, newsize - oldsize, XFS_DATA_FORK);
1001 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
1002
1003
1004
1005 if (args->inumber > XFS_DIR2_MAX_SHORT_INUM) {
1006 if (sfp->i8count == 1)
1007 xfs_dir2_sf_toino4(args);
1008 else
1009 sfp->i8count--;
1010 }
1011 xfs_dir2_sf_check(args);
1012 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
1013 return 0;
1014 }
1015
1016
1017
1018
1019 static bool
1020 xfs_dir2_sf_replace_needblock(
1021 struct xfs_inode *dp,
1022 xfs_ino_t inum)
1023 {
1024 int newsize;
1025 struct xfs_dir2_sf_hdr *sfp;
1026
1027 if (dp->i_df.if_format != XFS_DINODE_FMT_LOCAL)
1028 return false;
1029
1030 sfp = (struct xfs_dir2_sf_hdr *)dp->i_df.if_u1.if_data;
1031 newsize = dp->i_df.if_bytes + (sfp->count + 1) * XFS_INO64_DIFF;
1032
1033 return inum > XFS_DIR2_MAX_SHORT_INUM &&
1034 sfp->i8count == 0 && newsize > xfs_inode_data_fork_size(dp);
1035 }
1036
1037
1038
1039
1040 int
1041 xfs_dir2_sf_replace(
1042 xfs_da_args_t *args)
1043 {
1044 struct xfs_inode *dp = args->dp;
1045 struct xfs_mount *mp = dp->i_mount;
1046 int i;
1047 xfs_ino_t ino=0;
1048 int i8elevated;
1049 xfs_dir2_sf_entry_t *sfep;
1050 xfs_dir2_sf_hdr_t *sfp;
1051
1052 trace_xfs_dir2_sf_replace(args);
1053
1054 ASSERT(dp->i_df.if_format == XFS_DINODE_FMT_LOCAL);
1055 ASSERT(dp->i_disk_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
1056 ASSERT(dp->i_df.if_bytes == dp->i_disk_size);
1057 ASSERT(dp->i_df.if_u1.if_data != NULL);
1058 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
1059 ASSERT(dp->i_disk_size >= xfs_dir2_sf_hdr_size(sfp->i8count));
1060
1061
1062
1063
1064 if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->i8count == 0) {
1065 int error;
1066
1067
1068
1069
1070 if (xfs_dir2_sf_replace_needblock(dp, args->inumber)) {
1071 error = xfs_dir2_sf_to_block(args);
1072 if (error)
1073 return error;
1074 return xfs_dir2_block_replace(args);
1075 }
1076
1077
1078
1079 xfs_dir2_sf_toino8(args);
1080 i8elevated = 1;
1081 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
1082 } else
1083 i8elevated = 0;
1084
1085 ASSERT(args->namelen != 1 || args->name[0] != '.');
1086
1087
1088
1089 if (args->namelen == 2 &&
1090 args->name[0] == '.' && args->name[1] == '.') {
1091 ino = xfs_dir2_sf_get_parent_ino(sfp);
1092 ASSERT(args->inumber != ino);
1093 xfs_dir2_sf_put_parent_ino(sfp, args->inumber);
1094 }
1095
1096
1097
1098 else {
1099 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
1100 i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep)) {
1101 if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
1102 XFS_CMP_EXACT) {
1103 ino = xfs_dir2_sf_get_ino(mp, sfp, sfep);
1104 ASSERT(args->inumber != ino);
1105 xfs_dir2_sf_put_ino(mp, sfp, sfep,
1106 args->inumber);
1107 xfs_dir2_sf_put_ftype(mp, sfep, args->filetype);
1108 break;
1109 }
1110 }
1111
1112
1113
1114 if (i == sfp->count) {
1115 ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
1116 if (i8elevated)
1117 xfs_dir2_sf_toino4(args);
1118 return -ENOENT;
1119 }
1120 }
1121
1122
1123
1124 if (ino > XFS_DIR2_MAX_SHORT_INUM &&
1125 args->inumber <= XFS_DIR2_MAX_SHORT_INUM) {
1126
1127
1128
1129 if (sfp->i8count == 1)
1130 xfs_dir2_sf_toino4(args);
1131 else
1132 sfp->i8count--;
1133 }
1134
1135
1136
1137 if (ino <= XFS_DIR2_MAX_SHORT_INUM &&
1138 args->inumber > XFS_DIR2_MAX_SHORT_INUM) {
1139
1140
1141
1142
1143 ASSERT(sfp->i8count != 0);
1144 if (!i8elevated)
1145 sfp->i8count++;
1146 }
1147 xfs_dir2_sf_check(args);
1148 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA);
1149 return 0;
1150 }
1151
1152
1153
1154
1155
1156 static void
1157 xfs_dir2_sf_toino4(
1158 xfs_da_args_t *args)
1159 {
1160 struct xfs_inode *dp = args->dp;
1161 struct xfs_mount *mp = dp->i_mount;
1162 char *buf;
1163 int i;
1164 int newsize;
1165 xfs_dir2_sf_entry_t *oldsfep;
1166 xfs_dir2_sf_hdr_t *oldsfp;
1167 int oldsize;
1168 xfs_dir2_sf_entry_t *sfep;
1169 xfs_dir2_sf_hdr_t *sfp;
1170
1171 trace_xfs_dir2_sf_toino4(args);
1172
1173
1174
1175
1176
1177
1178 oldsize = dp->i_df.if_bytes;
1179 buf = kmem_alloc(oldsize, 0);
1180 oldsfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
1181 ASSERT(oldsfp->i8count == 1);
1182 memcpy(buf, oldsfp, oldsize);
1183
1184
1185
1186 newsize = oldsize - (oldsfp->count + 1) * XFS_INO64_DIFF;
1187 xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK);
1188 xfs_idata_realloc(dp, newsize, XFS_DATA_FORK);
1189
1190
1191
1192 oldsfp = (xfs_dir2_sf_hdr_t *)buf;
1193 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
1194
1195
1196
1197 sfp->count = oldsfp->count;
1198 sfp->i8count = 0;
1199 xfs_dir2_sf_put_parent_ino(sfp, xfs_dir2_sf_get_parent_ino(oldsfp));
1200
1201
1202
1203 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
1204 oldsfep = xfs_dir2_sf_firstentry(oldsfp);
1205 i < sfp->count;
1206 i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep),
1207 oldsfep = xfs_dir2_sf_nextentry(mp, oldsfp, oldsfep)) {
1208 sfep->namelen = oldsfep->namelen;
1209 memcpy(sfep->offset, oldsfep->offset, sizeof(sfep->offset));
1210 memcpy(sfep->name, oldsfep->name, sfep->namelen);
1211 xfs_dir2_sf_put_ino(mp, sfp, sfep,
1212 xfs_dir2_sf_get_ino(mp, oldsfp, oldsfep));
1213 xfs_dir2_sf_put_ftype(mp, sfep,
1214 xfs_dir2_sf_get_ftype(mp, oldsfep));
1215 }
1216
1217
1218
1219 kmem_free(buf);
1220 dp->i_disk_size = newsize;
1221 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
1222 }
1223
1224
1225
1226
1227
1228
1229 static void
1230 xfs_dir2_sf_toino8(
1231 xfs_da_args_t *args)
1232 {
1233 struct xfs_inode *dp = args->dp;
1234 struct xfs_mount *mp = dp->i_mount;
1235 char *buf;
1236 int i;
1237 int newsize;
1238 xfs_dir2_sf_entry_t *oldsfep;
1239 xfs_dir2_sf_hdr_t *oldsfp;
1240 int oldsize;
1241 xfs_dir2_sf_entry_t *sfep;
1242 xfs_dir2_sf_hdr_t *sfp;
1243
1244 trace_xfs_dir2_sf_toino8(args);
1245
1246
1247
1248
1249
1250
1251 oldsize = dp->i_df.if_bytes;
1252 buf = kmem_alloc(oldsize, 0);
1253 oldsfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
1254 ASSERT(oldsfp->i8count == 0);
1255 memcpy(buf, oldsfp, oldsize);
1256
1257
1258
1259 newsize = oldsize + (oldsfp->count + 1) * XFS_INO64_DIFF;
1260 xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK);
1261 xfs_idata_realloc(dp, newsize, XFS_DATA_FORK);
1262
1263
1264
1265 oldsfp = (xfs_dir2_sf_hdr_t *)buf;
1266 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
1267
1268
1269
1270 sfp->count = oldsfp->count;
1271 sfp->i8count = 1;
1272 xfs_dir2_sf_put_parent_ino(sfp, xfs_dir2_sf_get_parent_ino(oldsfp));
1273
1274
1275
1276 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
1277 oldsfep = xfs_dir2_sf_firstentry(oldsfp);
1278 i < sfp->count;
1279 i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep),
1280 oldsfep = xfs_dir2_sf_nextentry(mp, oldsfp, oldsfep)) {
1281 sfep->namelen = oldsfep->namelen;
1282 memcpy(sfep->offset, oldsfep->offset, sizeof(sfep->offset));
1283 memcpy(sfep->name, oldsfep->name, sfep->namelen);
1284 xfs_dir2_sf_put_ino(mp, sfp, sfep,
1285 xfs_dir2_sf_get_ino(mp, oldsfp, oldsfep));
1286 xfs_dir2_sf_put_ftype(mp, sfep,
1287 xfs_dir2_sf_get_ftype(mp, oldsfep));
1288 }
1289
1290
1291
1292 kmem_free(buf);
1293 dp->i_disk_size = newsize;
1294 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
1295 }