0001
0002
0003
0004
0005 #include <linux/module.h>
0006 #include <linux/compiler.h>
0007 #include <linux/fs.h>
0008 #include <linux/iomap.h>
0009 #include <linux/fiemap.h>
0010 #include <linux/pagemap.h>
0011
0012 static int iomap_to_fiemap(struct fiemap_extent_info *fi,
0013 const struct iomap *iomap, u32 flags)
0014 {
0015 switch (iomap->type) {
0016 case IOMAP_HOLE:
0017
0018 return 0;
0019 case IOMAP_DELALLOC:
0020 flags |= FIEMAP_EXTENT_DELALLOC | FIEMAP_EXTENT_UNKNOWN;
0021 break;
0022 case IOMAP_MAPPED:
0023 break;
0024 case IOMAP_UNWRITTEN:
0025 flags |= FIEMAP_EXTENT_UNWRITTEN;
0026 break;
0027 case IOMAP_INLINE:
0028 flags |= FIEMAP_EXTENT_DATA_INLINE;
0029 break;
0030 }
0031
0032 if (iomap->flags & IOMAP_F_MERGED)
0033 flags |= FIEMAP_EXTENT_MERGED;
0034 if (iomap->flags & IOMAP_F_SHARED)
0035 flags |= FIEMAP_EXTENT_SHARED;
0036
0037 return fiemap_fill_next_extent(fi, iomap->offset,
0038 iomap->addr != IOMAP_NULL_ADDR ? iomap->addr : 0,
0039 iomap->length, flags);
0040 }
0041
0042 static loff_t iomap_fiemap_iter(const struct iomap_iter *iter,
0043 struct fiemap_extent_info *fi, struct iomap *prev)
0044 {
0045 int ret;
0046
0047 if (iter->iomap.type == IOMAP_HOLE)
0048 return iomap_length(iter);
0049
0050 ret = iomap_to_fiemap(fi, prev, 0);
0051 *prev = iter->iomap;
0052 switch (ret) {
0053 case 0:
0054 return iomap_length(iter);
0055 case 1:
0056 return 0;
0057 default:
0058 return ret;
0059 }
0060 }
0061
0062 int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi,
0063 u64 start, u64 len, const struct iomap_ops *ops)
0064 {
0065 struct iomap_iter iter = {
0066 .inode = inode,
0067 .pos = start,
0068 .len = len,
0069 .flags = IOMAP_REPORT,
0070 };
0071 struct iomap prev = {
0072 .type = IOMAP_HOLE,
0073 };
0074 int ret;
0075
0076 ret = fiemap_prep(inode, fi, start, &iter.len, 0);
0077 if (ret)
0078 return ret;
0079
0080 while ((ret = iomap_iter(&iter, ops)) > 0)
0081 iter.processed = iomap_fiemap_iter(&iter, fi, &prev);
0082
0083 if (prev.type != IOMAP_HOLE) {
0084 ret = iomap_to_fiemap(fi, &prev, FIEMAP_EXTENT_LAST);
0085 if (ret < 0)
0086 return ret;
0087 }
0088
0089
0090 if (ret < 0 && ret != -ENOENT)
0091 return ret;
0092 return 0;
0093 }
0094 EXPORT_SYMBOL_GPL(iomap_fiemap);
0095
0096
0097 sector_t
0098 iomap_bmap(struct address_space *mapping, sector_t bno,
0099 const struct iomap_ops *ops)
0100 {
0101 struct iomap_iter iter = {
0102 .inode = mapping->host,
0103 .pos = (loff_t)bno << mapping->host->i_blkbits,
0104 .len = i_blocksize(mapping->host),
0105 .flags = IOMAP_REPORT,
0106 };
0107 const unsigned int blkshift = mapping->host->i_blkbits - SECTOR_SHIFT;
0108 int ret;
0109
0110 if (filemap_write_and_wait(mapping))
0111 return 0;
0112
0113 bno = 0;
0114 while ((ret = iomap_iter(&iter, ops)) > 0) {
0115 if (iter.iomap.type == IOMAP_MAPPED)
0116 bno = iomap_sector(&iter.iomap, iter.pos) >> blkshift;
0117
0118 }
0119 if (ret)
0120 return 0;
0121
0122 return bno;
0123 }
0124 EXPORT_SYMBOL_GPL(iomap_bmap);