seek.c 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2017 Red Hat, Inc.
  4. * Copyright (c) 2018-2021 Christoph Hellwig.
  5. */
  6. #include <linux/iomap.h>
  7. #include <linux/pagemap.h>
  8. static int iomap_seek_hole_iter(struct iomap_iter *iter,
  9. loff_t *hole_pos)
  10. {
  11. loff_t length = iomap_length(iter);
  12. switch (iter->iomap.type) {
  13. case IOMAP_UNWRITTEN:
  14. *hole_pos = mapping_seek_hole_data(iter->inode->i_mapping,
  15. iter->pos, iter->pos + length, SEEK_HOLE);
  16. if (*hole_pos == iter->pos + length)
  17. return iomap_iter_advance(iter, length);
  18. return 0;
  19. case IOMAP_HOLE:
  20. *hole_pos = iter->pos;
  21. return 0;
  22. default:
  23. return iomap_iter_advance(iter, length);
  24. }
  25. }
  26. loff_t
  27. iomap_seek_hole(struct inode *inode, loff_t pos, const struct iomap_ops *ops)
  28. {
  29. loff_t size = i_size_read(inode);
  30. struct iomap_iter iter = {
  31. .inode = inode,
  32. .pos = pos,
  33. .flags = IOMAP_REPORT,
  34. };
  35. int ret;
  36. /* Nothing to be found before or beyond the end of the file. */
  37. if (pos < 0 || pos >= size)
  38. return -ENXIO;
  39. iter.len = size - pos;
  40. while ((ret = iomap_iter(&iter, ops)) > 0)
  41. iter.status = iomap_seek_hole_iter(&iter, &pos);
  42. if (ret < 0)
  43. return ret;
  44. if (iter.len) /* found hole before EOF */
  45. return pos;
  46. return size;
  47. }
  48. EXPORT_SYMBOL_GPL(iomap_seek_hole);
  49. static int iomap_seek_data_iter(struct iomap_iter *iter,
  50. loff_t *hole_pos)
  51. {
  52. loff_t length = iomap_length(iter);
  53. switch (iter->iomap.type) {
  54. case IOMAP_HOLE:
  55. return iomap_iter_advance(iter, length);
  56. case IOMAP_UNWRITTEN:
  57. *hole_pos = mapping_seek_hole_data(iter->inode->i_mapping,
  58. iter->pos, iter->pos + length, SEEK_DATA);
  59. if (*hole_pos < 0)
  60. return iomap_iter_advance(iter, length);
  61. return 0;
  62. default:
  63. *hole_pos = iter->pos;
  64. return 0;
  65. }
  66. }
  67. loff_t
  68. iomap_seek_data(struct inode *inode, loff_t pos, const struct iomap_ops *ops)
  69. {
  70. loff_t size = i_size_read(inode);
  71. struct iomap_iter iter = {
  72. .inode = inode,
  73. .pos = pos,
  74. .flags = IOMAP_REPORT,
  75. };
  76. int ret;
  77. /* Nothing to be found before or beyond the end of the file. */
  78. if (pos < 0 || pos >= size)
  79. return -ENXIO;
  80. iter.len = size - pos;
  81. while ((ret = iomap_iter(&iter, ops)) > 0)
  82. iter.status = iomap_seek_data_iter(&iter, &pos);
  83. if (ret < 0)
  84. return ret;
  85. if (iter.len) /* found data before EOF */
  86. return pos;
  87. /* We've reached the end of the file without finding data */
  88. return -ENXIO;
  89. }
  90. EXPORT_SYMBOL_GPL(iomap_seek_data);