LCOV - code coverage report
Current view: top level - fs/xfs/libxfs - xfs_dir2_sf.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc3-djwx @ Mon Jul 31 20:08:22 PDT 2023 Lines: 479 605 79.2 %
Date: 2023-07-31 20:08:22 Functions: 19 23 82.6 %

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

Generated by: LCOV version 1.14