Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
0004  * All Rights Reserved.
0005  */
0006 #include "xfs.h"
0007 #include "xfs_fs.h"
0008 #include "xfs_shared.h"
0009 #include "xfs_format.h"
0010 #include "xfs_log_format.h"
0011 #include "xfs_trans_resv.h"
0012 #include "xfs_mount.h"
0013 #include "xfs_inode.h"
0014 #include "xfs_trans.h"
0015 #include "xfs_bmap.h"
0016 #include "xfs_dir2.h"
0017 #include "xfs_dir2_priv.h"
0018 #include "xfs_errortag.h"
0019 #include "xfs_error.h"
0020 #include "xfs_trace.h"
0021 
0022 const struct xfs_name xfs_name_dotdot = {
0023     .name   = (const unsigned char *)"..",
0024     .len    = 2,
0025     .type   = XFS_DIR3_FT_DIR,
0026 };
0027 
0028 /*
0029  * Convert inode mode to directory entry filetype
0030  */
0031 unsigned char
0032 xfs_mode_to_ftype(
0033     int     mode)
0034 {
0035     switch (mode & S_IFMT) {
0036     case S_IFREG:
0037         return XFS_DIR3_FT_REG_FILE;
0038     case S_IFDIR:
0039         return XFS_DIR3_FT_DIR;
0040     case S_IFCHR:
0041         return XFS_DIR3_FT_CHRDEV;
0042     case S_IFBLK:
0043         return XFS_DIR3_FT_BLKDEV;
0044     case S_IFIFO:
0045         return XFS_DIR3_FT_FIFO;
0046     case S_IFSOCK:
0047         return XFS_DIR3_FT_SOCK;
0048     case S_IFLNK:
0049         return XFS_DIR3_FT_SYMLINK;
0050     default:
0051         return XFS_DIR3_FT_UNKNOWN;
0052     }
0053 }
0054 
0055 /*
0056  * ASCII case-insensitive (ie. A-Z) support for directories that was
0057  * used in IRIX.
0058  */
0059 xfs_dahash_t
0060 xfs_ascii_ci_hashname(
0061     const struct xfs_name   *name)
0062 {
0063     xfs_dahash_t        hash;
0064     int         i;
0065 
0066     for (i = 0, hash = 0; i < name->len; i++)
0067         hash = tolower(name->name[i]) ^ rol32(hash, 7);
0068 
0069     return hash;
0070 }
0071 
0072 enum xfs_dacmp
0073 xfs_ascii_ci_compname(
0074     struct xfs_da_args  *args,
0075     const unsigned char *name,
0076     int         len)
0077 {
0078     enum xfs_dacmp      result;
0079     int         i;
0080 
0081     if (args->namelen != len)
0082         return XFS_CMP_DIFFERENT;
0083 
0084     result = XFS_CMP_EXACT;
0085     for (i = 0; i < len; i++) {
0086         if (args->name[i] == name[i])
0087             continue;
0088         if (tolower(args->name[i]) != tolower(name[i]))
0089             return XFS_CMP_DIFFERENT;
0090         result = XFS_CMP_CASE;
0091     }
0092 
0093     return result;
0094 }
0095 
0096 int
0097 xfs_da_mount(
0098     struct xfs_mount    *mp)
0099 {
0100     struct xfs_da_geometry  *dageo;
0101 
0102 
0103     ASSERT(mp->m_sb.sb_versionnum & XFS_SB_VERSION_DIRV2BIT);
0104     ASSERT(xfs_dir2_dirblock_bytes(&mp->m_sb) <= XFS_MAX_BLOCKSIZE);
0105 
0106     mp->m_dir_geo = kmem_zalloc(sizeof(struct xfs_da_geometry),
0107                     KM_MAYFAIL);
0108     mp->m_attr_geo = kmem_zalloc(sizeof(struct xfs_da_geometry),
0109                      KM_MAYFAIL);
0110     if (!mp->m_dir_geo || !mp->m_attr_geo) {
0111         kmem_free(mp->m_dir_geo);
0112         kmem_free(mp->m_attr_geo);
0113         return -ENOMEM;
0114     }
0115 
0116     /* set up directory geometry */
0117     dageo = mp->m_dir_geo;
0118     dageo->blklog = mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog;
0119     dageo->fsblog = mp->m_sb.sb_blocklog;
0120     dageo->blksize = xfs_dir2_dirblock_bytes(&mp->m_sb);
0121     dageo->fsbcount = 1 << mp->m_sb.sb_dirblklog;
0122     if (xfs_has_crc(mp)) {
0123         dageo->node_hdr_size = sizeof(struct xfs_da3_node_hdr);
0124         dageo->leaf_hdr_size = sizeof(struct xfs_dir3_leaf_hdr);
0125         dageo->free_hdr_size = sizeof(struct xfs_dir3_free_hdr);
0126         dageo->data_entry_offset =
0127                 sizeof(struct xfs_dir3_data_hdr);
0128     } else {
0129         dageo->node_hdr_size = sizeof(struct xfs_da_node_hdr);
0130         dageo->leaf_hdr_size = sizeof(struct xfs_dir2_leaf_hdr);
0131         dageo->free_hdr_size = sizeof(struct xfs_dir2_free_hdr);
0132         dageo->data_entry_offset =
0133                 sizeof(struct xfs_dir2_data_hdr);
0134     }
0135     dageo->leaf_max_ents = (dageo->blksize - dageo->leaf_hdr_size) /
0136             sizeof(struct xfs_dir2_leaf_entry);
0137     dageo->free_max_bests = (dageo->blksize - dageo->free_hdr_size) /
0138             sizeof(xfs_dir2_data_off_t);
0139 
0140     dageo->data_first_offset = dageo->data_entry_offset +
0141             xfs_dir2_data_entsize(mp, 1) +
0142             xfs_dir2_data_entsize(mp, 2);
0143 
0144     /*
0145      * Now we've set up the block conversion variables, we can calculate the
0146      * segment block constants using the geometry structure.
0147      */
0148     dageo->datablk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_DATA_OFFSET);
0149     dageo->leafblk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_LEAF_OFFSET);
0150     dageo->freeblk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_FREE_OFFSET);
0151     dageo->node_ents = (dageo->blksize - dageo->node_hdr_size) /
0152                 (uint)sizeof(xfs_da_node_entry_t);
0153     dageo->max_extents = (XFS_DIR2_MAX_SPACES * XFS_DIR2_SPACE_SIZE) >>
0154                     mp->m_sb.sb_blocklog;
0155     dageo->magicpct = (dageo->blksize * 37) / 100;
0156 
0157     /* set up attribute geometry - single fsb only */
0158     dageo = mp->m_attr_geo;
0159     dageo->blklog = mp->m_sb.sb_blocklog;
0160     dageo->fsblog = mp->m_sb.sb_blocklog;
0161     dageo->blksize = 1 << dageo->blklog;
0162     dageo->fsbcount = 1;
0163     dageo->node_hdr_size = mp->m_dir_geo->node_hdr_size;
0164     dageo->node_ents = (dageo->blksize - dageo->node_hdr_size) /
0165                 (uint)sizeof(xfs_da_node_entry_t);
0166 
0167     if (xfs_has_large_extent_counts(mp))
0168         dageo->max_extents = XFS_MAX_EXTCNT_ATTR_FORK_LARGE;
0169     else
0170         dageo->max_extents = XFS_MAX_EXTCNT_ATTR_FORK_SMALL;
0171 
0172     dageo->magicpct = (dageo->blksize * 37) / 100;
0173     return 0;
0174 }
0175 
0176 void
0177 xfs_da_unmount(
0178     struct xfs_mount    *mp)
0179 {
0180     kmem_free(mp->m_dir_geo);
0181     kmem_free(mp->m_attr_geo);
0182 }
0183 
0184 /*
0185  * Return 1 if directory contains only "." and "..".
0186  */
0187 int
0188 xfs_dir_isempty(
0189     xfs_inode_t *dp)
0190 {
0191     xfs_dir2_sf_hdr_t   *sfp;
0192 
0193     ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
0194     if (dp->i_disk_size == 0)   /* might happen during shutdown. */
0195         return 1;
0196     if (dp->i_disk_size > xfs_inode_data_fork_size(dp))
0197         return 0;
0198     sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
0199     return !sfp->count;
0200 }
0201 
0202 /*
0203  * Validate a given inode number.
0204  */
0205 int
0206 xfs_dir_ino_validate(
0207     xfs_mount_t *mp,
0208     xfs_ino_t   ino)
0209 {
0210     bool        ino_ok = xfs_verify_dir_ino(mp, ino);
0211 
0212     if (XFS_IS_CORRUPT(mp, !ino_ok) ||
0213         XFS_TEST_ERROR(false, mp, XFS_ERRTAG_DIR_INO_VALIDATE)) {
0214         xfs_warn(mp, "Invalid inode number 0x%Lx",
0215                 (unsigned long long) ino);
0216         return -EFSCORRUPTED;
0217     }
0218     return 0;
0219 }
0220 
0221 /*
0222  * Initialize a directory with its "." and ".." entries.
0223  */
0224 int
0225 xfs_dir_init(
0226     xfs_trans_t *tp,
0227     xfs_inode_t *dp,
0228     xfs_inode_t *pdp)
0229 {
0230     struct xfs_da_args *args;
0231     int     error;
0232 
0233     ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
0234     error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino);
0235     if (error)
0236         return error;
0237 
0238     args = kmem_zalloc(sizeof(*args), KM_NOFS);
0239     if (!args)
0240         return -ENOMEM;
0241 
0242     args->geo = dp->i_mount->m_dir_geo;
0243     args->dp = dp;
0244     args->trans = tp;
0245     error = xfs_dir2_sf_create(args, pdp->i_ino);
0246     kmem_free(args);
0247     return error;
0248 }
0249 
0250 /*
0251  * Enter a name in a directory, or check for available space.
0252  * If inum is 0, only the available space test is performed.
0253  */
0254 int
0255 xfs_dir_createname(
0256     struct xfs_trans    *tp,
0257     struct xfs_inode    *dp,
0258     const struct xfs_name   *name,
0259     xfs_ino_t       inum,       /* new entry inode number */
0260     xfs_extlen_t        total)      /* bmap's total block count */
0261 {
0262     struct xfs_da_args  *args;
0263     int         rval;
0264     int         v;      /* type-checking value */
0265 
0266     ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
0267 
0268     if (inum) {
0269         rval = xfs_dir_ino_validate(tp->t_mountp, inum);
0270         if (rval)
0271             return rval;
0272         XFS_STATS_INC(dp->i_mount, xs_dir_create);
0273     }
0274 
0275     args = kmem_zalloc(sizeof(*args), KM_NOFS);
0276     if (!args)
0277         return -ENOMEM;
0278 
0279     args->geo = dp->i_mount->m_dir_geo;
0280     args->name = name->name;
0281     args->namelen = name->len;
0282     args->filetype = name->type;
0283     args->hashval = xfs_dir2_hashname(dp->i_mount, name);
0284     args->inumber = inum;
0285     args->dp = dp;
0286     args->total = total;
0287     args->whichfork = XFS_DATA_FORK;
0288     args->trans = tp;
0289     args->op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
0290     if (!inum)
0291         args->op_flags |= XFS_DA_OP_JUSTCHECK;
0292 
0293     if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) {
0294         rval = xfs_dir2_sf_addname(args);
0295         goto out_free;
0296     }
0297 
0298     rval = xfs_dir2_isblock(args, &v);
0299     if (rval)
0300         goto out_free;
0301     if (v) {
0302         rval = xfs_dir2_block_addname(args);
0303         goto out_free;
0304     }
0305 
0306     rval = xfs_dir2_isleaf(args, &v);
0307     if (rval)
0308         goto out_free;
0309     if (v)
0310         rval = xfs_dir2_leaf_addname(args);
0311     else
0312         rval = xfs_dir2_node_addname(args);
0313 
0314 out_free:
0315     kmem_free(args);
0316     return rval;
0317 }
0318 
0319 /*
0320  * If doing a CI lookup and case-insensitive match, dup actual name into
0321  * args.value. Return EEXIST for success (ie. name found) or an error.
0322  */
0323 int
0324 xfs_dir_cilookup_result(
0325     struct xfs_da_args *args,
0326     const unsigned char *name,
0327     int     len)
0328 {
0329     if (args->cmpresult == XFS_CMP_DIFFERENT)
0330         return -ENOENT;
0331     if (args->cmpresult != XFS_CMP_CASE ||
0332                     !(args->op_flags & XFS_DA_OP_CILOOKUP))
0333         return -EEXIST;
0334 
0335     args->value = kmem_alloc(len, KM_NOFS | KM_MAYFAIL);
0336     if (!args->value)
0337         return -ENOMEM;
0338 
0339     memcpy(args->value, name, len);
0340     args->valuelen = len;
0341     return -EEXIST;
0342 }
0343 
0344 /*
0345  * Lookup a name in a directory, give back the inode number.
0346  * If ci_name is not NULL, returns the actual name in ci_name if it differs
0347  * to name, or ci_name->name is set to NULL for an exact match.
0348  */
0349 
0350 int
0351 xfs_dir_lookup(
0352     struct xfs_trans    *tp,
0353     struct xfs_inode    *dp,
0354     const struct xfs_name   *name,
0355     xfs_ino_t       *inum,    /* out: inode number */
0356     struct xfs_name     *ci_name) /* out: actual name if CI match */
0357 {
0358     struct xfs_da_args  *args;
0359     int         rval;
0360     int         v;    /* type-checking value */
0361     int         lock_mode;
0362 
0363     ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
0364     XFS_STATS_INC(dp->i_mount, xs_dir_lookup);
0365 
0366     /*
0367      * We need to use KM_NOFS here so that lockdep will not throw false
0368      * positive deadlock warnings on a non-transactional lookup path. It is
0369      * safe to recurse into inode recalim in that case, but lockdep can't
0370      * easily be taught about it. Hence KM_NOFS avoids having to add more
0371      * lockdep Doing this avoids having to add a bunch of lockdep class
0372      * annotations into the reclaim path for the ilock.
0373      */
0374     args = kmem_zalloc(sizeof(*args), KM_NOFS);
0375     args->geo = dp->i_mount->m_dir_geo;
0376     args->name = name->name;
0377     args->namelen = name->len;
0378     args->filetype = name->type;
0379     args->hashval = xfs_dir2_hashname(dp->i_mount, name);
0380     args->dp = dp;
0381     args->whichfork = XFS_DATA_FORK;
0382     args->trans = tp;
0383     args->op_flags = XFS_DA_OP_OKNOENT;
0384     if (ci_name)
0385         args->op_flags |= XFS_DA_OP_CILOOKUP;
0386 
0387     lock_mode = xfs_ilock_data_map_shared(dp);
0388     if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) {
0389         rval = xfs_dir2_sf_lookup(args);
0390         goto out_check_rval;
0391     }
0392 
0393     rval = xfs_dir2_isblock(args, &v);
0394     if (rval)
0395         goto out_free;
0396     if (v) {
0397         rval = xfs_dir2_block_lookup(args);
0398         goto out_check_rval;
0399     }
0400 
0401     rval = xfs_dir2_isleaf(args, &v);
0402     if (rval)
0403         goto out_free;
0404     if (v)
0405         rval = xfs_dir2_leaf_lookup(args);
0406     else
0407         rval = xfs_dir2_node_lookup(args);
0408 
0409 out_check_rval:
0410     if (rval == -EEXIST)
0411         rval = 0;
0412     if (!rval) {
0413         *inum = args->inumber;
0414         if (ci_name) {
0415             ci_name->name = args->value;
0416             ci_name->len = args->valuelen;
0417         }
0418     }
0419 out_free:
0420     xfs_iunlock(dp, lock_mode);
0421     kmem_free(args);
0422     return rval;
0423 }
0424 
0425 /*
0426  * Remove an entry from a directory.
0427  */
0428 int
0429 xfs_dir_removename(
0430     struct xfs_trans    *tp,
0431     struct xfs_inode    *dp,
0432     struct xfs_name     *name,
0433     xfs_ino_t       ino,
0434     xfs_extlen_t        total)      /* bmap's total block count */
0435 {
0436     struct xfs_da_args  *args;
0437     int         rval;
0438     int         v;      /* type-checking value */
0439 
0440     ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
0441     XFS_STATS_INC(dp->i_mount, xs_dir_remove);
0442 
0443     args = kmem_zalloc(sizeof(*args), KM_NOFS);
0444     if (!args)
0445         return -ENOMEM;
0446 
0447     args->geo = dp->i_mount->m_dir_geo;
0448     args->name = name->name;
0449     args->namelen = name->len;
0450     args->filetype = name->type;
0451     args->hashval = xfs_dir2_hashname(dp->i_mount, name);
0452     args->inumber = ino;
0453     args->dp = dp;
0454     args->total = total;
0455     args->whichfork = XFS_DATA_FORK;
0456     args->trans = tp;
0457 
0458     if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) {
0459         rval = xfs_dir2_sf_removename(args);
0460         goto out_free;
0461     }
0462 
0463     rval = xfs_dir2_isblock(args, &v);
0464     if (rval)
0465         goto out_free;
0466     if (v) {
0467         rval = xfs_dir2_block_removename(args);
0468         goto out_free;
0469     }
0470 
0471     rval = xfs_dir2_isleaf(args, &v);
0472     if (rval)
0473         goto out_free;
0474     if (v)
0475         rval = xfs_dir2_leaf_removename(args);
0476     else
0477         rval = xfs_dir2_node_removename(args);
0478 out_free:
0479     kmem_free(args);
0480     return rval;
0481 }
0482 
0483 /*
0484  * Replace the inode number of a directory entry.
0485  */
0486 int
0487 xfs_dir_replace(
0488     struct xfs_trans    *tp,
0489     struct xfs_inode    *dp,
0490     const struct xfs_name   *name,      /* name of entry to replace */
0491     xfs_ino_t       inum,       /* new inode number */
0492     xfs_extlen_t        total)      /* bmap's total block count */
0493 {
0494     struct xfs_da_args  *args;
0495     int         rval;
0496     int         v;      /* type-checking value */
0497 
0498     ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
0499 
0500     rval = xfs_dir_ino_validate(tp->t_mountp, inum);
0501     if (rval)
0502         return rval;
0503 
0504     args = kmem_zalloc(sizeof(*args), KM_NOFS);
0505     if (!args)
0506         return -ENOMEM;
0507 
0508     args->geo = dp->i_mount->m_dir_geo;
0509     args->name = name->name;
0510     args->namelen = name->len;
0511     args->filetype = name->type;
0512     args->hashval = xfs_dir2_hashname(dp->i_mount, name);
0513     args->inumber = inum;
0514     args->dp = dp;
0515     args->total = total;
0516     args->whichfork = XFS_DATA_FORK;
0517     args->trans = tp;
0518 
0519     if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) {
0520         rval = xfs_dir2_sf_replace(args);
0521         goto out_free;
0522     }
0523 
0524     rval = xfs_dir2_isblock(args, &v);
0525     if (rval)
0526         goto out_free;
0527     if (v) {
0528         rval = xfs_dir2_block_replace(args);
0529         goto out_free;
0530     }
0531 
0532     rval = xfs_dir2_isleaf(args, &v);
0533     if (rval)
0534         goto out_free;
0535     if (v)
0536         rval = xfs_dir2_leaf_replace(args);
0537     else
0538         rval = xfs_dir2_node_replace(args);
0539 out_free:
0540     kmem_free(args);
0541     return rval;
0542 }
0543 
0544 /*
0545  * See if this entry can be added to the directory without allocating space.
0546  */
0547 int
0548 xfs_dir_canenter(
0549     xfs_trans_t *tp,
0550     xfs_inode_t *dp,
0551     struct xfs_name *name)      /* name of entry to add */
0552 {
0553     return xfs_dir_createname(tp, dp, name, 0, 0);
0554 }
0555 
0556 /*
0557  * Utility routines.
0558  */
0559 
0560 /*
0561  * Add a block to the directory.
0562  *
0563  * This routine is for data and free blocks, not leaf/node blocks which are
0564  * handled by xfs_da_grow_inode.
0565  */
0566 int
0567 xfs_dir2_grow_inode(
0568     struct xfs_da_args  *args,
0569     int         space,  /* v2 dir's space XFS_DIR2_xxx_SPACE */
0570     xfs_dir2_db_t       *dbp)   /* out: block number added */
0571 {
0572     struct xfs_inode    *dp = args->dp;
0573     struct xfs_mount    *mp = dp->i_mount;
0574     xfs_fileoff_t       bno;    /* directory offset of new block */
0575     int         count;  /* count of filesystem blocks */
0576     int         error;
0577 
0578     trace_xfs_dir2_grow_inode(args, space);
0579 
0580     /*
0581      * Set lowest possible block in the space requested.
0582      */
0583     bno = XFS_B_TO_FSBT(mp, space * XFS_DIR2_SPACE_SIZE);
0584     count = args->geo->fsbcount;
0585 
0586     error = xfs_da_grow_inode_int(args, &bno, count);
0587     if (error)
0588         return error;
0589 
0590     *dbp = xfs_dir2_da_to_db(args->geo, (xfs_dablk_t)bno);
0591 
0592     /*
0593      * Update file's size if this is the data space and it grew.
0594      */
0595     if (space == XFS_DIR2_DATA_SPACE) {
0596         xfs_fsize_t size;       /* directory file (data) size */
0597 
0598         size = XFS_FSB_TO_B(mp, bno + count);
0599         if (size > dp->i_disk_size) {
0600             dp->i_disk_size = size;
0601             xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
0602         }
0603     }
0604     return 0;
0605 }
0606 
0607 /*
0608  * See if the directory is a single-block form directory.
0609  */
0610 int
0611 xfs_dir2_isblock(
0612     struct xfs_da_args  *args,
0613     int         *vp)    /* out: 1 is block, 0 is not block */
0614 {
0615     xfs_fileoff_t       last;   /* last file offset */
0616     int         rval;
0617 
0618     if ((rval = xfs_bmap_last_offset(args->dp, &last, XFS_DATA_FORK)))
0619         return rval;
0620     rval = XFS_FSB_TO_B(args->dp->i_mount, last) == args->geo->blksize;
0621     if (XFS_IS_CORRUPT(args->dp->i_mount,
0622                rval != 0 &&
0623                args->dp->i_disk_size != args->geo->blksize))
0624         return -EFSCORRUPTED;
0625     *vp = rval;
0626     return 0;
0627 }
0628 
0629 /*
0630  * See if the directory is a single-leaf form directory.
0631  */
0632 int
0633 xfs_dir2_isleaf(
0634     struct xfs_da_args  *args,
0635     int         *vp)    /* out: 1 is block, 0 is not block */
0636 {
0637     xfs_fileoff_t       last;   /* last file offset */
0638     int         rval;
0639 
0640     if ((rval = xfs_bmap_last_offset(args->dp, &last, XFS_DATA_FORK)))
0641         return rval;
0642     *vp = last == args->geo->leafblk + args->geo->fsbcount;
0643     return 0;
0644 }
0645 
0646 /*
0647  * Remove the given block from the directory.
0648  * This routine is used for data and free blocks, leaf/node are done
0649  * by xfs_da_shrink_inode.
0650  */
0651 int
0652 xfs_dir2_shrink_inode(
0653     struct xfs_da_args  *args,
0654     xfs_dir2_db_t       db,
0655     struct xfs_buf      *bp)
0656 {
0657     xfs_fileoff_t       bno;        /* directory file offset */
0658     xfs_dablk_t     da;     /* directory file offset */
0659     int         done;       /* bunmap is finished */
0660     struct xfs_inode    *dp;
0661     int         error;
0662     struct xfs_mount    *mp;
0663     struct xfs_trans    *tp;
0664 
0665     trace_xfs_dir2_shrink_inode(args, db);
0666 
0667     dp = args->dp;
0668     mp = dp->i_mount;
0669     tp = args->trans;
0670     da = xfs_dir2_db_to_da(args->geo, db);
0671 
0672     /* Unmap the fsblock(s). */
0673     error = xfs_bunmapi(tp, dp, da, args->geo->fsbcount, 0, 0, &done);
0674     if (error) {
0675         /*
0676          * ENOSPC actually can happen if we're in a removename with no
0677          * space reservation, and the resulting block removal would
0678          * cause a bmap btree split or conversion from extents to btree.
0679          * This can only happen for un-fragmented directory blocks,
0680          * since you need to be punching out the middle of an extent.
0681          * In this case we need to leave the block in the file, and not
0682          * binval it.  So the block has to be in a consistent empty
0683          * state and appropriately logged.  We don't free up the buffer,
0684          * the caller can tell it hasn't happened since it got an error
0685          * back.
0686          */
0687         return error;
0688     }
0689     ASSERT(done);
0690     /*
0691      * Invalidate the buffer from the transaction.
0692      */
0693     xfs_trans_binval(tp, bp);
0694     /*
0695      * If it's not a data block, we're done.
0696      */
0697     if (db >= xfs_dir2_byte_to_db(args->geo, XFS_DIR2_LEAF_OFFSET))
0698         return 0;
0699     /*
0700      * If the block isn't the last one in the directory, we're done.
0701      */
0702     if (dp->i_disk_size > xfs_dir2_db_off_to_byte(args->geo, db + 1, 0))
0703         return 0;
0704     bno = da;
0705     if ((error = xfs_bmap_last_before(tp, dp, &bno, XFS_DATA_FORK))) {
0706         /*
0707          * This can't really happen unless there's kernel corruption.
0708          */
0709         return error;
0710     }
0711     if (db == args->geo->datablk)
0712         ASSERT(bno == 0);
0713     else
0714         ASSERT(bno > 0);
0715     /*
0716      * Set the size to the new last block.
0717      */
0718     dp->i_disk_size = XFS_FSB_TO_B(mp, bno);
0719     xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
0720     return 0;
0721 }
0722 
0723 /* Returns true if the directory entry name is valid. */
0724 bool
0725 xfs_dir2_namecheck(
0726     const void  *name,
0727     size_t      length)
0728 {
0729     /*
0730      * MAXNAMELEN includes the trailing null, but (name/length) leave it
0731      * out, so use >= for the length check.
0732      */
0733     if (length >= MAXNAMELEN)
0734         return false;
0735 
0736     /* There shouldn't be any slashes or nulls here */
0737     return !memchr(name, '/', length) && !memchr(name, 0, length);
0738 }
0739 
0740 xfs_dahash_t
0741 xfs_dir2_hashname(
0742     struct xfs_mount    *mp,
0743     const struct xfs_name   *name)
0744 {
0745     if (unlikely(xfs_has_asciici(mp)))
0746         return xfs_ascii_ci_hashname(name);
0747     return xfs_da_hashname(name->name, name->len);
0748 }
0749 
0750 enum xfs_dacmp
0751 xfs_dir2_compname(
0752     struct xfs_da_args  *args,
0753     const unsigned char *name,
0754     int         len)
0755 {
0756     if (unlikely(xfs_has_asciici(args->dp->i_mount)))
0757         return xfs_ascii_ci_compname(args, name, len);
0758     return xfs_da_compname(args, name, len);
0759 }