root/fs/xfs/libxfs/xfs_dir2.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. xfs_mode_to_ftype
  2. xfs_ascii_ci_hashname
  3. xfs_ascii_ci_compname
  4. xfs_da_mount
  5. xfs_da_unmount
  6. xfs_dir_isempty
  7. xfs_dir_ino_validate
  8. xfs_dir_init
  9. xfs_dir_createname
  10. xfs_dir_cilookup_result
  11. xfs_dir_lookup
  12. xfs_dir_removename
  13. xfs_dir_replace
  14. xfs_dir_canenter
  15. xfs_dir2_grow_inode
  16. xfs_dir2_isblock
  17. xfs_dir2_isleaf
  18. xfs_dir2_shrink_inode
  19. xfs_dir2_namecheck

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Copyright (c) 2000-2001,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_bmap.h"
  16 #include "xfs_dir2.h"
  17 #include "xfs_dir2_priv.h"
  18 #include "xfs_errortag.h"
  19 #include "xfs_error.h"
  20 #include "xfs_trace.h"
  21 
  22 struct xfs_name xfs_name_dotdot = { (unsigned char *)"..", 2, XFS_DIR3_FT_DIR };
  23 
  24 /*
  25  * Convert inode mode to directory entry filetype
  26  */
  27 unsigned char
  28 xfs_mode_to_ftype(
  29         int             mode)
  30 {
  31         switch (mode & S_IFMT) {
  32         case S_IFREG:
  33                 return XFS_DIR3_FT_REG_FILE;
  34         case S_IFDIR:
  35                 return XFS_DIR3_FT_DIR;
  36         case S_IFCHR:
  37                 return XFS_DIR3_FT_CHRDEV;
  38         case S_IFBLK:
  39                 return XFS_DIR3_FT_BLKDEV;
  40         case S_IFIFO:
  41                 return XFS_DIR3_FT_FIFO;
  42         case S_IFSOCK:
  43                 return XFS_DIR3_FT_SOCK;
  44         case S_IFLNK:
  45                 return XFS_DIR3_FT_SYMLINK;
  46         default:
  47                 return XFS_DIR3_FT_UNKNOWN;
  48         }
  49 }
  50 
  51 /*
  52  * ASCII case-insensitive (ie. A-Z) support for directories that was
  53  * used in IRIX.
  54  */
  55 STATIC xfs_dahash_t
  56 xfs_ascii_ci_hashname(
  57         struct xfs_name *name)
  58 {
  59         xfs_dahash_t    hash;
  60         int             i;
  61 
  62         for (i = 0, hash = 0; i < name->len; i++)
  63                 hash = tolower(name->name[i]) ^ rol32(hash, 7);
  64 
  65         return hash;
  66 }
  67 
  68 STATIC enum xfs_dacmp
  69 xfs_ascii_ci_compname(
  70         struct xfs_da_args *args,
  71         const unsigned char *name,
  72         int             len)
  73 {
  74         enum xfs_dacmp  result;
  75         int             i;
  76 
  77         if (args->namelen != len)
  78                 return XFS_CMP_DIFFERENT;
  79 
  80         result = XFS_CMP_EXACT;
  81         for (i = 0; i < len; i++) {
  82                 if (args->name[i] == name[i])
  83                         continue;
  84                 if (tolower(args->name[i]) != tolower(name[i]))
  85                         return XFS_CMP_DIFFERENT;
  86                 result = XFS_CMP_CASE;
  87         }
  88 
  89         return result;
  90 }
  91 
  92 static const struct xfs_nameops xfs_ascii_ci_nameops = {
  93         .hashname       = xfs_ascii_ci_hashname,
  94         .compname       = xfs_ascii_ci_compname,
  95 };
  96 
  97 int
  98 xfs_da_mount(
  99         struct xfs_mount        *mp)
 100 {
 101         struct xfs_da_geometry  *dageo;
 102         int                     nodehdr_size;
 103 
 104 
 105         ASSERT(mp->m_sb.sb_versionnum & XFS_SB_VERSION_DIRV2BIT);
 106         ASSERT(xfs_dir2_dirblock_bytes(&mp->m_sb) <= XFS_MAX_BLOCKSIZE);
 107 
 108         mp->m_dir_inode_ops = xfs_dir_get_ops(mp, NULL);
 109         mp->m_nondir_inode_ops = xfs_nondir_get_ops(mp, NULL);
 110 
 111         nodehdr_size = mp->m_dir_inode_ops->node_hdr_size;
 112         mp->m_dir_geo = kmem_zalloc(sizeof(struct xfs_da_geometry),
 113                                     KM_MAYFAIL);
 114         mp->m_attr_geo = kmem_zalloc(sizeof(struct xfs_da_geometry),
 115                                      KM_MAYFAIL);
 116         if (!mp->m_dir_geo || !mp->m_attr_geo) {
 117                 kmem_free(mp->m_dir_geo);
 118                 kmem_free(mp->m_attr_geo);
 119                 return -ENOMEM;
 120         }
 121 
 122         /* set up directory geometry */
 123         dageo = mp->m_dir_geo;
 124         dageo->blklog = mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog;
 125         dageo->fsblog = mp->m_sb.sb_blocklog;
 126         dageo->blksize = xfs_dir2_dirblock_bytes(&mp->m_sb);
 127         dageo->fsbcount = 1 << mp->m_sb.sb_dirblklog;
 128 
 129         /*
 130          * Now we've set up the block conversion variables, we can calculate the
 131          * segment block constants using the geometry structure.
 132          */
 133         dageo->datablk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_DATA_OFFSET);
 134         dageo->leafblk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_LEAF_OFFSET);
 135         dageo->freeblk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_FREE_OFFSET);
 136         dageo->node_ents = (dageo->blksize - nodehdr_size) /
 137                                 (uint)sizeof(xfs_da_node_entry_t);
 138         dageo->magicpct = (dageo->blksize * 37) / 100;
 139 
 140         /* set up attribute geometry - single fsb only */
 141         dageo = mp->m_attr_geo;
 142         dageo->blklog = mp->m_sb.sb_blocklog;
 143         dageo->fsblog = mp->m_sb.sb_blocklog;
 144         dageo->blksize = 1 << dageo->blklog;
 145         dageo->fsbcount = 1;
 146         dageo->node_ents = (dageo->blksize - nodehdr_size) /
 147                                 (uint)sizeof(xfs_da_node_entry_t);
 148         dageo->magicpct = (dageo->blksize * 37) / 100;
 149 
 150         if (xfs_sb_version_hasasciici(&mp->m_sb))
 151                 mp->m_dirnameops = &xfs_ascii_ci_nameops;
 152         else
 153                 mp->m_dirnameops = &xfs_default_nameops;
 154 
 155         return 0;
 156 }
 157 
 158 void
 159 xfs_da_unmount(
 160         struct xfs_mount        *mp)
 161 {
 162         kmem_free(mp->m_dir_geo);
 163         kmem_free(mp->m_attr_geo);
 164 }
 165 
 166 /*
 167  * Return 1 if directory contains only "." and "..".
 168  */
 169 int
 170 xfs_dir_isempty(
 171         xfs_inode_t     *dp)
 172 {
 173         xfs_dir2_sf_hdr_t       *sfp;
 174 
 175         ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
 176         if (dp->i_d.di_size == 0)       /* might happen during shutdown. */
 177                 return 1;
 178         if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp))
 179                 return 0;
 180         sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
 181         return !sfp->count;
 182 }
 183 
 184 /*
 185  * Validate a given inode number.
 186  */
 187 int
 188 xfs_dir_ino_validate(
 189         xfs_mount_t     *mp,
 190         xfs_ino_t       ino)
 191 {
 192         bool            ino_ok = xfs_verify_dir_ino(mp, ino);
 193 
 194         if (unlikely(XFS_TEST_ERROR(!ino_ok, mp, XFS_ERRTAG_DIR_INO_VALIDATE))) {
 195                 xfs_warn(mp, "Invalid inode number 0x%Lx",
 196                                 (unsigned long long) ino);
 197                 XFS_ERROR_REPORT("xfs_dir_ino_validate", XFS_ERRLEVEL_LOW, mp);
 198                 return -EFSCORRUPTED;
 199         }
 200         return 0;
 201 }
 202 
 203 /*
 204  * Initialize a directory with its "." and ".." entries.
 205  */
 206 int
 207 xfs_dir_init(
 208         xfs_trans_t     *tp,
 209         xfs_inode_t     *dp,
 210         xfs_inode_t     *pdp)
 211 {
 212         struct xfs_da_args *args;
 213         int             error;
 214 
 215         ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
 216         error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino);
 217         if (error)
 218                 return error;
 219 
 220         args = kmem_zalloc(sizeof(*args), KM_NOFS);
 221         if (!args)
 222                 return -ENOMEM;
 223 
 224         args->geo = dp->i_mount->m_dir_geo;
 225         args->dp = dp;
 226         args->trans = tp;
 227         error = xfs_dir2_sf_create(args, pdp->i_ino);
 228         kmem_free(args);
 229         return error;
 230 }
 231 
 232 /*
 233  * Enter a name in a directory, or check for available space.
 234  * If inum is 0, only the available space test is performed.
 235  */
 236 int
 237 xfs_dir_createname(
 238         struct xfs_trans        *tp,
 239         struct xfs_inode        *dp,
 240         struct xfs_name         *name,
 241         xfs_ino_t               inum,           /* new entry inode number */
 242         xfs_extlen_t            total)          /* bmap's total block count */
 243 {
 244         struct xfs_da_args      *args;
 245         int                     rval;
 246         int                     v;              /* type-checking value */
 247 
 248         ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
 249 
 250         if (inum) {
 251                 rval = xfs_dir_ino_validate(tp->t_mountp, inum);
 252                 if (rval)
 253                         return rval;
 254                 XFS_STATS_INC(dp->i_mount, xs_dir_create);
 255         }
 256 
 257         args = kmem_zalloc(sizeof(*args), KM_NOFS);
 258         if (!args)
 259                 return -ENOMEM;
 260 
 261         args->geo = dp->i_mount->m_dir_geo;
 262         args->name = name->name;
 263         args->namelen = name->len;
 264         args->filetype = name->type;
 265         args->hashval = dp->i_mount->m_dirnameops->hashname(name);
 266         args->inumber = inum;
 267         args->dp = dp;
 268         args->total = total;
 269         args->whichfork = XFS_DATA_FORK;
 270         args->trans = tp;
 271         args->op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
 272         if (!inum)
 273                 args->op_flags |= XFS_DA_OP_JUSTCHECK;
 274 
 275         if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
 276                 rval = xfs_dir2_sf_addname(args);
 277                 goto out_free;
 278         }
 279 
 280         rval = xfs_dir2_isblock(args, &v);
 281         if (rval)
 282                 goto out_free;
 283         if (v) {
 284                 rval = xfs_dir2_block_addname(args);
 285                 goto out_free;
 286         }
 287 
 288         rval = xfs_dir2_isleaf(args, &v);
 289         if (rval)
 290                 goto out_free;
 291         if (v)
 292                 rval = xfs_dir2_leaf_addname(args);
 293         else
 294                 rval = xfs_dir2_node_addname(args);
 295 
 296 out_free:
 297         kmem_free(args);
 298         return rval;
 299 }
 300 
 301 /*
 302  * If doing a CI lookup and case-insensitive match, dup actual name into
 303  * args.value. Return EEXIST for success (ie. name found) or an error.
 304  */
 305 int
 306 xfs_dir_cilookup_result(
 307         struct xfs_da_args *args,
 308         const unsigned char *name,
 309         int             len)
 310 {
 311         if (args->cmpresult == XFS_CMP_DIFFERENT)
 312                 return -ENOENT;
 313         if (args->cmpresult != XFS_CMP_CASE ||
 314                                         !(args->op_flags & XFS_DA_OP_CILOOKUP))
 315                 return -EEXIST;
 316 
 317         args->value = kmem_alloc(len, KM_NOFS | KM_MAYFAIL);
 318         if (!args->value)
 319                 return -ENOMEM;
 320 
 321         memcpy(args->value, name, len);
 322         args->valuelen = len;
 323         return -EEXIST;
 324 }
 325 
 326 /*
 327  * Lookup a name in a directory, give back the inode number.
 328  * If ci_name is not NULL, returns the actual name in ci_name if it differs
 329  * to name, or ci_name->name is set to NULL for an exact match.
 330  */
 331 
 332 int
 333 xfs_dir_lookup(
 334         xfs_trans_t     *tp,
 335         xfs_inode_t     *dp,
 336         struct xfs_name *name,
 337         xfs_ino_t       *inum,          /* out: inode number */
 338         struct xfs_name *ci_name)       /* out: actual name if CI match */
 339 {
 340         struct xfs_da_args *args;
 341         int             rval;
 342         int             v;              /* type-checking value */
 343         int             lock_mode;
 344 
 345         ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
 346         XFS_STATS_INC(dp->i_mount, xs_dir_lookup);
 347 
 348         /*
 349          * We need to use KM_NOFS here so that lockdep will not throw false
 350          * positive deadlock warnings on a non-transactional lookup path. It is
 351          * safe to recurse into inode recalim in that case, but lockdep can't
 352          * easily be taught about it. Hence KM_NOFS avoids having to add more
 353          * lockdep Doing this avoids having to add a bunch of lockdep class
 354          * annotations into the reclaim path for the ilock.
 355          */
 356         args = kmem_zalloc(sizeof(*args), KM_NOFS);
 357         args->geo = dp->i_mount->m_dir_geo;
 358         args->name = name->name;
 359         args->namelen = name->len;
 360         args->filetype = name->type;
 361         args->hashval = dp->i_mount->m_dirnameops->hashname(name);
 362         args->dp = dp;
 363         args->whichfork = XFS_DATA_FORK;
 364         args->trans = tp;
 365         args->op_flags = XFS_DA_OP_OKNOENT;
 366         if (ci_name)
 367                 args->op_flags |= XFS_DA_OP_CILOOKUP;
 368 
 369         lock_mode = xfs_ilock_data_map_shared(dp);
 370         if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
 371                 rval = xfs_dir2_sf_lookup(args);
 372                 goto out_check_rval;
 373         }
 374 
 375         rval = xfs_dir2_isblock(args, &v);
 376         if (rval)
 377                 goto out_free;
 378         if (v) {
 379                 rval = xfs_dir2_block_lookup(args);
 380                 goto out_check_rval;
 381         }
 382 
 383         rval = xfs_dir2_isleaf(args, &v);
 384         if (rval)
 385                 goto out_free;
 386         if (v)
 387                 rval = xfs_dir2_leaf_lookup(args);
 388         else
 389                 rval = xfs_dir2_node_lookup(args);
 390 
 391 out_check_rval:
 392         if (rval == -EEXIST)
 393                 rval = 0;
 394         if (!rval) {
 395                 *inum = args->inumber;
 396                 if (ci_name) {
 397                         ci_name->name = args->value;
 398                         ci_name->len = args->valuelen;
 399                 }
 400         }
 401 out_free:
 402         xfs_iunlock(dp, lock_mode);
 403         kmem_free(args);
 404         return rval;
 405 }
 406 
 407 /*
 408  * Remove an entry from a directory.
 409  */
 410 int
 411 xfs_dir_removename(
 412         struct xfs_trans        *tp,
 413         struct xfs_inode        *dp,
 414         struct xfs_name         *name,
 415         xfs_ino_t               ino,
 416         xfs_extlen_t            total)          /* bmap's total block count */
 417 {
 418         struct xfs_da_args      *args;
 419         int                     rval;
 420         int                     v;              /* type-checking value */
 421 
 422         ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
 423         XFS_STATS_INC(dp->i_mount, xs_dir_remove);
 424 
 425         args = kmem_zalloc(sizeof(*args), KM_NOFS);
 426         if (!args)
 427                 return -ENOMEM;
 428 
 429         args->geo = dp->i_mount->m_dir_geo;
 430         args->name = name->name;
 431         args->namelen = name->len;
 432         args->filetype = name->type;
 433         args->hashval = dp->i_mount->m_dirnameops->hashname(name);
 434         args->inumber = ino;
 435         args->dp = dp;
 436         args->total = total;
 437         args->whichfork = XFS_DATA_FORK;
 438         args->trans = tp;
 439 
 440         if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
 441                 rval = xfs_dir2_sf_removename(args);
 442                 goto out_free;
 443         }
 444 
 445         rval = xfs_dir2_isblock(args, &v);
 446         if (rval)
 447                 goto out_free;
 448         if (v) {
 449                 rval = xfs_dir2_block_removename(args);
 450                 goto out_free;
 451         }
 452 
 453         rval = xfs_dir2_isleaf(args, &v);
 454         if (rval)
 455                 goto out_free;
 456         if (v)
 457                 rval = xfs_dir2_leaf_removename(args);
 458         else
 459                 rval = xfs_dir2_node_removename(args);
 460 out_free:
 461         kmem_free(args);
 462         return rval;
 463 }
 464 
 465 /*
 466  * Replace the inode number of a directory entry.
 467  */
 468 int
 469 xfs_dir_replace(
 470         struct xfs_trans        *tp,
 471         struct xfs_inode        *dp,
 472         struct xfs_name         *name,          /* name of entry to replace */
 473         xfs_ino_t               inum,           /* new inode number */
 474         xfs_extlen_t            total)          /* bmap's total block count */
 475 {
 476         struct xfs_da_args      *args;
 477         int                     rval;
 478         int                     v;              /* type-checking value */
 479 
 480         ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
 481 
 482         rval = xfs_dir_ino_validate(tp->t_mountp, inum);
 483         if (rval)
 484                 return rval;
 485 
 486         args = kmem_zalloc(sizeof(*args), KM_NOFS);
 487         if (!args)
 488                 return -ENOMEM;
 489 
 490         args->geo = dp->i_mount->m_dir_geo;
 491         args->name = name->name;
 492         args->namelen = name->len;
 493         args->filetype = name->type;
 494         args->hashval = dp->i_mount->m_dirnameops->hashname(name);
 495         args->inumber = inum;
 496         args->dp = dp;
 497         args->total = total;
 498         args->whichfork = XFS_DATA_FORK;
 499         args->trans = tp;
 500 
 501         if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) {
 502                 rval = xfs_dir2_sf_replace(args);
 503                 goto out_free;
 504         }
 505 
 506         rval = xfs_dir2_isblock(args, &v);
 507         if (rval)
 508                 goto out_free;
 509         if (v) {
 510                 rval = xfs_dir2_block_replace(args);
 511                 goto out_free;
 512         }
 513 
 514         rval = xfs_dir2_isleaf(args, &v);
 515         if (rval)
 516                 goto out_free;
 517         if (v)
 518                 rval = xfs_dir2_leaf_replace(args);
 519         else
 520                 rval = xfs_dir2_node_replace(args);
 521 out_free:
 522         kmem_free(args);
 523         return rval;
 524 }
 525 
 526 /*
 527  * See if this entry can be added to the directory without allocating space.
 528  */
 529 int
 530 xfs_dir_canenter(
 531         xfs_trans_t     *tp,
 532         xfs_inode_t     *dp,
 533         struct xfs_name *name)          /* name of entry to add */
 534 {
 535         return xfs_dir_createname(tp, dp, name, 0, 0);
 536 }
 537 
 538 /*
 539  * Utility routines.
 540  */
 541 
 542 /*
 543  * Add a block to the directory.
 544  *
 545  * This routine is for data and free blocks, not leaf/node blocks which are
 546  * handled by xfs_da_grow_inode.
 547  */
 548 int
 549 xfs_dir2_grow_inode(
 550         struct xfs_da_args      *args,
 551         int                     space,  /* v2 dir's space XFS_DIR2_xxx_SPACE */
 552         xfs_dir2_db_t           *dbp)   /* out: block number added */
 553 {
 554         struct xfs_inode        *dp = args->dp;
 555         struct xfs_mount        *mp = dp->i_mount;
 556         xfs_fileoff_t           bno;    /* directory offset of new block */
 557         int                     count;  /* count of filesystem blocks */
 558         int                     error;
 559 
 560         trace_xfs_dir2_grow_inode(args, space);
 561 
 562         /*
 563          * Set lowest possible block in the space requested.
 564          */
 565         bno = XFS_B_TO_FSBT(mp, space * XFS_DIR2_SPACE_SIZE);
 566         count = args->geo->fsbcount;
 567 
 568         error = xfs_da_grow_inode_int(args, &bno, count);
 569         if (error)
 570                 return error;
 571 
 572         *dbp = xfs_dir2_da_to_db(args->geo, (xfs_dablk_t)bno);
 573 
 574         /*
 575          * Update file's size if this is the data space and it grew.
 576          */
 577         if (space == XFS_DIR2_DATA_SPACE) {
 578                 xfs_fsize_t     size;           /* directory file (data) size */
 579 
 580                 size = XFS_FSB_TO_B(mp, bno + count);
 581                 if (size > dp->i_d.di_size) {
 582                         dp->i_d.di_size = size;
 583                         xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
 584                 }
 585         }
 586         return 0;
 587 }
 588 
 589 /*
 590  * See if the directory is a single-block form directory.
 591  */
 592 int
 593 xfs_dir2_isblock(
 594         struct xfs_da_args      *args,
 595         int                     *vp)    /* out: 1 is block, 0 is not block */
 596 {
 597         xfs_fileoff_t           last;   /* last file offset */
 598         int                     rval;
 599 
 600         if ((rval = xfs_bmap_last_offset(args->dp, &last, XFS_DATA_FORK)))
 601                 return rval;
 602         rval = XFS_FSB_TO_B(args->dp->i_mount, last) == args->geo->blksize;
 603         if (rval != 0 && args->dp->i_d.di_size != args->geo->blksize)
 604                 return -EFSCORRUPTED;
 605         *vp = rval;
 606         return 0;
 607 }
 608 
 609 /*
 610  * See if the directory is a single-leaf form directory.
 611  */
 612 int
 613 xfs_dir2_isleaf(
 614         struct xfs_da_args      *args,
 615         int                     *vp)    /* out: 1 is block, 0 is not block */
 616 {
 617         xfs_fileoff_t           last;   /* last file offset */
 618         int                     rval;
 619 
 620         if ((rval = xfs_bmap_last_offset(args->dp, &last, XFS_DATA_FORK)))
 621                 return rval;
 622         *vp = last == args->geo->leafblk + args->geo->fsbcount;
 623         return 0;
 624 }
 625 
 626 /*
 627  * Remove the given block from the directory.
 628  * This routine is used for data and free blocks, leaf/node are done
 629  * by xfs_da_shrink_inode.
 630  */
 631 int
 632 xfs_dir2_shrink_inode(
 633         struct xfs_da_args      *args,
 634         xfs_dir2_db_t           db,
 635         struct xfs_buf          *bp)
 636 {
 637         xfs_fileoff_t           bno;            /* directory file offset */
 638         xfs_dablk_t             da;             /* directory file offset */
 639         int                     done;           /* bunmap is finished */
 640         struct xfs_inode        *dp;
 641         int                     error;
 642         struct xfs_mount        *mp;
 643         struct xfs_trans        *tp;
 644 
 645         trace_xfs_dir2_shrink_inode(args, db);
 646 
 647         dp = args->dp;
 648         mp = dp->i_mount;
 649         tp = args->trans;
 650         da = xfs_dir2_db_to_da(args->geo, db);
 651 
 652         /* Unmap the fsblock(s). */
 653         error = xfs_bunmapi(tp, dp, da, args->geo->fsbcount, 0, 0, &done);
 654         if (error) {
 655                 /*
 656                  * ENOSPC actually can happen if we're in a removename with no
 657                  * space reservation, and the resulting block removal would
 658                  * cause a bmap btree split or conversion from extents to btree.
 659                  * This can only happen for un-fragmented directory blocks,
 660                  * since you need to be punching out the middle of an extent.
 661                  * In this case we need to leave the block in the file, and not
 662                  * binval it.  So the block has to be in a consistent empty
 663                  * state and appropriately logged.  We don't free up the buffer,
 664                  * the caller can tell it hasn't happened since it got an error
 665                  * back.
 666                  */
 667                 return error;
 668         }
 669         ASSERT(done);
 670         /*
 671          * Invalidate the buffer from the transaction.
 672          */
 673         xfs_trans_binval(tp, bp);
 674         /*
 675          * If it's not a data block, we're done.
 676          */
 677         if (db >= xfs_dir2_byte_to_db(args->geo, XFS_DIR2_LEAF_OFFSET))
 678                 return 0;
 679         /*
 680          * If the block isn't the last one in the directory, we're done.
 681          */
 682         if (dp->i_d.di_size > xfs_dir2_db_off_to_byte(args->geo, db + 1, 0))
 683                 return 0;
 684         bno = da;
 685         if ((error = xfs_bmap_last_before(tp, dp, &bno, XFS_DATA_FORK))) {
 686                 /*
 687                  * This can't really happen unless there's kernel corruption.
 688                  */
 689                 return error;
 690         }
 691         if (db == args->geo->datablk)
 692                 ASSERT(bno == 0);
 693         else
 694                 ASSERT(bno > 0);
 695         /*
 696          * Set the size to the new last block.
 697          */
 698         dp->i_d.di_size = XFS_FSB_TO_B(mp, bno);
 699         xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
 700         return 0;
 701 }
 702 
 703 /* Returns true if the directory entry name is valid. */
 704 bool
 705 xfs_dir2_namecheck(
 706         const void      *name,
 707         size_t          length)
 708 {
 709         /*
 710          * MAXNAMELEN includes the trailing null, but (name/length) leave it
 711          * out, so use >= for the length check.
 712          */
 713         if (length >= MAXNAMELEN)
 714                 return false;
 715 
 716         /* There shouldn't be any slashes or nulls here */
 717         return !memchr(name, '/', length) && !memchr(name, 0, length);
 718 }

/* [<][>][^][v][top][bottom][index][help] */