locking.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * I/O and data path helper functionality.
  4. *
  5. * Borrowed from NFS Copyright (c) 2016 Trond Myklebust
  6. */
  7. #include <linux/kernel.h>
  8. #include <linux/netfs.h>
  9. #include "internal.h"
  10. /*
  11. * inode_dio_wait_interruptible - wait for outstanding DIO requests to finish
  12. * @inode: inode to wait for
  13. *
  14. * Waits for all pending direct I/O requests to finish so that we can
  15. * proceed with a truncate or equivalent operation.
  16. *
  17. * Must be called under a lock that serializes taking new references
  18. * to i_dio_count, usually by inode->i_mutex.
  19. */
  20. static int netfs_inode_dio_wait_interruptible(struct inode *inode)
  21. {
  22. if (inode_dio_finished(inode))
  23. return 0;
  24. inode_dio_wait_interruptible(inode);
  25. return !inode_dio_finished(inode) ? -ERESTARTSYS : 0;
  26. }
  27. /* Call with exclusively locked inode->i_rwsem */
  28. static int netfs_block_o_direct(struct netfs_inode *ictx)
  29. {
  30. if (!test_bit(NETFS_ICTX_ODIRECT, &ictx->flags))
  31. return 0;
  32. clear_bit(NETFS_ICTX_ODIRECT, &ictx->flags);
  33. return netfs_inode_dio_wait_interruptible(&ictx->inode);
  34. }
  35. /**
  36. * netfs_start_io_read - declare the file is being used for buffered reads
  37. * @inode: file inode
  38. *
  39. * Declare that a buffered read operation is about to start, and ensure
  40. * that we block all direct I/O.
  41. * On exit, the function ensures that the NETFS_ICTX_ODIRECT flag is unset,
  42. * and holds a shared lock on inode->i_rwsem to ensure that the flag
  43. * cannot be changed.
  44. * In practice, this means that buffered read operations are allowed to
  45. * execute in parallel, thanks to the shared lock, whereas direct I/O
  46. * operations need to wait to grab an exclusive lock in order to set
  47. * NETFS_ICTX_ODIRECT.
  48. * Note that buffered writes and truncates both take a write lock on
  49. * inode->i_rwsem, meaning that those are serialised w.r.t. the reads.
  50. */
  51. int netfs_start_io_read(struct inode *inode)
  52. __acquires(inode->i_rwsem)
  53. {
  54. struct netfs_inode *ictx = netfs_inode(inode);
  55. /* Be an optimist! */
  56. if (down_read_interruptible(&inode->i_rwsem) < 0)
  57. return -ERESTARTSYS;
  58. if (test_bit(NETFS_ICTX_ODIRECT, &ictx->flags) == 0)
  59. return 0;
  60. up_read(&inode->i_rwsem);
  61. /* Slow path.... */
  62. if (down_write_killable(&inode->i_rwsem) < 0)
  63. return -ERESTARTSYS;
  64. if (netfs_block_o_direct(ictx) < 0) {
  65. up_write(&inode->i_rwsem);
  66. return -ERESTARTSYS;
  67. }
  68. downgrade_write(&inode->i_rwsem);
  69. return 0;
  70. }
  71. EXPORT_SYMBOL(netfs_start_io_read);
  72. /**
  73. * netfs_end_io_read - declare that the buffered read operation is done
  74. * @inode: file inode
  75. *
  76. * Declare that a buffered read operation is done, and release the shared
  77. * lock on inode->i_rwsem.
  78. */
  79. void netfs_end_io_read(struct inode *inode)
  80. __releases(inode->i_rwsem)
  81. {
  82. up_read(&inode->i_rwsem);
  83. }
  84. EXPORT_SYMBOL(netfs_end_io_read);
  85. /**
  86. * netfs_start_io_write - declare the file is being used for buffered writes
  87. * @inode: file inode
  88. *
  89. * Declare that a buffered read operation is about to start, and ensure
  90. * that we block all direct I/O.
  91. */
  92. int netfs_start_io_write(struct inode *inode)
  93. __acquires(inode->i_rwsem)
  94. {
  95. struct netfs_inode *ictx = netfs_inode(inode);
  96. if (down_write_killable(&inode->i_rwsem) < 0)
  97. return -ERESTARTSYS;
  98. if (netfs_block_o_direct(ictx) < 0) {
  99. up_write(&inode->i_rwsem);
  100. return -ERESTARTSYS;
  101. }
  102. downgrade_write(&inode->i_rwsem);
  103. return 0;
  104. }
  105. EXPORT_SYMBOL(netfs_start_io_write);
  106. /**
  107. * netfs_end_io_write - declare that the buffered write operation is done
  108. * @inode: file inode
  109. *
  110. * Declare that a buffered write operation is done, and release the
  111. * lock on inode->i_rwsem.
  112. */
  113. void netfs_end_io_write(struct inode *inode)
  114. __releases(inode->i_rwsem)
  115. {
  116. up_read(&inode->i_rwsem);
  117. }
  118. EXPORT_SYMBOL(netfs_end_io_write);
  119. /* Call with exclusively locked inode->i_rwsem */
  120. static int netfs_block_buffered(struct inode *inode)
  121. {
  122. struct netfs_inode *ictx = netfs_inode(inode);
  123. int ret;
  124. if (!test_bit(NETFS_ICTX_ODIRECT, &ictx->flags)) {
  125. set_bit(NETFS_ICTX_ODIRECT, &ictx->flags);
  126. if (inode->i_mapping->nrpages != 0) {
  127. unmap_mapping_range(inode->i_mapping, 0, 0, 0);
  128. ret = filemap_fdatawait(inode->i_mapping);
  129. if (ret < 0) {
  130. clear_bit(NETFS_ICTX_ODIRECT, &ictx->flags);
  131. return ret;
  132. }
  133. }
  134. }
  135. return 0;
  136. }
  137. /**
  138. * netfs_start_io_direct - declare the file is being used for direct i/o
  139. * @inode: file inode
  140. *
  141. * Declare that a direct I/O operation is about to start, and ensure
  142. * that we block all buffered I/O.
  143. * On exit, the function ensures that the NETFS_ICTX_ODIRECT flag is set,
  144. * and holds a shared lock on inode->i_rwsem to ensure that the flag
  145. * cannot be changed.
  146. * In practice, this means that direct I/O operations are allowed to
  147. * execute in parallel, thanks to the shared lock, whereas buffered I/O
  148. * operations need to wait to grab an exclusive lock in order to clear
  149. * NETFS_ICTX_ODIRECT.
  150. * Note that buffered writes and truncates both take a write lock on
  151. * inode->i_rwsem, meaning that those are serialised w.r.t. O_DIRECT.
  152. */
  153. int netfs_start_io_direct(struct inode *inode)
  154. __acquires(inode->i_rwsem)
  155. {
  156. struct netfs_inode *ictx = netfs_inode(inode);
  157. int ret;
  158. /* Be an optimist! */
  159. if (down_read_interruptible(&inode->i_rwsem) < 0)
  160. return -ERESTARTSYS;
  161. if (test_bit(NETFS_ICTX_ODIRECT, &ictx->flags) != 0)
  162. return 0;
  163. up_read(&inode->i_rwsem);
  164. /* Slow path.... */
  165. if (down_write_killable(&inode->i_rwsem) < 0)
  166. return -ERESTARTSYS;
  167. ret = netfs_block_buffered(inode);
  168. if (ret < 0) {
  169. up_write(&inode->i_rwsem);
  170. return ret;
  171. }
  172. downgrade_write(&inode->i_rwsem);
  173. return 0;
  174. }
  175. EXPORT_SYMBOL(netfs_start_io_direct);
  176. /**
  177. * netfs_end_io_direct - declare that the direct i/o operation is done
  178. * @inode: file inode
  179. *
  180. * Declare that a direct I/O operation is done, and release the shared
  181. * lock on inode->i_rwsem.
  182. */
  183. void netfs_end_io_direct(struct inode *inode)
  184. __releases(inode->i_rwsem)
  185. {
  186. up_read(&inode->i_rwsem);
  187. }
  188. EXPORT_SYMBOL(netfs_end_io_direct);