LCOV - code coverage report
Current view: top level - fs/xfs - xfs_imeta_utils.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc4-xfsa @ Mon Jul 31 20:08:27 PDT 2023 Lines: 75 110 68.2 %
Date: 2023-07-31 20:08:27 Functions: 7 10 70.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-or-later
       2             : /*
       3             :  * Copyright (C) 2018-2023 Oracle.  All Rights Reserved.
       4             :  * Author: Darrick J. Wong <djwong@kernel.org>
       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_da_format.h"
      12             : #include "xfs_trans_resv.h"
      13             : #include "xfs_trans_space.h"
      14             : #include "xfs_mount.h"
      15             : #include "xfs_trans.h"
      16             : #include "xfs_inode.h"
      17             : #include "xfs_da_btree.h"
      18             : #include "xfs_bmap_btree.h"
      19             : #include "xfs_bit.h"
      20             : #include "xfs_sb.h"
      21             : #include "xfs_quota.h"
      22             : #include "xfs_imeta.h"
      23             : #include "xfs_imeta_utils.h"
      24             : #include "xfs_trace.h"
      25             : #include "xfs_parent.h"
      26             : #include "xfs_health.h"
      27             : 
      28             : static inline int
      29       16860 : xfs_imeta_init(
      30             :         struct xfs_mount                *mp,
      31             :         const struct xfs_imeta_path     *path,
      32             :         struct xfs_imeta_update         *upd)
      33             : {
      34       16860 :         int                             error;
      35             : 
      36       16860 :         memset(upd, 0, sizeof(struct xfs_imeta_update));
      37       16860 :         upd->mp = mp;
      38       16860 :         upd->path = path;
      39             : 
      40       16860 :         if (!xfs_has_metadir(mp))
      41             :                 return 0;
      42             : 
      43             :         /*
      44             :          * Find the parent of the last path component.  If the parent path does
      45             :          * not exist, we consider this corruption because paths are supposed
      46             :          * to exist.  For example, if the path is /quota/user, we require that
      47             :          * /quota already exists.
      48             :          */
      49       16538 :         error = xfs_imeta_dir_parent(mp, upd->path, &upd->dp);
      50       16538 :         if (error == -ENOENT) {
      51           0 :                 xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR);
      52           0 :                 return -EFSCORRUPTED;
      53             :         }
      54       16538 :         if (error)
      55             :                 return error;
      56             : 
      57       16538 :         return xfs_parent_start(mp, &upd->parent);
      58             : }
      59             : 
      60             : /*
      61             :  * Begin the process of creating a metadata file by allocating transactions
      62             :  * and taking whatever resources we're going to need.
      63             :  */
      64             : int
      65       16860 : xfs_imeta_start_create(
      66             :         struct xfs_mount                *mp,
      67             :         const struct xfs_imeta_path     *path,
      68             :         struct xfs_imeta_update         *upd)
      69             : {
      70       16860 :         int                             error;
      71             : 
      72       16860 :         error = xfs_imeta_init(mp, path, upd);
      73       16860 :         if (error)
      74             :                 return error;
      75             : 
      76             :         /*
      77             :          * If we ever need the ability to create rt metadata files on a
      78             :          * pre-metadir filesystem, we'll need to dqattach the parent here.
      79             :          * Currently we assume that mkfs will create the files and quotacheck
      80             :          * will account for them.
      81             :          */
      82             : 
      83       16860 :         error = xfs_trans_alloc(mp, &M_RES(mp)->tr_imeta_create,
      84             :                         xfs_create_space_res(mp, MAXNAMELEN), 0, 0, &upd->tp);
      85       16860 :         if (error)
      86             :                 return error;
      87             : 
      88             :         /*
      89             :          * Lock the parent directory if there is one.  We can't ijoin it to
      90             :          * the transaction until after the child file has been created.
      91             :          */
      92       16860 :         if (upd->dp) {
      93       16538 :                 xfs_ilock(upd->dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
      94       16538 :                 upd->dp_locked = true;
      95             :         }
      96             : 
      97       16860 :         trace_xfs_imeta_start_create(upd);
      98       16860 :         return 0;
      99             : }
     100             : 
     101             : /*
     102             :  * Begin the process of linking a metadata file by allocating transactions
     103             :  * and locking whatever resources we're going to need.
     104             :  */
     105             : static inline int
     106           0 : xfs_imeta_start_dir_update(
     107             :         struct xfs_mount                *mp,
     108             :         const struct xfs_imeta_path     *path,
     109             :         struct xfs_inode                *ip,
     110             :         struct xfs_trans_res            *tr_resv,
     111             :         unsigned int                    resblks,
     112             :         struct xfs_imeta_update         *upd)
     113             : {
     114           0 :         int                             error;
     115             : 
     116           0 :         error = xfs_imeta_init(mp, path, upd);
     117           0 :         if (error)
     118             :                 return error;
     119             : 
     120           0 :         upd->ip = ip;
     121             : 
     122           0 :         if (upd->dp) {
     123           0 :                 int                     nospace_error = 0;
     124             : 
     125           0 :                 error = xfs_trans_alloc_dir(upd->dp, tr_resv, upd->ip,
     126             :                                 &resblks, &upd->tp, &nospace_error);
     127           0 :                 if (error)
     128           0 :                         return error;
     129           0 :                 if (!resblks) {
     130             :                         /* We don't allow reservationless updates. */
     131           0 :                         xfs_trans_cancel(upd->tp);
     132           0 :                         upd->tp = NULL;
     133           0 :                         xfs_iunlock(upd->dp, XFS_ILOCK_EXCL);
     134           0 :                         xfs_iunlock(upd->ip, XFS_ILOCK_EXCL);
     135           0 :                         return nospace_error;
     136             :                 }
     137             : 
     138           0 :                 upd->dp_locked = true;
     139             :         } else {
     140           0 :                 error = xfs_trans_alloc_inode(upd->ip, tr_resv, resblks, 0,
     141             :                                 false, &upd->tp);
     142           0 :                 if (error)
     143             :                         return error;
     144             :         }
     145             : 
     146           0 :         upd->ip_locked = true;
     147           0 :         return 0;
     148             : }
     149             : 
     150             : /*
     151             :  * Begin the process of linking a metadata file by allocating transactions
     152             :  * and locking whatever resources we're going to need.
     153             :  */
     154             : int
     155           0 : xfs_imeta_start_link(
     156             :         struct xfs_mount                *mp,
     157             :         const struct xfs_imeta_path     *path,
     158             :         struct xfs_inode                *ip,
     159             :         struct xfs_imeta_update         *upd)
     160             : {
     161           0 :         int                             error;
     162             : 
     163           0 :         error = xfs_imeta_start_dir_update(mp, path, ip,
     164             :                         &M_RES(mp)->tr_imeta_link,
     165             :                         xfs_link_space_res(mp, MAXNAMELEN), upd);
     166           0 :         if (error)
     167             :                 return error;
     168             : 
     169           0 :         trace_xfs_imeta_start_link(upd);
     170           0 :         return 0;
     171             : }
     172             : 
     173             : /*
     174             :  * Begin the process of unlinking a metadata file by allocating transactions
     175             :  * and locking whatever resources we're going to need.
     176             :  */
     177             : int
     178           0 : xfs_imeta_start_unlink(
     179             :         struct xfs_mount                *mp,
     180             :         const struct xfs_imeta_path     *path,
     181             :         struct xfs_inode                *ip,
     182             :         struct xfs_imeta_update         *upd)
     183             : {
     184           0 :         int                             error;
     185             : 
     186           0 :         error = xfs_imeta_start_dir_update(mp, path, ip,
     187             :                         &M_RES(mp)->tr_imeta_unlink,
     188             :                         xfs_remove_space_res(mp, MAXNAMELEN), upd);
     189           0 :         if (error)
     190             :                 return error;
     191             : 
     192           0 :         trace_xfs_imeta_start_unlink(upd);
     193           0 :         return 0;
     194             : }
     195             : 
     196             : /*
     197             :  * Unlock and release resources after committing (or cancelling) a metadata
     198             :  * directory tree operation.  The caller retains its reference to @upd->ip
     199             :  * and must release it explicitly.
     200             :  */
     201             : static inline void
     202       16862 : xfs_imeta_end_update(
     203             :         struct xfs_imeta_update         *upd,
     204             :         int                             error)
     205             : {
     206       16862 :         trace_xfs_imeta_end_update(upd, error);
     207             : 
     208       16862 :         if (upd->ip) {
     209       11392 :                 if (upd->ip_locked)
     210       11392 :                         xfs_iunlock(upd->ip, XFS_ILOCK_EXCL);
     211       11392 :                 upd->ip_locked = false;
     212             :         }
     213             : 
     214       16862 :         if (upd->dp) {
     215       16538 :                 if (upd->dp_locked)
     216       16538 :                         xfs_iunlock(upd->dp, XFS_ILOCK_EXCL);
     217       16538 :                 upd->dp_locked = false;
     218             : 
     219       16538 :                 xfs_imeta_irele(upd->dp);
     220       16538 :                 upd->dp = NULL;
     221             :         }
     222             : 
     223       16862 :         xfs_parent_finish(upd->mp, upd->parent);
     224       16862 : }
     225             : 
     226             : /* Commit a metadir update and unlock/drop all resources. */
     227             : int
     228       11394 : xfs_imeta_commit_update(
     229             :         struct xfs_imeta_update         *upd)
     230             : {
     231       11394 :         int                             error;
     232             : 
     233       11394 :         trace_xfs_imeta_update_commit(upd);
     234             : 
     235       11394 :         error = xfs_trans_commit(upd->tp);
     236       11394 :         upd->tp = NULL;
     237             : 
     238       11394 :         xfs_imeta_end_update(upd, error);
     239       11394 :         return error;
     240             : }
     241             : 
     242             : /* Cancel a metadir update and unlock/drop all resources. */
     243             : void
     244        5468 : xfs_imeta_cancel_update(
     245             :         struct xfs_imeta_update         *upd,
     246             :         int                             error)
     247             : {
     248        5468 :         trace_xfs_imeta_update_cancel(upd);
     249             : 
     250        5468 :         xfs_trans_cancel(upd->tp);
     251        5468 :         upd->tp = NULL;
     252             : 
     253        5468 :         xfs_imeta_end_update(upd, error);
     254        5468 : }
     255             : 
     256             : /* Create a metadata for the last component of the path. */
     257             : STATIC int
     258        8285 : xfs_imeta_mkdir(
     259             :         struct xfs_mount                *mp,
     260             :         const struct xfs_imeta_path     *path)
     261             : {
     262        8285 :         struct xfs_imeta_update         upd;
     263        8285 :         struct xfs_inode                *ip = NULL;
     264        8285 :         int                             error;
     265             : 
     266       16570 :         if (xfs_is_shutdown(mp))
     267             :                 return -EIO;
     268             : 
     269             :         /* Allocate a transaction to create the last directory. */
     270        8269 :         error = xfs_imeta_start_create(mp, path, &upd);
     271        8269 :         if (error)
     272             :                 return error;
     273             : 
     274             :         /* Create the subdirectory and take our reference. */
     275        8269 :         error = xfs_imeta_create(&upd, S_IFDIR, &ip);
     276        8269 :         if (error)
     277        5468 :                 goto out_cancel;
     278             : 
     279        2801 :         error = xfs_imeta_commit_update(&upd);
     280             : 
     281             :         /*
     282             :          * We don't pass the directory we just created to the caller, so finish
     283             :          * setting up the inode, then release the dir and the dquots.
     284             :          */
     285        2801 :         goto out_irele;
     286             : 
     287             : out_cancel:
     288        5468 :         xfs_imeta_cancel_update(&upd, error);
     289        8269 : out_irele:
     290             :         /* Have to finish setting up the inode to ensure it's deleted. */
     291        8269 :         if (ip) {
     292        2801 :                 xfs_finish_inode_setup(ip);
     293        2801 :                 xfs_irele(ip);
     294             :         }
     295             :         return error;
     296             : }
     297             : 
     298             : /*
     299             :  * Make sure that every metadata directory path component exists and is a
     300             :  * directory.
     301             :  */
     302             : int
     303        8285 : xfs_imeta_ensure_dirpath(
     304             :         struct xfs_mount                *mp,
     305             :         const struct xfs_imeta_path     *path)
     306             : {
     307        8285 :         struct xfs_imeta_path           temp_path = {
     308        8285 :                 .im_path                = path->im_path,
     309             :                 .im_depth               = 1,
     310             :                 .im_ftype               = XFS_DIR3_FT_DIR,
     311             :         };
     312        8285 :         unsigned int                    i;
     313        8285 :         int                             error = 0;
     314             : 
     315        8285 :         if (!xfs_has_metadir(mp))
     316             :                 return 0;
     317             : 
     318       16554 :         for (i = 0; i < path->im_depth - 1; i++, temp_path.im_depth++) {
     319        8285 :                 error = xfs_imeta_mkdir(mp, &temp_path);
     320        8285 :                 if (error && error != -EEXIST)
     321          16 :                         return error;
     322             :         }
     323             : 
     324             :         return 0;
     325             : }

Generated by: LCOV version 1.14