linux/fs/xfs/xfs_trans_rmap.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2016 Oracle.  All Rights Reserved.
   4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
   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_defer.h"
  14#include "xfs_trans.h"
  15#include "xfs_trans_priv.h"
  16#include "xfs_rmap_item.h"
  17#include "xfs_alloc.h"
  18#include "xfs_rmap.h"
  19
  20/* Set the map extent flags for this reverse mapping. */
  21static void
  22xfs_trans_set_rmap_flags(
  23        struct xfs_map_extent           *rmap,
  24        enum xfs_rmap_intent_type       type,
  25        int                             whichfork,
  26        xfs_exntst_t                    state)
  27{
  28        rmap->me_flags = 0;
  29        if (state == XFS_EXT_UNWRITTEN)
  30                rmap->me_flags |= XFS_RMAP_EXTENT_UNWRITTEN;
  31        if (whichfork == XFS_ATTR_FORK)
  32                rmap->me_flags |= XFS_RMAP_EXTENT_ATTR_FORK;
  33        switch (type) {
  34        case XFS_RMAP_MAP:
  35                rmap->me_flags |= XFS_RMAP_EXTENT_MAP;
  36                break;
  37        case XFS_RMAP_MAP_SHARED:
  38                rmap->me_flags |= XFS_RMAP_EXTENT_MAP_SHARED;
  39                break;
  40        case XFS_RMAP_UNMAP:
  41                rmap->me_flags |= XFS_RMAP_EXTENT_UNMAP;
  42                break;
  43        case XFS_RMAP_UNMAP_SHARED:
  44                rmap->me_flags |= XFS_RMAP_EXTENT_UNMAP_SHARED;
  45                break;
  46        case XFS_RMAP_CONVERT:
  47                rmap->me_flags |= XFS_RMAP_EXTENT_CONVERT;
  48                break;
  49        case XFS_RMAP_CONVERT_SHARED:
  50                rmap->me_flags |= XFS_RMAP_EXTENT_CONVERT_SHARED;
  51                break;
  52        case XFS_RMAP_ALLOC:
  53                rmap->me_flags |= XFS_RMAP_EXTENT_ALLOC;
  54                break;
  55        case XFS_RMAP_FREE:
  56                rmap->me_flags |= XFS_RMAP_EXTENT_FREE;
  57                break;
  58        default:
  59                ASSERT(0);
  60        }
  61}
  62
  63struct xfs_rud_log_item *
  64xfs_trans_get_rud(
  65        struct xfs_trans                *tp,
  66        struct xfs_rui_log_item         *ruip)
  67{
  68        struct xfs_rud_log_item         *rudp;
  69
  70        rudp = xfs_rud_init(tp->t_mountp, ruip);
  71        xfs_trans_add_item(tp, &rudp->rud_item);
  72        return rudp;
  73}
  74
  75/*
  76 * Finish an rmap update and log it to the RUD. Note that the transaction is
  77 * marked dirty regardless of whether the rmap update succeeds or fails to
  78 * support the RUI/RUD lifecycle rules.
  79 */
  80int
  81xfs_trans_log_finish_rmap_update(
  82        struct xfs_trans                *tp,
  83        struct xfs_rud_log_item         *rudp,
  84        enum xfs_rmap_intent_type       type,
  85        uint64_t                        owner,
  86        int                             whichfork,
  87        xfs_fileoff_t                   startoff,
  88        xfs_fsblock_t                   startblock,
  89        xfs_filblks_t                   blockcount,
  90        xfs_exntst_t                    state,
  91        struct xfs_btree_cur            **pcur)
  92{
  93        int                             error;
  94
  95        error = xfs_rmap_finish_one(tp, type, owner, whichfork, startoff,
  96                        startblock, blockcount, state, pcur);
  97
  98        /*
  99         * Mark the transaction dirty, even on error. This ensures the
 100         * transaction is aborted, which:
 101         *
 102         * 1.) releases the RUI and frees the RUD
 103         * 2.) shuts down the filesystem
 104         */
 105        tp->t_flags |= XFS_TRANS_DIRTY;
 106        set_bit(XFS_LI_DIRTY, &rudp->rud_item.li_flags);
 107
 108        return error;
 109}
 110
 111/* Sort rmap intents by AG. */
 112static int
 113xfs_rmap_update_diff_items(
 114        void                            *priv,
 115        struct list_head                *a,
 116        struct list_head                *b)
 117{
 118        struct xfs_mount                *mp = priv;
 119        struct xfs_rmap_intent          *ra;
 120        struct xfs_rmap_intent          *rb;
 121
 122        ra = container_of(a, struct xfs_rmap_intent, ri_list);
 123        rb = container_of(b, struct xfs_rmap_intent, ri_list);
 124        return  XFS_FSB_TO_AGNO(mp, ra->ri_bmap.br_startblock) -
 125                XFS_FSB_TO_AGNO(mp, rb->ri_bmap.br_startblock);
 126}
 127
 128/* Get an RUI. */
 129STATIC void *
 130xfs_rmap_update_create_intent(
 131        struct xfs_trans                *tp,
 132        unsigned int                    count)
 133{
 134        struct xfs_rui_log_item         *ruip;
 135
 136        ASSERT(tp != NULL);
 137        ASSERT(count > 0);
 138
 139        ruip = xfs_rui_init(tp->t_mountp, count);
 140        ASSERT(ruip != NULL);
 141
 142        /*
 143         * Get a log_item_desc to point at the new item.
 144         */
 145        xfs_trans_add_item(tp, &ruip->rui_item);
 146        return ruip;
 147}
 148
 149/* Log rmap updates in the intent item. */
 150STATIC void
 151xfs_rmap_update_log_item(
 152        struct xfs_trans                *tp,
 153        void                            *intent,
 154        struct list_head                *item)
 155{
 156        struct xfs_rui_log_item         *ruip = intent;
 157        struct xfs_rmap_intent          *rmap;
 158        uint                            next_extent;
 159        struct xfs_map_extent           *map;
 160
 161        rmap = container_of(item, struct xfs_rmap_intent, ri_list);
 162
 163        tp->t_flags |= XFS_TRANS_DIRTY;
 164        set_bit(XFS_LI_DIRTY, &ruip->rui_item.li_flags);
 165
 166        /*
 167         * atomic_inc_return gives us the value after the increment;
 168         * we want to use it as an array index so we need to subtract 1 from
 169         * it.
 170         */
 171        next_extent = atomic_inc_return(&ruip->rui_next_extent) - 1;
 172        ASSERT(next_extent < ruip->rui_format.rui_nextents);
 173        map = &ruip->rui_format.rui_extents[next_extent];
 174        map->me_owner = rmap->ri_owner;
 175        map->me_startblock = rmap->ri_bmap.br_startblock;
 176        map->me_startoff = rmap->ri_bmap.br_startoff;
 177        map->me_len = rmap->ri_bmap.br_blockcount;
 178        xfs_trans_set_rmap_flags(map, rmap->ri_type, rmap->ri_whichfork,
 179                        rmap->ri_bmap.br_state);
 180}
 181
 182/* Get an RUD so we can process all the deferred rmap updates. */
 183STATIC void *
 184xfs_rmap_update_create_done(
 185        struct xfs_trans                *tp,
 186        void                            *intent,
 187        unsigned int                    count)
 188{
 189        return xfs_trans_get_rud(tp, intent);
 190}
 191
 192/* Process a deferred rmap update. */
 193STATIC int
 194xfs_rmap_update_finish_item(
 195        struct xfs_trans                *tp,
 196        struct list_head                *item,
 197        void                            *done_item,
 198        void                            **state)
 199{
 200        struct xfs_rmap_intent          *rmap;
 201        int                             error;
 202
 203        rmap = container_of(item, struct xfs_rmap_intent, ri_list);
 204        error = xfs_trans_log_finish_rmap_update(tp, done_item,
 205                        rmap->ri_type,
 206                        rmap->ri_owner, rmap->ri_whichfork,
 207                        rmap->ri_bmap.br_startoff,
 208                        rmap->ri_bmap.br_startblock,
 209                        rmap->ri_bmap.br_blockcount,
 210                        rmap->ri_bmap.br_state,
 211                        (struct xfs_btree_cur **)state);
 212        kmem_free(rmap);
 213        return error;
 214}
 215
 216/* Clean up after processing deferred rmaps. */
 217STATIC void
 218xfs_rmap_update_finish_cleanup(
 219        struct xfs_trans        *tp,
 220        void                    *state,
 221        int                     error)
 222{
 223        struct xfs_btree_cur    *rcur = state;
 224
 225        xfs_rmap_finish_one_cleanup(tp, rcur, error);
 226}
 227
 228/* Abort all pending RUIs. */
 229STATIC void
 230xfs_rmap_update_abort_intent(
 231        void                            *intent)
 232{
 233        xfs_rui_release(intent);
 234}
 235
 236/* Cancel a deferred rmap update. */
 237STATIC void
 238xfs_rmap_update_cancel_item(
 239        struct list_head                *item)
 240{
 241        struct xfs_rmap_intent          *rmap;
 242
 243        rmap = container_of(item, struct xfs_rmap_intent, ri_list);
 244        kmem_free(rmap);
 245}
 246
 247static const struct xfs_defer_op_type xfs_rmap_update_defer_type = {
 248        .type           = XFS_DEFER_OPS_TYPE_RMAP,
 249        .max_items      = XFS_RUI_MAX_FAST_EXTENTS,
 250        .diff_items     = xfs_rmap_update_diff_items,
 251        .create_intent  = xfs_rmap_update_create_intent,
 252        .abort_intent   = xfs_rmap_update_abort_intent,
 253        .log_item       = xfs_rmap_update_log_item,
 254        .create_done    = xfs_rmap_update_create_done,
 255        .finish_item    = xfs_rmap_update_finish_item,
 256        .finish_cleanup = xfs_rmap_update_finish_cleanup,
 257        .cancel_item    = xfs_rmap_update_cancel_item,
 258};
 259
 260/* Register the deferred op type. */
 261void
 262xfs_rmap_update_init_defer_op(void)
 263{
 264        xfs_defer_init_op_type(&xfs_rmap_update_defer_type);
 265}
 266