~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/netfs/objects.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php