linux/fs/iomap/fiemap.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2016-2021 Christoph Hellwig.
   4 */
   5#include <linux/module.h>
   6#include <linux/compiler.h>
   7#include <linux/fs.h>
   8#include <linux/iomap.h>
   9#include <linux/fiemap.h>
  10
  11static int iomap_to_fiemap(struct fiemap_extent_info *fi,
  12                const struct iomap *iomap, u32 flags)
  13{
  14        switch (iomap->type) {
  15        case IOMAP_HOLE:
  16                /* skip holes */
  17                return 0;
  18        case IOMAP_DELALLOC:
  19                flags |= FIEMAP_EXTENT_DELALLOC | FIEMAP_EXTENT_UNKNOWN;
  20                break;
  21        case IOMAP_MAPPED:
  22                break;
  23        case IOMAP_UNWRITTEN:
  24                flags |= FIEMAP_EXTENT_UNWRITTEN;
  25                break;
  26        case IOMAP_INLINE:
  27                flags |= FIEMAP_EXTENT_DATA_INLINE;
  28                break;
  29        }
  30
  31        if (iomap->flags & IOMAP_F_MERGED)
  32                flags |= FIEMAP_EXTENT_MERGED;
  33        if (iomap->flags & IOMAP_F_SHARED)
  34                flags |= FIEMAP_EXTENT_SHARED;
  35
  36        return fiemap_fill_next_extent(fi, iomap->offset,
  37                        iomap->addr != IOMAP_NULL_ADDR ? iomap->addr : 0,
  38                        iomap->length, flags);
  39}
  40
  41static loff_t iomap_fiemap_iter(const struct iomap_iter *iter,
  42                struct fiemap_extent_info *fi, struct iomap *prev)
  43{
  44        int ret;
  45
  46        if (iter->iomap.type == IOMAP_HOLE)
  47                return iomap_length(iter);
  48
  49        ret = iomap_to_fiemap(fi, prev, 0);
  50        *prev = iter->iomap;
  51        switch (ret) {
  52        case 0:         /* success */
  53                return iomap_length(iter);
  54        case 1:         /* extent array full */
  55                return 0;
  56        default:        /* error */
  57                return ret;
  58        }
  59}
  60
  61int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi,
  62                u64 start, u64 len, const struct iomap_ops *ops)
  63{
  64        struct iomap_iter iter = {
  65                .inode          = inode,
  66                .pos            = start,
  67                .len            = len,
  68                .flags          = IOMAP_REPORT,
  69        };
  70        struct iomap prev = {
  71                .type           = IOMAP_HOLE,
  72        };
  73        int ret;
  74
  75        ret = fiemap_prep(inode, fi, start, &iter.len, 0);
  76        if (ret)
  77                return ret;
  78
  79        while ((ret = iomap_iter(&iter, ops)) > 0)
  80                iter.processed = iomap_fiemap_iter(&iter, fi, &prev);
  81
  82        if (prev.type != IOMAP_HOLE) {
  83                ret = iomap_to_fiemap(fi, &prev, FIEMAP_EXTENT_LAST);
  84                if (ret < 0)
  85                        return ret;
  86        }
  87
  88        /* inode with no (attribute) mapping will give ENOENT */
  89        if (ret < 0 && ret != -ENOENT)
  90                return ret;
  91        return 0;
  92}
  93EXPORT_SYMBOL_GPL(iomap_fiemap);
  94
  95/* legacy ->bmap interface.  0 is the error return (!) */
  96sector_t
  97iomap_bmap(struct address_space *mapping, sector_t bno,
  98                const struct iomap_ops *ops)
  99{
 100        struct iomap_iter iter = {
 101                .inode  = mapping->host,
 102                .pos    = (loff_t)bno << mapping->host->i_blkbits,
 103                .len    = i_blocksize(mapping->host),
 104                .flags  = IOMAP_REPORT,
 105        };
 106        const unsigned int blkshift = mapping->host->i_blkbits - SECTOR_SHIFT;
 107        int ret;
 108
 109        if (filemap_write_and_wait(mapping))
 110                return 0;
 111
 112        bno = 0;
 113        while ((ret = iomap_iter(&iter, ops)) > 0) {
 114                if (iter.iomap.type == IOMAP_MAPPED)
 115                        bno = iomap_sector(&iter.iomap, iter.pos) >> blkshift;
 116                /* leave iter.processed unset to abort loop */
 117        }
 118        if (ret)
 119                return 0;
 120
 121        return bno;
 122}
 123EXPORT_SYMBOL_GPL(iomap_bmap);
 124