linux/fs/iomap/fiemap.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2016-2018 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
  11struct fiemap_ctx {
  12        struct fiemap_extent_info *fi;
  13        struct iomap prev;
  14};
  15
  16static int iomap_to_fiemap(struct fiemap_extent_info *fi,
  17                struct iomap *iomap, u32 flags)
  18{
  19        switch (iomap->type) {
  20        case IOMAP_HOLE:
  21                /* skip holes */
  22                return 0;
  23        case IOMAP_DELALLOC:
  24                flags |= FIEMAP_EXTENT_DELALLOC | FIEMAP_EXTENT_UNKNOWN;
  25                break;
  26        case IOMAP_MAPPED:
  27                break;
  28        case IOMAP_UNWRITTEN:
  29                flags |= FIEMAP_EXTENT_UNWRITTEN;
  30                break;
  31        case IOMAP_INLINE:
  32                flags |= FIEMAP_EXTENT_DATA_INLINE;
  33                break;
  34        }
  35
  36        if (iomap->flags & IOMAP_F_MERGED)
  37                flags |= FIEMAP_EXTENT_MERGED;
  38        if (iomap->flags & IOMAP_F_SHARED)
  39                flags |= FIEMAP_EXTENT_SHARED;
  40
  41        return fiemap_fill_next_extent(fi, iomap->offset,
  42                        iomap->addr != IOMAP_NULL_ADDR ? iomap->addr : 0,
  43                        iomap->length, flags);
  44}
  45
  46static loff_t
  47iomap_fiemap_actor(struct inode *inode, loff_t pos, loff_t length, void *data,
  48                struct iomap *iomap, struct iomap *srcmap)
  49{
  50        struct fiemap_ctx *ctx = data;
  51        loff_t ret = length;
  52
  53        if (iomap->type == IOMAP_HOLE)
  54                return length;
  55
  56        ret = iomap_to_fiemap(ctx->fi, &ctx->prev, 0);
  57        ctx->prev = *iomap;
  58        switch (ret) {
  59        case 0:         /* success */
  60                return length;
  61        case 1:         /* extent array full */
  62                return 0;
  63        default:
  64                return ret;
  65        }
  66}
  67
  68int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi,
  69                u64 start, u64 len, const struct iomap_ops *ops)
  70{
  71        struct fiemap_ctx ctx;
  72        loff_t ret;
  73
  74        memset(&ctx, 0, sizeof(ctx));
  75        ctx.fi = fi;
  76        ctx.prev.type = IOMAP_HOLE;
  77
  78        ret = fiemap_prep(inode, fi, start, &len, 0);
  79        if (ret)
  80                return ret;
  81
  82        while (len > 0) {
  83                ret = iomap_apply(inode, start, len, IOMAP_REPORT, ops, &ctx,
  84                                iomap_fiemap_actor);
  85                /* inode with no (attribute) mapping will give ENOENT */
  86                if (ret == -ENOENT)
  87                        break;
  88                if (ret < 0)
  89                        return ret;
  90                if (ret == 0)
  91                        break;
  92
  93                start += ret;
  94                len -= ret;
  95        }
  96
  97        if (ctx.prev.type != IOMAP_HOLE) {
  98                ret = iomap_to_fiemap(fi, &ctx.prev, FIEMAP_EXTENT_LAST);
  99                if (ret < 0)
 100                        return ret;
 101        }
 102
 103        return 0;
 104}
 105EXPORT_SYMBOL_GPL(iomap_fiemap);
 106
 107static loff_t
 108iomap_bmap_actor(struct inode *inode, loff_t pos, loff_t length,
 109                void *data, struct iomap *iomap, struct iomap *srcmap)
 110{
 111        sector_t *bno = data, addr;
 112
 113        if (iomap->type == IOMAP_MAPPED) {
 114                addr = (pos - iomap->offset + iomap->addr) >> inode->i_blkbits;
 115                *bno = addr;
 116        }
 117        return 0;
 118}
 119
 120/* legacy ->bmap interface.  0 is the error return (!) */
 121sector_t
 122iomap_bmap(struct address_space *mapping, sector_t bno,
 123                const struct iomap_ops *ops)
 124{
 125        struct inode *inode = mapping->host;
 126        loff_t pos = bno << inode->i_blkbits;
 127        unsigned blocksize = i_blocksize(inode);
 128        int ret;
 129
 130        if (filemap_write_and_wait(mapping))
 131                return 0;
 132
 133        bno = 0;
 134        ret = iomap_apply(inode, pos, blocksize, 0, ops, &bno,
 135                          iomap_bmap_actor);
 136        if (ret)
 137                return 0;
 138        return bno;
 139}
 140EXPORT_SYMBOL_GPL(iomap_bmap);
 141