objects.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* Object lifetime handling and tracing.
  3. *
  4. * Copyright (C) 2022 Red Hat, Inc. All Rights Reserved.
  5. * Written by David Howells (dhowells@redhat.com)
  6. */
  7. #include <linux/slab.h>
  8. #include <linux/mempool.h>
  9. #include <linux/delay.h>
  10. #include "internal.h"
  11. /*
  12. * Allocate an I/O request and initialise it.
  13. */
  14. struct netfs_io_request *netfs_alloc_request(struct address_space *mapping,
  15. struct file *file,
  16. loff_t start, size_t len,
  17. enum netfs_io_origin origin)
  18. {
  19. static atomic_t debug_ids;
  20. struct inode *inode = file ? file_inode(file) : mapping->host;
  21. struct netfs_inode *ctx = netfs_inode(inode);
  22. struct netfs_io_request *rreq;
  23. mempool_t *mempool = ctx->ops->request_pool ?: &netfs_request_pool;
  24. struct kmem_cache *cache = mempool->pool_data;
  25. int ret;
  26. for (;;) {
  27. rreq = mempool_alloc(mempool, GFP_KERNEL);
  28. if (rreq)
  29. break;
  30. msleep(10);
  31. }
  32. memset(rreq, 0, kmem_cache_size(cache));
  33. rreq->start = start;
  34. rreq->len = len;
  35. rreq->origin = origin;
  36. rreq->netfs_ops = ctx->ops;
  37. rreq->mapping = mapping;
  38. rreq->inode = inode;
  39. rreq->i_size = i_size_read(inode);
  40. rreq->debug_id = atomic_inc_return(&debug_ids);
  41. rreq->wsize = INT_MAX;
  42. rreq->io_streams[0].sreq_max_len = ULONG_MAX;
  43. rreq->io_streams[0].sreq_max_segs = 0;
  44. spin_lock_init(&rreq->lock);
  45. INIT_LIST_HEAD(&rreq->io_streams[0].subrequests);
  46. INIT_LIST_HEAD(&rreq->io_streams[1].subrequests);
  47. INIT_LIST_HEAD(&rreq->subrequests);
  48. refcount_set(&rreq->ref, 1);
  49. if (origin == NETFS_READAHEAD ||
  50. origin == NETFS_READPAGE ||
  51. origin == NETFS_READ_GAPS ||
  52. origin == NETFS_READ_FOR_WRITE ||
  53. origin == NETFS_DIO_READ)
  54. INIT_WORK(&rreq->work, netfs_read_termination_worker);
  55. else
  56. INIT_WORK(&rreq->work, netfs_write_collection_worker);
  57. __set_bit(NETFS_RREQ_IN_PROGRESS, &rreq->flags);
  58. if (file && file->f_flags & O_NONBLOCK)
  59. __set_bit(NETFS_RREQ_NONBLOCK, &rreq->flags);
  60. if (rreq->netfs_ops->init_request) {
  61. ret = rreq->netfs_ops->init_request(rreq, file);
  62. if (ret < 0) {
  63. mempool_free(rreq, rreq->netfs_ops->request_pool ?: &netfs_request_pool);
  64. return ERR_PTR(ret);
  65. }
  66. }
  67. atomic_inc(&ctx->io_count);
  68. trace_netfs_rreq_ref(rreq->debug_id, 1, netfs_rreq_trace_new);
  69. netfs_proc_add_rreq(rreq);
  70. netfs_stat(&netfs_n_rh_rreq);
  71. return rreq;
  72. }
  73. void netfs_get_request(struct netfs_io_request *rreq, enum netfs_rreq_ref_trace what)
  74. {
  75. int r;
  76. __refcount_inc(&rreq->ref, &r);
  77. trace_netfs_rreq_ref(rreq->debug_id, r + 1, what);
  78. }
  79. void netfs_clear_subrequests(struct netfs_io_request *rreq, bool was_async)
  80. {
  81. struct netfs_io_subrequest *subreq;
  82. struct netfs_io_stream *stream;
  83. int s;
  84. while (!list_empty(&rreq->subrequests)) {
  85. subreq = list_first_entry(&rreq->subrequests,
  86. struct netfs_io_subrequest, rreq_link);
  87. list_del(&subreq->rreq_link);
  88. netfs_put_subrequest(subreq, was_async,
  89. netfs_sreq_trace_put_clear);
  90. }
  91. for (s = 0; s < ARRAY_SIZE(rreq->io_streams); s++) {
  92. stream = &rreq->io_streams[s];
  93. while (!list_empty(&stream->subrequests)) {
  94. subreq = list_first_entry(&stream->subrequests,
  95. struct netfs_io_subrequest, rreq_link);
  96. list_del(&subreq->rreq_link);
  97. netfs_put_subrequest(subreq, was_async,
  98. netfs_sreq_trace_put_clear);
  99. }
  100. }
  101. }
  102. static void netfs_free_request_rcu(struct rcu_head *rcu)
  103. {
  104. struct netfs_io_request *rreq = container_of(rcu, struct netfs_io_request, rcu);
  105. mempool_free(rreq, rreq->netfs_ops->request_pool ?: &netfs_request_pool);
  106. netfs_stat_d(&netfs_n_rh_rreq);
  107. }
  108. static void netfs_free_request(struct work_struct *work)
  109. {
  110. struct netfs_io_request *rreq =
  111. container_of(work, struct netfs_io_request, work);
  112. struct netfs_inode *ictx = netfs_inode(rreq->inode);
  113. unsigned int i;
  114. trace_netfs_rreq(rreq, netfs_rreq_trace_free);
  115. netfs_proc_del_rreq(rreq);
  116. netfs_clear_subrequests(rreq, false);
  117. if (rreq->netfs_ops->free_request)
  118. rreq->netfs_ops->free_request(rreq);
  119. if (rreq->cache_resources.ops)
  120. rreq->cache_resources.ops->end_operation(&rreq->cache_resources);
  121. if (rreq->direct_bv) {
  122. for (i = 0; i < rreq->direct_bv_count; i++) {
  123. if (rreq->direct_bv[i].bv_page) {
  124. if (rreq->direct_bv_unpin)
  125. unpin_user_page(rreq->direct_bv[i].bv_page);
  126. }
  127. }
  128. kvfree(rreq->direct_bv);
  129. }
  130. netfs_clear_buffer(rreq);
  131. if (atomic_dec_and_test(&ictx->io_count))
  132. wake_up_var(&ictx->io_count);
  133. call_rcu(&rreq->rcu, netfs_free_request_rcu);
  134. }
  135. void netfs_put_request(struct netfs_io_request *rreq, bool was_async,
  136. enum netfs_rreq_ref_trace what)
  137. {
  138. unsigned int debug_id;
  139. bool dead;
  140. int r;
  141. if (rreq) {
  142. debug_id = rreq->debug_id;
  143. dead = __refcount_dec_and_test(&rreq->ref, &r);
  144. trace_netfs_rreq_ref(debug_id, r - 1, what);
  145. if (dead) {
  146. if (was_async) {
  147. rreq->work.func = netfs_free_request;
  148. if (!queue_work(system_unbound_wq, &rreq->work))
  149. WARN_ON(1);
  150. } else {
  151. netfs_free_request(&rreq->work);
  152. }
  153. }
  154. }
  155. }
  156. /*
  157. * Allocate and partially initialise an I/O request structure.
  158. */
  159. struct netfs_io_subrequest *netfs_alloc_subrequest(struct netfs_io_request *rreq)
  160. {
  161. struct netfs_io_subrequest *subreq;
  162. mempool_t *mempool = rreq->netfs_ops->subrequest_pool ?: &netfs_subrequest_pool;
  163. struct kmem_cache *cache = mempool->pool_data;
  164. for (;;) {
  165. subreq = mempool_alloc(rreq->netfs_ops->subrequest_pool ?: &netfs_subrequest_pool,
  166. GFP_KERNEL);
  167. if (subreq)
  168. break;
  169. msleep(10);
  170. }
  171. memset(subreq, 0, kmem_cache_size(cache));
  172. INIT_WORK(&subreq->work, NULL);
  173. INIT_LIST_HEAD(&subreq->rreq_link);
  174. refcount_set(&subreq->ref, 2);
  175. subreq->rreq = rreq;
  176. subreq->debug_index = atomic_inc_return(&rreq->subreq_counter);
  177. netfs_get_request(rreq, netfs_rreq_trace_get_subreq);
  178. netfs_stat(&netfs_n_rh_sreq);
  179. return subreq;
  180. }
  181. void netfs_get_subrequest(struct netfs_io_subrequest *subreq,
  182. enum netfs_sreq_ref_trace what)
  183. {
  184. int r;
  185. __refcount_inc(&subreq->ref, &r);
  186. trace_netfs_sreq_ref(subreq->rreq->debug_id, subreq->debug_index, r + 1,
  187. what);
  188. }
  189. static void netfs_free_subrequest(struct netfs_io_subrequest *subreq,
  190. bool was_async)
  191. {
  192. struct netfs_io_request *rreq = subreq->rreq;
  193. trace_netfs_sreq(subreq, netfs_sreq_trace_free);
  194. if (rreq->netfs_ops->free_subrequest)
  195. rreq->netfs_ops->free_subrequest(subreq);
  196. mempool_free(subreq, rreq->netfs_ops->subrequest_pool ?: &netfs_subrequest_pool);
  197. netfs_stat_d(&netfs_n_rh_sreq);
  198. netfs_put_request(rreq, was_async, netfs_rreq_trace_put_subreq);
  199. }
  200. void netfs_put_subrequest(struct netfs_io_subrequest *subreq, bool was_async,
  201. enum netfs_sreq_ref_trace what)
  202. {
  203. unsigned int debug_index = subreq->debug_index;
  204. unsigned int debug_id = subreq->rreq->debug_id;
  205. bool dead;
  206. int r;
  207. dead = __refcount_dec_and_test(&subreq->ref, &r);
  208. trace_netfs_sreq_ref(debug_id, debug_index, r - 1, what);
  209. if (dead)
  210. netfs_free_subrequest(subreq, was_async);
  211. }