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-djwa @ Mon Jul 31 20:08:17 PDT 2023 Lines: 478 604 79.1 %
Date: 2023-07-31 20:08:17 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  6410082300 :         int                     count = len;
      47             : 
      48  6410082300 :         count += sizeof(struct xfs_dir2_sf_entry);      /* namelen + offset */
      49           0 :         count += hdr->i8count ? XFS_INO64_SIZE : XFS_INO32_SIZE; /* ino # */
      50             : 
      51  6410082300 :         if (xfs_has_ftype(mp))
      52  6410080976 :                 count += sizeof(uint8_t);
      53  6410082300 :         return count;
      54             : }
      55             : 
      56             : struct xfs_dir2_sf_entry *
      57   871848029 : 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  5794078257 :         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  5326650841 : 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  5326650841 :         uint8_t                         *from = sfep->name + sfep->namelen;
      78             : 
      79  5326650841 :         if (xfs_has_ftype(mp))
      80  5326517175 :                 from++;
      81             : 
      82  5326650841 :         if (!hdr->i8count)
      83  5326650841 :                 return get_unaligned_be32(from);
      84           0 :         return get_unaligned_be64(from) & XFS_MAXINUMBER;
      85             : }
      86             : 
      87             : void
      88    44203729 : 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    44203729 :         uint8_t                         *to = sfep->name + sfep->namelen;
      95             : 
      96    44203729 :         ASSERT(ino <= XFS_MAXINUMBER);
      97             : 
      98    44203729 :         if (xfs_has_ftype(mp))
      99    44203543 :                 to++;
     100             : 
     101    44203729 :         if (hdr->i8count)
     102           0 :                 put_unaligned_be64(ino, to);
     103             :         else
     104    44203729 :                 put_unaligned_be32(ino, to);
     105    44203716 : }
     106             : 
     107             : xfs_ino_t
     108  1232188941 : xfs_dir2_sf_get_parent_ino(
     109             :         struct xfs_dir2_sf_hdr  *hdr)
     110             : {
     111  1232188941 :         if (!hdr->i8count)
     112  1232188939 :                 return get_unaligned_be32(hdr->parent);
     113           2 :         return get_unaligned_be64(hdr->parent) & XFS_MAXINUMBER;
     114             : }
     115             : 
     116             : void
     117    12300186 : xfs_dir2_sf_put_parent_ino(
     118             :         struct xfs_dir2_sf_hdr          *hdr,
     119             :         xfs_ino_t                       ino)
     120             : {
     121    12300186 :         ASSERT(ino <= XFS_MAXINUMBER);
     122             : 
     123    12300186 :         if (hdr->i8count)
     124           0 :                 put_unaligned_be64(ino, hdr->parent);
     125             :         else
     126    12300186 :                 put_unaligned_be32(ino, hdr->parent);
     127    12300307 : }
     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   875277504 : xfs_dir2_sf_get_ftype(
     135             :         struct xfs_mount                *mp,
     136             :         struct xfs_dir2_sf_entry        *sfep)
     137             : {
     138   875277504 :         if (xfs_has_ftype(mp)) {
     139  1213532864 :                 uint8_t                 ftype = sfep->name[sfep->namelen];
     140             : 
     141  1213532864 :                 if (ftype < XFS_DIR3_FT_MAX)
     142  1213567520 :                         return ftype;
     143             :         }
     144             : 
     145             :         return XFS_DIR3_FT_UNKNOWN;
     146             : }
     147             : 
     148             : void
     149    44203583 : xfs_dir2_sf_put_ftype(
     150             :         struct xfs_mount        *mp,
     151             :         struct xfs_dir2_sf_entry *sfep,
     152             :         uint8_t                 ftype)
     153             : {
     154    44203583 :         ASSERT(ftype < XFS_DIR3_FT_MAX);
     155             : 
     156    44203583 :         if (xfs_has_ftype(mp))
     157    44203845 :                 sfep->name[sfep->namelen] = ftype;
     158    44203583 : }
     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      718179 : 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      718179 :         xfs_dir2_dataptr_t      addr;           /* data entry address */
     173      718179 :         xfs_dir2_leaf_entry_t   *blp;           /* leaf area of the block */
     174      718179 :         xfs_dir2_block_tail_t   *btp;           /* tail area of the block */
     175      718179 :         int                     count;          /* shortform entry count */
     176      718179 :         xfs_dir2_data_entry_t   *dep;           /* data entry in the block */
     177      718179 :         int                     i;              /* block entry index */
     178      718179 :         int                     i8count;        /* count of big-inode entries */
     179      718179 :         int                     isdot;          /* entry is "." */
     180      718179 :         int                     isdotdot;       /* entry is ".." */
     181      718179 :         xfs_mount_t             *mp;            /* mount structure pointer */
     182      718179 :         int                     namelen;        /* total name bytes */
     183      718179 :         xfs_ino_t               parent = 0;     /* parent inode number */
     184      718179 :         int                     size=0;         /* total computed size */
     185      718179 :         int                     has_ftype;
     186      718179 :         struct xfs_da_geometry  *geo;
     187             : 
     188      718179 :         mp = dp->i_mount;
     189      718179 :         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      718179 :         has_ftype = xfs_has_ftype(mp) ? 1 : 0;
     196             : 
     197      718179 :         count = i8count = namelen = 0;
     198      718179 :         btp = xfs_dir2_block_tail_p(geo, hdr);
     199      718179 :         blp = xfs_dir2_block_leaf_p(btp);
     200             : 
     201             :         /*
     202             :          * Iterate over the block's data entries by using the leaf pointers.
     203             :          */
     204    54142384 :         for (i = 0; i < be32_to_cpu(btp->count); i++) {
     205    54050828 :                 if ((addr = be32_to_cpu(blp[i].address)) == XFS_DIR2_NULL_DATAPTR)
     206     8624172 :                         continue;
     207             :                 /*
     208             :                  * Calculate the pointer to the entry at hand.
     209             :                  */
     210    18401242 :                 dep = (xfs_dir2_data_entry_t *)((char *)hdr +
     211    18401242 :                                 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    18401242 :                 isdot = dep->namelen == 1 && dep->name[0] == '.';
     218    18401242 :                 isdotdot =
     219             :                         dep->namelen == 2 &&
     220    18401242 :                         dep->name[0] == '.' && dep->name[1] == '.';
     221             : 
     222    18401242 :                 if (!isdot)
     223    17683074 :                         i8count += be64_to_cpu(dep->inumber) > XFS_DIR2_MAX_SHORT_INUM;
     224             : 
     225             :                 /* take into account the file type field */
     226    18401242 :                 if (!isdot && !isdotdot) {
     227    16964895 :                         count++;
     228    16964895 :                         namelen += dep->namelen + has_ftype;
     229     1436347 :                 } else if (isdotdot)
     230      718178 :                         parent = be64_to_cpu(dep->inumber);
     231             :                 /*
     232             :                  * Calculate the new size, see if we should give up yet.
     233             :                  */
     234    18401242 :                 size = xfs_dir2_sf_hdr_size(i8count) +  /* header */
     235    18401242 :                        count * 3 * sizeof(u8) +         /* namelen + offset */
     236    18401242 :                        namelen +                        /* name */
     237             :                        (i8count ?                       /* inumber */
     238           0 :                                 count * XFS_INO64_SIZE :
     239    18401242 :                                 count * XFS_INO32_SIZE);
     240    18401242 :                 if (size > xfs_inode_data_fork_size(dp))
     241      672401 :                         return size;            /* size value is a failure */
     242             :         }
     243             :         /*
     244             :          * Create the output header, if it worked.
     245             :          */
     246       45778 :         sfhp->count = count;
     247       45778 :         sfhp->i8count = i8count;
     248       45778 :         xfs_dir2_sf_put_parent_ino(sfhp, parent);
     249       45778 :         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       45778 : 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       45778 :         struct xfs_inode        *dp = args->dp;
     264       45778 :         struct xfs_mount        *mp = dp->i_mount;
     265       45778 :         int                     error;          /* error return value */
     266       45778 :         int                     logflags;       /* inode logging flags */
     267       45778 :         struct xfs_dir2_sf_entry *sfep;         /* shortform entry */
     268       45778 :         struct xfs_dir2_sf_hdr  *sfp;           /* shortform directory header */
     269       45778 :         unsigned int            offset = args->geo->data_entry_offset;
     270       45778 :         unsigned int            end;
     271             : 
     272       45778 :         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       45778 :         sfp = kmem_alloc(mp->m_sb.sb_inodesize, 0);
     280       91556 :         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       45778 :         end = xfs_dir3_data_end_offset(args->geo, bp->b_addr);
     287       45778 :         sfep = xfs_dir2_sf_firstentry(sfp);
     288     1288407 :         while (offset < end) {
     289     1242629 :                 struct xfs_dir2_data_unused     *dup = bp->b_addr + offset;
     290     1242629 :                 struct xfs_dir2_data_entry      *dep = bp->b_addr + offset;
     291             : 
     292             :                 /*
     293             :                  * If it's unused, just skip over it.
     294             :                  */
     295     1242629 :                 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
     296      345231 :                         offset += be16_to_cpu(dup->length);
     297      345231 :                         continue;
     298             :                 }
     299             : 
     300             :                 /*
     301             :                  * Skip .
     302             :                  */
     303      897398 :                 if (dep->namelen == 1 && dep->name[0] == '.')
     304       45778 :                         ASSERT(be64_to_cpu(dep->inumber) == dp->i_ino);
     305             :                 /*
     306             :                  * Skip .., but make sure the inode number is right.
     307             :                  */
     308      851620 :                 else if (dep->namelen == 2 &&
     309       45778 :                          dep->name[0] == '.' && dep->name[1] == '.')
     310       45778 :                         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      805842 :                         sfep->namelen = dep->namelen;
     317      805842 :                         xfs_dir2_sf_put_offset(sfep, offset);
     318     1611684 :                         memcpy(sfep->name, dep->name, dep->namelen);
     319      805842 :                         xfs_dir2_sf_put_ino(mp, sfp, sfep,
     320      805842 :                                               be64_to_cpu(dep->inumber));
     321      805842 :                         xfs_dir2_sf_put_ftype(mp, sfep,
     322             :                                         xfs_dir2_data_get_ftype(mp, dep));
     323             : 
     324      805842 :                         sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
     325             :                 }
     326     1794796 :                 offset += xfs_dir2_data_entsize(mp, dep->namelen);
     327             :         }
     328       45778 :         ASSERT((char *)sfep - (char *)sfp == size);
     329             : 
     330             :         /* now we are done with the block, we can shrink the inode */
     331       45778 :         logflags = XFS_ILOG_CORE;
     332       45778 :         error = xfs_dir2_shrink_inode(args, args->geo->datablk, bp);
     333       45778 :         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       45778 :         ASSERT(dp->i_df.if_bytes == 0);
     345       45778 :         xfs_init_local_fork(dp, XFS_DATA_FORK, sfp, size);
     346       45778 :         dp->i_df.if_format = XFS_DINODE_FMT_LOCAL;
     347       45778 :         dp->i_disk_size = size;
     348             : 
     349       45778 :         logflags |= XFS_ILOG_DDATA;
     350       45778 :         xfs_dir2_sf_check(args);
     351       45778 : out:
     352       45778 :         xfs_trans_log_inode(args->trans, dp, logflags);
     353       45778 :         kmem_free(sfp);
     354       45778 :         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    29249518 : xfs_dir2_sf_addname(
     365             :         xfs_da_args_t           *args)          /* operation arguments */
     366             : {
     367    29249518 :         xfs_inode_t             *dp;            /* incore directory inode */
     368    29249518 :         int                     error;          /* error return value */
     369    29249518 :         int                     incr_isize;     /* total change in size */
     370    29249518 :         int                     new_isize;      /* size after adding name */
     371    29249518 :         int                     objchange;      /* changing to 8-byte inodes */
     372    29249518 :         xfs_dir2_data_aoff_t    offset = 0;     /* offset for new entry */
     373    29249518 :         int                     pick;           /* which algorithm to use */
     374    29249518 :         xfs_dir2_sf_hdr_t       *sfp;           /* shortform structure */
     375    29249518 :         xfs_dir2_sf_entry_t     *sfep = NULL;   /* shortform entry */
     376             : 
     377    29249518 :         trace_xfs_dir2_sf_addname(args);
     378             : 
     379    29249994 :         ASSERT(xfs_dir2_sf_lookup(args) == -ENOENT);
     380    29249815 :         dp = args->dp;
     381    29249815 :         ASSERT(dp->i_df.if_format == XFS_DINODE_FMT_LOCAL);
     382    29249815 :         ASSERT(dp->i_disk_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
     383    29249815 :         ASSERT(dp->i_df.if_bytes == dp->i_disk_size);
     384    29249815 :         ASSERT(dp->i_df.if_u1.if_data != NULL);
     385    29249815 :         sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
     386    29249815 :         ASSERT(dp->i_disk_size >= xfs_dir2_sf_hdr_size(sfp->i8count));
     387             :         /*
     388             :          * Compute entry (and change in) size.
     389             :          */
     390    29249815 :         incr_isize = xfs_dir2_sf_entsize(dp->i_mount, sfp, args->namelen);
     391    29249815 :         objchange = 0;
     392             : 
     393             :         /*
     394             :          * Do we have to change to 8 byte inodes?
     395             :          */
     396    29249815 :         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    29249815 :         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    58447189 :         if (new_isize > xfs_inode_data_fork_size(dp) ||
     410             :             (pick =
     411    29197424 :              xfs_dir2_sf_addname_pick(args, objchange, &sfep, &offset)) == 0) {
     412             :                 /*
     413             :                  * Just checking or no space reservation, it doesn't fit.
     414             :                  */
     415       58882 :                 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       57958 :                 error = xfs_dir2_sf_to_block(args);
     421       57957 :                 if (error)
     422             :                         return error;
     423       57957 :                 return xfs_dir2_block_addname(args);
     424             :         }
     425             :         /*
     426             :          * Just checking, it fits.
     427             :          */
     428    29190883 :         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    29018582 :         if (pick == 1)
     434    29004205 :                 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       14377 :                 ASSERT(pick == 2);
     441       14377 :                 if (objchange)
     442           0 :                         xfs_dir2_sf_toino8(args);
     443       14377 :                 xfs_dir2_sf_addname_hard(args, objchange, new_isize);
     444             :         }
     445    29018545 :         xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
     446    29018545 :         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    29004405 : 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    29004405 :         struct xfs_inode        *dp = args->dp;
     464    29004405 :         struct xfs_mount        *mp = dp->i_mount;
     465    29004405 :         int                     byteoff;        /* byte offset in sf dir */
     466    29004405 :         xfs_dir2_sf_hdr_t       *sfp;           /* shortform structure */
     467             : 
     468    29004405 :         sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
     469    29004405 :         byteoff = (int)((char *)sfep - (char *)sfp);
     470             :         /*
     471             :          * Grow the in-inode space.
     472             :          */
     473    58008810 :         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    29003827 :         sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
     479    29003827 :         sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + byteoff);
     480             :         /*
     481             :          * Fill in the new entry.
     482             :          */
     483    29003827 :         sfep->namelen = args->namelen;
     484    29003827 :         xfs_dir2_sf_put_offset(sfep, offset);
     485    58007940 :         memcpy(sfep->name, args->name, sfep->namelen);
     486    29003970 :         xfs_dir2_sf_put_ino(mp, sfp, sfep, args->inumber);
     487    29003898 :         xfs_dir2_sf_put_ftype(mp, sfep, args->filetype);
     488             : 
     489             :         /*
     490             :          * Update the header and inode.
     491             :          */
     492    29004360 :         sfp->count++;
     493    29004360 :         if (args->inumber > XFS_DIR2_MAX_SHORT_INUM)
     494           0 :                 sfp->i8count++;
     495    29004360 :         dp->i_disk_size = new_isize;
     496    29004360 :         xfs_dir2_sf_check(args);
     497    29004046 : }
     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       14377 : 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       14377 :         struct xfs_inode        *dp = args->dp;
     515       14377 :         struct xfs_mount        *mp = dp->i_mount;
     516       14377 :         int                     add_datasize;   /* data size need for new ent */
     517       14377 :         char                    *buf;           /* buffer for old */
     518       14377 :         int                     eof;            /* reached end of old dir */
     519       14377 :         int                     nbytes;         /* temp for byte copies */
     520       14377 :         xfs_dir2_data_aoff_t    new_offset;     /* next offset value */
     521       14377 :         xfs_dir2_data_aoff_t    offset;         /* current offset value */
     522       14377 :         int                     old_isize;      /* previous size */
     523       14377 :         xfs_dir2_sf_entry_t     *oldsfep;       /* entry in original dir */
     524       14377 :         xfs_dir2_sf_hdr_t       *oldsfp;        /* original shortform dir */
     525       14377 :         xfs_dir2_sf_entry_t     *sfep;          /* entry in new dir */
     526       14377 :         xfs_dir2_sf_hdr_t       *sfp;           /* new shortform dir */
     527             : 
     528             :         /*
     529             :          * Copy the old directory to the stack buffer.
     530             :          */
     531       14377 :         sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
     532       14377 :         old_isize = (int)dp->i_disk_size;
     533       14377 :         buf = kmem_alloc(old_isize, 0);
     534       14377 :         oldsfp = (xfs_dir2_sf_hdr_t *)buf;
     535       28754 :         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       14377 :         for (offset = args->geo->data_first_offset,
     542             :               oldsfep = xfs_dir2_sf_firstentry(oldsfp),
     543       14377 :               add_datasize = xfs_dir2_data_entsize(mp, args->namelen),
     544       14377 :               eof = (char *)oldsfep == &buf[old_isize];
     545       57195 :              !eof;
     546       42818 :              offset = new_offset + xfs_dir2_data_entsize(mp, oldsfep->namelen),
     547       42818 :               oldsfep = xfs_dir2_sf_nextentry(mp, oldsfp, oldsfep),
     548       42818 :               eof = (char *)oldsfep == &buf[old_isize]) {
     549       57195 :                 new_offset = xfs_dir2_sf_get_offset(oldsfep);
     550       57195 :                 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       14377 :         xfs_idata_realloc(dp, -old_isize, XFS_DATA_FORK);
     559       14377 :         xfs_idata_realloc(dp, new_isize, XFS_DATA_FORK);
     560             :         /*
     561             :          * Reset the pointer since the buffer was reallocated.
     562             :          */
     563       14377 :         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       14377 :         nbytes = (int)((char *)oldsfep - (char *)oldsfp);
     568       28754 :         memcpy(sfp, oldsfp, nbytes);
     569       14377 :         sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + nbytes);
     570             :         /*
     571             :          * Fill in the new entry, and update the header counts.
     572             :          */
     573       14377 :         sfep->namelen = args->namelen;
     574       14377 :         xfs_dir2_sf_put_offset(sfep, offset);
     575       28754 :         memcpy(sfep->name, args->name, sfep->namelen);
     576       14377 :         xfs_dir2_sf_put_ino(mp, sfp, sfep, args->inumber);
     577       14377 :         xfs_dir2_sf_put_ftype(mp, sfep, args->filetype);
     578       14377 :         sfp->count++;
     579       14377 :         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       14377 :         if (!eof) {
     585       14377 :                 sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
     586       28754 :                 memcpy(sfep, oldsfep, old_isize - nbytes);
     587             :         }
     588       14377 :         kmem_free(buf);
     589       14377 :         dp->i_disk_size = new_isize;
     590       14377 :         xfs_dir2_sf_check(args);
     591       14377 : }
     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    29197604 : 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    29197604 :         struct xfs_inode        *dp = args->dp;
     608    29197604 :         struct xfs_mount        *mp = dp->i_mount;
     609    29197604 :         int                     holefit;        /* found hole it will fit in */
     610    29197604 :         int                     i;              /* entry number */
     611    29197604 :         xfs_dir2_data_aoff_t    offset;         /* data block offset */
     612    29197604 :         xfs_dir2_sf_entry_t     *sfep;          /* shortform entry */
     613    29197604 :         xfs_dir2_sf_hdr_t       *sfp;           /* shortform structure */
     614    29197604 :         int                     size;           /* entry's data size */
     615    29197604 :         int                     used;           /* data bytes used */
     616             : 
     617    29197604 :         sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
     618    29197604 :         size = xfs_dir2_data_entsize(mp, args->namelen);
     619    29197604 :         offset = args->geo->data_first_offset;
     620    29197604 :         sfep = xfs_dir2_sf_firstentry(sfp);
     621    29197604 :         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   144447736 :         for (i = 0; i < sfp->count; i++) {
     628   115250132 :                 if (!holefit)
     629    55308643 :                         holefit = offset + size <= xfs_dir2_sf_get_offset(sfep);
     630   115250132 :                 offset = xfs_dir2_sf_get_offset(sfep) +
     631   115250132 :                          xfs_dir2_data_entsize(mp, sfep->namelen);
     632   115250132 :                 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    29197604 :         used = offset +
     639    29197604 :                (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    43070326 :         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    29191117 :         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    29191117 :         if (used + size > args->geo->blksize)
     657             :                 return 2;
     658             :         /*
     659             :          * Do it the easy way.
     660             :          */
     661    29176668 :         *sfepp = sfep;
     662    29176668 :         *offsetp = offset;
     663    29176668 :         return 1;
     664             : }
     665             : 
     666             : #ifdef DEBUG
     667             : /*
     668             :  * Check consistency of shortform directory, assert if bad.
     669             :  */
     670             : static void
     671   732840379 : xfs_dir2_sf_check(
     672             :         xfs_da_args_t           *args)          /* operation arguments */
     673             : {
     674   732840379 :         struct xfs_inode        *dp = args->dp;
     675   732840379 :         struct xfs_mount        *mp = dp->i_mount;
     676   732840379 :         int                     i;              /* entry number */
     677   732840379 :         int                     i8count;        /* number of big inode#s */
     678   732840379 :         xfs_ino_t               ino;            /* entry inode number */
     679   732840379 :         int                     offset;         /* data offset */
     680   732840379 :         xfs_dir2_sf_entry_t     *sfep;          /* shortform dir entry */
     681   732840379 :         xfs_dir2_sf_hdr_t       *sfp;           /* shortform structure */
     682             : 
     683   732840379 :         sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
     684   732840379 :         offset = args->geo->data_first_offset;
     685   732840379 :         ino = xfs_dir2_sf_get_parent_ino(sfp);
     686   732840379 :         i8count = ino > XFS_DIR2_MAX_SHORT_INUM;
     687             : 
     688   732840379 :         for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
     689  4392206842 :              i < sfp->count;
     690  3659366463 :              i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep)) {
     691  3659254321 :                 ASSERT(xfs_dir2_sf_get_offset(sfep) >= offset);
     692  3659366463 :                 ino = xfs_dir2_sf_get_ino(mp, sfp, sfep);
     693  3659366463 :                 i8count += ino > XFS_DIR2_MAX_SHORT_INUM;
     694  3659366463 :                 offset =
     695  3659366463 :                         xfs_dir2_sf_get_offset(sfep) +
     696  3659366463 :                         xfs_dir2_data_entsize(mp, sfep->namelen);
     697  3659366463 :                 ASSERT(xfs_dir2_sf_get_ftype(mp, sfep) < XFS_DIR3_FT_MAX);
     698             :         }
     699   732952521 :         ASSERT(i8count == sfp->i8count);
     700   732952521 :         ASSERT((char *)sfep - (char *)sfp == dp->i_disk_size);
     701   732952521 :         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   732952521 : }
     705             : #endif  /* DEBUG */
     706             : 
     707             : /* Verify the consistency of an inline directory. */
     708             : xfs_failaddr_t
     709    85624855 : xfs_dir2_sf_verify(
     710             :         struct xfs_inode                *ip)
     711             : {
     712    85624855 :         struct xfs_mount                *mp = ip->i_mount;
     713    85624855 :         struct xfs_ifork                *ifp = xfs_ifork_ptr(ip, XFS_DATA_FORK);
     714    85624855 :         struct xfs_dir2_sf_hdr          *sfp;
     715    85624855 :         struct xfs_dir2_sf_entry        *sfep;
     716    85624855 :         struct xfs_dir2_sf_entry        *next_sfep;
     717    85624855 :         char                            *endp;
     718    85624855 :         xfs_ino_t                       ino;
     719    85624855 :         int                             i;
     720    85624855 :         int                             i8count;
     721    85624855 :         int                             offset;
     722    85624855 :         int64_t                         size;
     723    85624855 :         int                             error;
     724    85624855 :         uint8_t                         filetype;
     725             : 
     726    85624855 :         ASSERT(ifp->if_format == XFS_DINODE_FMT_LOCAL);
     727             : 
     728    85624855 :         sfp = (struct xfs_dir2_sf_hdr *)ifp->if_u1.if_data;
     729    85624855 :         size = ifp->if_bytes;
     730             : 
     731             :         /*
     732             :          * Give up if the directory is way too short.
     733             :          */
     734    85624855 :         if (size <= offsetof(struct xfs_dir2_sf_hdr, parent) ||
     735    85624857 :             size < xfs_dir2_sf_hdr_size(sfp->i8count))
     736           0 :                 return __this_address;
     737             : 
     738    85625248 :         endp = (char *)sfp + size;
     739             : 
     740             :         /* Check .. entry */
     741    85625248 :         ino = xfs_dir2_sf_get_parent_ino(sfp);
     742    85625248 :         i8count = ino > XFS_DIR2_MAX_SHORT_INUM;
     743    85625248 :         error = xfs_dir_ino_validate(mp, ino);
     744    85625782 :         if (error)
     745           2 :                 return __this_address;
     746    85625780 :         offset = mp->m_dir_geo->data_first_offset;
     747             : 
     748             :         /* Check all reported entries */
     749    85625780 :         sfep = xfs_dir2_sf_firstentry(sfp);
     750   511482984 :         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   425856934 :                 if (((char *)sfep + sizeof(*sfep)) >= endp)
     757           0 :                         return __this_address;
     758             : 
     759             :                 /* Don't allow names with known bad length. */
     760   425856934 :                 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   425856934 :                 next_sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep);
     769   425856934 :                 if (endp < (char *)next_sfep)
     770           0 :                         return __this_address;
     771             : 
     772             :                 /* Check that the offsets always increase. */
     773   425856934 :                 if (xfs_dir2_sf_get_offset(sfep) < offset)
     774           0 :                         return __this_address;
     775             : 
     776             :                 /* Check the inode number. */
     777   425856934 :                 ino = xfs_dir2_sf_get_ino(mp, sfp, sfep);
     778   425856934 :                 i8count += ino > XFS_DIR2_MAX_SHORT_INUM;
     779   425856934 :                 error = xfs_dir_ino_validate(mp, ino);
     780   425857204 :                 if (error)
     781           0 :                         return __this_address;
     782             : 
     783             :                 /* Check the file type. */
     784   425857204 :                 filetype = xfs_dir2_sf_get_ftype(mp, sfep);
     785             :                 if (filetype >= XFS_DIR3_FT_MAX)
     786   425857204 :                         return __this_address;
     787             : 
     788   425857204 :                 offset = xfs_dir2_sf_get_offset(sfep) +
     789   425857204 :                                 xfs_dir2_data_entsize(mp, sfep->namelen);
     790             : 
     791   425857204 :                 sfep = next_sfep;
     792             :         }
     793    85626050 :         if (i8count != sfp->i8count)
     794           0 :                 return __this_address;
     795    85626050 :         if ((void *)sfep != (void *)endp)
     796           0 :                 return __this_address;
     797             : 
     798             :         /* Make sure this whole thing ought to be in local format. */
     799    85626050 :         if (offset + (sfp->count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) +
     800    85626050 :             (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     3252154 : xfs_dir2_sf_create(
     811             :         xfs_da_args_t   *args,          /* operation arguments */
     812             :         xfs_ino_t       pino)           /* parent inode number */
     813             : {
     814     3252154 :         xfs_inode_t     *dp;            /* incore directory inode */
     815     3252154 :         int             i8count;        /* parent inode is an 8-byte number */
     816     3252154 :         xfs_dir2_sf_hdr_t *sfp;         /* shortform structure */
     817     3252154 :         int             size;           /* directory size */
     818             : 
     819     3252154 :         trace_xfs_dir2_sf_create(args);
     820             : 
     821     3252165 :         dp = args->dp;
     822             : 
     823     3252165 :         ASSERT(dp != NULL);
     824     3252165 :         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     3252165 :         if (dp->i_df.if_format == XFS_DINODE_FMT_EXTENTS) {
     830     3252154 :                 dp->i_df.if_format = XFS_DINODE_FMT_LOCAL;
     831     3252154 :                 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
     832             :         }
     833     3252178 :         ASSERT(dp->i_df.if_format == XFS_DINODE_FMT_LOCAL);
     834     3252178 :         ASSERT(dp->i_df.if_bytes == 0);
     835     3252178 :         i8count = pino > XFS_DIR2_MAX_SHORT_INUM;
     836     3252178 :         size = xfs_dir2_sf_hdr_size(i8count);
     837             :         /*
     838             :          * Make a buffer for the data.
     839             :          */
     840     3252178 :         xfs_idata_realloc(dp, size, XFS_DATA_FORK);
     841             :         /*
     842             :          * Fill in the header,
     843             :          */
     844     3252151 :         sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
     845     3252151 :         sfp->i8count = i8count;
     846             :         /*
     847             :          * Now can put in the inode number, since i8count is set.
     848             :          */
     849     3252151 :         xfs_dir2_sf_put_parent_ino(sfp, pino);
     850     3252152 :         sfp->count = 0;
     851     3252152 :         dp->i_disk_size = size;
     852     3252152 :         xfs_dir2_sf_check(args);
     853     3252161 :         xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
     854     3252168 :         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   660862080 : xfs_dir2_sf_lookup(
     863             :         xfs_da_args_t           *args)          /* operation arguments */
     864             : {
     865   660862080 :         struct xfs_inode        *dp = args->dp;
     866   660862080 :         struct xfs_mount        *mp = dp->i_mount;
     867   660862080 :         int                     i;              /* entry index */
     868   660862080 :         xfs_dir2_sf_entry_t     *sfep;          /* shortform directory entry */
     869   660862080 :         xfs_dir2_sf_hdr_t       *sfp;           /* shortform structure */
     870   660862080 :         enum xfs_dacmp          cmp;            /* comparison result */
     871   660862080 :         xfs_dir2_sf_entry_t     *ci_sfep;       /* case-insens. entry */
     872             : 
     873   660862080 :         trace_xfs_dir2_sf_lookup(args);
     874             : 
     875   660867592 :         xfs_dir2_sf_check(args);
     876             : 
     877   660954138 :         ASSERT(dp->i_df.if_format == XFS_DINODE_FMT_LOCAL);
     878   660954138 :         ASSERT(dp->i_disk_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
     879   660954138 :         ASSERT(dp->i_df.if_bytes == dp->i_disk_size);
     880   660954138 :         ASSERT(dp->i_df.if_u1.if_data != NULL);
     881   660954138 :         sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
     882   660954138 :         ASSERT(dp->i_disk_size >= xfs_dir2_sf_hdr_size(sfp->i8count));
     883             :         /*
     884             :          * Special case for .
     885             :          */
     886   660954138 :         if (args->namelen == 1 && args->name[0] == '.') {
     887    79522006 :                 args->inumber = dp->i_ino;
     888    79522006 :                 args->cmpresult = XFS_CMP_EXACT;
     889    79522006 :                 args->filetype = XFS_DIR3_FT_DIR;
     890    79522006 :                 return -EEXIST;
     891             :         }
     892             :         /*
     893             :          * Special case for ..
     894             :          */
     895   581432132 :         if (args->namelen == 2 &&
     896   183167131 :             args->name[0] == '.' && args->name[1] == '.') {
     897   181580395 :                 args->inumber = xfs_dir2_sf_get_parent_ino(sfp);
     898   181580395 :                 args->cmpresult = XFS_CMP_EXACT;
     899   181580395 :                 args->filetype = XFS_DIR3_FT_DIR;
     900   181580395 :                 return -EEXIST;
     901             :         }
     902             :         /*
     903             :          * Loop over all the entries trying to match ours.
     904             :          */
     905   399851737 :         ci_sfep = NULL;
     906  1995112774 :         for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
     907  1195409300 :              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  1533588483 :                 cmp = xfs_dir2_compname(args, sfep->name, sfep->namelen);
     914  1533590452 :                 if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
     915   338195243 :                         args->cmpresult = cmp;
     916   338195243 :                         args->inumber = xfs_dir2_sf_get_ino(mp, sfp, sfep);
     917   338195243 :                         args->filetype = xfs_dir2_sf_get_ftype(mp, sfep);
     918   338195243 :                         if (cmp == XFS_CMP_EXACT)
     919             :                                 return -EEXIST;
     920             :                         ci_sfep = sfep;
     921             :                 }
     922             :         }
     923    61672554 :         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    61672554 :         if (!ci_sfep)
     929             :                 return -ENOENT;
     930             :         /* otherwise process the CI match as required by the caller */
     931         949 :         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    16585506 : xfs_dir2_sf_removename(
     939             :         xfs_da_args_t           *args)
     940             : {
     941    16585506 :         struct xfs_inode        *dp = args->dp;
     942    16585506 :         struct xfs_mount        *mp = dp->i_mount;
     943    16585506 :         int                     byteoff;        /* offset of removed entry */
     944    16585506 :         int                     entsize;        /* this entry's size */
     945    16585506 :         int                     i;              /* shortform entry index */
     946    16585506 :         int                     newsize;        /* new inode size */
     947    16585506 :         int                     oldsize;        /* old inode size */
     948    16585506 :         xfs_dir2_sf_entry_t     *sfep;          /* shortform directory entry */
     949    16585506 :         xfs_dir2_sf_hdr_t       *sfp;           /* shortform structure */
     950             : 
     951    16585506 :         trace_xfs_dir2_sf_removename(args);
     952             : 
     953    16585533 :         ASSERT(dp->i_df.if_format == XFS_DINODE_FMT_LOCAL);
     954    16585533 :         oldsize = (int)dp->i_disk_size;
     955    16585533 :         ASSERT(oldsize >= offsetof(struct xfs_dir2_sf_hdr, parent));
     956    16585533 :         ASSERT(dp->i_df.if_bytes == oldsize);
     957    16585533 :         ASSERT(dp->i_df.if_u1.if_data != NULL);
     958    16585533 :         sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
     959    16585533 :         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    68338495 :         for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
     965    35167429 :              i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep)) {
     966    51752928 :                 if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
     967             :                                                                 XFS_CMP_EXACT) {
     968    16585528 :                         ASSERT(xfs_dir2_sf_get_ino(mp, sfp, sfep) ==
     969             :                                args->inumber);
     970             :                         break;
     971             :                 }
     972             :         }
     973             :         /*
     974             :          * Didn't find it.
     975             :          */
     976    16585562 :         if (i == sfp->count)
     977             :                 return -ENOENT;
     978             :         /*
     979             :          * Calculate sizes.
     980             :          */
     981    16585562 :         byteoff = (int)((char *)sfep - (char *)sfp);
     982    16585562 :         entsize = xfs_dir2_sf_entsize(mp, sfp, args->namelen);
     983    16585562 :         newsize = oldsize - entsize;
     984             :         /*
     985             :          * Copy the part if any after the removed entry, sliding it down.
     986             :          */
     987    16585562 :         if (byteoff + entsize < oldsize)
     988    22978980 :                 memmove((char *)sfp + byteoff, (char *)sfp + byteoff + entsize,
     989             :                         oldsize - (byteoff + entsize));
     990             :         /*
     991             :          * Fix up the header and file size.
     992             :          */
     993    16585562 :         sfp->count--;
     994    16585562 :         dp->i_disk_size = newsize;
     995             :         /*
     996             :          * Reallocate, making it smaller.
     997             :          */
     998    16585562 :         xfs_idata_realloc(dp, newsize - oldsize, XFS_DATA_FORK);
     999    16585499 :         sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
    1000             :         /*
    1001             :          * Are we changing inode number size?
    1002             :          */
    1003    16585499 :         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    16585499 :         xfs_dir2_sf_check(args);
    1010    16585521 :         xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA);
    1011    16585521 :         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    23382181 : xfs_dir2_sf_replace(
    1040             :         xfs_da_args_t           *args)          /* operation arguments */
    1041             : {
    1042    23382181 :         struct xfs_inode        *dp = args->dp;
    1043    23382181 :         struct xfs_mount        *mp = dp->i_mount;
    1044    23382181 :         int                     i;              /* entry index */
    1045    23382181 :         xfs_ino_t               ino=0;          /* entry old inode number */
    1046    23382181 :         int                     i8elevated;     /* sf_toino8 set i8count=1 */
    1047    23382181 :         xfs_dir2_sf_entry_t     *sfep;          /* shortform directory entry */
    1048    23382181 :         xfs_dir2_sf_hdr_t       *sfp;           /* shortform structure */
    1049             : 
    1050    23382181 :         trace_xfs_dir2_sf_replace(args);
    1051             : 
    1052    23382188 :         ASSERT(dp->i_df.if_format == XFS_DINODE_FMT_LOCAL);
    1053    23382188 :         ASSERT(dp->i_disk_size >= offsetof(struct xfs_dir2_sf_hdr, parent));
    1054    23382188 :         ASSERT(dp->i_df.if_bytes == dp->i_disk_size);
    1055    23382188 :         ASSERT(dp->i_df.if_u1.if_data != NULL);
    1056    23382188 :         sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
    1057    23382188 :         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    23382188 :         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    23382188 :         ASSERT(args->namelen != 1 || args->name[0] != '.');
    1084             :         /*
    1085             :          * Replace ..'s entry.
    1086             :          */
    1087    23382188 :         if (args->namelen == 2 &&
    1088     9030040 :             args->name[0] == '.' && args->name[1] == '.') {
    1089     9002521 :                 ino = xfs_dir2_sf_get_parent_ino(sfp);
    1090     9002521 :                 ASSERT(args->inumber != ino);
    1091     9002521 :                 xfs_dir2_sf_put_parent_ino(sfp, args->inumber);
    1092             :         }
    1093             :         /*
    1094             :          * Normal entry, look for the name.
    1095             :          */
    1096             :         else {
    1097    60240528 :                 for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
    1098    31481194 :                      i++, sfep = xfs_dir2_sf_nextentry(mp, sfp, sfep)) {
    1099    45860861 :                         if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
    1100             :                                                                 XFS_CMP_EXACT) {
    1101    14379669 :                                 ino = xfs_dir2_sf_get_ino(mp, sfp, sfep);
    1102    14379669 :                                 ASSERT(args->inumber != ino);
    1103    14379669 :                                 xfs_dir2_sf_put_ino(mp, sfp, sfep,
    1104             :                                                 args->inumber);
    1105    14379668 :                                 xfs_dir2_sf_put_ftype(mp, sfep, args->filetype);
    1106    14379668 :                                 break;
    1107             :                         }
    1108             :                 }
    1109             :                 /*
    1110             :                  * Didn't find it.
    1111             :                  */
    1112    14379666 :                 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    23382187 :         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    23382187 :         if (ino <= XFS_DIR2_MAX_SHORT_INUM &&
    1136    23382185 :             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    23382187 :         xfs_dir2_sf_check(args);
    1146    23382191 :         xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA);
    1147    23382191 :         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