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