|
@@ -584,6 +584,100 @@ int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi,
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(iomap_fiemap);
|
|
|
|
|
|
+static loff_t
|
|
|
+iomap_seek_hole_actor(struct inode *inode, loff_t offset, loff_t length,
|
|
|
+ void *data, struct iomap *iomap)
|
|
|
+{
|
|
|
+ switch (iomap->type) {
|
|
|
+ case IOMAP_UNWRITTEN:
|
|
|
+ offset = page_cache_seek_hole_data(inode, offset, length,
|
|
|
+ SEEK_HOLE);
|
|
|
+ if (offset < 0)
|
|
|
+ return length;
|
|
|
+ /* fall through */
|
|
|
+ case IOMAP_HOLE:
|
|
|
+ *(loff_t *)data = offset;
|
|
|
+ return 0;
|
|
|
+ default:
|
|
|
+ return length;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+loff_t
|
|
|
+iomap_seek_hole(struct inode *inode, loff_t offset, const struct iomap_ops *ops)
|
|
|
+{
|
|
|
+ loff_t size = i_size_read(inode);
|
|
|
+ loff_t length = size - offset;
|
|
|
+ loff_t ret;
|
|
|
+
|
|
|
+ /* Nothing to be found beyond the end of the file. */
|
|
|
+ if (offset >= size)
|
|
|
+ return -ENXIO;
|
|
|
+
|
|
|
+ while (length > 0) {
|
|
|
+ ret = iomap_apply(inode, offset, length, IOMAP_REPORT, ops,
|
|
|
+ &offset, iomap_seek_hole_actor);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+ if (ret == 0)
|
|
|
+ break;
|
|
|
+
|
|
|
+ offset += ret;
|
|
|
+ length -= ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ return offset;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(iomap_seek_hole);
|
|
|
+
|
|
|
+static loff_t
|
|
|
+iomap_seek_data_actor(struct inode *inode, loff_t offset, loff_t length,
|
|
|
+ void *data, struct iomap *iomap)
|
|
|
+{
|
|
|
+ switch (iomap->type) {
|
|
|
+ case IOMAP_HOLE:
|
|
|
+ return length;
|
|
|
+ case IOMAP_UNWRITTEN:
|
|
|
+ offset = page_cache_seek_hole_data(inode, offset, length,
|
|
|
+ SEEK_DATA);
|
|
|
+ if (offset < 0)
|
|
|
+ return length;
|
|
|
+ /*FALLTHRU*/
|
|
|
+ default:
|
|
|
+ *(loff_t *)data = offset;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+loff_t
|
|
|
+iomap_seek_data(struct inode *inode, loff_t offset, const struct iomap_ops *ops)
|
|
|
+{
|
|
|
+ loff_t size = i_size_read(inode);
|
|
|
+ loff_t length = size - offset;
|
|
|
+ loff_t ret;
|
|
|
+
|
|
|
+ /* Nothing to be found beyond the end of the file. */
|
|
|
+ if (offset >= size)
|
|
|
+ return -ENXIO;
|
|
|
+
|
|
|
+ while (length > 0) {
|
|
|
+ ret = iomap_apply(inode, offset, length, IOMAP_REPORT, ops,
|
|
|
+ &offset, iomap_seek_data_actor);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+ if (ret == 0)
|
|
|
+ break;
|
|
|
+
|
|
|
+ offset += ret;
|
|
|
+ length -= ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (length <= 0)
|
|
|
+ return -ENXIO;
|
|
|
+ return offset;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(iomap_seek_data);
|
|
|
+
|
|
|
/*
|
|
|
* Private flags for iomap_dio, must not overlap with the public ones in
|
|
|
* iomap.h:
|