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-rc4-xfsa @ Mon Jul 31 20:08:27 PDT 2023 Lines: 478 604 79.1 %
Date: 2023-07-31 20:08:27 Functions: 20 24 83.3 %

          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  8027179927 :         int                     count = len;
      47             : 
      48  8027179927 :         count += sizeof(struct xfs_dir2_sf_entry);      /* namelen + offset */
      49           0 :         count += hdr->i8count ? XFS_INO64_SIZE : XFS_INO32_SIZE; /* ino # */
      50             : 
      51  8027179927 :         if (xfs_has_ftype(mp))
      52  8027616520 :                 count += sizeof(uint8_t);
      53  8027179927 :         return count;
      54             : }
      55             : 
      56             : struct xfs_dir2_sf_entry *
      57  3588446449 : 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  7155522958 :         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  6850583536 : 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  6850583536 :         uint8_t                         *from = sfep->name + sfep->namelen;
      78             : 
      79  6850583536 :         if (xfs_has_ftype(mp))
      80  6851463287 :                 from++;
      81             : 
      82  6850583536 :         if (!hdr->i8count)
      83  6850583536 :                 return get_unaligned_be32(from);
      84           0 :         return get_unaligned_be64(from) & XFS_MAXINUMBER;
      85             : }
      86             : 
      87             : void
      88    72406245 : 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    72406245 :         uint8_t                         *to = sfep->name + sfep->namelen;
      95             : 
      96    72406245 :         ASSERT(ino <= XFS_MAXINUMBER);
      97             : 
      98    72406245 :         if (xfs_has_ftype(mp))
      99    72406142 :                 to++;
     100             : 
     101    72406245 :         if (hdr->i8count)
     102           0 :                 put_unaligned_be64(ino, to);
     103             :         else
     104    72406245 :                 put_unaligned_be32(ino, to);
     105    72406203 : }
     106             : 
     107             : xfs_ino_t
     108  1673562803 : xfs_dir2_sf_get_parent_ino(
     109             :         struct xfs_dir2_sf_hdr  *hdr)
     110             : {
     111  1673562803 :         if (!hdr->i8count)
     112  1673562801 :                 return get_unaligned_be32(hdr->parent);
     113           2 :         return get_unaligned_be64(hdr->parent) & XFS_MAXINUMBER;
     114             : }
     115             : 
     116             : void
     117    20166528 : xfs_dir2_sf_put_parent_ino(
     118             :         struct xfs_dir2_sf_hdr          *hdr,
     119             :         xfs_ino_t                       ino)
     120             : {
     121    20166528 :         ASSERT(ino <= XFS_MAXINUMBER);
     122             : 
     123    20166528 :         if (hdr->i8count)
     124           0 :                 put_unaligned_be64(ino, hdr->parent);
     125             :         else
     126    20166528 :                 put_unaligned_be32(ino, hdr->parent);
     127    20166576 : }
     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  3587412833 : xfs_dir2_sf_get_ftype(
     135             :         struct xfs_mount                *mp,
     136             :         struct xfs_dir2_sf_entry        *sfep)
     137             : {
     138  3587412833 :         if (xfs_has_ftype(mp)) {
     139  3789764991 :                 uint8_t                 ftype = sfep->name[sfep->namelen];
     140             : 
     141  3789764991 :                 if (ftype < XFS_DIR3_FT_MAX)
     142  3792317001 :                         return ftype;
     143             :         }
     144             : 
     145             :         return XFS_DIR3_FT_UNKNOWN;
     146             : }
     147             : 
     148             : void
     149    72407032 : xfs_dir2_sf_put_ftype(
     150             :         struct xfs_mount        *mp,
     151             :         struct xfs_dir2_sf_entry *sfep,
     152             :         uint8_t                 ftype)
     153             : {
     154    72407032 :         ASSERT(ftype < XFS_DIR3_FT_MAX);
     155             : 
     156    72407032 :         if (xfs_has_ftype(mp))
     157    72407422 :                 sfep->name[sfep->namelen] = ftype;
     158    72407032 : }
     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     1843775 : 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     1843775 :         xfs_dir2_dataptr_t      addr;           /* data entry address */
     173     1843775 :         xfs_dir2_leaf_entry_t   *blp;           /* leaf area of the block */
     174     1843775 :         xfs_dir2_block_tail_t   *btp;           /* tail area of the block */
     175     1843775 :         int                     count;          /* shortform entry count */
     176     1843775 :         xfs_dir2_data_entry_t   *dep;           /* data entry in the block */
     177     1843775 :         int                     i;              /* block entry index */
     178     1843775 :         int                     i8count;        /* count of big-inode entries */
     179     1843775 :         int                     isdot;          /* entry is "." */
     180     1843775 :         int                     isdotdot;       /* entry is ".." */
     181     1843775 :         xfs_mount_t             *mp;            /* mount structure pointer */
     182     1843775 :         int                     namelen;        /* total name bytes */
     183     1843775 :         xfs_ino_t               parent = 0;     /* parent inode number */
     184     1843775 :         int                     size=0;         /* total computed size */
     185     1843775 :         int                     has_ftype;
     186     1843775 :         struct xfs_da_geometry  *geo;
     187             : 
     188     1843775 :         mp = dp->i_mount;
     189     1843775 :         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     1843775 :         has_ftype = xfs_has_ftype(mp) ? 1 : 0;
     196             : 
     197     1843775 :         count = i8count = namelen = 0;
     198     1843775 :         btp = xfs_dir2_block_tail_p(geo, hdr);
     199     1843775 :         blp = xfs_dir2_block_leaf_p(btp);
     200             : 
     201             :         /*
     202             :          * Iterate over the block's data entries by using the leaf pointers.
     203             :          */
     204    89429334 :         for (i = 0; i < be32_to_cpu(btp->count); i++) {
     205    88883806 :                 if ((addr = be32_to_cpu(blp[i].address)) == XFS_DIR2_NULL_DATAPTR)
     206    14181307 :                         continue;
     207             :                 /*
     208             :                  * Calculate the pointer to the entry at hand.
     209             :                  */
     210    30260596 :                 dep = (xfs_dir2_data_entry_t *)((char *)hdr +
     211    30260596 :                                 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    30260596 :                 isdot = dep->namelen == 1 && dep->name[0] == '.';
     218    30260596 :                 isdotdot =
     219             :                         dep->namelen == 2 &&
     220    30260596 :                         dep->name[0] == '.' && dep->name[1] == '.';
     221             : 
     222    30260596 :                 if (!isdot)
     223    28416705 :                         i8count += be64_to_cpu(dep->inumber) > XFS_DIR2_MAX_SHORT_INUM;
     224             : 
     225             :                 /* take into account the file type field */
     226    30260596 :                 if (!isdot && !isdotdot) {
     227    26573062 :                         count++;
     228    26573062 :                         namelen += dep->namelen + has_ftype;
     229     3687534 :                 } else if (isdotdot)
     230     1843761 :                         parent = be64_to_cpu(dep->inumber);
     231             :                 /*
     232             :                  * Calculate the new size, see if we should give up yet.
     233             :                  */
     234    30260596 :                 size = xfs_dir2_sf_hdr_size(i8count) +  /* header */
     235    30260596 :                        count * 3 * sizeof(u8) +         /* namelen + offset */
     236    30260596 :                        namelen +                        /* name */
     237             :                        (i8count ?                       /* inumber */
     238           0 :                                 count * XFS_INO64_SIZE :
     239    30260596 :                                 count * XFS_INO32_SIZE);
     240    30260596 :                 if (size > xfs_inode_data_fork_size(dp))
     241     1571011 :                         return size;            /* size value is a failure */
     242             :         }
     243             :         /*
     244             :          * Create the output header, if it worked.
     245             :          */
     246      272764 :         sfhp->count = count;
     247      272764 :         sfhp->i8count = i8count;
     248      272764 :         xfs_dir2_sf_put_parent_ino(sfhp, parent);
     249      272764 :         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      272764 : 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      272764 :         struct xfs_inode        *dp = args->dp;
     264      272764 :         struct xfs_mount        *mp = dp->i_mount;
     265      272764 :         int                     error;          /* error return value */
     266      272764 :         int                     logflags;       /* inode logging flags */
     267      272764 :         struct xfs_dir2_sf_entry *sfep;         /* shortform entry */
     268      272764 :         struct xfs_dir2_sf_hdr  *sfp;           /* shortform directory header */
     269      272764 :         unsigned int            offset = args->geo->data_entry_offset;
     270      272764 :         unsigned int            end;
     271             : 
     272      272764 :         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      272764 :         sfp = kmem_alloc(mp->m_sb.sb_inodesize, 0);
     280      545528 :         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      272764 :         end = xfs_dir3_data_end_offset(args->geo, bp->b_addr);
     287      272764 :         sfep = xfs_dir2_sf_firstentry(sfp);
     288     6163871 :         while (offset < end) {
     289     5891107 :                 struct xfs_dir2_data_unused     *dup = bp->b_addr + offset;
     290     5891107 :                 struct xfs_dir2_data_entry      *dep = bp->b_addr + offset;
     291             : 
     292             :                 /*
     293             :                  * If it's unused, just skip over it.
     294             :                  */
     295     5891107 :                 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
     296     1590246 :                         offset += be16_to_cpu(dup->length);
     297     1590246 :                         continue;
     298             :                 }
     299             : 
     300             :                 /*
     301             :                  * Skip .
     302             :                  */
     303     4300861 :                 if (dep->namelen == 1 && dep->name[0] == '.')
     304      272764 :                         ASSERT(be64_to_cpu(dep->inumber) == dp->i_ino);
     305             :                 /*
     306             :                  * Skip .., but make sure the inode number is right.
     307             :                  */
     308     4028097 :                 else if (dep->namelen == 2 &&
     309      272764 :                          dep->name[0] == '.' && dep->name[1] == '.')
     310      272764 :                         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     3755333 :                         sfep->namelen = dep->namelen;
     317     3755333 :                         xfs_dir2_sf_put_offset(sfep, offset);
     318     7510666 :                         memcpy(sfep->name, dep->name, dep->namelen);
     319     3755333 :                         xfs_dir2_sf_put_ino(mp, sfp, sfep,
     320     3755333 :                                               be64_to_cpu(dep->inumber));
     321     3755333 :                         xfs_dir2_sf_put_ftype(mp, sfep,
     322             :                                         xfs_dir2_data_get_ftype(mp, dep));
     323             : 
     324     3755333 :                         sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
     325             :                 }
     326     8601722 :                 offset += xfs_dir2_data_entsize(mp, dep->namelen);
     327             :         }
     328      272764 :         ASSERT((char *)sfep - (char *)sfp == size);
     329             : 
     330             :         /* now we are done with the block, we can shrink the inode */
     331      272764 :         logflags = XFS_ILOG_CORE;
     332      272764 :         error = xfs_dir2_shrink_inode(args, args->geo->datablk, bp);
     333      272764 :         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      272764 :         ASSERT(dp->i_df.if_bytes == 0);
     345      272764 :         xfs_init_local_fork(dp, XFS_DATA_FORK, sfp, size);
     346      272763 :         dp->i_df.if_format = XFS_DINODE_FMT_LOCAL;
     347      272763 :         dp->i_disk_size = size;
     348             : 
     349      272763 :         logflags |= XFS_ILOG_DDATA;
     350      272763 :         xfs_dir2_sf_check(args);
     351      272763 : out:
     352      272763 :         xfs_trans_log_inode(args->trans, dp, logflags);
     353      272763 :         kmem_free(sfp);
     354      272764 :         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    50877083 : xfs_dir2_sf_addname(
     365             :         xfs_da_args_t           *args)          /* operation arguments */
     366             : {
     367    50877083 :         xfs_inode_t             *dp;            /* incore directory inode */
     368    50877083 :         int                     error;          /* error return value */
     369    50877083 :         int                     incr_isize;     /* total change in size */
     370    50877083 :         int                     new_isize;      /* size after adding name */
     371    50877083 :         int                     objchange;      /* changing to 8-byte inodes */
     372    50877083 :         xfs_dir2_data_aoff_t    offset = 0;     /* offset for new entry */
     373    50877083 :         int                     pick;           /* which algorithm to use */
     374    50877083 :         xfs_dir2_sf_hdr_t       *sfp;           /* shortform structure */
     375    50877083 :         xfs_dir2_sf_entry_t     *sfep = NULL;   /* shortform entry */
     376             : 
     377    50877083 :         trace_xfs_dir2_sf_addname(args);
     378             : 
     379    50877613 :         ASSERT(xfs_dir2_sf_lookup(args) == -ENOENT);
     380    50877562 :         dp = args->dp;
     381    50877562 :         ASSERT(dp->i_df.if_format == XFS_DINODE_FMT_LOCAL);
     382    50877562 :         ASSERT(dp->i_disk_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
     383    50877562 :         ASSERT(dp->i_df.if_bytes == dp->i_disk_size);
     384    50877562 :         ASSERT(dp->i_df.if_u1.if_data != NULL);
     385    50877562 :         sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
     386    50877562 :         ASSERT(dp->i_disk_size >= xfs_dir2_sf_hdr_size(sfp->i8count));
     387             :         /*
     388             :          * Compute entry (and change in) size.
     389             :          */
     390    50877562 :         incr_isize = xfs_dir2_sf_entsize(dp->i_mount, sfp, args->namelen);
     391    50877562 :         objchange = 0;
     392             : 
     393             :         /*
     394             :          * Do we have to change to 8 byte inodes?
     395             :          */
     396    50877562 :         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    50877562 :         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   101360710 :         if (new_isize > xfs_inode_data_fork_size(dp) ||
     410             :             (pick =
     411    50483958 :              xfs_dir2_sf_addname_pick(args, objchange, &sfep, &offset)) == 0) {
     412             :                 /*
     413             :                  * Just checking or no space reservation, it doesn't fit.
     414             :                  */
     415      394019 :                 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      394019 :                 error = xfs_dir2_sf_to_block(args);
     421      394019 :                 if (error)
     422             :                         return error;
     423      394019 :                 return xfs_dir2_block_addname(args);
     424             :         }
     425             :         /*
     426             :          * Just checking, it fits.
     427             :          */
     428    50482733 :         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    50482733 :         if (pick == 1)
     434    50479834 :                 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        2899 :                 ASSERT(pick == 2);
     441        2899 :                 if (objchange)
     442           0 :                         xfs_dir2_sf_toino8(args);
     443        2899 :                 xfs_dir2_sf_addname_hard(args, objchange, new_isize);
     444             :         }
     445    50483295 :         xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
     446    50483295 :         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    50480255 : 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    50480255 :         struct xfs_inode        *dp = args->dp;
     464    50480255 :         struct xfs_mount        *mp = dp->i_mount;
     465    50480255 :         int                     byteoff;        /* byte offset in sf dir */
     466    50480255 :         xfs_dir2_sf_hdr_t       *sfp;           /* shortform structure */
     467             : 
     468    50480255 :         sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
     469    50480255 :         byteoff = (int)((char *)sfep - (char *)sfp);
     470             :         /*
     471             :          * Grow the in-inode space.
     472             :          */
     473   100960510 :         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    50478877 :         sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
     479    50478877 :         sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + byteoff);
     480             :         /*
     481             :          * Fill in the new entry.
     482             :          */
     483    50478877 :         sfep->namelen = args->namelen;
     484    50478877 :         xfs_dir2_sf_put_offset(sfep, offset);
     485   100958624 :         memcpy(sfep->name, args->name, sfep->namelen);
     486    50479312 :         xfs_dir2_sf_put_ino(mp, sfp, sfep, args->inumber);
     487    50479878 :         xfs_dir2_sf_put_ftype(mp, sfep, args->filetype);
     488             : 
     489             :         /*
     490             :          * Update the header and inode.
     491             :          */
     492    50480342 :         sfp->count++;
     493    50480342 :         if (args->inumber > XFS_DIR2_MAX_SHORT_INUM)
     494           0 :                 sfp->i8count++;
     495    50480342 :         dp->i_disk_size = new_isize;
     496    50480342 :         xfs_dir2_sf_check(args);
     497    50480188 : }
     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        2899 : 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        2899 :         struct xfs_inode        *dp = args->dp;
     515        2899 :         struct xfs_mount        *mp = dp->i_mount;
     516        2899 :         int                     add_datasize;   /* data size need for new ent */
     517        2899 :         char                    *buf;           /* buffer for old */
     518        2899 :         int                     eof;            /* reached end of old dir */
     519        2899 :         int                     nbytes;         /* temp for byte copies */
     520        2899 :         xfs_dir2_data_aoff_t    new_offset;     /* next offset value */
     521        2899 :         xfs_dir2_data_aoff_t    offset;         /* current offset value */
     522        2899 :         int                     old_isize;      /* previous size */
     523        2899 :         xfs_dir2_sf_entry_t     *oldsfep;       /* entry in original dir */
     524        2899 :         xfs_dir2_sf_hdr_t       *oldsfp;        /* original shortform dir */
     525        2899 :         xfs_dir2_sf_entry_t     *sfep;          /* entry in new dir */
     526        2899 :         xfs_dir2_sf_hdr_t       *sfp;           /* new shortform dir */
     527             : 
     528             :         /*
     529             :          * Copy the old directory to the stack buffer.
     530             :          */
     531        2899 :         sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
     532        2899 :         old_isize = (int)dp->i_disk_size;
     533        2899 :         buf = kmem_alloc(old_isize, 0);
     534        2899 :         oldsfp = (xfs_dir2_sf_hdr_t *)buf;
     535        5798 :         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        2899 :         for (offset = args->geo->data_first_offset,
     542             :               oldsfep = xfs_dir2_sf_firstentry(oldsfp),
     543        2899 :               add_datasize = xfs_dir2_data_entsize(mp, args->namelen),
     544        2899 :               eof = (char *)oldsfep == &buf[old_isize];
     545       12005 :              !eof;
     546        9106 :              offset = new_offset + xfs_dir2_data_entsize(mp, oldsfep->namelen),
     547        9106 :               oldsfep = xfs_dir2_sf_nextentry(mp, oldsfp, oldsfep),
     548        9106 :               eof = (char *)oldsfep == &buf[old_isize]) {
     549       12005 :                 new_offset = xfs_dir2_sf_get_offset(oldsfep);
     550       12005 :                 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        2899 :         xfs_idata_realloc(dp, -old_isize, XFS_DATA_FORK);
     559        2899 :         xfs_idata_realloc(dp, new_isize, XFS_DATA_FORK);
     560             :         /*
     561             :          * Reset the pointer since the buffer was reallocated.
     562             :          */
     563        2899 :         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        2899 :         nbytes = (int)((char *)oldsfep - (char *)oldsfp);
     568        5798 :         memcpy(sfp, oldsfp, nbytes);
     569        2899 :         sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + nbytes);
     570             :         /*
     571             :          * Fill in the new entry, and update the header counts.
     572             :          */
     573        2899 :         sfep->namelen = args->namelen;
     574        2899 :         xfs_dir2_sf_put_offset(sfep, offset);
     575        5798 :         memcpy(sfep->name, args->name, sfep->namelen);
     576        2899 :         xfs_dir2_sf_put_ino(mp, sfp, sfep, args->inumber);
     577        2899 :         xfs_dir2_sf_put_ftype(mp, sfep, args->filetype);
     578        2899 :         sfp->count++;
     579        2899 :         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        2899 :         if (!eof) {
     585        2899 :                 sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
     586        5798 :                 memcpy(sfep, oldsfep, old_isize - nbytes);
     587             :         }
     588        2899 :         kmem_free(buf);
     589        2899 :         dp->i_disk_size = new_isize;
     590        2899 :         xfs_dir2_sf_check(args);
     591        2899 : }
     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    50484255 : 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    50484255 :         struct xfs_inode        *dp = args->dp;
     608    50484255 :         struct xfs_mount        *mp = dp->i_mount;
     609    50484255 :         int                     holefit;        /* found hole it will fit in */
     610    50484255 :         int                     i;              /* entry number */
     611    50484255 :         xfs_dir2_data_aoff_t    offset;         /* data block offset */
     612    50484255 :         xfs_dir2_sf_entry_t     *sfep;          /* shortform entry */
     613    50484255 :         xfs_dir2_sf_hdr_t       *sfp;           /* shortform structure */
     614    50484255 :         int                     size;           /* entry's data size */
     615    50484255 :         int                     used;           /* data bytes used */
     616             : 
     617    50484255 :         sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
     618    50484255 :         size = xfs_dir2_data_entsize(mp, args->namelen);
     619    50484255 :         offset = args->geo->data_first_offset;
     620    50484255 :         sfep = xfs_dir2_sf_firstentry(sfp);
     621    50484255 :         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   228036096 :         for (i = 0; i < sfp->count; i++) {
     628   177551841 :                 if (!holefit)
     629    93487532 :                         holefit = offset + size <= xfs_dir2_sf_get_offset(sfep);
     630   177551841 :                 offset = xfs_dir2_sf_get_offset(sfep) +
     631   177551841 :                          xfs_dir2_data_entsize(mp, sfep->namelen);
     632   177551841 :                 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    50484255 :         used = offset +
     639    50484255 :                (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    78724748 :         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    50483039 :         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    50483039 :         if (used + size > args->geo->blksize)
     657             :                 return 2;
     658             :         /*
     659             :          * Do it the easy way.
     660             :          */
     661    50480140 :         *sfepp = sfep;
     662    50480140 :         *offsetp = offset;
     663    50480140 :         return 1;
     664             : }
     665             : 
     666             : #ifdef DEBUG
     667             : /*
     668             :  * Check consistency of shortform directory, assert if bad.
     669             :  */
     670             : static void
     671   458444862 : xfs_dir2_sf_check(
     672             :         xfs_da_args_t           *args)          /* operation arguments */
     673             : {
     674   458444862 :         struct xfs_inode        *dp = args->dp;
     675   458444862 :         struct xfs_mount        *mp = dp->i_mount;
     676   458444862 :         int                     i;              /* entry number */
     677   458444862 :         int                     i8count;        /* number of big inode#s */
     678   458444862 :         xfs_ino_t               ino;            /* entry inode number */
     679   458444862 :         int                     offset;         /* data offset */
     680   458444862 :         xfs_dir2_sf_entry_t     *sfep;          /* shortform dir entry */
     681   458444862 :         xfs_dir2_sf_hdr_t       *sfp;           /* shortform structure */
     682             : 
     683   458444862 :         sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
     684   458444862 :         offset = args->geo->data_first_offset;
     685   458444862 :         ino = xfs_dir2_sf_get_parent_ino(sfp);
     686   458444862 :         i8count = ino > XFS_DIR2_MAX_SHORT_INUM;
     687             : 
     688   458444862 :         for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
     689  2912313736 :              i < sfp->count;
     690  2453868874 :              i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep)) {
     691  2453857227 :                 ASSERT(xfs_dir2_sf_get_offset(sfep) >= offset);
     692  2453868874 :                 ino = xfs_dir2_sf_get_ino(mp, sfp, sfep);
     693  2453868874 :                 i8count += ino > XFS_DIR2_MAX_SHORT_INUM;
     694  2453868874 :                 offset =
     695  2453868874 :                         xfs_dir2_sf_get_offset(sfep) +
     696  2453868874 :                         xfs_dir2_data_entsize(mp, sfep->namelen);
     697  2453868874 :                 ASSERT(xfs_dir2_sf_get_ftype(mp, sfep) < XFS_DIR3_FT_MAX);
     698             :         }
     699   458456509 :         ASSERT(i8count == sfp->i8count);
     700   458456509 :         ASSERT((char *)sfep - (char *)sfp == dp->i_disk_size);
     701   458456509 :         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   458456509 : }
     705             : #endif  /* DEBUG */
     706             : 
     707             : /* Verify the consistency of an inline directory. */
     708             : xfs_failaddr_t
     709   128791982 : xfs_dir2_sf_verify_struct(
     710             :         struct xfs_mount                *mp,
     711             :         struct xfs_dir2_sf_hdr          *sfp,
     712             :         int64_t                         size)
     713             : {
     714   128791982 :         struct xfs_dir2_sf_entry        *sfep;
     715   128791982 :         struct xfs_dir2_sf_entry        *next_sfep;
     716   128791982 :         char                            *endp;
     717   128791982 :         xfs_ino_t                       ino;
     718   128791982 :         int                             i;
     719   128791982 :         int                             i8count;
     720   128791982 :         int                             offset;
     721   128791982 :         int                             error;
     722   128791982 :         uint8_t                         filetype;
     723             : 
     724             :         /*
     725             :          * Give up if the directory is way too short.
     726             :          */
     727   128791982 :         if (size <= offsetof(struct xfs_dir2_sf_hdr, parent) ||
     728   128791984 :             size < xfs_dir2_sf_hdr_size(sfp->i8count))
     729           0 :                 return __this_address;
     730             : 
     731   128793163 :         endp = (char *)sfp + size;
     732             : 
     733             :         /* Check .. entry */
     734   128793163 :         ino = xfs_dir2_sf_get_parent_ino(sfp);
     735   128793163 :         i8count = ino > XFS_DIR2_MAX_SHORT_INUM;
     736   128793163 :         error = xfs_dir_ino_validate(mp, ino);
     737   128794250 :         if (error)
     738           2 :                 return __this_address;
     739   128794248 :         offset = mp->m_dir_geo->data_first_offset;
     740             : 
     741             :         /* Check all reported entries */
     742   128794248 :         sfep = xfs_dir2_sf_firstentry(sfp);
     743   696608141 :         for (i = 0; i < sfp->count; i++) {
     744             :                 /*
     745             :                  * struct xfs_dir2_sf_entry has a variable length.
     746             :                  * Check the fixed-offset parts of the structure are
     747             :                  * within the data buffer.
     748             :                  */
     749   567813319 :                 if (((char *)sfep + sizeof(*sfep)) >= endp)
     750           0 :                         return __this_address;
     751             : 
     752             :                 /* Don't allow names with known bad length. */
     753   567813319 :                 if (sfep->namelen == 0)
     754           0 :                         return __this_address;
     755             : 
     756             :                 /*
     757             :                  * Check that the variable-length part of the structure is
     758             :                  * within the data buffer.  The next entry starts after the
     759             :                  * name component, so nextentry is an acceptable test.
     760             :                  */
     761   567813319 :                 next_sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
     762   567813319 :                 if (endp < (char *)next_sfep)
     763           0 :                         return __this_address;
     764             : 
     765             :                 /* Check that the offsets always increase. */
     766   567813319 :                 if (xfs_dir2_sf_get_offset(sfep) < offset)
     767           0 :                         return __this_address;
     768             : 
     769             :                 /* Check the inode number. */
     770   567813319 :                 ino = xfs_dir2_sf_get_ino(mp, sfp, sfep);
     771   567813319 :                 i8count += ino > XFS_DIR2_MAX_SHORT_INUM;
     772   567813319 :                 error = xfs_dir_ino_validate(mp, ino);
     773   567813893 :                 if (error)
     774           0 :                         return __this_address;
     775             : 
     776             :                 /* Check the file type. */
     777   567813893 :                 filetype = xfs_dir2_sf_get_ftype(mp, sfep);
     778             :                 if (filetype >= XFS_DIR3_FT_MAX)
     779   567813893 :                         return __this_address;
     780             : 
     781   567813893 :                 offset = xfs_dir2_sf_get_offset(sfep) +
     782   567813893 :                                 xfs_dir2_data_entsize(mp, sfep->namelen);
     783             : 
     784   567813893 :                 sfep = next_sfep;
     785             :         }
     786   128794822 :         if (i8count != sfp->i8count)
     787           0 :                 return __this_address;
     788   128794822 :         if ((void *)sfep != (void *)endp)
     789           0 :                 return __this_address;
     790             : 
     791             :         /* Make sure this whole thing ought to be in local format. */
     792   128794822 :         if (offset + (sfp->count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) +
     793   128794822 :             (uint)sizeof(xfs_dir2_block_tail_t) > mp->m_dir_geo->blksize)
     794           0 :                 return __this_address;
     795             : 
     796             :         return NULL;
     797             : }
     798             : 
     799             : xfs_failaddr_t
     800   128792994 : xfs_dir2_sf_verify(
     801             :         struct xfs_inode                *ip)
     802             : {
     803   128792994 :         struct xfs_mount                *mp = ip->i_mount;
     804   128792994 :         struct xfs_ifork                *ifp = xfs_ifork_ptr(ip, XFS_DATA_FORK);
     805   128792994 :         struct xfs_dir2_sf_hdr          *sfp;
     806             : 
     807   128792994 :         ASSERT(ifp->if_format == XFS_DINODE_FMT_LOCAL);
     808             : 
     809   128792994 :         sfp = (struct xfs_dir2_sf_hdr *)ifp->if_u1.if_data;
     810   128792994 :         return xfs_dir2_sf_verify_struct(mp, sfp, ifp->if_bytes);
     811             : }
     812             : 
     813             : /*
     814             :  * Create a new (shortform) directory.
     815             :  */
     816             : int                                     /* error, always 0 */
     817     6880384 : xfs_dir2_sf_create(
     818             :         xfs_da_args_t   *args,          /* operation arguments */
     819             :         xfs_ino_t       pino)           /* parent inode number */
     820             : {
     821     6880384 :         xfs_inode_t     *dp;            /* incore directory inode */
     822     6880384 :         int             i8count;        /* parent inode is an 8-byte number */
     823     6880384 :         xfs_dir2_sf_hdr_t *sfp;         /* shortform structure */
     824     6880384 :         int             size;           /* directory size */
     825             : 
     826     6880384 :         trace_xfs_dir2_sf_create(args);
     827             : 
     828     6880437 :         dp = args->dp;
     829             : 
     830     6880437 :         ASSERT(dp != NULL);
     831     6880437 :         ASSERT(dp->i_disk_size == 0);
     832             :         /*
     833             :          * If it's currently a zero-length extent file,
     834             :          * convert it to local format.
     835             :          */
     836     6880437 :         if (dp->i_df.if_format == XFS_DINODE_FMT_EXTENTS) {
     837     6857331 :                 dp->i_df.if_format = XFS_DINODE_FMT_LOCAL;
     838     6857331 :                 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
     839             :         }
     840     6880448 :         ASSERT(dp->i_df.if_format == XFS_DINODE_FMT_LOCAL);
     841     6880448 :         ASSERT(dp->i_df.if_bytes == 0);
     842     6880448 :         i8count = pino > XFS_DIR2_MAX_SHORT_INUM;
     843     6880448 :         size = xfs_dir2_sf_hdr_size(i8count);
     844             :         /*
     845             :          * Make a buffer for the data.
     846             :          */
     847     6880448 :         xfs_idata_realloc(dp, size, XFS_DATA_FORK);
     848             :         /*
     849             :          * Fill in the header,
     850             :          */
     851     6880396 :         sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
     852     6880396 :         sfp->i8count = i8count;
     853             :         /*
     854             :          * Now can put in the inode number, since i8count is set.
     855             :          */
     856     6880396 :         xfs_dir2_sf_put_parent_ino(sfp, pino);
     857     6880330 :         sfp->count = 0;
     858     6880330 :         dp->i_disk_size = size;
     859     6880330 :         xfs_dir2_sf_check(args);
     860     6880316 :         xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
     861     6880369 :         return 0;
     862             : }
     863             : 
     864             : /*
     865             :  * Lookup an entry in a shortform directory.
     866             :  * Returns EEXIST if found, ENOENT if not found.
     867             :  */
     868             : int                                             /* error */
     869   344754319 : xfs_dir2_sf_lookup(
     870             :         xfs_da_args_t           *args)          /* operation arguments */
     871             : {
     872   344754319 :         struct xfs_inode        *dp = args->dp;
     873   344754319 :         struct xfs_mount        *mp = dp->i_mount;
     874   344754319 :         int                     i;              /* entry index */
     875   344754319 :         xfs_dir2_sf_entry_t     *sfep;          /* shortform directory entry */
     876   344754319 :         xfs_dir2_sf_hdr_t       *sfp;           /* shortform structure */
     877   344754319 :         enum xfs_dacmp          cmp;            /* comparison result */
     878   344754319 :         xfs_dir2_sf_entry_t     *ci_sfep;       /* case-insens. entry */
     879             : 
     880   344754319 :         trace_xfs_dir2_sf_lookup(args);
     881             : 
     882   344758534 :         xfs_dir2_sf_check(args);
     883             : 
     884   344781797 :         ASSERT(dp->i_df.if_format == XFS_DINODE_FMT_LOCAL);
     885   344781797 :         ASSERT(dp->i_disk_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
     886   344781797 :         ASSERT(dp->i_df.if_bytes == dp->i_disk_size);
     887   344781797 :         ASSERT(dp->i_df.if_u1.if_data != NULL);
     888   344781797 :         sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
     889   344781797 :         ASSERT(dp->i_disk_size >= xfs_dir2_sf_hdr_size(sfp->i8count));
     890             :         /*
     891             :          * Special case for .
     892             :          */
     893   344781797 :         if (args->namelen == 1 && args->name[0] == '.') {
     894    11005287 :                 args->inumber = dp->i_ino;
     895    11005287 :                 args->cmpresult = XFS_CMP_EXACT;
     896    11005287 :                 args->filetype = XFS_DIR3_FT_DIR;
     897    11005287 :                 return -EEXIST;
     898             :         }
     899             :         /*
     900             :          * Special case for ..
     901             :          */
     902   333776510 :         if (args->namelen == 2 &&
     903    27131373 :             args->name[0] == '.' && args->name[1] == '.') {
     904    23670532 :                 args->inumber = xfs_dir2_sf_get_parent_ino(sfp);
     905    23670532 :                 args->cmpresult = XFS_CMP_EXACT;
     906    23670532 :                 args->filetype = XFS_DIR3_FT_DIR;
     907    23670532 :                 return -EEXIST;
     908             :         }
     909             :         /*
     910             :          * Loop over all the entries trying to match ours.
     911             :          */
     912   310105978 :         ci_sfep = NULL;
     913  1638764401 :         for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
     914  1018552445 :              i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep)) {
     915             :                 /*
     916             :                  * Compare name and if it's an exact match, return the inode
     917             :                  * number. If it's the first case-insensitive match, store the
     918             :                  * inode number and continue looking for an exact match.
     919             :                  */
     920  1220763129 :                 cmp = xfs_dir2_compname(args, sfep->name, sfep->namelen);
     921  1220775937 :                 if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
     922   202223785 :                         args->cmpresult = cmp;
     923   202223785 :                         args->inumber = xfs_dir2_sf_get_ino(mp, sfp, sfep);
     924   202223785 :                         args->filetype = xfs_dir2_sf_get_ftype(mp, sfep);
     925   202223785 :                         if (cmp == XFS_CMP_EXACT)
     926             :                                 return -EEXIST;
     927             :                         ci_sfep = sfep;
     928             :                 }
     929             :         }
     930   107895294 :         ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
     931             :         /*
     932             :          * Here, we can only be doing a lookup (not a rename or replace).
     933             :          * If a case-insensitive match was not found, return -ENOENT.
     934             :          */
     935   107895294 :         if (!ci_sfep)
     936             :                 return -ENOENT;
     937             :         /* otherwise process the CI match as required by the caller */
     938         530 :         return xfs_dir_cilookup_result(args, ci_sfep->name, ci_sfep->namelen);
     939             : }
     940             : 
     941             : /*
     942             :  * Remove an entry from a shortform directory.
     943             :  */
     944             : int                                             /* error */
     945    24921948 : xfs_dir2_sf_removename(
     946             :         xfs_da_args_t           *args)
     947             : {
     948    24921948 :         struct xfs_inode        *dp = args->dp;
     949    24921948 :         struct xfs_mount        *mp = dp->i_mount;
     950    24921948 :         int                     byteoff;        /* offset of removed entry */
     951    24921948 :         int                     entsize;        /* this entry's size */
     952    24921948 :         int                     i;              /* shortform entry index */
     953    24921948 :         int                     newsize;        /* new inode size */
     954    24921948 :         int                     oldsize;        /* old inode size */
     955    24921948 :         xfs_dir2_sf_entry_t     *sfep;          /* shortform directory entry */
     956    24921948 :         xfs_dir2_sf_hdr_t       *sfp;           /* shortform structure */
     957             : 
     958    24921948 :         trace_xfs_dir2_sf_removename(args);
     959             : 
     960    24921733 :         ASSERT(dp->i_df.if_format == XFS_DINODE_FMT_LOCAL);
     961    24921733 :         oldsize = (int)dp->i_disk_size;
     962    24921733 :         ASSERT(oldsize >= offsetof(struct xfs_dir2_sf_hdr, parent));
     963    24921733 :         ASSERT(dp->i_df.if_bytes == oldsize);
     964    24921733 :         ASSERT(dp->i_df.if_u1.if_data != NULL);
     965    24921733 :         sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
     966    24921733 :         ASSERT(oldsize >= xfs_dir2_sf_hdr_size(sfp->i8count));
     967             :         /*
     968             :          * Loop over the old directory entries.
     969             :          * Find the one we're deleting.
     970             :          */
     971    99719133 :         for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
     972    49875667 :              i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep)) {
     973    74797342 :                 if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
     974             :                                                                 XFS_CMP_EXACT) {
     975    24921929 :                         ASSERT(xfs_dir2_sf_get_ino(mp, sfp, sfep) ==
     976             :                                args->inumber);
     977             :                         break;
     978             :                 }
     979             :         }
     980             :         /*
     981             :          * Didn't find it.
     982             :          */
     983    24921987 :         if (i == sfp->count)
     984             :                 return -ENOENT;
     985             :         /*
     986             :          * Calculate sizes.
     987             :          */
     988    24921987 :         byteoff = (int)((char *)sfep - (char *)sfp);
     989    24921987 :         entsize = xfs_dir2_sf_entsize(mp, sfp, args->namelen);
     990    24921987 :         newsize = oldsize - entsize;
     991             :         /*
     992             :          * Copy the part if any after the removed entry, sliding it down.
     993             :          */
     994    24921987 :         if (byteoff + entsize < oldsize)
     995    32199294 :                 memmove((char *)sfp + byteoff, (char *)sfp + byteoff + entsize,
     996             :                         oldsize - (byteoff + entsize));
     997             :         /*
     998             :          * Fix up the header and file size.
     999             :          */
    1000    24921987 :         sfp->count--;
    1001    24921987 :         dp->i_disk_size = newsize;
    1002             :         /*
    1003             :          * Reallocate, making it smaller.
    1004             :          */
    1005    24921987 :         xfs_idata_realloc(dp, newsize - oldsize, XFS_DATA_FORK);
    1006    24921783 :         sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
    1007             :         /*
    1008             :          * Are we changing inode number size?
    1009             :          */
    1010    24921783 :         if (args->inumber > XFS_DIR2_MAX_SHORT_INUM) {
    1011           0 :                 if (sfp->i8count == 1)
    1012           0 :                         xfs_dir2_sf_toino4(args);
    1013             :                 else
    1014           0 :                         sfp->i8count--;
    1015             :         }
    1016    24921783 :         xfs_dir2_sf_check(args);
    1017    24921991 :         xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
    1018    24921991 :         return 0;
    1019             : }
    1020             : 
    1021             : /*
    1022             :  * Check whether the sf dir replace operation need more blocks.
    1023             :  */
    1024             : static bool
    1025           0 : xfs_dir2_sf_replace_needblock(
    1026             :         struct xfs_inode        *dp,
    1027             :         xfs_ino_t               inum)
    1028             : {
    1029           0 :         int                     newsize;
    1030           0 :         struct xfs_dir2_sf_hdr  *sfp;
    1031             : 
    1032           0 :         if (dp->i_df.if_format != XFS_DINODE_FMT_LOCAL)
    1033             :                 return false;
    1034             : 
    1035           0 :         sfp = (struct xfs_dir2_sf_hdr *)dp->i_df.if_u1.if_data;
    1036           0 :         newsize = dp->i_df.if_bytes + (sfp->count + 1) * XFS_INO64_DIFF;
    1037             : 
    1038           0 :         return inum > XFS_DIR2_MAX_SHORT_INUM &&
    1039           0 :                sfp->i8count == 0 && newsize > xfs_inode_data_fork_size(dp);
    1040             : }
    1041             : 
    1042             : /*
    1043             :  * Replace the inode number of an entry in a shortform directory.
    1044             :  */
    1045             : int                                             /* error */
    1046    31182736 : xfs_dir2_sf_replace(
    1047             :         xfs_da_args_t           *args)          /* operation arguments */
    1048             : {
    1049    31182736 :         struct xfs_inode        *dp = args->dp;
    1050    31182736 :         struct xfs_mount        *mp = dp->i_mount;
    1051    31182736 :         int                     i;              /* entry index */
    1052    31182736 :         xfs_ino_t               ino=0;          /* entry old inode number */
    1053    31182736 :         int                     i8elevated;     /* sf_toino8 set i8count=1 */
    1054    31182736 :         xfs_dir2_sf_entry_t     *sfep;          /* shortform directory entry */
    1055    31182736 :         xfs_dir2_sf_hdr_t       *sfp;           /* shortform structure */
    1056             : 
    1057    31182736 :         trace_xfs_dir2_sf_replace(args);
    1058             : 
    1059    31182790 :         ASSERT(dp->i_df.if_format == XFS_DINODE_FMT_LOCAL);
    1060    31182790 :         ASSERT(dp->i_disk_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
    1061    31182790 :         ASSERT(dp->i_df.if_bytes == dp->i_disk_size);
    1062    31182790 :         ASSERT(dp->i_df.if_u1.if_data != NULL);
    1063    31182790 :         sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
    1064    31182790 :         ASSERT(dp->i_disk_size >= xfs_dir2_sf_hdr_size(sfp->i8count));
    1065             : 
    1066             :         /*
    1067             :          * New inode number is large, and need to convert to 8-byte inodes.
    1068             :          */
    1069    31182790 :         if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->i8count == 0) {
    1070           0 :                 int     error;                  /* error return value */
    1071             : 
    1072             :                 /*
    1073             :                  * Won't fit as shortform, convert to block then do replace.
    1074             :                  */
    1075           0 :                 if (xfs_dir2_sf_replace_needblock(dp, args->inumber)) {
    1076           0 :                         error = xfs_dir2_sf_to_block(args);
    1077           0 :                         if (error)
    1078             :                                 return error;
    1079           0 :                         return xfs_dir2_block_replace(args);
    1080             :                 }
    1081             :                 /*
    1082             :                  * Still fits, convert to 8-byte now.
    1083             :                  */
    1084           0 :                 xfs_dir2_sf_toino8(args);
    1085           0 :                 i8elevated = 1;
    1086           0 :                 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
    1087             :         } else
    1088             :                 i8elevated = 0;
    1089             : 
    1090    31182790 :         ASSERT(args->namelen != 1 || args->name[0] != '.');
    1091             :         /*
    1092             :          * Replace ..'s entry.
    1093             :          */
    1094    31182790 :         if (args->namelen == 2 &&
    1095    13040516 :             args->name[0] == '.' && args->name[1] == '.') {
    1096    13013537 :                 ino = xfs_dir2_sf_get_parent_ino(sfp);
    1097    13013537 :                 ASSERT(args->inumber != ino);
    1098    13013537 :                 xfs_dir2_sf_put_parent_ino(sfp, args->inumber);
    1099             :         }
    1100             :         /*
    1101             :          * Normal entry, look for the name.
    1102             :          */
    1103             :         else {
    1104    77362696 :                 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
    1105    41024190 :                      i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep)) {
    1106    59193443 :                         if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
    1107             :                                                                 XFS_CMP_EXACT) {
    1108    18169252 :                                 ino = xfs_dir2_sf_get_ino(mp, sfp, sfep);
    1109    18169252 :                                 ASSERT(args->inumber != ino);
    1110    18169252 :                                 xfs_dir2_sf_put_ino(mp, sfp, sfep,
    1111             :                                                 args->inumber);
    1112    18169250 :                                 xfs_dir2_sf_put_ftype(mp, sfep, args->filetype);
    1113    18169250 :                                 break;
    1114             :                         }
    1115             :                 }
    1116             :                 /*
    1117             :                  * Didn't find it.
    1118             :                  */
    1119    18169249 :                 if (i == sfp->count) {
    1120           0 :                         ASSERT(args->op_flags & XFS_DA_OP_OKNOENT);
    1121           0 :                         if (i8elevated)
    1122           0 :                                 xfs_dir2_sf_toino4(args);
    1123           0 :                         return -ENOENT;
    1124             :                 }
    1125             :         }
    1126             :         /*
    1127             :          * See if the old number was large, the new number is small.
    1128             :          */
    1129    31182792 :         if (ino > XFS_DIR2_MAX_SHORT_INUM &&
    1130           0 :             args->inumber <= XFS_DIR2_MAX_SHORT_INUM) {
    1131             :                 /*
    1132             :                  * And the old count was one, so need to convert to small.
    1133             :                  */
    1134           0 :                 if (sfp->i8count == 1)
    1135           0 :                         xfs_dir2_sf_toino4(args);
    1136             :                 else
    1137           0 :                         sfp->i8count--;
    1138             :         }
    1139             :         /*
    1140             :          * See if the old number was small, the new number is large.
    1141             :          */
    1142    31182792 :         if (ino <= XFS_DIR2_MAX_SHORT_INUM &&
    1143    31182780 :             args->inumber > XFS_DIR2_MAX_SHORT_INUM) {
    1144             :                 /*
    1145             :                  * add to the i8count unless we just converted to 8-byte
    1146             :                  * inodes (which does an implied i8count = 1)
    1147             :                  */
    1148           0 :                 ASSERT(sfp->i8count != 0);
    1149           0 :                 if (!i8elevated)
    1150           0 :                         sfp->i8count++;
    1151             :         }
    1152    31182792 :         xfs_dir2_sf_check(args);
    1153    31182780 :         xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA);
    1154    31182780 :         return 0;
    1155             : }
    1156             : 
    1157             : /*
    1158             :  * Convert from 8-byte inode numbers to 4-byte inode numbers.
    1159             :  * The last 8-byte inode number is gone, but the count is still 1.
    1160             :  */
    1161             : static void
    1162           0 : xfs_dir2_sf_toino4(
    1163             :         xfs_da_args_t           *args)          /* operation arguments */
    1164             : {
    1165           0 :         struct xfs_inode        *dp = args->dp;
    1166           0 :         struct xfs_mount        *mp = dp->i_mount;
    1167           0 :         char                    *buf;           /* old dir's buffer */
    1168           0 :         int                     i;              /* entry index */
    1169           0 :         int                     newsize;        /* new inode size */
    1170           0 :         xfs_dir2_sf_entry_t     *oldsfep;       /* old sf entry */
    1171           0 :         xfs_dir2_sf_hdr_t       *oldsfp;        /* old sf directory */
    1172           0 :         int                     oldsize;        /* old inode size */
    1173           0 :         xfs_dir2_sf_entry_t     *sfep;          /* new sf entry */
    1174           0 :         xfs_dir2_sf_hdr_t       *sfp;           /* new sf directory */
    1175             : 
    1176           0 :         trace_xfs_dir2_sf_toino4(args);
    1177             : 
    1178             :         /*
    1179             :          * Copy the old directory to the buffer.
    1180             :          * Then nuke it from the inode, and add the new buffer to the inode.
    1181             :          * Don't want xfs_idata_realloc copying the data here.
    1182             :          */
    1183           0 :         oldsize = dp->i_df.if_bytes;
    1184           0 :         buf = kmem_alloc(oldsize, 0);
    1185           0 :         oldsfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
    1186           0 :         ASSERT(oldsfp->i8count == 1);
    1187           0 :         memcpy(buf, oldsfp, oldsize);
    1188             :         /*
    1189             :          * Compute the new inode size.
    1190             :          */
    1191           0 :         newsize = oldsize - (oldsfp->count + 1) * XFS_INO64_DIFF;
    1192           0 :         xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK);
    1193           0 :         xfs_idata_realloc(dp, newsize, XFS_DATA_FORK);
    1194             :         /*
    1195             :          * Reset our pointers, the data has moved.
    1196             :          */
    1197           0 :         oldsfp = (xfs_dir2_sf_hdr_t *)buf;
    1198           0 :         sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
    1199             :         /*
    1200             :          * Fill in the new header.
    1201             :          */
    1202           0 :         sfp->count = oldsfp->count;
    1203           0 :         sfp->i8count = 0;
    1204           0 :         xfs_dir2_sf_put_parent_ino(sfp, xfs_dir2_sf_get_parent_ino(oldsfp));
    1205             :         /*
    1206             :          * Copy the entries field by field.
    1207             :          */
    1208           0 :         for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
    1209             :                     oldsfep = xfs_dir2_sf_firstentry(oldsfp);
    1210           0 :              i < sfp->count;
    1211           0 :              i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep),
    1212             :                   oldsfep = xfs_dir2_sf_nextentry(mp, oldsfp, oldsfep)) {
    1213           0 :                 sfep->namelen = oldsfep->namelen;
    1214           0 :                 memcpy(sfep->offset, oldsfep->offset, sizeof(sfep->offset));
    1215           0 :                 memcpy(sfep->name, oldsfep->name, sfep->namelen);
    1216           0 :                 xfs_dir2_sf_put_ino(mp, sfp, sfep,
    1217             :                                 xfs_dir2_sf_get_ino(mp, oldsfp, oldsfep));
    1218           0 :                 xfs_dir2_sf_put_ftype(mp, sfep,
    1219             :                                 xfs_dir2_sf_get_ftype(mp, oldsfep));
    1220             :         }
    1221             :         /*
    1222             :          * Clean up the inode.
    1223             :          */
    1224           0 :         kmem_free(buf);
    1225           0 :         dp->i_disk_size = newsize;
    1226           0 :         xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
    1227           0 : }
    1228             : 
    1229             : /*
    1230             :  * Convert existing entries from 4-byte inode numbers to 8-byte inode numbers.
    1231             :  * The new entry w/ an 8-byte inode number is not there yet; we leave with
    1232             :  * i8count set to 1, but no corresponding 8-byte entry.
    1233             :  */
    1234             : static void
    1235           0 : xfs_dir2_sf_toino8(
    1236             :         xfs_da_args_t           *args)          /* operation arguments */
    1237             : {
    1238           0 :         struct xfs_inode        *dp = args->dp;
    1239           0 :         struct xfs_mount        *mp = dp->i_mount;
    1240           0 :         char                    *buf;           /* old dir's buffer */
    1241           0 :         int                     i;              /* entry index */
    1242           0 :         int                     newsize;        /* new inode size */
    1243           0 :         xfs_dir2_sf_entry_t     *oldsfep;       /* old sf entry */
    1244           0 :         xfs_dir2_sf_hdr_t       *oldsfp;        /* old sf directory */
    1245           0 :         int                     oldsize;        /* old inode size */
    1246           0 :         xfs_dir2_sf_entry_t     *sfep;          /* new sf entry */
    1247           0 :         xfs_dir2_sf_hdr_t       *sfp;           /* new sf directory */
    1248             : 
    1249           0 :         trace_xfs_dir2_sf_toino8(args);
    1250             : 
    1251             :         /*
    1252             :          * Copy the old directory to the buffer.
    1253             :          * Then nuke it from the inode, and add the new buffer to the inode.
    1254             :          * Don't want xfs_idata_realloc copying the data here.
    1255             :          */
    1256           0 :         oldsize = dp->i_df.if_bytes;
    1257           0 :         buf = kmem_alloc(oldsize, 0);
    1258           0 :         oldsfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
    1259           0 :         ASSERT(oldsfp->i8count == 0);
    1260           0 :         memcpy(buf, oldsfp, oldsize);
    1261             :         /*
    1262             :          * Compute the new inode size (nb: entry count + 1 for parent)
    1263             :          */
    1264           0 :         newsize = oldsize + (oldsfp->count + 1) * XFS_INO64_DIFF;
    1265           0 :         xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK);
    1266           0 :         xfs_idata_realloc(dp, newsize, XFS_DATA_FORK);
    1267             :         /*
    1268             :          * Reset our pointers, the data has moved.
    1269             :          */
    1270           0 :         oldsfp = (xfs_dir2_sf_hdr_t *)buf;
    1271           0 :         sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
    1272             :         /*
    1273             :          * Fill in the new header.
    1274             :          */
    1275           0 :         sfp->count = oldsfp->count;
    1276           0 :         sfp->i8count = 1;
    1277           0 :         xfs_dir2_sf_put_parent_ino(sfp, xfs_dir2_sf_get_parent_ino(oldsfp));
    1278             :         /*
    1279             :          * Copy the entries field by field.
    1280             :          */
    1281           0 :         for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
    1282             :                     oldsfep = xfs_dir2_sf_firstentry(oldsfp);
    1283           0 :              i < sfp->count;
    1284           0 :              i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep),
    1285             :                   oldsfep = xfs_dir2_sf_nextentry(mp, oldsfp, oldsfep)) {
    1286           0 :                 sfep->namelen = oldsfep->namelen;
    1287           0 :                 memcpy(sfep->offset, oldsfep->offset, sizeof(sfep->offset));
    1288           0 :                 memcpy(sfep->name, oldsfep->name, sfep->namelen);
    1289           0 :                 xfs_dir2_sf_put_ino(mp, sfp, sfep,
    1290             :                                 xfs_dir2_sf_get_ino(mp, oldsfp, oldsfep));
    1291           0 :                 xfs_dir2_sf_put_ftype(mp, sfep,
    1292             :                                 xfs_dir2_sf_get_ftype(mp, oldsfep));
    1293             :         }
    1294             :         /*
    1295             :          * Clean up the inode.
    1296             :          */
    1297           0 :         kmem_free(buf);
    1298           0 :         dp->i_disk_size = newsize;
    1299           0 :         xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
    1300           0 : }

Generated by: LCOV version 1.14