linux/fs/xfs/xfs_icreate_item.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2008-2010, 2013 Dave Chinner
   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_trans_priv.h"
  16#include "xfs_icreate_item.h"
  17#include "xfs_log.h"
  18#include "xfs_log_priv.h"
  19#include "xfs_log_recover.h"
  20#include "xfs_ialloc.h"
  21#include "xfs_trace.h"
  22
  23kmem_zone_t     *xfs_icreate_zone;              /* inode create item zone */
  24
  25static inline struct xfs_icreate_item *ICR_ITEM(struct xfs_log_item *lip)
  26{
  27        return container_of(lip, struct xfs_icreate_item, ic_item);
  28}
  29
  30/*
  31 * This returns the number of iovecs needed to log the given inode item.
  32 *
  33 * We only need one iovec for the icreate log structure.
  34 */
  35STATIC void
  36xfs_icreate_item_size(
  37        struct xfs_log_item     *lip,
  38        int                     *nvecs,
  39        int                     *nbytes)
  40{
  41        *nvecs += 1;
  42        *nbytes += sizeof(struct xfs_icreate_log);
  43}
  44
  45/*
  46 * This is called to fill in the vector of log iovecs for the
  47 * given inode create log item.
  48 */
  49STATIC void
  50xfs_icreate_item_format(
  51        struct xfs_log_item     *lip,
  52        struct xfs_log_vec      *lv)
  53{
  54        struct xfs_icreate_item *icp = ICR_ITEM(lip);
  55        struct xfs_log_iovec    *vecp = NULL;
  56
  57        xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ICREATE,
  58                        &icp->ic_format,
  59                        sizeof(struct xfs_icreate_log));
  60}
  61
  62STATIC void
  63xfs_icreate_item_release(
  64        struct xfs_log_item     *lip)
  65{
  66        kmem_cache_free(xfs_icreate_zone, ICR_ITEM(lip));
  67}
  68
  69static const struct xfs_item_ops xfs_icreate_item_ops = {
  70        .flags          = XFS_ITEM_RELEASE_WHEN_COMMITTED,
  71        .iop_size       = xfs_icreate_item_size,
  72        .iop_format     = xfs_icreate_item_format,
  73        .iop_release    = xfs_icreate_item_release,
  74};
  75
  76
  77/*
  78 * Initialize the inode log item for a newly allocated (in-core) inode.
  79 *
  80 * Inode extents can only reside within an AG. Hence specify the starting
  81 * block for the inode chunk by offset within an AG as well as the
  82 * length of the allocated extent.
  83 *
  84 * This joins the item to the transaction and marks it dirty so
  85 * that we don't need a separate call to do this, nor does the
  86 * caller need to know anything about the icreate item.
  87 */
  88void
  89xfs_icreate_log(
  90        struct xfs_trans        *tp,
  91        xfs_agnumber_t          agno,
  92        xfs_agblock_t           agbno,
  93        unsigned int            count,
  94        unsigned int            inode_size,
  95        xfs_agblock_t           length,
  96        unsigned int            generation)
  97{
  98        struct xfs_icreate_item *icp;
  99
 100        icp = kmem_cache_zalloc(xfs_icreate_zone, GFP_KERNEL | __GFP_NOFAIL);
 101
 102        xfs_log_item_init(tp->t_mountp, &icp->ic_item, XFS_LI_ICREATE,
 103                          &xfs_icreate_item_ops);
 104
 105        icp->ic_format.icl_type = XFS_LI_ICREATE;
 106        icp->ic_format.icl_size = 1;    /* single vector */
 107        icp->ic_format.icl_ag = cpu_to_be32(agno);
 108        icp->ic_format.icl_agbno = cpu_to_be32(agbno);
 109        icp->ic_format.icl_count = cpu_to_be32(count);
 110        icp->ic_format.icl_isize = cpu_to_be32(inode_size);
 111        icp->ic_format.icl_length = cpu_to_be32(length);
 112        icp->ic_format.icl_gen = cpu_to_be32(generation);
 113
 114        xfs_trans_add_item(tp, &icp->ic_item);
 115        tp->t_flags |= XFS_TRANS_DIRTY;
 116        set_bit(XFS_LI_DIRTY, &icp->ic_item.li_flags);
 117}
 118
 119static enum xlog_recover_reorder
 120xlog_recover_icreate_reorder(
 121                struct xlog_recover_item *item)
 122{
 123        /*
 124         * Inode allocation buffers must be replayed before subsequent inode
 125         * items try to modify those buffers.  ICREATE items are the logical
 126         * equivalent of logging a newly initialized inode buffer, so recover
 127         * these at the same time that we recover logged buffers.
 128         */
 129        return XLOG_REORDER_BUFFER_LIST;
 130}
 131
 132/*
 133 * This routine is called when an inode create format structure is found in a
 134 * committed transaction in the log.  It's purpose is to initialise the inodes
 135 * being allocated on disk. This requires us to get inode cluster buffers that
 136 * match the range to be initialised, stamped with inode templates and written
 137 * by delayed write so that subsequent modifications will hit the cached buffer
 138 * and only need writing out at the end of recovery.
 139 */
 140STATIC int
 141xlog_recover_icreate_commit_pass2(
 142        struct xlog                     *log,
 143        struct list_head                *buffer_list,
 144        struct xlog_recover_item        *item,
 145        xfs_lsn_t                       lsn)
 146{
 147        struct xfs_mount                *mp = log->l_mp;
 148        struct xfs_icreate_log          *icl;
 149        struct xfs_ino_geometry         *igeo = M_IGEO(mp);
 150        xfs_agnumber_t                  agno;
 151        xfs_agblock_t                   agbno;
 152        unsigned int                    count;
 153        unsigned int                    isize;
 154        xfs_agblock_t                   length;
 155        int                             bb_per_cluster;
 156        int                             cancel_count;
 157        int                             nbufs;
 158        int                             i;
 159
 160        icl = (struct xfs_icreate_log *)item->ri_buf[0].i_addr;
 161        if (icl->icl_type != XFS_LI_ICREATE) {
 162                xfs_warn(log->l_mp, "xlog_recover_do_icreate_trans: bad type");
 163                return -EINVAL;
 164        }
 165
 166        if (icl->icl_size != 1) {
 167                xfs_warn(log->l_mp, "xlog_recover_do_icreate_trans: bad icl size");
 168                return -EINVAL;
 169        }
 170
 171        agno = be32_to_cpu(icl->icl_ag);
 172        if (agno >= mp->m_sb.sb_agcount) {
 173                xfs_warn(log->l_mp, "xlog_recover_do_icreate_trans: bad agno");
 174                return -EINVAL;
 175        }
 176        agbno = be32_to_cpu(icl->icl_agbno);
 177        if (!agbno || agbno == NULLAGBLOCK || agbno >= mp->m_sb.sb_agblocks) {
 178                xfs_warn(log->l_mp, "xlog_recover_do_icreate_trans: bad agbno");
 179                return -EINVAL;
 180        }
 181        isize = be32_to_cpu(icl->icl_isize);
 182        if (isize != mp->m_sb.sb_inodesize) {
 183                xfs_warn(log->l_mp, "xlog_recover_do_icreate_trans: bad isize");
 184                return -EINVAL;
 185        }
 186        count = be32_to_cpu(icl->icl_count);
 187        if (!count) {
 188                xfs_warn(log->l_mp, "xlog_recover_do_icreate_trans: bad count");
 189                return -EINVAL;
 190        }
 191        length = be32_to_cpu(icl->icl_length);
 192        if (!length || length >= mp->m_sb.sb_agblocks) {
 193                xfs_warn(log->l_mp, "xlog_recover_do_icreate_trans: bad length");
 194                return -EINVAL;
 195        }
 196
 197        /*
 198         * The inode chunk is either full or sparse and we only support
 199         * m_ino_geo.ialloc_min_blks sized sparse allocations at this time.
 200         */
 201        if (length != igeo->ialloc_blks &&
 202            length != igeo->ialloc_min_blks) {
 203                xfs_warn(log->l_mp,
 204                         "%s: unsupported chunk length", __func__);
 205                return -EINVAL;
 206        }
 207
 208        /* verify inode count is consistent with extent length */
 209        if ((count >> mp->m_sb.sb_inopblog) != length) {
 210                xfs_warn(log->l_mp,
 211                         "%s: inconsistent inode count and chunk length",
 212                         __func__);
 213                return -EINVAL;
 214        }
 215
 216        /*
 217         * The icreate transaction can cover multiple cluster buffers and these
 218         * buffers could have been freed and reused. Check the individual
 219         * buffers for cancellation so we don't overwrite anything written after
 220         * a cancellation.
 221         */
 222        bb_per_cluster = XFS_FSB_TO_BB(mp, igeo->blocks_per_cluster);
 223        nbufs = length / igeo->blocks_per_cluster;
 224        for (i = 0, cancel_count = 0; i < nbufs; i++) {
 225                xfs_daddr_t     daddr;
 226
 227                daddr = XFS_AGB_TO_DADDR(mp, agno,
 228                                agbno + i * igeo->blocks_per_cluster);
 229                if (xlog_is_buffer_cancelled(log, daddr, bb_per_cluster))
 230                        cancel_count++;
 231        }
 232
 233        /*
 234         * We currently only use icreate for a single allocation at a time. This
 235         * means we should expect either all or none of the buffers to be
 236         * cancelled. Be conservative and skip replay if at least one buffer is
 237         * cancelled, but warn the user that something is awry if the buffers
 238         * are not consistent.
 239         *
 240         * XXX: This must be refined to only skip cancelled clusters once we use
 241         * icreate for multiple chunk allocations.
 242         */
 243        ASSERT(!cancel_count || cancel_count == nbufs);
 244        if (cancel_count) {
 245                if (cancel_count != nbufs)
 246                        xfs_warn(mp,
 247        "WARNING: partial inode chunk cancellation, skipped icreate.");
 248                trace_xfs_log_recover_icreate_cancel(log, icl);
 249                return 0;
 250        }
 251
 252        trace_xfs_log_recover_icreate_recover(log, icl);
 253        return xfs_ialloc_inode_init(mp, NULL, buffer_list, count, agno, agbno,
 254                                     length, be32_to_cpu(icl->icl_gen));
 255}
 256
 257const struct xlog_recover_item_ops xlog_icreate_item_ops = {
 258        .item_type              = XFS_LI_ICREATE,
 259        .reorder                = xlog_recover_icreate_reorder,
 260        .commit_pass2           = xlog_recover_icreate_commit_pass2,
 261};
 262