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 bnobt irec into a fsmap */
 371STATIC int
 372xfs_getfsmap_datadev_bnobt_helper(
 373        struct xfs_btree_cur            *cur,
 374        struct xfs_alloc_rec_incore     *rec,
 375        void                            *priv)
 376{
 377        struct xfs_mount                *mp = cur->bc_mp;
 378        struct xfs_getfsmap_info        *info = priv;
 379        struct xfs_rmap_irec            irec;
 380        xfs_daddr_t                     rec_daddr;
 381
 382        rec_daddr = XFS_AGB_TO_DADDR(mp, cur->bc_private.a.agno,
 383                        rec->ar_startblock);
 384
 385        irec.rm_startblock = rec->ar_startblock;
 386        irec.rm_blockcount = rec->ar_blockcount;
 387        irec.rm_owner = XFS_RMAP_OWN_NULL;      /* "free" */
 388        irec.rm_offset = 0;
 389        irec.rm_flags = 0;
 390
 391        return xfs_getfsmap_helper(cur->bc_tp, info, &irec, rec_daddr);
 392}
 393
 394/* Set rmap flags based on the getfsmap flags */
 395static void
 396xfs_getfsmap_set_irec_flags(
 397        struct xfs_rmap_irec    *irec,
 398        struct xfs_fsmap        *fmr)
 399{
 400        irec->rm_flags = 0;
 401        if (fmr->fmr_flags & FMR_OF_ATTR_FORK)
 402                irec->rm_flags |= XFS_RMAP_ATTR_FORK;
 403        if (fmr->fmr_flags & FMR_OF_EXTENT_MAP)
 404                irec->rm_flags |= XFS_RMAP_BMBT_BLOCK;
 405        if (fmr->fmr_flags & FMR_OF_PREALLOC)
 406                irec->rm_flags |= XFS_RMAP_UNWRITTEN;
 407}
 408
 409/* Execute a getfsmap query against the log device. */
 410STATIC int
 411xfs_getfsmap_logdev(
 412        struct xfs_trans                *tp,
 413        struct xfs_fsmap                *keys,
 414        struct xfs_getfsmap_info        *info)
 415{
 416        struct xfs_mount                *mp = tp->t_mountp;
 417        struct xfs_rmap_irec            rmap;
 418        int                             error;
 419
 420        /* Set up search keys */
 421        info->low.rm_startblock = XFS_BB_TO_FSBT(mp, keys[0].fmr_physical);
 422        info->low.rm_offset = XFS_BB_TO_FSBT(mp, keys[0].fmr_offset);
 423        error = xfs_fsmap_owner_to_rmap(&info->low, keys);
 424        if (error)
 425                return error;
 426        info->low.rm_blockcount = 0;
 427        xfs_getfsmap_set_irec_flags(&info->low, &keys[0]);
 428
 429        error = xfs_fsmap_owner_to_rmap(&info->high, keys + 1);
 430        if (error)
 431                return error;
 432        info->high.rm_startblock = -1U;
 433        info->high.rm_owner = ULLONG_MAX;
 434        info->high.rm_offset = ULLONG_MAX;
 435        info->high.rm_blockcount = 0;
 436        info->high.rm_flags = XFS_RMAP_KEY_FLAGS | XFS_RMAP_REC_FLAGS;
 437        info->missing_owner = XFS_FMR_OWN_FREE;
 438
 439        trace_xfs_fsmap_low_key(mp, info->dev, info->agno, &info->low);
 440        trace_xfs_fsmap_high_key(mp, info->dev, info->agno, &info->high);
 441
 442        if (keys[0].fmr_physical > 0)
 443                return 0;
 444
 445        /* Fabricate an rmap entry for the external log device. */
 446        rmap.rm_startblock = 0;
 447        rmap.rm_blockcount = mp->m_sb.sb_logblocks;
 448        rmap.rm_owner = XFS_RMAP_OWN_LOG;
 449        rmap.rm_offset = 0;
 450        rmap.rm_flags = 0;
 451
 452        return xfs_getfsmap_helper(tp, info, &rmap, 0);
 453}
 454
 455#ifdef CONFIG_XFS_RT
 456/* Transform a rtbitmap "record" into a fsmap */
 457STATIC int
 458xfs_getfsmap_rtdev_rtbitmap_helper(
 459        struct xfs_trans                *tp,
 460        struct xfs_rtalloc_rec          *rec,
 461        void                            *priv)
 462{
 463        struct xfs_mount                *mp = tp->t_mountp;
 464        struct xfs_getfsmap_info        *info = priv;
 465        struct xfs_rmap_irec            irec;
 466        xfs_daddr_t                     rec_daddr;
 467
 468        rec_daddr = XFS_FSB_TO_BB(mp, rec->ar_startblock);
 469
 470        irec.rm_startblock = rec->ar_startblock;
 471        irec.rm_blockcount = rec->ar_blockcount;
 472        irec.rm_owner = XFS_RMAP_OWN_NULL;      /* "free" */
 473        irec.rm_offset = 0;
 474        irec.rm_flags = 0;
 475
 476        return xfs_getfsmap_helper(tp, info, &irec, rec_daddr);
 477}
 478
 479/* Execute a getfsmap query against the realtime device. */
 480STATIC int
 481__xfs_getfsmap_rtdev(
 482        struct xfs_trans                *tp,
 483        struct xfs_fsmap                *keys,
 484        int                             (*query_fn)(struct xfs_trans *,
 485                                                    struct xfs_getfsmap_info *),
 486        struct xfs_getfsmap_info        *info)
 487{
 488        struct xfs_mount                *mp = tp->t_mountp;
 489        xfs_fsblock_t                   start_fsb;
 490        xfs_fsblock_t                   end_fsb;
 491        xfs_daddr_t                     eofs;
 492        int                             error = 0;
 493
 494        eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks);
 495        if (keys[0].fmr_physical >= eofs)
 496                return 0;
 497        if (keys[1].fmr_physical >= eofs)
 498                keys[1].fmr_physical = eofs - 1;
 499        start_fsb = XFS_BB_TO_FSBT(mp, keys[0].fmr_physical);
 500        end_fsb = XFS_BB_TO_FSB(mp, keys[1].fmr_physical);
 501
 502        /* Set up search keys */
 503        info->low.rm_startblock = start_fsb;
 504        error = xfs_fsmap_owner_to_rmap(&info->low, &keys[0]);
 505        if (error)
 506                return error;
 507        info->low.rm_offset = XFS_BB_TO_FSBT(mp, keys[0].fmr_offset);
 508        info->low.rm_blockcount = 0;
 509        xfs_getfsmap_set_irec_flags(&info->low, &keys[0]);
 510
 511        info->high.rm_startblock = end_fsb;
 512        error = xfs_fsmap_owner_to_rmap(&info->high, &keys[1]);
 513        if (error)
 514                return error;
 515        info->high.rm_offset = XFS_BB_TO_FSBT(mp, keys[1].fmr_offset);
 516        info->high.rm_blockcount = 0;
 517        xfs_getfsmap_set_irec_flags(&info->high, &keys[1]);
 518
 519        trace_xfs_fsmap_low_key(mp, info->dev, info->agno, &info->low);
 520        trace_xfs_fsmap_high_key(mp, info->dev, info->agno, &info->high);
 521
 522        return query_fn(tp, info);
 523}
 524
 525/* Actually query the realtime bitmap. */
 526STATIC int
 527xfs_getfsmap_rtdev_rtbitmap_query(
 528        struct xfs_trans                *tp,
 529        struct xfs_getfsmap_info        *info)
 530{
 531        struct xfs_rtalloc_rec          alow;
 532        struct xfs_rtalloc_rec          ahigh;
 533        int                             error;
 534
 535        xfs_ilock(tp->t_mountp->m_rbmip, XFS_ILOCK_SHARED);
 536
 537        alow.ar_startblock = info->low.rm_startblock;
 538        ahigh.ar_startblock = info->high.rm_startblock;
 539        error = xfs_rtalloc_query_range(tp, &alow, &ahigh,
 540                        xfs_getfsmap_rtdev_rtbitmap_helper, info);
 541        if (error)
 542                goto err;
 543
 544        /* Report any gaps at the end of the rtbitmap */
 545        info->last = true;
 546        error = xfs_getfsmap_rtdev_rtbitmap_helper(tp, &ahigh, info);
 547        if (error)
 548                goto err;
 549err:
 550        xfs_iunlock(tp->t_mountp->m_rbmip, XFS_ILOCK_SHARED);
 551        return error;
 552}
 553
 554/* Execute a getfsmap query against the realtime device rtbitmap. */
 555STATIC int
 556xfs_getfsmap_rtdev_rtbitmap(
 557        struct xfs_trans                *tp,
 558        struct xfs_fsmap                *keys,
 559        struct xfs_getfsmap_info        *info)
 560{
 561        info->missing_owner = XFS_FMR_OWN_UNKNOWN;
 562        return __xfs_getfsmap_rtdev(tp, keys, xfs_getfsmap_rtdev_rtbitmap_query,
 563                        info);
 564}
 565#endif /* CONFIG_XFS_RT */
 566
 567/* Execute a getfsmap query against the regular data device. */
 568STATIC int
 569__xfs_getfsmap_datadev(
 570        struct xfs_trans                *tp,
 571        struct xfs_fsmap                *keys,
 572        struct xfs_getfsmap_info        *info,
 573        int                             (*query_fn)(struct xfs_trans *,
 574                                                    struct xfs_getfsmap_info *,
 575                                                    struct xfs_btree_cur **,
 576                                                    void *),
 577        void                            *priv)
 578{
 579        struct xfs_mount                *mp = tp->t_mountp;
 580        struct xfs_btree_cur            *bt_cur = NULL;
 581        xfs_fsblock_t                   start_fsb;
 582        xfs_fsblock_t                   end_fsb;
 583        xfs_agnumber_t                  start_ag;
 584        xfs_agnumber_t                  end_ag;
 585        xfs_daddr_t                     eofs;
 586        int                             error = 0;
 587
 588        eofs = XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks);
 589        if (keys[0].fmr_physical >= eofs)
 590                return 0;
 591        if (keys[1].fmr_physical >= eofs)
 592                keys[1].fmr_physical = eofs - 1;
 593        start_fsb = XFS_DADDR_TO_FSB(mp, keys[0].fmr_physical);
 594        end_fsb = XFS_DADDR_TO_FSB(mp, keys[1].fmr_physical);
 595
 596        /*
 597         * Convert the fsmap low/high keys to AG based keys.  Initialize
 598         * low to the fsmap low key and max out the high key to the end
 599         * of the AG.
 600         */
 601        info->low.rm_startblock = XFS_FSB_TO_AGBNO(mp, start_fsb);
 602        info->low.rm_offset = XFS_BB_TO_FSBT(mp, keys[0].fmr_offset);
 603        error = xfs_fsmap_owner_to_rmap(&info->low, &keys[0]);
 604        if (error)
 605                return error;
 606        info->low.rm_blockcount = 0;
 607        xfs_getfsmap_set_irec_flags(&info->low, &keys[0]);
 608
 609        info->high.rm_startblock = -1U;
 610        info->high.rm_owner = ULLONG_MAX;
 611        info->high.rm_offset = ULLONG_MAX;
 612        info->high.rm_blockcount = 0;
 613        info->high.rm_flags = XFS_RMAP_KEY_FLAGS | XFS_RMAP_REC_FLAGS;
 614
 615        start_ag = XFS_FSB_TO_AGNO(mp, start_fsb);
 616        end_ag = XFS_FSB_TO_AGNO(mp, end_fsb);
 617
 618        /* Query each AG */
 619        for (info->agno = start_ag; info->agno <= end_ag; info->agno++) {
 620                /*
 621                 * Set the AG high key from the fsmap high key if this
 622                 * is the last AG that we're querying.
 623                 */
 624                if (info->agno == end_ag) {
 625                        info->high.rm_startblock = XFS_FSB_TO_AGBNO(mp,
 626                                        end_fsb);
 627                        info->high.rm_offset = XFS_BB_TO_FSBT(mp,
 628                                        keys[1].fmr_offset);
 629                        error = xfs_fsmap_owner_to_rmap(&info->high, &keys[1]);
 630                        if (error)
 631                                goto err;
 632                        xfs_getfsmap_set_irec_flags(&info->high, &keys[1]);
 633                }
 634
 635                if (bt_cur) {
 636                        xfs_btree_del_cursor(bt_cur, XFS_BTREE_NOERROR);
 637                        bt_cur = NULL;
 638                        xfs_trans_brelse(tp, info->agf_bp);
 639                        info->agf_bp = NULL;
 640                }
 641
 642                error = xfs_alloc_read_agf(mp, tp, info->agno, 0,
 643                                &info->agf_bp);
 644                if (error)
 645                        goto err;
 646
 647                trace_xfs_fsmap_low_key(mp, info->dev, info->agno, &info->low);
 648                trace_xfs_fsmap_high_key(mp, info->dev, info->agno,
 649                                &info->high);
 650
 651                error = query_fn(tp, info, &bt_cur, priv);
 652                if (error)
 653                        goto err;
 654
 655                /*
 656                 * Set the AG low key to the start of the AG prior to
 657                 * moving on to the next AG.
 658                 */
 659                if (info->agno == start_ag) {
 660                        info->low.rm_startblock = 0;
 661                        info->low.rm_owner = 0;
 662                        info->low.rm_offset = 0;
 663                        info->low.rm_flags = 0;
 664                }
 665        }
 666
 667        /* Report any gap at the end of the AG */
 668        info->last = true;
 669        error = query_fn(tp, info, &bt_cur, priv);
 670        if (error)
 671                goto err;
 672
 673err:
 674        if (bt_cur)
 675                xfs_btree_del_cursor(bt_cur, error < 0 ? XFS_BTREE_ERROR :
 676                                                         XFS_BTREE_NOERROR);
 677        if (info->agf_bp) {
 678                xfs_trans_brelse(tp, info->agf_bp);
 679                info->agf_bp = NULL;
 680        }
 681
 682        return error;
 683}
 684
 685/* Actually query the rmap btree. */
 686STATIC int
 687xfs_getfsmap_datadev_rmapbt_query(
 688        struct xfs_trans                *tp,
 689        struct xfs_getfsmap_info        *info,
 690        struct xfs_btree_cur            **curpp,
 691        void                            *priv)
 692{
 693        /* Report any gap at the end of the last AG. */
 694        if (info->last)
 695                return xfs_getfsmap_datadev_helper(*curpp, &info->high, info);
 696
 697        /* Allocate cursor for this AG and query_range it. */
 698        *curpp = xfs_rmapbt_init_cursor(tp->t_mountp, tp, info->agf_bp,
 699                        info->agno);
 700        return xfs_rmap_query_range(*curpp, &info->low, &info->high,
 701                        xfs_getfsmap_datadev_helper, info);
 702}
 703
 704/* Execute a getfsmap query against the regular data device rmapbt. */
 705STATIC int
 706xfs_getfsmap_datadev_rmapbt(
 707        struct xfs_trans                *tp,
 708        struct xfs_fsmap                *keys,
 709        struct xfs_getfsmap_info        *info)
 710{
 711        info->missing_owner = XFS_FMR_OWN_FREE;
 712        return __xfs_getfsmap_datadev(tp, keys, info,
 713                        xfs_getfsmap_datadev_rmapbt_query, NULL);
 714}
 715
 716/* Actually query the bno btree. */
 717STATIC int
 718xfs_getfsmap_datadev_bnobt_query(
 719        struct xfs_trans                *tp,
 720        struct xfs_getfsmap_info        *info,
 721        struct xfs_btree_cur            **curpp,
 722        void                            *priv)
 723{
 724        struct xfs_alloc_rec_incore     *key = priv;
 725
 726        /* Report any gap at the end of the last AG. */
 727        if (info->last)
 728                return xfs_getfsmap_datadev_bnobt_helper(*curpp, &key[1], info);
 729
 730        /* Allocate cursor for this AG and query_range it. */
 731        *curpp = xfs_allocbt_init_cursor(tp->t_mountp, tp, info->agf_bp,
 732                        info->agno, XFS_BTNUM_BNO);
 733        key->ar_startblock = info->low.rm_startblock;
 734        key[1].ar_startblock = info->high.rm_startblock;
 735        return xfs_alloc_query_range(*curpp, key, &key[1],
 736                        xfs_getfsmap_datadev_bnobt_helper, info);
 737}
 738
 739/* Execute a getfsmap query against the regular data device's bnobt. */
 740STATIC int
 741xfs_getfsmap_datadev_bnobt(
 742        struct xfs_trans                *tp,
 743        struct xfs_fsmap                *keys,
 744        struct xfs_getfsmap_info        *info)
 745{
 746        struct xfs_alloc_rec_incore     akeys[2];
 747
 748        info->missing_owner = XFS_FMR_OWN_UNKNOWN;
 749        return __xfs_getfsmap_datadev(tp, keys, info,
 750                        xfs_getfsmap_datadev_bnobt_query, &akeys[0]);
 751}
 752
 753/* Do we recognize the device? */
 754STATIC bool
 755xfs_getfsmap_is_valid_device(
 756        struct xfs_mount        *mp,
 757        struct xfs_fsmap        *fm)
 758{
 759        if (fm->fmr_device == 0 || fm->fmr_device == UINT_MAX ||
 760            fm->fmr_device == new_encode_dev(mp->m_ddev_targp->bt_dev))
 761                return true;
 762        if (mp->m_logdev_targp &&
 763            fm->fmr_device == new_encode_dev(mp->m_logdev_targp->bt_dev))
 764                return true;
 765        if (mp->m_rtdev_targp &&
 766            fm->fmr_device == new_encode_dev(mp->m_rtdev_targp->bt_dev))
 767                return true;
 768        return false;
 769}
 770
 771/* Ensure that the low key is less than the high key. */
 772STATIC bool
 773xfs_getfsmap_check_keys(
 774        struct xfs_fsmap                *low_key,
 775        struct xfs_fsmap                *high_key)
 776{
 777        if (low_key->fmr_device > high_key->fmr_device)
 778                return false;
 779        if (low_key->fmr_device < high_key->fmr_device)
 780                return true;
 781
 782        if (low_key->fmr_physical > high_key->fmr_physical)
 783                return false;
 784        if (low_key->fmr_physical < high_key->fmr_physical)
 785                return true;
 786
 787        if (low_key->fmr_owner > high_key->fmr_owner)
 788                return false;
 789        if (low_key->fmr_owner < high_key->fmr_owner)
 790                return true;
 791
 792        if (low_key->fmr_offset > high_key->fmr_offset)
 793                return false;
 794        if (low_key->fmr_offset < high_key->fmr_offset)
 795                return true;
 796
 797        return false;
 798}
 799
 800/*
 801 * There are only two devices if we didn't configure RT devices at build time.
 802 */
 803#ifdef CONFIG_XFS_RT
 804#define XFS_GETFSMAP_DEVS       3
 805#else
 806#define XFS_GETFSMAP_DEVS       2
 807#endif /* CONFIG_XFS_RT */
 808
 809/*
 810 * Get filesystem's extents as described in head, and format for
 811 * output.  Calls formatter to fill the user's buffer until all
 812 * extents are mapped, until the passed-in head->fmh_count slots have
 813 * been filled, or until the formatter short-circuits the loop, if it
 814 * is tracking filled-in extents on its own.
 815 *
 816 * Key to Confusion
 817 * ----------------
 818 * There are multiple levels of keys and counters at work here:
 819 * xfs_fsmap_head.fmh_keys      -- low and high fsmap keys passed in;
 820 *                                 these reflect fs-wide sector addrs.
 821 * dkeys                        -- fmh_keys used to query each device;
 822 *                                 these are fmh_keys but w/ the low key
 823 *                                 bumped up by fmr_length.
 824 * xfs_getfsmap_info.next_daddr -- next disk addr we expect to see; this
 825 *                                 is how we detect gaps in the fsmap
 826                                   records and report them.
 827 * xfs_getfsmap_info.low/high   -- per-AG low/high keys computed from
 828 *                                 dkeys; used to query the metadata.
 829 */
 830int
 831xfs_getfsmap(
 832        struct xfs_mount                *mp,
 833        struct xfs_fsmap_head           *head,
 834        xfs_fsmap_format_t              formatter,
 835        void                            *arg)
 836{
 837        struct xfs_trans                *tp = NULL;
 838        struct xfs_fsmap                dkeys[2];       /* per-dev keys */
 839        struct xfs_getfsmap_dev         handlers[XFS_GETFSMAP_DEVS];
 840        struct xfs_getfsmap_info        info = { NULL };
 841        bool                            use_rmap;
 842        int                             i;
 843        int                             error = 0;
 844
 845        if (head->fmh_iflags & ~FMH_IF_VALID)
 846                return -EINVAL;
 847        if (!xfs_getfsmap_is_valid_device(mp, &head->fmh_keys[0]) ||
 848            !xfs_getfsmap_is_valid_device(mp, &head->fmh_keys[1]))
 849                return -EINVAL;
 850
 851        use_rmap = capable(CAP_SYS_ADMIN) &&
 852                   xfs_sb_version_hasrmapbt(&mp->m_sb);
 853        head->fmh_entries = 0;
 854
 855        /* Set up our device handlers. */
 856        memset(handlers, 0, sizeof(handlers));
 857        handlers[0].dev = new_encode_dev(mp->m_ddev_targp->bt_dev);
 858        if (use_rmap)
 859                handlers[0].fn = xfs_getfsmap_datadev_rmapbt;
 860        else
 861                handlers[0].fn = xfs_getfsmap_datadev_bnobt;
 862        if (mp->m_logdev_targp != mp->m_ddev_targp) {
 863                handlers[1].dev = new_encode_dev(mp->m_logdev_targp->bt_dev);
 864                handlers[1].fn = xfs_getfsmap_logdev;
 865        }
 866#ifdef CONFIG_XFS_RT
 867        if (mp->m_rtdev_targp) {
 868                handlers[2].dev = new_encode_dev(mp->m_rtdev_targp->bt_dev);
 869                handlers[2].fn = xfs_getfsmap_rtdev_rtbitmap;
 870        }
 871#endif /* CONFIG_XFS_RT */
 872
 873        xfs_sort(handlers, XFS_GETFSMAP_DEVS, sizeof(struct xfs_getfsmap_dev),
 874                        xfs_getfsmap_dev_compare);
 875
 876        /*
 877         * To continue where we left off, we allow userspace to use the
 878         * last mapping from a previous call as the low key of the next.
 879         * This is identified by a non-zero length in the low key. We
 880         * have to increment the low key in this scenario to ensure we
 881         * don't return the same mapping again, and instead return the
 882         * very next mapping.
 883         *
 884         * If the low key mapping refers to file data, the same physical
 885         * blocks could be mapped to several other files/offsets.
 886         * According to rmapbt record ordering, the minimal next
 887         * possible record for the block range is the next starting
 888         * offset in the same inode. Therefore, bump the file offset to
 889         * continue the search appropriately.  For all other low key
 890         * mapping types (attr blocks, metadata), bump the physical
 891         * offset as there can be no other mapping for the same physical
 892         * block range.
 893         */
 894        dkeys[0] = head->fmh_keys[0];
 895        if (dkeys[0].fmr_flags & (FMR_OF_SPECIAL_OWNER | FMR_OF_EXTENT_MAP)) {
 896                dkeys[0].fmr_physical += dkeys[0].fmr_length;
 897                dkeys[0].fmr_owner = 0;
 898                if (dkeys[0].fmr_offset)
 899                        return -EINVAL;
 900        } else
 901                dkeys[0].fmr_offset += dkeys[0].fmr_length;
 902        dkeys[0].fmr_length = 0;
 903        memset(&dkeys[1], 0xFF, sizeof(struct xfs_fsmap));
 904
 905        if (!xfs_getfsmap_check_keys(dkeys, &head->fmh_keys[1]))
 906                return -EINVAL;
 907
 908        info.next_daddr = head->fmh_keys[0].fmr_physical +
 909                          head->fmh_keys[0].fmr_length;
 910        info.formatter = formatter;
 911        info.format_arg = arg;
 912        info.head = head;
 913
 914        /* For each device we support... */
 915        for (i = 0; i < XFS_GETFSMAP_DEVS; i++) {
 916                /* Is this device within the range the user asked for? */
 917                if (!handlers[i].fn)
 918                        continue;
 919                if (head->fmh_keys[0].fmr_device > handlers[i].dev)
 920                        continue;
 921                if (head->fmh_keys[1].fmr_device < handlers[i].dev)
 922                        break;
 923
 924                /*
 925                 * If this device number matches the high key, we have
 926                 * to pass the high key to the handler to limit the
 927                 * query results.  If the device number exceeds the
 928                 * low key, zero out the low key so that we get
 929                 * everything from the beginning.
 930                 */
 931                if (handlers[i].dev == head->fmh_keys[1].fmr_device)
 932                        dkeys[1] = head->fmh_keys[1];
 933                if (handlers[i].dev > head->fmh_keys[0].fmr_device)
 934                        memset(&dkeys[0], 0, sizeof(struct xfs_fsmap));
 935
 936                error = xfs_trans_alloc_empty(mp, &tp);
 937                if (error)
 938                        break;
 939
 940                info.dev = handlers[i].dev;
 941                info.last = false;
 942                info.agno = NULLAGNUMBER;
 943                error = handlers[i].fn(tp, dkeys, &info);
 944                if (error)
 945                        break;
 946                xfs_trans_cancel(tp);
 947                tp = NULL;
 948                info.next_daddr = 0;
 949        }
 950
 951        if (tp)
 952                xfs_trans_cancel(tp);
 953        head->fmh_oflags = FMH_OF_DEV_T;
 954        return error;
 955}
 956