linux/fs/xfs/xfs_fsmap.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2017 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_sb.h"
  27#include "xfs_mount.h"
  28#include "xfs_defer.h"
  29#include "xfs_inode.h"
  30#include "xfs_trans.h"
  31#include "xfs_error.h"
  32#include "xfs_btree.h"
  33#include "xfs_rmap_btree.h"
  34#include "xfs_trace.h"
  35#include "xfs_log.h"
  36#include "xfs_rmap.h"
  37#include "xfs_alloc.h"
  38#include "xfs_bit.h"
  39#include <linux/fsmap.h>
  40#include "xfs_fsmap.h"
  41#include "xfs_refcount.h"
  42#include "xfs_refcount_btree.h"
  43#include "xfs_alloc_btree.h"
  44#include "xfs_rtalloc.h"
  45
  46/* Convert an xfs_fsmap to an fsmap. */
  47void
  48xfs_fsmap_from_internal(
  49        struct fsmap            *dest,
  50        struct xfs_fsmap        *src)
  51{
  52        dest->fmr_device = src->fmr_device;
  53        dest->fmr_flags = src->fmr_flags;
  54        dest->fmr_physical = BBTOB(src->fmr_physical);
  55        dest->fmr_owner = src->fmr_owner;
  56        dest->fmr_offset = BBTOB(src->fmr_offset);
  57        dest->fmr_length = BBTOB(src->fmr_length);
  58        dest->fmr_reserved[0] = 0;
  59        dest->fmr_reserved[1] = 0;
  60        dest->fmr_reserved[2] = 0;
  61}
  62
  63/* Convert an fsmap to an xfs_fsmap. */
  64void
  65xfs_fsmap_to_internal(
  66        struct xfs_fsmap        *dest,
  67        struct fsmap            *src)
  68{
  69        dest->fmr_device = src->fmr_device;
  70        dest->fmr_flags = src->fmr_flags;
  71        dest->fmr_physical = BTOBBT(src->fmr_physical);
  72        dest->fmr_owner = src->fmr_owner;
  73        dest->fmr_offset = BTOBBT(src->fmr_offset);
  74        dest->fmr_length = BTOBBT(src->fmr_length);
  75}
  76
  77/* Convert an fsmap owner into an rmapbt owner. */
  78static int
  79xfs_fsmap_owner_to_rmap(
  80        struct xfs_rmap_irec    *dest,
  81        struct xfs_fsmap        *src)
  82{
  83        if (!(src->fmr_flags & FMR_OF_SPECIAL_OWNER)) {
  84                dest->rm_owner = src->fmr_owner;
  85                return 0;
  86        }
  87
  88        switch (src->fmr_owner) {
  89        case 0:                 /* "lowest owner id possible" */
  90        case -1ULL:             /* "highest owner id possible" */
  91                dest->rm_owner = 0;
  92                break;
  93        case XFS_FMR_OWN_FREE:
  94                dest->rm_owner = XFS_RMAP_OWN_NULL;
  95                break;
  96        case XFS_FMR_OWN_UNKNOWN:
  97                dest->rm_owner = XFS_RMAP_OWN_UNKNOWN;
  98                break;
  99        case XFS_FMR_OWN_FS:
 100                dest->rm_owner = XFS_RMAP_OWN_FS;
 101                break;
 102        case XFS_FMR_OWN_LOG:
 103                dest->rm_owner = XFS_RMAP_OWN_LOG;
 104                break;
 105        case XFS_FMR_OWN_AG:
 106                dest->rm_owner = XFS_RMAP_OWN_AG;
 107                break;
 108        case XFS_FMR_OWN_INOBT:
 109                dest->rm_owner = XFS_RMAP_OWN_INOBT;
 110                break;
 111        case XFS_FMR_OWN_INODES:
 112                dest->rm_owner = XFS_RMAP_OWN_INODES;
 113                break;
 114        case XFS_FMR_OWN_REFC:
 115                dest->rm_owner = XFS_RMAP_OWN_REFC;
 116                break;
 117        case XFS_FMR_OWN_COW:
 118                dest->rm_owner = XFS_RMAP_OWN_COW;
 119                break;
 120        case XFS_FMR_OWN_DEFECTIVE:     /* not implemented */
 121                /* fall through */
 122        default:
 123                return -EINVAL;
 124        }
 125        return 0;
 126}
 127
 128/* Convert an rmapbt owner into an fsmap owner. */
 129static int
 130xfs_fsmap_owner_from_rmap(
 131        struct xfs_fsmap        *dest,
 132        struct xfs_rmap_irec    *src)
 133{
 134        dest->fmr_flags = 0;
 135        if (!XFS_RMAP_NON_INODE_OWNER(src->rm_owner)) {
 136                dest->fmr_owner = src->rm_owner;
 137                return 0;
 138        }
 139        dest->fmr_flags |= FMR_OF_SPECIAL_OWNER;
 140
 141        switch (src->rm_owner) {
 142        case XFS_RMAP_OWN_FS:
 143                dest->fmr_owner = XFS_FMR_OWN_FS;
 144                break;
 145        case XFS_RMAP_OWN_LOG:
 146                dest->fmr_owner = XFS_FMR_OWN_LOG;
 147                break;
 148        case XFS_RMAP_OWN_AG:
 149                dest->fmr_owner = XFS_FMR_OWN_AG;
 150                break;
 151        case XFS_RMAP_OWN_INOBT:
 152                dest->fmr_owner = XFS_FMR_OWN_INOBT;
 153                break;
 154        case XFS_RMAP_OWN_INODES:
 155                dest->fmr_owner = XFS_FMR_OWN_INODES;
 156                break;
 157        case XFS_RMAP_OWN_REFC:
 158                dest->fmr_owner = XFS_FMR_OWN_REFC;
 159                break;
 160        case XFS_RMAP_OWN_COW:
 161                dest->fmr_owner = XFS_FMR_OWN_COW;
 162                break;
 163        case XFS_RMAP_OWN_NULL: /* "free" */
 164                dest->fmr_owner = XFS_FMR_OWN_FREE;
 165                break;
 166        default:
 167                return -EFSCORRUPTED;
 168        }
 169        return 0;
 170}
 171
 172/* getfsmap query state */
 173struct xfs_getfsmap_info {
 174        struct xfs_fsmap_head   *head;
 175        xfs_fsmap_format_t      formatter;      /* formatting fn */
 176        void                    *format_arg;    /* format buffer */
 177        struct xfs_buf          *agf_bp;        /* AGF, for refcount queries */
 178        xfs_daddr_t             next_daddr;     /* next daddr we expect */
 179        u64                     missing_owner;  /* owner of holes */
 180        u32                     dev;            /* device id */
 181        xfs_agnumber_t          agno;           /* AG number, if applicable */
 182        struct xfs_rmap_irec    low;            /* low rmap key */
 183        struct xfs_rmap_irec    high;           /* high rmap key */
 184        bool                    last;           /* last extent? */
 185};
 186
 187/* Associate a device with a getfsmap handler. */
 188struct xfs_getfsmap_dev {
 189        u32                     dev;
 190        int                     (*fn)(struct xfs_trans *tp,
 191                                      struct xfs_fsmap *keys,
 192                                      struct xfs_getfsmap_info *info);
 193};
 194
 195/* Compare two getfsmap device handlers. */
 196static int
 197xfs_getfsmap_dev_compare(
 198        const void                      *p1,
 199        const void                      *p2)
 200{
 201        const struct xfs_getfsmap_dev   *d1 = p1;
 202        const struct xfs_getfsmap_dev   *d2 = p2;
 203
 204        return d1->dev - d2->dev;
 205}
 206
 207/* Decide if this mapping is shared. */
 208STATIC int
 209xfs_getfsmap_is_shared(
 210        struct xfs_trans                *tp,
 211        struct xfs_getfsmap_info        *info,
 212        struct xfs_rmap_irec            *rec,
 213        bool                            *stat)
 214{
 215        struct xfs_mount                *mp = tp->t_mountp;
 216        struct xfs_btree_cur            *cur;
 217        xfs_agblock_t                   fbno;
 218        xfs_extlen_t                    flen;
 219        int                             error;
 220
 221        *stat = false;
 222        if (!xfs_sb_version_hasreflink(&mp->m_sb))
 223                return 0;
 224        /* rt files will have agno set to NULLAGNUMBER */
 225        if (info->agno == NULLAGNUMBER)
 226                return 0;
 227
 228        /* Are there any shared blocks here? */
 229        flen = 0;
 230        cur = xfs_refcountbt_init_cursor(mp, tp, info->agf_bp,
 231                        info->agno, NULL);
 232
 233        error = xfs_refcount_find_shared(cur, rec->rm_startblock,
 234                        rec->rm_blockcount, &fbno, &flen, false);
 235
 236        xfs_btree_del_cursor(cur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
 237        if (error)
 238                return error;
 239
 240        *stat = flen > 0;
 241        return 0;
 242}
 243
 244/*
 245 * Format a reverse mapping for getfsmap, having translated rm_startblock
 246 * into the appropriate daddr units.
 247 */
 248STATIC int
 249xfs_getfsmap_helper(
 250        struct xfs_trans                *tp,
 251        struct xfs_getfsmap_info        *info,
 252        struct xfs_rmap_irec            *rec,
 253        xfs_daddr_t                     rec_daddr)
 254{
 255        struct xfs_fsmap                fmr;
 256        struct xfs_mount                *mp = tp->t_mountp;
 257        bool                            shared;
 258        int                             error;
 259
 260        if (fatal_signal_pending(current))
 261                return -EINTR;
 262
 263        /*
 264         * Filter out records that start before our startpoint, if the
 265         * caller requested that.
 266         */
 267        if (xfs_rmap_compare(rec, &info->low) < 0) {
 268                rec_daddr += XFS_FSB_TO_BB(mp, rec->rm_blockcount);
 269                if (info->next_daddr < rec_daddr)
 270                        info->next_daddr = rec_daddr;
 271                return XFS_BTREE_QUERY_RANGE_CONTINUE;
 272        }
 273
 274        /* Are we just counting mappings? */
 275        if (info->head->fmh_count == 0) {
 276                if (rec_daddr > info->next_daddr)
 277                        info->head->fmh_entries++;
 278
 279                if (info->last)
 280                        return XFS_BTREE_QUERY_RANGE_CONTINUE;
 281
 282                info->head->fmh_entries++;
 283
 284                rec_daddr += XFS_FSB_TO_BB(mp, rec->rm_blockcount);
 285                if (info->next_daddr < rec_daddr)
 286                        info->next_daddr = rec_daddr;
 287                return XFS_BTREE_QUERY_RANGE_CONTINUE;
 288        }
 289
 290        /*
 291         * If the record starts past the last physical block we saw,
 292         * then we've found a gap.  Report the gap as being owned by
 293         * whatever the caller specified is the missing owner.
 294         */
 295        if (rec_daddr > info->next_daddr) {
 296                if (info->head->fmh_entries >= info->head->fmh_count)
 297                        return XFS_BTREE_QUERY_RANGE_ABORT;
 298
 299                fmr.fmr_device = info->dev;
 300                fmr.fmr_physical = info->next_daddr;
 301                fmr.fmr_owner = info->missing_owner;
 302                fmr.fmr_offset = 0;
 303                fmr.fmr_length = rec_daddr - info->next_daddr;
 304                fmr.fmr_flags = FMR_OF_SPECIAL_OWNER;
 305                error = info->formatter(&fmr, info->format_arg);
 306                if (error)
 307                        return error;
 308                info->head->fmh_entries++;
 309        }
 310
 311        if (info->last)
 312                goto out;
 313
 314        /* Fill out the extent we found */
 315        if (info->head->fmh_entries >= info->head->fmh_count)
 316                return XFS_BTREE_QUERY_RANGE_ABORT;
 317
 318        trace_xfs_fsmap_mapping(mp, info->dev, info->agno, rec);
 319
 320        fmr.fmr_device = info->dev;
 321        fmr.fmr_physical = rec_daddr;
 322        error = xfs_fsmap_owner_from_rmap(&fmr, rec);
 323        if (error)
 324                return error;
 325        fmr.fmr_offset = XFS_FSB_TO_BB(mp, rec->rm_offset);
 326        fmr.fmr_length = XFS_FSB_TO_BB(mp, rec->rm_blockcount);
 327        if (rec->rm_flags & XFS_RMAP_UNWRITTEN)
 328                fmr.fmr_flags |= FMR_OF_PREALLOC;
 329        if (rec->rm_flags & XFS_RMAP_ATTR_FORK)
 330                fmr.fmr_flags |= FMR_OF_ATTR_FORK;
 331        if (rec->rm_flags & XFS_RMAP_BMBT_BLOCK)
 332                fmr.fmr_flags |= FMR_OF_EXTENT_MAP;
 333        if (fmr.fmr_flags == 0) {
 334                error = xfs_getfsmap_is_shared(tp, info, rec, &shared);
 335                if (error)
 336                        return error;
 337                if (shared)
 338                        fmr.fmr_flags |= FMR_OF_SHARED;
 339        }
 340        error = info->formatter(&fmr, info->format_arg);
 341        if (error)
 342                return error;
 343        info->head->fmh_entries++;
 344
 345out:
 346        rec_daddr += XFS_FSB_TO_BB(mp, rec->rm_blockcount);
 347        if (info->next_daddr < rec_daddr)
 348                info->next_daddr = rec_daddr;
 349        return XFS_BTREE_QUERY_RANGE_CONTINUE;
 350}
 351
 352/* Transform a rmapbt irec into a fsmap */
 353STATIC int
 354xfs_getfsmap_datadev_helper(
 355        struct xfs_btree_cur            *cur,
 356        struct xfs_rmap_irec            *rec,
 357        void                            *priv)
 358{
 359        struct xfs_mount                *mp = cur->bc_mp;
 360        struct xfs_getfsmap_info        *info = priv;
 361        xfs_fsblock_t                   fsb;
 362        xfs_daddr_t                     rec_daddr;
 363
 364        fsb = XFS_AGB_TO_FSB(mp, cur->bc_private.a.agno, rec->rm_startblock);
 365        rec_daddr = XFS_FSB_TO_DADDR(mp, fsb);
 366
 367        return xfs_getfsmap_helper(cur->bc_tp, info, rec, rec_daddr);
 368}
 369
 370/* Transform a rtbitmap "record" into a fsmap */
 371STATIC int
 372xfs_getfsmap_rtdev_rtbitmap_helper(
 373        struct xfs_trans                *tp,
 374        struct xfs_rtalloc_rec          *rec,
 375        void                            *priv)
 376{
 377        struct xfs_mount                *mp = tp->t_mountp;
 378        struct xfs_getfsmap_info        *info = priv;
 379        struct xfs_rmap_irec            irec;
 380        xfs_daddr_t                     rec_daddr;
 381
 382        rec_daddr = XFS_FSB_TO_BB(mp, rec->ar_startblock);
 383
 384        irec.rm_startblock = rec->ar_startblock;
 385        irec.rm_blockcount = rec->ar_blockcount;
 386        irec.rm_owner = XFS_RMAP_OWN_NULL;      /* "free" */
 387        irec.rm_offset = 0;
 388        irec.rm_flags = 0;
 389
 390        return xfs_getfsmap_helper(tp, info, &irec, rec_daddr);
 391}
 392
 393/* Transform a bnobt irec into a fsmap */
 394STATIC int
 395xfs_getfsmap_datadev_bnobt_helper(
 396        struct xfs_btree_cur            *cur,
 397        struct xfs_alloc_rec_incore     *rec,
 398        void                            *priv)
 399{
 400        struct xfs_mount                *mp = cur->bc_mp;
 401        struct xfs_getfsmap_info        *info = priv;
 402        struct xfs_rmap_irec            irec;
 403        xfs_daddr_t                     rec_daddr;
 404
 405        rec_daddr = XFS_AGB_TO_DADDR(mp, cur->bc_private.a.agno,
 406                        rec->ar_startblock);
 407
 408        irec.rm_startblock = rec->ar_startblock;
 409        irec.rm_blockcount = rec->ar_blockcount;
 410        irec.rm_owner = XFS_RMAP_OWN_NULL;      /* "free" */
 411        irec.rm_offset = 0;
 412        irec.rm_flags = 0;
 413
 414        return xfs_getfsmap_helper(cur->bc_tp, info, &irec, rec_daddr);
 415}
 416
 417/* Set rmap flags based on the getfsmap flags */
 418static void
 419xfs_getfsmap_set_irec_flags(
 420        struct xfs_rmap_irec    *irec,
 421        struct xfs_fsmap        *fmr)
 422{
 423        irec->rm_flags = 0;
 424        if (fmr->fmr_flags & FMR_OF_ATTR_FORK)
 425                irec->rm_flags |= XFS_RMAP_ATTR_FORK;
 426        if (fmr->fmr_flags & FMR_OF_EXTENT_MAP)
 427                irec->rm_flags |= XFS_RMAP_BMBT_BLOCK;
 428        if (fmr->fmr_flags & FMR_OF_PREALLOC)
 429                irec->rm_flags |= XFS_RMAP_UNWRITTEN;
 430}
 431
 432/* Execute a getfsmap query against the log device. */
 433STATIC int
 434xfs_getfsmap_logdev(
 435        struct xfs_trans                *tp,
 436        struct xfs_fsmap                *keys,
 437        struct xfs_getfsmap_info        *info)
 438{
 439        struct xfs_mount                *mp = tp->t_mountp;
 440        struct xfs_rmap_irec            rmap;
 441        int                             error;
 442
 443        /* Set up search keys */
 444        info->low.rm_startblock = XFS_BB_TO_FSBT(mp, keys[0].fmr_physical);
 445        info->low.rm_offset = XFS_BB_TO_FSBT(mp, keys[0].fmr_offset);
 446        error = xfs_fsmap_owner_to_rmap(&info->low, keys);
 447        if (error)
 448                return error;
 449        info->low.rm_blockcount = 0;
 450        xfs_getfsmap_set_irec_flags(&info->low, &keys[0]);
 451
 452        error = xfs_fsmap_owner_to_rmap(&info->high, keys + 1);
 453        if (error)
 454                return error;
 455        info->high.rm_startblock = -1U;
 456        info->high.rm_owner = ULLONG_MAX;
 457        info->high.rm_offset = ULLONG_MAX;
 458        info->high.rm_blockcount = 0;
 459        info->high.rm_flags = XFS_RMAP_KEY_FLAGS | XFS_RMAP_REC_FLAGS;
 460        info->missing_owner = XFS_FMR_OWN_FREE;
 461
 462        trace_xfs_fsmap_low_key(mp, info->dev, info->agno, &info->low);
 463        trace_xfs_fsmap_high_key(mp, info->dev, info->agno, &info->high);
 464
 465        if (keys[0].fmr_physical > 0)
 466                return 0;
 467
 468        /* Fabricate an rmap entry for the external log device. */
 469        rmap.rm_startblock = 0;
 470        rmap.rm_blockcount = mp->m_sb.sb_logblocks;
 471        rmap.rm_owner = XFS_RMAP_OWN_LOG;
 472        rmap.rm_offset = 0;
 473        rmap.rm_flags = 0;
 474
 475        return xfs_getfsmap_helper(tp, info, &rmap, 0);
 476}
 477
 478/* Execute a getfsmap query against the realtime device. */
 479STATIC int
 480__xfs_getfsmap_rtdev(
 481        struct xfs_trans                *tp,
 482        struct xfs_fsmap                *keys,
 483        int                             (*query_fn)(struct xfs_trans *,
 484                                                    struct xfs_getfsmap_info *),
 485        struct xfs_getfsmap_info        *info)
 486{
 487        struct xfs_mount                *mp = tp->t_mountp;
 488        xfs_fsblock_t                   start_fsb;
 489        xfs_fsblock_t                   end_fsb;
 490        xfs_daddr_t                     eofs;
 491        int                             error = 0;
 492
 493        eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks);
 494        if (keys[0].fmr_physical >= eofs)
 495                return 0;
 496        if (keys[1].fmr_physical >= eofs)
 497                keys[1].fmr_physical = eofs - 1;
 498        start_fsb = XFS_BB_TO_FSBT(mp, keys[0].fmr_physical);
 499        end_fsb = XFS_BB_TO_FSB(mp, keys[1].fmr_physical);
 500
 501        /* Set up search keys */
 502        info->low.rm_startblock = start_fsb;
 503        error = xfs_fsmap_owner_to_rmap(&info->low, &keys[0]);
 504        if (error)
 505                return error;
 506        info->low.rm_offset = XFS_BB_TO_FSBT(mp, keys[0].fmr_offset);
 507        info->low.rm_blockcount = 0;
 508        xfs_getfsmap_set_irec_flags(&info->low, &keys[0]);
 509
 510        info->high.rm_startblock = end_fsb;
 511        error = xfs_fsmap_owner_to_rmap(&info->high, &keys[1]);
 512        if (error)
 513                return error;
 514        info->high.rm_offset = XFS_BB_TO_FSBT(mp, keys[1].fmr_offset);
 515        info->high.rm_blockcount = 0;
 516        xfs_getfsmap_set_irec_flags(&info->high, &keys[1]);
 517
 518        trace_xfs_fsmap_low_key(mp, info->dev, info->agno, &info->low);
 519        trace_xfs_fsmap_high_key(mp, info->dev, info->agno, &info->high);
 520
 521        return query_fn(tp, info);
 522}
 523
 524/* Actually query the realtime bitmap. */
 525STATIC int
 526xfs_getfsmap_rtdev_rtbitmap_query(
 527        struct xfs_trans                *tp,
 528        struct xfs_getfsmap_info        *info)
 529{
 530        struct xfs_rtalloc_rec          alow;
 531        struct xfs_rtalloc_rec          ahigh;
 532        int                             error;
 533
 534        xfs_ilock(tp->t_mountp->m_rbmip, XFS_ILOCK_SHARED);
 535
 536        alow.ar_startblock = info->low.rm_startblock;
 537        ahigh.ar_startblock = info->high.rm_startblock;
 538        error = xfs_rtalloc_query_range(tp, &alow, &ahigh,
 539                        xfs_getfsmap_rtdev_rtbitmap_helper, info);
 540        if (error)
 541                goto err;
 542
 543        /* Report any gaps at the end of the rtbitmap */
 544        info->last = true;
 545        error = xfs_getfsmap_rtdev_rtbitmap_helper(tp, &ahigh, info);
 546        if (error)
 547                goto err;
 548err:
 549        xfs_iunlock(tp->t_mountp->m_rbmip, XFS_ILOCK_SHARED);
 550        return error;
 551}
 552
 553/* Execute a getfsmap query against the realtime device rtbitmap. */
 554STATIC int
 555xfs_getfsmap_rtdev_rtbitmap(
 556        struct xfs_trans                *tp,
 557        struct xfs_fsmap                *keys,
 558        struct xfs_getfsmap_info        *info)
 559{
 560        info->missing_owner = XFS_FMR_OWN_UNKNOWN;
 561        return __xfs_getfsmap_rtdev(tp, keys, xfs_getfsmap_rtdev_rtbitmap_query,
 562                        info);
 563}
 564
 565/* Execute a getfsmap query against the regular data device. */
 566STATIC int
 567__xfs_getfsmap_datadev(
 568        struct xfs_trans                *tp,
 569        struct xfs_fsmap                *keys,
 570        struct xfs_getfsmap_info        *info,
 571        int                             (*query_fn)(struct xfs_trans *,
 572                                                    struct xfs_getfsmap_info *,
 573                                                    struct xfs_btree_cur **,
 574                                                    void *),
 575        void                            *priv)
 576{
 577        struct xfs_mount                *mp = tp->t_mountp;
 578        struct xfs_btree_cur            *bt_cur = NULL;
 579        xfs_fsblock_t                   start_fsb;
 580        xfs_fsblock_t                   end_fsb;
 581        xfs_agnumber_t                  start_ag;
 582        xfs_agnumber_t                  end_ag;
 583        xfs_daddr_t                     eofs;
 584        int                             error = 0;
 585
 586        eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks);
 587        if (keys[0].fmr_physical >= eofs)
 588                return 0;
 589        if (keys[1].fmr_physical >= eofs)
 590                keys[1].fmr_physical = eofs - 1;
 591        start_fsb = XFS_DADDR_TO_FSB(mp, keys[0].fmr_physical);
 592        end_fsb = XFS_DADDR_TO_FSB(mp, keys[1].fmr_physical);
 593
 594        /*
 595         * Convert the fsmap low/high keys to AG based keys.  Initialize
 596         * low to the fsmap low key and max out the high key to the end
 597         * of the AG.
 598         */
 599        info->low.rm_startblock = XFS_FSB_TO_AGBNO(mp, start_fsb);
 600        info->low.rm_offset = XFS_BB_TO_FSBT(mp, keys[0].fmr_offset);
 601        error = xfs_fsmap_owner_to_rmap(&info->low, &keys[0]);
 602        if (error)
 603                return error;
 604        info->low.rm_blockcount = 0;
 605        xfs_getfsmap_set_irec_flags(&info->low, &keys[0]);
 606
 607        info->high.rm_startblock = -1U;
 608        info->high.rm_owner = ULLONG_MAX;
 609        info->high.rm_offset = ULLONG_MAX;
 610        info->high.rm_blockcount = 0;
 611        info->high.rm_flags = XFS_RMAP_KEY_FLAGS | XFS_RMAP_REC_FLAGS;
 612
 613        start_ag = XFS_FSB_TO_AGNO(mp, start_fsb);
 614        end_ag = XFS_FSB_TO_AGNO(mp, end_fsb);
 615
 616        /* Query each AG */
 617        for (info->agno = start_ag; info->agno <= end_ag; info->agno++) {
 618                /*
 619                 * Set the AG high key from the fsmap high key if this
 620                 * is the last AG that we're querying.
 621                 */
 622                if (info->agno == end_ag) {
 623                        info->high.rm_startblock = XFS_FSB_TO_AGBNO(mp,
 624                                        end_fsb);
 625                        info->high.rm_offset = XFS_BB_TO_FSBT(mp,
 626                                        keys[1].fmr_offset);
 627                        error = xfs_fsmap_owner_to_rmap(&info->high, &keys[1]);
 628                        if (error)
 629                                goto err;
 630                        xfs_getfsmap_set_irec_flags(&info->high, &keys[1]);
 631                }
 632
 633                if (bt_cur) {
 634                        xfs_btree_del_cursor(bt_cur, XFS_BTREE_NOERROR);
 635                        bt_cur = NULL;
 636                        xfs_trans_brelse(tp, info->agf_bp);
 637                        info->agf_bp = NULL;
 638                }
 639
 640                error = xfs_alloc_read_agf(mp, tp, info->agno, 0,
 641                                &info->agf_bp);
 642                if (error)
 643                        goto err;
 644
 645                trace_xfs_fsmap_low_key(mp, info->dev, info->agno, &info->low);
 646                trace_xfs_fsmap_high_key(mp, info->dev, info->agno,
 647                                &info->high);
 648
 649                error = query_fn(tp, info, &bt_cur, priv);
 650                if (error)
 651                        goto err;
 652
 653                /*
 654                 * Set the AG low key to the start of the AG prior to
 655                 * moving on to the next AG.
 656                 */
 657                if (info->agno == start_ag) {
 658                        info->low.rm_startblock = 0;
 659                        info->low.rm_owner = 0;
 660                        info->low.rm_offset = 0;
 661                        info->low.rm_flags = 0;
 662                }
 663        }
 664
 665        /* Report any gap at the end of the AG */
 666        info->last = true;
 667        error = query_fn(tp, info, &bt_cur, priv);
 668        if (error)
 669                goto err;
 670
 671err:
 672        if (bt_cur)
 673                xfs_btree_del_cursor(bt_cur, error < 0 ? XFS_BTREE_ERROR :
 674                                                         XFS_BTREE_NOERROR);
 675        if (info->agf_bp) {
 676                xfs_trans_brelse(tp, info->agf_bp);
 677                info->agf_bp = NULL;
 678        }
 679
 680        return error;
 681}
 682
 683/* Actually query the rmap btree. */
 684STATIC int
 685xfs_getfsmap_datadev_rmapbt_query(
 686        struct xfs_trans                *tp,
 687        struct xfs_getfsmap_info        *info,
 688        struct xfs_btree_cur            **curpp,
 689        void                            *priv)
 690{
 691        /* Report any gap at the end of the last AG. */
 692        if (info->last)
 693                return xfs_getfsmap_datadev_helper(*curpp, &info->high, info);
 694
 695        /* Allocate cursor for this AG and query_range it. */
 696        *curpp = xfs_rmapbt_init_cursor(tp->t_mountp, tp, info->agf_bp,
 697                        info->agno);
 698        return xfs_rmap_query_range(*curpp, &info->low, &info->high,
 699                        xfs_getfsmap_datadev_helper, info);
 700}
 701
 702/* Execute a getfsmap query against the regular data device rmapbt. */
 703STATIC int
 704xfs_getfsmap_datadev_rmapbt(
 705        struct xfs_trans                *tp,
 706        struct xfs_fsmap                *keys,
 707        struct xfs_getfsmap_info        *info)
 708{
 709        info->missing_owner = XFS_FMR_OWN_FREE;
 710        return __xfs_getfsmap_datadev(tp, keys, info,
 711                        xfs_getfsmap_datadev_rmapbt_query, NULL);
 712}
 713
 714/* Actually query the bno btree. */
 715STATIC int
 716xfs_getfsmap_datadev_bnobt_query(
 717        struct xfs_trans                *tp,
 718        struct xfs_getfsmap_info        *info,
 719        struct xfs_btree_cur            **curpp,
 720        void                            *priv)
 721{
 722        struct xfs_alloc_rec_incore     *key = priv;
 723
 724        /* Report any gap at the end of the last AG. */
 725        if (info->last)
 726                return xfs_getfsmap_datadev_bnobt_helper(*curpp, &key[1], info);
 727
 728        /* Allocate cursor for this AG and query_range it. */
 729        *curpp = xfs_allocbt_init_cursor(tp->t_mountp, tp, info->agf_bp,
 730                        info->agno, XFS_BTNUM_BNO);
 731        key->ar_startblock = info->low.rm_startblock;
 732        key[1].ar_startblock = info->high.rm_startblock;
 733        return xfs_alloc_query_range(*curpp, key, &key[1],
 734                        xfs_getfsmap_datadev_bnobt_helper, info);
 735}
 736
 737/* Execute a getfsmap query against the regular data device's bnobt. */
 738STATIC int
 739xfs_getfsmap_datadev_bnobt(
 740        struct xfs_trans                *tp,
 741        struct xfs_fsmap                *keys,
 742        struct xfs_getfsmap_info        *info)
 743{
 744        struct xfs_alloc_rec_incore     akeys[2];
 745
 746        info->missing_owner = XFS_FMR_OWN_UNKNOWN;
 747        return __xfs_getfsmap_datadev(tp, keys, info,
 748                        xfs_getfsmap_datadev_bnobt_query, &akeys[0]);
 749}
 750
 751/* Do we recognize the device? */
 752STATIC bool
 753xfs_getfsmap_is_valid_device(
 754        struct xfs_mount        *mp,
 755        struct xfs_fsmap        *fm)
 756{
 757        if (fm->fmr_device == 0 || fm->fmr_device == UINT_MAX ||
 758            fm->fmr_device == new_encode_dev(mp->m_ddev_targp->bt_dev))
 759                return true;
 760        if (mp->m_logdev_targp &&
 761            fm->fmr_device == new_encode_dev(mp->m_logdev_targp->bt_dev))
 762                return true;
 763        if (mp->m_rtdev_targp &&
 764            fm->fmr_device == new_encode_dev(mp->m_rtdev_targp->bt_dev))
 765                return true;
 766        return false;
 767}
 768
 769/* Ensure that the low key is less than the high key. */
 770STATIC bool
 771xfs_getfsmap_check_keys(
 772        struct xfs_fsmap                *low_key,
 773        struct xfs_fsmap                *high_key)
 774{
 775        if (low_key->fmr_device > high_key->fmr_device)
 776                return false;
 777        if (low_key->fmr_device < high_key->fmr_device)
 778                return true;
 779
 780        if (low_key->fmr_physical > high_key->fmr_physical)
 781                return false;
 782        if (low_key->fmr_physical < high_key->fmr_physical)
 783                return true;
 784
 785        if (low_key->fmr_owner > high_key->fmr_owner)
 786                return false;
 787        if (low_key->fmr_owner < high_key->fmr_owner)
 788                return true;
 789
 790        if (low_key->fmr_offset > high_key->fmr_offset)
 791                return false;
 792        if (low_key->fmr_offset < high_key->fmr_offset)
 793                return true;
 794
 795        return false;
 796}
 797
 798#define XFS_GETFSMAP_DEVS       3
 799/*
 800 * Get filesystem's extents as described in head, and format for
 801 * output.  Calls formatter to fill the user's buffer until all
 802 * extents are mapped, until the passed-in head->fmh_count slots have
 803 * been filled, or until the formatter short-circuits the loop, if it
 804 * is tracking filled-in extents on its own.
 805 *
 806 * Key to Confusion
 807 * ----------------
 808 * There are multiple levels of keys and counters at work here:
 809 * xfs_fsmap_head.fmh_keys      -- low and high fsmap keys passed in;
 810 *                                 these reflect fs-wide sector addrs.
 811 * dkeys                        -- fmh_keys used to query each device;
 812 *                                 these are fmh_keys but w/ the low key
 813 *                                 bumped up by fmr_length.
 814 * xfs_getfsmap_info.next_daddr -- next disk addr we expect to see; this
 815 *                                 is how we detect gaps in the fsmap
 816                                   records and report them.
 817 * xfs_getfsmap_info.low/high   -- per-AG low/high keys computed from
 818 *                                 dkeys; used to query the metadata.
 819 */
 820int
 821xfs_getfsmap(
 822        struct xfs_mount                *mp,
 823        struct xfs_fsmap_head           *head,
 824        xfs_fsmap_format_t              formatter,
 825        void                            *arg)
 826{
 827        struct xfs_trans                *tp = NULL;
 828        struct xfs_fsmap                dkeys[2];       /* per-dev keys */
 829        struct xfs_getfsmap_dev         handlers[XFS_GETFSMAP_DEVS];
 830        struct xfs_getfsmap_info        info = { NULL };
 831        bool                            use_rmap;
 832        int                             i;
 833        int                             error = 0;
 834
 835        if (head->fmh_iflags & ~FMH_IF_VALID)
 836                return -EINVAL;
 837        if (!xfs_getfsmap_is_valid_device(mp, &head->fmh_keys[0]) ||
 838            !xfs_getfsmap_is_valid_device(mp, &head->fmh_keys[1]))
 839                return -EINVAL;
 840
 841        use_rmap = capable(CAP_SYS_ADMIN) &&
 842                   xfs_sb_version_hasrmapbt(&mp->m_sb);
 843        head->fmh_entries = 0;
 844
 845        /* Set up our device handlers. */
 846        memset(handlers, 0, sizeof(handlers));
 847        handlers[0].dev = new_encode_dev(mp->m_ddev_targp->bt_dev);
 848        if (use_rmap)
 849                handlers[0].fn = xfs_getfsmap_datadev_rmapbt;
 850        else
 851                handlers[0].fn = xfs_getfsmap_datadev_bnobt;
 852        if (mp->m_logdev_targp != mp->m_ddev_targp) {
 853                handlers[1].dev = new_encode_dev(mp->m_logdev_targp->bt_dev);
 854                handlers[1].fn = xfs_getfsmap_logdev;
 855        }
 856        if (mp->m_rtdev_targp) {
 857                handlers[2].dev = new_encode_dev(mp->m_rtdev_targp->bt_dev);
 858                handlers[2].fn = xfs_getfsmap_rtdev_rtbitmap;
 859        }
 860
 861        xfs_sort(handlers, XFS_GETFSMAP_DEVS, sizeof(struct xfs_getfsmap_dev),
 862                        xfs_getfsmap_dev_compare);
 863
 864        /*
 865         * To continue where we left off, we allow userspace to use the
 866         * last mapping from a previous call as the low key of the next.
 867         * This is identified by a non-zero length in the low key. We
 868         * have to increment the low key in this scenario to ensure we
 869         * don't return the same mapping again, and instead return the
 870         * very next mapping.
 871         *
 872         * If the low key mapping refers to file data, the same physical
 873         * blocks could be mapped to several other files/offsets.
 874         * According to rmapbt record ordering, the minimal next
 875         * possible record for the block range is the next starting
 876         * offset in the same inode. Therefore, bump the file offset to
 877         * continue the search appropriately.  For all other low key
 878         * mapping types (attr blocks, metadata), bump the physical
 879         * offset as there can be no other mapping for the same physical
 880         * block range.
 881         */
 882        dkeys[0] = head->fmh_keys[0];
 883        if (dkeys[0].fmr_flags & (FMR_OF_SPECIAL_OWNER | FMR_OF_EXTENT_MAP)) {
 884                dkeys[0].fmr_physical += dkeys[0].fmr_length;
 885                dkeys[0].fmr_owner = 0;
 886                if (dkeys[0].fmr_offset)
 887                        return -EINVAL;
 888        } else
 889                dkeys[0].fmr_offset += dkeys[0].fmr_length;
 890        dkeys[0].fmr_length = 0;
 891        memset(&dkeys[1], 0xFF, sizeof(struct xfs_fsmap));
 892
 893        if (!xfs_getfsmap_check_keys(dkeys, &head->fmh_keys[1]))
 894                return -EINVAL;
 895
 896        info.next_daddr = head->fmh_keys[0].fmr_physical +
 897                          head->fmh_keys[0].fmr_length;
 898        info.formatter = formatter;
 899        info.format_arg = arg;
 900        info.head = head;
 901
 902        /* For each device we support... */
 903        for (i = 0; i < XFS_GETFSMAP_DEVS; i++) {
 904                /* Is this device within the range the user asked for? */
 905                if (!handlers[i].fn)
 906                        continue;
 907                if (head->fmh_keys[0].fmr_device > handlers[i].dev)
 908                        continue;
 909                if (head->fmh_keys[1].fmr_device < handlers[i].dev)
 910                        break;
 911
 912                /*
 913                 * If this device number matches the high key, we have
 914                 * to pass the high key to the handler to limit the
 915                 * query results.  If the device number exceeds the
 916                 * low key, zero out the low key so that we get
 917                 * everything from the beginning.
 918                 */
 919                if (handlers[i].dev == head->fmh_keys[1].fmr_device)
 920                        dkeys[1] = head->fmh_keys[1];
 921                if (handlers[i].dev > head->fmh_keys[0].fmr_device)
 922                        memset(&dkeys[0], 0, sizeof(struct xfs_fsmap));
 923
 924                error = xfs_trans_alloc_empty(mp, &tp);
 925                if (error)
 926                        break;
 927
 928                info.dev = handlers[i].dev;
 929                info.last = false;
 930                info.agno = NULLAGNUMBER;
 931                error = handlers[i].fn(tp, dkeys, &info);
 932                if (error)
 933                        break;
 934                xfs_trans_cancel(tp);
 935                tp = NULL;
 936                info.next_daddr = 0;
 937        }
 938
 939        if (tp)
 940                xfs_trans_cancel(tp);
 941        head->fmh_oflags = FMH_OF_DEV_T;
 942        return error;
 943}
 944