LCOV - code coverage report
Current view: top level - fs/xfs/libxfs - xfs_parent.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc3-achx @ Mon Jul 31 20:08:12 PDT 2023 Lines: 117 133 88.0 %
Date: 2023-07-31 20:08:12 Functions: 13 15 86.7 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  * Copyright (c) 2022-2023 Oracle, Inc.
       4             :  * All rights reserved.
       5             :  */
       6             : #include "xfs.h"
       7             : #include "xfs_fs.h"
       8             : #include "xfs_format.h"
       9             : #include "xfs_da_format.h"
      10             : #include "xfs_log_format.h"
      11             : #include "xfs_shared.h"
      12             : #include "xfs_trans_resv.h"
      13             : #include "xfs_mount.h"
      14             : #include "xfs_bmap_btree.h"
      15             : #include "xfs_inode.h"
      16             : #include "xfs_error.h"
      17             : #include "xfs_trace.h"
      18             : #include "xfs_trans.h"
      19             : #include "xfs_da_btree.h"
      20             : #include "xfs_attr.h"
      21             : #include "xfs_dir2.h"
      22             : #include "xfs_dir2_priv.h"
      23             : #include "xfs_attr_sf.h"
      24             : #include "xfs_bmap.h"
      25             : #include "xfs_defer.h"
      26             : #include "xfs_log.h"
      27             : #include "xfs_xattr.h"
      28             : #include "xfs_parent.h"
      29             : #include "xfs_trans_space.h"
      30             : #include "xfs_health.h"
      31             : 
      32             : struct kmem_cache               *xfs_parent_intent_cache;
      33             : 
      34             : /*
      35             :  * Parent pointer attribute handling.
      36             :  *
      37             :  * Because the attribute value is a filename component, it will never be longer
      38             :  * than 255 bytes. This means the attribute will always be a local format
      39             :  * attribute as it is xfs_attr_leaf_entsize_local_max() for v5 filesystems will
      40             :  * always be larger than this (max is 75% of block size).
      41             :  *
      42             :  * Creating a new parent attribute will always create a new attribute - there
      43             :  * should never, ever be an existing attribute in the tree for a new inode.
      44             :  * ENOSPC behavior is problematic - creating the inode without the parent
      45             :  * pointer is effectively a corruption, so we allow parent attribute creation
      46             :  * to dip into the reserve block pool to avoid unexpected ENOSPC errors from
      47             :  * occurring.
      48             :  */
      49             : 
      50             : /* Return true if parent pointer EA name is valid. */
      51             : bool
      52  6833594308 : xfs_parent_namecheck(
      53             :         struct xfs_mount                        *mp,
      54             :         const struct xfs_parent_name_rec        *rec,
      55             :         size_t                                  reclen,
      56             :         unsigned int                            attr_flags)
      57             : {
      58  6833594308 :         xfs_ino_t                               p_ino;
      59             : 
      60  6833594308 :         if (!(attr_flags & XFS_ATTR_PARENT))
      61             :                 return false;
      62             : 
      63             :         /* pptr updates use logged xattrs, so we should never see this flag */
      64  6833594308 :         if (attr_flags & XFS_ATTR_INCOMPLETE)
      65             :                 return false;
      66             : 
      67  6833594308 :         if (reclen != sizeof(struct xfs_parent_name_rec))
      68             :                 return false;
      69             : 
      70             :         /* Only one namespace bit allowed. */
      71  6825795169 :         if (hweight32(attr_flags & XFS_ATTR_NSP_ONDISK_MASK) > 1)
      72             :                 return false;
      73             : 
      74  6825655755 :         p_ino = be64_to_cpu(rec->p_ino);
      75  6825655755 :         if (!xfs_verify_ino(mp, p_ino))
      76           0 :                 return false;
      77             : 
      78             :         return true;
      79             : }
      80             : 
      81             : /* Return true if parent pointer EA value is valid. */
      82             : bool
      83  5816639411 : xfs_parent_valuecheck(
      84             :         struct xfs_mount                *mp,
      85             :         const void                      *value,
      86             :         size_t                          valuelen)
      87             : {
      88  5816639411 :         if (valuelen == 0 || valuelen > XFS_PARENT_DIRENT_NAME_MAX_SIZE)
      89             :                 return false;
      90             : 
      91  5816639411 :         if (value == NULL)
      92             :                 return false;
      93             : 
      94             :         /* Valid dirent name? */
      95  5816639411 :         if (!xfs_dir2_namecheck(value, valuelen))
      96           0 :                 return false;
      97             : 
      98             :         return true;
      99             : }
     100             : 
     101             : /* Initializes a xfs_parent_name_rec to be stored as an attribute name. */
     102             : static inline void
     103   282082160 : xfs_init_parent_name_rec(
     104             :         struct xfs_parent_name_rec      *rec,
     105             :         const struct xfs_inode          *dp,
     106             :         const struct xfs_name           *name,
     107             :         struct xfs_inode                *ip)
     108             : {
     109   282082160 :         rec->p_ino = cpu_to_be64(dp->i_ino);
     110   282082160 :         rec->p_gen = cpu_to_be32(VFS_IC(dp)->i_generation);
     111   282082160 :         rec->p_namehash = cpu_to_be32(xfs_dir2_hashname(dp->i_mount, name));
     112   282075474 : }
     113             : 
     114             : /* Point the da args value fields at the non-key parts of a parent pointer. */
     115             : static inline void
     116             : xfs_init_parent_davalue(
     117             :         struct xfs_da_args              *args,
     118             :         const struct xfs_name           *name)
     119             : {
     120   224811265 :         args->valuelen = name->len;
     121   224811265 :         args->value = (void *)name->name;
     122             : }
     123             : 
     124             : /*
     125             :  * Point the da args new value fields at the non-key parts of a replacement
     126             :  * parent pointer.
     127             :  */
     128             : static inline void
     129             : xfs_init_parent_danewvalue(
     130             :         struct xfs_da_args              *args,
     131             :         const struct xfs_name           *name)
     132             : {
     133    57239778 :         args->new_valuelen = name->len;
     134    57239778 :         args->new_value = (void *)name->name;
     135             : }
     136             : 
     137             : /*
     138             :  * Allocate memory to control a logged parent pointer update as part of a
     139             :  * dirent operation.
     140             :  */
     141             : int
     142   331459143 : __xfs_parent_init(
     143             :         struct xfs_mount                *mp,
     144             :         bool                            grab_log,
     145             :         struct xfs_parent_defer         **parentp)
     146             : {
     147   331459143 :         struct xfs_parent_defer         *parent;
     148   331459143 :         int                             error;
     149             : 
     150   331459143 :         if (grab_log) {
     151   212250673 :                 error = xfs_attr_grab_log_assist(mp);
     152   212680853 :                 if (error)
     153             :                         return error;
     154             :         }
     155             : 
     156   331889146 :         parent = kmem_cache_zalloc(xfs_parent_intent_cache, GFP_KERNEL);
     157   331708244 :         if (!parent) {
     158           0 :                 if (grab_log)
     159           0 :                         xfs_attr_rele_log_assist(mp);
     160           0 :                 return -ENOMEM;
     161             :         }
     162             : 
     163             :         /* init parent da_args */
     164   331708244 :         parent->have_log = grab_log;
     165   331708244 :         parent->args.geo = mp->m_attr_geo;
     166   331708244 :         parent->args.whichfork = XFS_ATTR_FORK;
     167   331708244 :         parent->args.attr_filter = XFS_ATTR_PARENT;
     168   331708244 :         parent->args.op_flags = XFS_DA_OP_OKNOENT | XFS_DA_OP_LOGGED |
     169             :                                 XFS_DA_OP_NVLOOKUP;
     170   331708244 :         parent->args.name = (const uint8_t *)&parent->rec;
     171   331708244 :         parent->args.namelen = sizeof(struct xfs_parent_name_rec);
     172             : 
     173   331708244 :         *parentp = parent;
     174   331708244 :         return 0;
     175             : }
     176             : 
     177             : static inline xfs_dahash_t
     178             : xfs_parent_hashname(
     179             :         struct xfs_inode                *ip,
     180             :         const struct xfs_parent_defer   *parent)
     181             : {
     182   224851836 :         return xfs_da_hashname((const void *)&parent->rec,
     183             :                         sizeof(struct xfs_parent_name_rec));
     184             : }
     185             : 
     186             : /* Add a parent pointer to reflect a dirent addition. */
     187             : int
     188   106536470 : xfs_parent_add(
     189             :         struct xfs_trans        *tp,
     190             :         struct xfs_parent_defer *parent,
     191             :         struct xfs_inode        *dp,
     192             :         const struct xfs_name   *parent_name,
     193             :         struct xfs_inode        *child)
     194             : {
     195   106536470 :         struct xfs_da_args      *args = &parent->args;
     196             : 
     197   106536470 :         xfs_init_parent_name_rec(&parent->rec, dp, parent_name, child);
     198   106513556 :         args->hashval = xfs_parent_hashname(dp, parent);
     199             : 
     200   106472503 :         args->trans = tp;
     201   106472503 :         args->dp = child;
     202   106472503 :         args->owner = child->i_ino;
     203             : 
     204   106472503 :         xfs_init_parent_davalue(&parent->args, parent_name);
     205             : 
     206   106472503 :         return xfs_attr_defer_add(args);
     207             : }
     208             : 
     209             : /* Remove a parent pointer to reflect a dirent removal. */
     210             : int
     211    61089355 : xfs_parent_remove(
     212             :         struct xfs_trans        *tp,
     213             :         struct xfs_parent_defer *parent,
     214             :         struct xfs_inode        *dp,
     215             :         const struct xfs_name   *parent_name,
     216             :         struct xfs_inode        *child)
     217             : {
     218    61089355 :         struct xfs_da_args      *args = &parent->args;
     219             : 
     220             :         /*
     221             :          * For regular attrs, removing an attr from a !hasattr inode is a nop.
     222             :          * For parent pointers, we require that the pointer must exist if the
     223             :          * caller wants us to remove the pointer.
     224             :          */
     225    61089355 :         if (XFS_IS_CORRUPT(child->i_mount, !xfs_inode_hasattr(child))) {
     226           0 :                 xfs_inode_mark_sick(child, XFS_SICK_INO_PARENT);
     227           0 :                 return -EFSCORRUPTED;
     228             :         }
     229             : 
     230    61090914 :         xfs_init_parent_name_rec(&parent->rec, dp, parent_name, child);
     231    61098553 :         args->hashval = xfs_parent_hashname(dp, parent);
     232             : 
     233    61098984 :         args->trans = tp;
     234    61098984 :         args->dp = child;
     235    61098984 :         args->owner = child->i_ino;
     236             : 
     237    61098984 :         xfs_init_parent_davalue(&parent->args, parent_name);
     238             : 
     239    61098984 :         return xfs_attr_defer_remove(args);
     240             : }
     241             : 
     242             : /* Replace one parent pointer with another to reflect a rename. */
     243             : int
     244    57239768 : xfs_parent_replace(
     245             :         struct xfs_trans        *tp,
     246             :         struct xfs_parent_defer *parent,
     247             :         struct xfs_inode        *old_dp,
     248             :         const struct xfs_name   *old_name,
     249             :         struct xfs_inode        *new_dp,
     250             :         const struct xfs_name   *new_name,
     251             :         struct xfs_inode        *child)
     252             : {
     253    57239768 :         struct xfs_da_args      *args = &parent->args;
     254             : 
     255             :         /*
     256             :          * For regular attrs, replacing an attr from a !hasattr inode becomes
     257             :          * an attr-set operation.  For replacing a parent pointer, however, we
     258             :          * require that the old pointer must exist.
     259             :          */
     260    57239768 :         if (XFS_IS_CORRUPT(child->i_mount, !xfs_inode_hasattr(child))) {
     261           0 :                 xfs_inode_mark_sick(child, XFS_SICK_INO_PARENT);
     262           0 :                 return -EFSCORRUPTED;
     263             :         }
     264             : 
     265    57239602 :         xfs_init_parent_name_rec(&parent->rec, old_dp, old_name, child);
     266    57239727 :         args->hashval = xfs_parent_hashname(old_dp, parent);
     267             : 
     268    57239764 :         xfs_init_parent_name_rec(&parent->new_rec, new_dp, new_name, child);
     269    57239778 :         args->new_name = (const uint8_t *)&parent->new_rec;
     270    57239778 :         args->new_namelen = sizeof(struct xfs_parent_name_rec);
     271             : 
     272    57239778 :         args->trans = tp;
     273    57239778 :         args->dp = child;
     274    57239778 :         args->owner = child->i_ino;
     275             : 
     276    57239778 :         xfs_init_parent_davalue(&parent->args, old_name);
     277    57239778 :         xfs_init_parent_danewvalue(&parent->args, new_name);
     278             : 
     279    57239778 :         return xfs_attr_defer_replace(args);
     280             : }
     281             : 
     282             : /* Cancel a parent pointer operation. */
     283             : void
     284   331598609 : __xfs_parent_cancel(
     285             :         struct xfs_mount        *mp,
     286             :         struct xfs_parent_defer *parent)
     287             : {
     288   331598609 :         if (parent->have_log)
     289   212520041 :                 xlog_drop_incompat_feat(mp->m_log, XLOG_INCOMPAT_FEAT_XATTRS);
     290   331769712 :         kmem_cache_free(xfs_parent_intent_cache, parent);
     291   331591519 : }
     292             : 
     293             : /* Convert an ondisk parent pointer to the incore format. */
     294             : void
     295  5826671948 : xfs_parent_irec_from_disk(
     296             :         struct xfs_parent_name_irec     *irec,
     297             :         const struct xfs_parent_name_rec *rec,
     298             :         const void                      *value,
     299             :         unsigned int                    valuelen)
     300             : {
     301  5826671948 :         irec->p_ino = be64_to_cpu(rec->p_ino);
     302  5826671948 :         irec->p_gen = be32_to_cpu(rec->p_gen);
     303  5826671948 :         irec->p_namehash = be32_to_cpu(rec->p_namehash);
     304  5826671948 :         irec->p_namelen = valuelen;
     305 11653343896 :         memcpy(irec->p_name, value, valuelen);
     306  5826671948 : }
     307             : 
     308             : /* Convert an incore parent pointer to the ondisk attr name format. */
     309             : void
     310           0 : xfs_parent_irec_to_disk(
     311             :         struct xfs_parent_name_rec      *rec,
     312             :         const struct xfs_parent_name_irec *irec)
     313             : {
     314   203239973 :         rec->p_ino = cpu_to_be64(irec->p_ino);
     315   203239973 :         rec->p_gen = cpu_to_be32(irec->p_gen);
     316   203239973 :         rec->p_namehash = cpu_to_be32(irec->p_namehash);
     317           0 : }
     318             : 
     319             : /* Compute p_namehash for the this parent pointer. */
     320             : void
     321   203461122 : xfs_parent_irec_hashname(
     322             :         struct xfs_mount                *mp,
     323             :         struct xfs_parent_name_irec     *irec)
     324             : {
     325   203461122 :         struct xfs_name                 dname = {
     326   203461122 :                 .name                   = irec->p_name,
     327   203461122 :                 .len                    = irec->p_namelen,
     328             :         };
     329             : 
     330   203461122 :         irec->p_namehash = xfs_dir2_hashname(mp, &dname);
     331   203196152 : }
     332             : 
     333             : static inline void
     334   203157264 : xfs_parent_scratch_init(
     335             :         struct xfs_trans                *tp,
     336             :         struct xfs_inode                *ip,
     337             :         xfs_ino_t                       owner,
     338             :         const struct xfs_parent_name_irec *pptr,
     339             :         struct xfs_parent_scratch       *scr)
     340             : {
     341   203157264 :         memset(&scr->args, 0, sizeof(struct xfs_da_args));
     342   203157264 :         scr->args.attr_filter        = XFS_ATTR_PARENT;
     343   203157264 :         scr->args.dp         = ip;
     344   203157264 :         scr->args.geo                = ip->i_mount->m_attr_geo;
     345   203157264 :         scr->args.name               = (const unsigned char *)&scr->rec;
     346   203157264 :         scr->args.namelen    = sizeof(struct xfs_parent_name_rec);
     347   203157264 :         scr->args.op_flags   = XFS_DA_OP_NVLOOKUP;
     348   203157264 :         scr->args.trans              = tp;
     349   203157264 :         scr->args.value              = (void *)pptr->p_name;
     350   203157264 :         scr->args.valuelen   = pptr->p_namelen;
     351   203157264 :         scr->args.whichfork  = XFS_ATTR_FORK;
     352   203157264 :         scr->args.hashval    = xfs_da_hashname((const void *)&scr->rec,
     353             :                                         sizeof(struct xfs_parent_name_rec));
     354   203100191 :         scr->args.owner              = owner;
     355   203100191 : }
     356             : 
     357             : /*
     358             :  * Look up the @name associated with the parent pointer (@pptr) of @ip.
     359             :  * Caller must hold at least ILOCK_SHARED.  Returns 0 if the pointer is found,
     360             :  * -ENOATTR if there is no match, or a negative errno.  The scratchpad need not
     361             :  *  be initialized.
     362             :  */
     363             : int
     364   201052736 : xfs_parent_lookup(
     365             :         struct xfs_trans                *tp,
     366             :         struct xfs_inode                *ip,
     367             :         const struct xfs_parent_name_irec *pptr,
     368             :         struct xfs_parent_scratch       *scr)
     369             : {
     370   201052736 :         xfs_parent_irec_to_disk(&scr->rec, pptr);
     371   201052736 :         xfs_parent_scratch_init(tp, ip, ip->i_ino, pptr, scr);
     372   200912482 :         scr->args.op_flags |= XFS_DA_OP_OKNOENT;
     373             : 
     374   200912482 :         return xfs_attr_get_ilocked(&scr->args);
     375             : }
     376             : 
     377             : /*
     378             :  * Attach the parent pointer (@pptr -> @name) to @ip immediately.  Caller must
     379             :  * not have a transaction or hold the ILOCK.  The update will not use logged
     380             :  * xattrs.  This is for specialized repair functions only.  The scratchpad need
     381             :  * not be initialized.
     382             :  */
     383             : int
     384     2187237 : xfs_parent_set(
     385             :         struct xfs_inode                *ip,
     386             :         xfs_ino_t                       owner,
     387             :         const struct xfs_parent_name_irec *pptr,
     388             :         struct xfs_parent_scratch       *scr)
     389             : {
     390     2187237 :         xfs_parent_irec_to_disk(&scr->rec, pptr);
     391     2187237 :         xfs_parent_scratch_init(NULL, ip, owner, pptr, scr);
     392             : 
     393     2187311 :         return xfs_attr_set(&scr->args);
     394             : }
     395             : 
     396             : /*
     397             :  * Remove the parent pointer (@rec -> @name) from @ip immediately.  Caller must
     398             :  * not have a transaction or hold the ILOCK.  The update will not use logged
     399             :  * xattrs.  This is for specialized repair functions only.  The scratchpad need
     400             :  * not be initialized.
     401             :  */
     402             : int
     403           0 : xfs_parent_unset(
     404             :         struct xfs_inode                *ip,
     405             :         xfs_ino_t                       owner,
     406             :         const struct xfs_parent_name_irec *pptr,
     407             :         struct xfs_parent_scratch       *scr)
     408             : {
     409           0 :         xfs_parent_irec_to_disk(&scr->rec, pptr);
     410           0 :         xfs_parent_scratch_init(NULL, ip, owner, pptr, scr);
     411           0 :         scr->args.op_flags |= XFS_DA_OP_REMOVE;
     412             : 
     413           0 :         return xfs_attr_set(&scr->args);
     414             : }

Generated by: LCOV version 1.14