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