0001
0002
0003
0004
0005
0006 #include <linux/module.h>
0007 #include <linux/compiler.h>
0008 #include <linux/fs.h>
0009 #include <linux/iomap.h>
0010 #include <linux/pagemap.h>
0011 #include <linux/pagevec.h>
0012
0013 static loff_t iomap_seek_hole_iter(const struct iomap_iter *iter,
0014 loff_t *hole_pos)
0015 {
0016 loff_t length = iomap_length(iter);
0017
0018 switch (iter->iomap.type) {
0019 case IOMAP_UNWRITTEN:
0020 *hole_pos = mapping_seek_hole_data(iter->inode->i_mapping,
0021 iter->pos, iter->pos + length, SEEK_HOLE);
0022 if (*hole_pos == iter->pos + length)
0023 return length;
0024 return 0;
0025 case IOMAP_HOLE:
0026 *hole_pos = iter->pos;
0027 return 0;
0028 default:
0029 return length;
0030 }
0031 }
0032
0033 loff_t
0034 iomap_seek_hole(struct inode *inode, loff_t pos, const struct iomap_ops *ops)
0035 {
0036 loff_t size = i_size_read(inode);
0037 struct iomap_iter iter = {
0038 .inode = inode,
0039 .pos = pos,
0040 .flags = IOMAP_REPORT,
0041 };
0042 int ret;
0043
0044
0045 if (pos < 0 || pos >= size)
0046 return -ENXIO;
0047
0048 iter.len = size - pos;
0049 while ((ret = iomap_iter(&iter, ops)) > 0)
0050 iter.processed = iomap_seek_hole_iter(&iter, &pos);
0051 if (ret < 0)
0052 return ret;
0053 if (iter.len)
0054 return pos;
0055 return size;
0056 }
0057 EXPORT_SYMBOL_GPL(iomap_seek_hole);
0058
0059 static loff_t iomap_seek_data_iter(const struct iomap_iter *iter,
0060 loff_t *hole_pos)
0061 {
0062 loff_t length = iomap_length(iter);
0063
0064 switch (iter->iomap.type) {
0065 case IOMAP_HOLE:
0066 return length;
0067 case IOMAP_UNWRITTEN:
0068 *hole_pos = mapping_seek_hole_data(iter->inode->i_mapping,
0069 iter->pos, iter->pos + length, SEEK_DATA);
0070 if (*hole_pos < 0)
0071 return length;
0072 return 0;
0073 default:
0074 *hole_pos = iter->pos;
0075 return 0;
0076 }
0077 }
0078
0079 loff_t
0080 iomap_seek_data(struct inode *inode, loff_t pos, const struct iomap_ops *ops)
0081 {
0082 loff_t size = i_size_read(inode);
0083 struct iomap_iter iter = {
0084 .inode = inode,
0085 .pos = pos,
0086 .flags = IOMAP_REPORT,
0087 };
0088 int ret;
0089
0090
0091 if (pos < 0 || pos >= size)
0092 return -ENXIO;
0093
0094 iter.len = size - pos;
0095 while ((ret = iomap_iter(&iter, ops)) > 0)
0096 iter.processed = iomap_seek_data_iter(&iter, &pos);
0097 if (ret < 0)
0098 return ret;
0099 if (iter.len)
0100 return pos;
0101
0102 return -ENXIO;
0103 }
0104 EXPORT_SYMBOL_GPL(iomap_seek_data);