2  * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
 
   5  * This program is free software; you can redistribute it and/or
 
   6  * modify it under the terms of the GNU General Public License as
 
   7  * published by the Free Software Foundation.
 
   9  * This program is distributed in the hope that it would be useful,
 
  10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  12  * GNU General Public License for more details.
 
  14  * You should have received a copy of the GNU General Public License
 
  15  * along with this program; if not, write the Free Software Foundation,
 
  16  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
  20 #include "xfs_types.h"
 
  24 #include "xfs_trans.h"
 
  29 #include "xfs_dmapi.h"
 
  30 #include "xfs_mount.h"
 
  31 #include "xfs_da_btree.h"
 
  32 #include "xfs_bmap_btree.h"
 
  33 #include "xfs_alloc_btree.h"
 
  34 #include "xfs_dir_sf.h"
 
  35 #include "xfs_dir2_sf.h"
 
  36 #include "xfs_attr_sf.h"
 
  37 #include "xfs_dinode.h"
 
  38 #include "xfs_inode.h"
 
  39 #include "xfs_inode_item.h"
 
  41 #include "xfs_dir_leaf.h"
 
  42 #include "xfs_dir2_data.h"
 
  43 #include "xfs_dir2_leaf.h"
 
  44 #include "xfs_dir2_block.h"
 
  45 #include "xfs_dir2_node.h"
 
  46 #include "xfs_dir2_trace.h"
 
  47 #include "xfs_error.h"
 
  50  * Declarations for interface routines.
 
  52 static void     xfs_dir2_mount(xfs_mount_t *mp);
 
  53 static int      xfs_dir2_isempty(xfs_inode_t *dp);
 
  54 static int      xfs_dir2_init(xfs_trans_t *tp, xfs_inode_t *dp,
 
  56 static int      xfs_dir2_createname(xfs_trans_t *tp, xfs_inode_t *dp,
 
  57                                     char *name, int namelen, xfs_ino_t inum,
 
  59                                     xfs_bmap_free_t *flist, xfs_extlen_t total);
 
  60 static int      xfs_dir2_lookup(xfs_trans_t *tp, xfs_inode_t *dp, char *name,
 
  61                                 int namelen, xfs_ino_t *inum);
 
  62 static int      xfs_dir2_removename(xfs_trans_t *tp, xfs_inode_t *dp,
 
  63                                     char *name, int namelen, xfs_ino_t ino,
 
  65                                     xfs_bmap_free_t *flist, xfs_extlen_t total);
 
  66 static int      xfs_dir2_getdents(xfs_trans_t *tp, xfs_inode_t *dp, uio_t *uio,
 
  68 static int      xfs_dir2_replace(xfs_trans_t *tp, xfs_inode_t *dp, char *name,
 
  69                                  int namelen, xfs_ino_t inum,
 
  70                                  xfs_fsblock_t *first, xfs_bmap_free_t *flist,
 
  72 static int      xfs_dir2_canenter(xfs_trans_t *tp, xfs_inode_t *dp, char *name,
 
  74 static int      xfs_dir2_shortform_validate_ondisk(xfs_mount_t *mp,
 
  78  * Utility routine declarations.
 
  80 static int      xfs_dir2_put_dirent64_direct(xfs_dir2_put_args_t *pa);
 
  81 static int      xfs_dir2_put_dirent64_uio(xfs_dir2_put_args_t *pa);
 
  84  * Directory operations vector.
 
  86 xfs_dirops_t    xfsv2_dirops = {
 
  87         .xd_mount                       = xfs_dir2_mount,
 
  88         .xd_isempty                     = xfs_dir2_isempty,
 
  89         .xd_init                        = xfs_dir2_init,
 
  90         .xd_createname                  = xfs_dir2_createname,
 
  91         .xd_lookup                      = xfs_dir2_lookup,
 
  92         .xd_removename                  = xfs_dir2_removename,
 
  93         .xd_getdents                    = xfs_dir2_getdents,
 
  94         .xd_replace                     = xfs_dir2_replace,
 
  95         .xd_canenter                    = xfs_dir2_canenter,
 
  96         .xd_shortform_validate_ondisk   = xfs_dir2_shortform_validate_ondisk,
 
  97         .xd_shortform_to_single         = xfs_dir2_sf_to_block,
 
 101  * Interface routines.
 
 105  * Initialize directory-related fields in the mount structure.
 
 109         xfs_mount_t     *mp)            /* filesystem mount point */
 
 111         mp->m_dirversion = 2;
 
 112         ASSERT((1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog)) <=
 
 114         mp->m_dirblksize = 1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog);
 
 115         mp->m_dirblkfsbs = 1 << mp->m_sb.sb_dirblklog;
 
 116         mp->m_dirdatablk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_DATA_FIRSTDB(mp));
 
 117         mp->m_dirleafblk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_LEAF_FIRSTDB(mp));
 
 118         mp->m_dirfreeblk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_FREE_FIRSTDB(mp));
 
 119         mp->m_attr_node_ents =
 
 120                 (mp->m_sb.sb_blocksize - (uint)sizeof(xfs_da_node_hdr_t)) /
 
 121                 (uint)sizeof(xfs_da_node_entry_t);
 
 122         mp->m_dir_node_ents =
 
 123                 (mp->m_dirblksize - (uint)sizeof(xfs_da_node_hdr_t)) /
 
 124                 (uint)sizeof(xfs_da_node_entry_t);
 
 125         mp->m_dir_magicpct = (mp->m_dirblksize * 37) / 100;
 
 129  * Return 1 if directory contains only "." and "..".
 
 131 static int                              /* return code */
 
 133         xfs_inode_t     *dp)            /* incore inode structure */
 
 135         xfs_dir2_sf_t   *sfp;           /* shortform directory structure */
 
 137         ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
 
 139          * Might happen during shutdown.
 
 141         if (dp->i_d.di_size == 0) {
 
 144         if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp))
 
 146         sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
 
 147         return !sfp->hdr.count;
 
 151  * Initialize a directory with its "." and ".." entries.
 
 153 static int                              /* error */
 
 155         xfs_trans_t     *tp,            /* transaction pointer */
 
 156         xfs_inode_t     *dp,            /* incore directory inode */
 
 157         xfs_inode_t     *pdp)           /* incore parent directory inode */
 
 159         xfs_da_args_t   args;           /* operation arguments */
 
 160         int             error;          /* error return value */
 
 162         memset((char *)&args, 0, sizeof(args));
 
 165         ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
 
 166         if ((error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino))) {
 
 169         return xfs_dir2_sf_create(&args, pdp->i_ino);
 
 173   Enter a name in a directory.
 
 175 static int                                      /* error */
 
 177         xfs_trans_t             *tp,            /* transaction pointer */
 
 178         xfs_inode_t             *dp,            /* incore directory inode */
 
 179         char                    *name,          /* new entry name */
 
 180         int                     namelen,        /* new entry name length */
 
 181         xfs_ino_t               inum,           /* new entry inode number */
 
 182         xfs_fsblock_t           *first,         /* bmap's firstblock */
 
 183         xfs_bmap_free_t         *flist,         /* bmap's freeblock list */
 
 184         xfs_extlen_t            total)          /* bmap's total block count */
 
 186         xfs_da_args_t           args;           /* operation arguments */
 
 187         int                     rval;           /* return value */
 
 188         int                     v;              /* type-checking value */
 
 190         ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
 
 191         if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) {
 
 194         XFS_STATS_INC(xs_dir_create);
 
 196          * Fill in the arg structure for this request.
 
 199         args.namelen = namelen;
 
 200         args.hashval = xfs_da_hashname(name, namelen);
 
 203         args.firstblock = first;
 
 206         args.whichfork = XFS_DATA_FORK;
 
 209         args.addname = args.oknoent = 1;
 
 211          * Decide on what work routines to call based on the inode size.
 
 213         if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
 
 214                 rval = xfs_dir2_sf_addname(&args);
 
 215         else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {
 
 218                 rval = xfs_dir2_block_addname(&args);
 
 219         else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) {
 
 222                 rval = xfs_dir2_leaf_addname(&args);
 
 224                 rval = xfs_dir2_node_addname(&args);
 
 229  * Lookup a name in a directory, give back the inode number.
 
 231 static int                              /* error */
 
 233         xfs_trans_t     *tp,            /* transaction pointer */
 
 234         xfs_inode_t     *dp,            /* incore directory inode */
 
 235         char            *name,          /* lookup name */
 
 236         int             namelen,        /* lookup name length */
 
 237         xfs_ino_t       *inum)          /* out: inode number */
 
 239         xfs_da_args_t   args;           /* operation arguments */
 
 240         int             rval;           /* return value */
 
 241         int             v;              /* type-checking value */
 
 243         ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
 
 244         XFS_STATS_INC(xs_dir_lookup);
 
 247          * Fill in the arg structure for this request.
 
 250         args.namelen = namelen;
 
 251         args.hashval = xfs_da_hashname(name, namelen);
 
 254         args.firstblock = NULL;
 
 257         args.whichfork = XFS_DATA_FORK;
 
 259         args.justcheck = args.addname = 0;
 
 262          * Decide on what work routines to call based on the inode size.
 
 264         if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
 
 265                 rval = xfs_dir2_sf_lookup(&args);
 
 266         else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {
 
 269                 rval = xfs_dir2_block_lookup(&args);
 
 270         else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) {
 
 273                 rval = xfs_dir2_leaf_lookup(&args);
 
 275                 rval = xfs_dir2_node_lookup(&args);
 
 279                 *inum = args.inumber;
 
 284  * Remove an entry from a directory.
 
 286 static int                              /* error */
 
 288         xfs_trans_t     *tp,            /* transaction pointer */
 
 289         xfs_inode_t     *dp,            /* incore directory inode */
 
 290         char            *name,          /* name of entry to remove */
 
 291         int             namelen,        /* name length of entry to remove */
 
 292         xfs_ino_t       ino,            /* inode number of entry to remove */
 
 293         xfs_fsblock_t   *first,         /* bmap's firstblock */
 
 294         xfs_bmap_free_t *flist,         /* bmap's freeblock list */
 
 295         xfs_extlen_t    total)          /* bmap's total block count */
 
 297         xfs_da_args_t   args;           /* operation arguments */
 
 298         int             rval;           /* return value */
 
 299         int             v;              /* type-checking value */
 
 301         ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
 
 302         XFS_STATS_INC(xs_dir_remove);
 
 304          * Fill in the arg structure for this request.
 
 307         args.namelen = namelen;
 
 308         args.hashval = xfs_da_hashname(name, namelen);
 
 311         args.firstblock = first;
 
 314         args.whichfork = XFS_DATA_FORK;
 
 316         args.justcheck = args.addname = args.oknoent = 0;
 
 318          * Decide on what work routines to call based on the inode size.
 
 320         if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
 
 321                 rval = xfs_dir2_sf_removename(&args);
 
 322         else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {
 
 325                 rval = xfs_dir2_block_removename(&args);
 
 326         else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) {
 
 329                 rval = xfs_dir2_leaf_removename(&args);
 
 331                 rval = xfs_dir2_node_removename(&args);
 
 338 static int                              /* error */
 
 340         xfs_trans_t     *tp,            /* transaction pointer */
 
 341         xfs_inode_t     *dp,            /* incore directory inode */
 
 342         uio_t           *uio,           /* caller's buffer control */
 
 343         int             *eofp)          /* out: eof reached */
 
 345         int             alignment;      /* alignment required for ABI */
 
 346         xfs_dirent_t    *dbp;           /* malloc'ed buffer */
 
 347         xfs_dir2_put_t  put;            /* entry formatting routine */
 
 348         int             rval;           /* return value */
 
 349         int             v;              /* type-checking value */
 
 351         ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
 
 352         XFS_STATS_INC(xs_dir_getdents);
 
 354          * If our caller has given us a single contiguous aligned memory buffer,
 
 355          * just work directly within that buffer.  If it's in user memory,
 
 356          * lock it down first.
 
 358         alignment = sizeof(xfs_off_t) - 1;
 
 359         if ((uio->uio_iovcnt == 1) &&
 
 360             (((__psint_t)uio->uio_iov[0].iov_base & alignment) == 0) &&
 
 361             ((uio->uio_iov[0].iov_len & alignment) == 0)) {
 
 363                 put = xfs_dir2_put_dirent64_direct;
 
 365                 dbp = kmem_alloc(sizeof(*dbp) + MAXNAMELEN, KM_SLEEP);
 
 366                 put = xfs_dir2_put_dirent64_uio;
 
 371          * Decide on what work routines to call based on the inode size.
 
 373         if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
 
 374                 rval = xfs_dir2_sf_getdents(dp, uio, eofp, dbp, put);
 
 375         else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {
 
 378                 rval = xfs_dir2_block_getdents(tp, dp, uio, eofp, dbp, put);
 
 380                 rval = xfs_dir2_leaf_getdents(tp, dp, uio, eofp, dbp, put);
 
 382                 kmem_free(dbp, sizeof(*dbp) + MAXNAMELEN);
 
 387  * Replace the inode number of a directory entry.
 
 389 static int                              /* error */
 
 391         xfs_trans_t     *tp,            /* transaction pointer */
 
 392         xfs_inode_t     *dp,            /* incore directory inode */
 
 393         char            *name,          /* name of entry to replace */
 
 394         int             namelen,        /* name length of entry to replace */
 
 395         xfs_ino_t       inum,           /* new inode number */
 
 396         xfs_fsblock_t   *first,         /* bmap's firstblock */
 
 397         xfs_bmap_free_t *flist,         /* bmap's freeblock list */
 
 398         xfs_extlen_t    total)          /* bmap's total block count */
 
 400         xfs_da_args_t   args;           /* operation arguments */
 
 401         int             rval;           /* return value */
 
 402         int             v;              /* type-checking value */
 
 404         ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
 
 406         if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) {
 
 410          * Fill in the arg structure for this request.
 
 413         args.namelen = namelen;
 
 414         args.hashval = xfs_da_hashname(name, namelen);
 
 417         args.firstblock = first;
 
 420         args.whichfork = XFS_DATA_FORK;
 
 422         args.justcheck = args.addname = args.oknoent = 0;
 
 424          * Decide on what work routines to call based on the inode size.
 
 426         if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
 
 427                 rval = xfs_dir2_sf_replace(&args);
 
 428         else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {
 
 431                 rval = xfs_dir2_block_replace(&args);
 
 432         else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) {
 
 435                 rval = xfs_dir2_leaf_replace(&args);
 
 437                 rval = xfs_dir2_node_replace(&args);
 
 442  * See if this entry can be added to the directory without allocating space.
 
 444 static int                              /* error */
 
 446         xfs_trans_t     *tp,            /* transaction pointer */
 
 447         xfs_inode_t     *dp,            /* incore directory inode */
 
 448         char            *name,          /* name of entry to add */
 
 449         int             namelen)        /* name length of entry to add */
 
 451         xfs_da_args_t   args;           /* operation arguments */
 
 452         int             rval;           /* return value */
 
 453         int             v;              /* type-checking value */
 
 455         ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
 
 457          * Fill in the arg structure for this request.
 
 460         args.namelen = namelen;
 
 461         args.hashval = xfs_da_hashname(name, namelen);
 
 464         args.firstblock = NULL;
 
 467         args.whichfork = XFS_DATA_FORK;
 
 469         args.justcheck = args.addname = args.oknoent = 1;
 
 471          * Decide on what work routines to call based on the inode size.
 
 473         if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
 
 474                 rval = xfs_dir2_sf_addname(&args);
 
 475         else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {
 
 478                 rval = xfs_dir2_block_addname(&args);
 
 479         else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) {
 
 482                 rval = xfs_dir2_leaf_addname(&args);
 
 484                 rval = xfs_dir2_node_addname(&args);
 
 489  * Dummy routine for shortform inode validation.
 
 490  * Can't really do this.
 
 493 static int                              /* error */
 
 494 xfs_dir2_shortform_validate_ondisk(
 
 495         xfs_mount_t     *mp,            /* filesystem mount point */
 
 496         xfs_dinode_t    *dip)           /* ondisk inode */
 
 506  * Add a block to the directory.
 
 507  * This routine is for data and free blocks, not leaf/node blocks
 
 508  * which are handled by xfs_da_grow_inode.
 
 512         xfs_da_args_t   *args,          /* operation arguments */
 
 513         int             space,          /* v2 dir's space XFS_DIR2_xxx_SPACE */
 
 514         xfs_dir2_db_t   *dbp)           /* out: block number added */
 
 516         xfs_fileoff_t   bno;            /* directory offset of new block */
 
 517         int             count;          /* count of filesystem blocks */
 
 518         xfs_inode_t     *dp;            /* incore directory inode */
 
 519         int             error;          /* error return value */
 
 520         int             got;            /* blocks actually mapped */
 
 521         int             i;              /* temp mapping index */
 
 522         xfs_bmbt_irec_t map;            /* single structure for bmap */
 
 523         int             mapi;           /* mapping index */
 
 524         xfs_bmbt_irec_t *mapp;          /* bmap mapping structure(s) */
 
 525         xfs_mount_t     *mp;            /* filesystem mount point */
 
 526         int             nmap;           /* number of bmap entries */
 
 527         xfs_trans_t     *tp;            /* transaction pointer */
 
 529         xfs_dir2_trace_args_s("grow_inode", args, space);
 
 534          * Set lowest possible block in the space requested.
 
 536         bno = XFS_B_TO_FSBT(mp, space * XFS_DIR2_SPACE_SIZE);
 
 537         count = mp->m_dirblkfsbs;
 
 539          * Find the first hole for our block.
 
 541         if ((error = xfs_bmap_first_unused(tp, dp, count, &bno, XFS_DATA_FORK))) {
 
 545         ASSERT(args->firstblock != NULL);
 
 547          * Try mapping the new block contiguously (one extent).
 
 549         if ((error = xfs_bmapi(tp, dp, bno, count,
 
 550                         XFS_BMAPI_WRITE|XFS_BMAPI_METADATA|XFS_BMAPI_CONTIG,
 
 551                         args->firstblock, args->total, &map, &nmap,
 
 564          * Didn't work and this is a multiple-fsb directory block.
 
 565          * Try again with contiguous flag turned on.
 
 567         else if (nmap == 0 && count > 1) {
 
 568                 xfs_fileoff_t   b;      /* current file offset */
 
 571                  * Space for maximum number of mappings.
 
 573                 mapp = kmem_alloc(sizeof(*mapp) * count, KM_SLEEP);
 
 575                  * Iterate until we get to the end of our block.
 
 577                 for (b = bno, mapi = 0; b < bno + count; ) {
 
 578                         int     c;      /* current fsb count */
 
 581                          * Can't map more than MAX_NMAP at once.
 
 583                         nmap = MIN(XFS_BMAP_MAX_NMAP, count);
 
 584                         c = (int)(bno + count - b);
 
 585                         if ((error = xfs_bmapi(tp, dp, b, c,
 
 586                                         XFS_BMAPI_WRITE|XFS_BMAPI_METADATA,
 
 587                                         args->firstblock, args->total,
 
 588                                         &mapp[mapi], &nmap, args->flist))) {
 
 589                                 kmem_free(mapp, sizeof(*mapp) * count);
 
 595                          * Add this bunch into our table, go to the next offset.
 
 598                         b = mapp[mapi - 1].br_startoff +
 
 599                             mapp[mapi - 1].br_blockcount;
 
 610          * See how many fsb's we got.
 
 612         for (i = 0, got = 0; i < mapi; i++)
 
 613                 got += mapp[i].br_blockcount;
 
 615          * Didn't get enough fsb's, or the first/last block's are wrong.
 
 617         if (got != count || mapp[0].br_startoff != bno ||
 
 618             mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount !=
 
 621                         kmem_free(mapp, sizeof(*mapp) * count);
 
 622                 return XFS_ERROR(ENOSPC);
 
 625          * Done with the temporary mapping table.
 
 628                 kmem_free(mapp, sizeof(*mapp) * count);
 
 629         *dbp = XFS_DIR2_DA_TO_DB(mp, (xfs_dablk_t)bno);
 
 631          * Update file's size if this is the data space and it grew.
 
 633         if (space == XFS_DIR2_DATA_SPACE) {
 
 634                 xfs_fsize_t     size;           /* directory file (data) size */
 
 636                 size = XFS_FSB_TO_B(mp, bno + count);
 
 637                 if (size > dp->i_d.di_size) {
 
 638                         dp->i_d.di_size = size;
 
 639                         xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
 
 646  * See if the directory is a single-block form directory.
 
 650         xfs_trans_t     *tp,            /* transaction pointer */
 
 651         xfs_inode_t     *dp,            /* incore directory inode */
 
 652         int             *vp)            /* out: 1 is block, 0 is not block */
 
 654         xfs_fileoff_t   last;           /* last file offset */
 
 655         xfs_mount_t     *mp;            /* filesystem mount point */
 
 656         int             rval;           /* return value */
 
 659         if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK))) {
 
 662         rval = XFS_FSB_TO_B(mp, last) == mp->m_dirblksize;
 
 663         ASSERT(rval == 0 || dp->i_d.di_size == mp->m_dirblksize);
 
 669  * See if the directory is a single-leaf form directory.
 
 673         xfs_trans_t     *tp,            /* transaction pointer */
 
 674         xfs_inode_t     *dp,            /* incore directory inode */
 
 675         int             *vp)            /* out: 1 is leaf, 0 is not leaf */
 
 677         xfs_fileoff_t   last;           /* last file offset */
 
 678         xfs_mount_t     *mp;            /* filesystem mount point */
 
 679         int             rval;           /* return value */
 
 682         if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK))) {
 
 685         *vp = last == mp->m_dirleafblk + (1 << mp->m_sb.sb_dirblklog);
 
 690  * Getdents put routine for 64-bit ABI, direct form.
 
 692 static int                                      /* error */
 
 693 xfs_dir2_put_dirent64_direct(
 
 694         xfs_dir2_put_args_t     *pa)            /* argument bundle */
 
 696         xfs_dirent_t            *idbp;          /* dirent pointer */
 
 697         iovec_t                 *iovp;          /* io vector */
 
 698         int                     namelen;        /* entry name length */
 
 699         int                     reclen;         /* entry total length */
 
 700         uio_t                   *uio;           /* I/O control */
 
 702         namelen = pa->namelen;
 
 703         reclen = DIRENTSIZE(namelen);
 
 706          * Won't fit in the remaining space.
 
 708         if (reclen > uio->uio_resid) {
 
 713         idbp = (xfs_dirent_t *)iovp->iov_base;
 
 714         iovp->iov_base = (char *)idbp + reclen;
 
 715         iovp->iov_len -= reclen;
 
 716         uio->uio_resid -= reclen;
 
 717         idbp->d_reclen = reclen;
 
 718         idbp->d_ino = pa->ino;
 
 719         idbp->d_off = pa->cook;
 
 720         idbp->d_name[namelen] = '\0';
 
 722         memcpy(idbp->d_name, pa->name, namelen);
 
 727  * Getdents put routine for 64-bit ABI, uio form.
 
 729 static int                                      /* error */
 
 730 xfs_dir2_put_dirent64_uio(
 
 731         xfs_dir2_put_args_t     *pa)            /* argument bundle */
 
 733         xfs_dirent_t            *idbp;          /* dirent pointer */
 
 734         int                     namelen;        /* entry name length */
 
 735         int                     reclen;         /* entry total length */
 
 736         int                     rval;           /* return value */
 
 737         uio_t                   *uio;           /* I/O control */
 
 739         namelen = pa->namelen;
 
 740         reclen = DIRENTSIZE(namelen);
 
 743          * Won't fit in the remaining space.
 
 745         if (reclen > uio->uio_resid) {
 
 750         idbp->d_reclen = reclen;
 
 751         idbp->d_ino = pa->ino;
 
 752         idbp->d_off = pa->cook;
 
 753         idbp->d_name[namelen] = '\0';
 
 754         memcpy(idbp->d_name, pa->name, namelen);
 
 755         rval = uio_read((caddr_t)idbp, reclen, uio);
 
 756         pa->done = (rval == 0);
 
 761  * Remove the given block from the directory.
 
 762  * This routine is used for data and free blocks, leaf/node are done
 
 763  * by xfs_da_shrink_inode.
 
 766 xfs_dir2_shrink_inode(
 
 767         xfs_da_args_t   *args,          /* operation arguments */
 
 768         xfs_dir2_db_t   db,             /* directory block number */
 
 769         xfs_dabuf_t     *bp)            /* block's buffer */
 
 771         xfs_fileoff_t   bno;            /* directory file offset */
 
 772         xfs_dablk_t     da;             /* directory file offset */
 
 773         int             done;           /* bunmap is finished */
 
 774         xfs_inode_t     *dp;            /* incore directory inode */
 
 775         int             error;          /* error return value */
 
 776         xfs_mount_t     *mp;            /* filesystem mount point */
 
 777         xfs_trans_t     *tp;            /* transaction pointer */
 
 779         xfs_dir2_trace_args_db("shrink_inode", args, db, bp);
 
 783         da = XFS_DIR2_DB_TO_DA(mp, db);
 
 785          * Unmap the fsblock(s).
 
 787         if ((error = xfs_bunmapi(tp, dp, da, mp->m_dirblkfsbs,
 
 788                         XFS_BMAPI_METADATA, 0, args->firstblock, args->flist,
 
 791                  * ENOSPC actually can happen if we're in a removename with
 
 792                  * no space reservation, and the resulting block removal
 
 793                  * would cause a bmap btree split or conversion from extents
 
 794                  * to btree.  This can only happen for un-fragmented
 
 795                  * directory blocks, since you need to be punching out
 
 796                  * the middle of an extent.
 
 797                  * In this case we need to leave the block in the file,
 
 799                  * So the block has to be in a consistent empty state
 
 800                  * and appropriately logged.
 
 801                  * We don't free up the buffer, the caller can tell it
 
 802                  * hasn't happened since it got an error back.
 
 808          * Invalidate the buffer from the transaction.
 
 810         xfs_da_binval(tp, bp);
 
 812          * If it's not a data block, we're done.
 
 814         if (db >= XFS_DIR2_LEAF_FIRSTDB(mp))
 
 817          * If the block isn't the last one in the directory, we're done.
 
 819         if (dp->i_d.di_size > XFS_DIR2_DB_OFF_TO_BYTE(mp, db + 1, 0))
 
 822         if ((error = xfs_bmap_last_before(tp, dp, &bno, XFS_DATA_FORK))) {
 
 824                  * This can't really happen unless there's kernel corruption.
 
 828         if (db == mp->m_dirdatablk)
 
 833          * Set the size to the new last block.
 
 835         dp->i_d.di_size = XFS_FSB_TO_B(mp, bno);
 
 836         xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);