Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* Object lifetime handling and tracing.
0003  *
0004  * Copyright (C) 2022 Red Hat, Inc. All Rights Reserved.
0005  * Written by David Howells (dhowells@redhat.com)
0006  */
0007 
0008 #include <linux/slab.h>
0009 #include "internal.h"
0010 
0011 /*
0012  * Allocate an I/O request and initialise it.
0013  */
0014 struct netfs_io_request *netfs_alloc_request(struct address_space *mapping,
0015                          struct file *file,
0016                          loff_t start, size_t len,
0017                          enum netfs_io_origin origin)
0018 {
0019     static atomic_t debug_ids;
0020     struct inode *inode = file ? file_inode(file) : mapping->host;
0021     struct netfs_inode *ctx = netfs_inode(inode);
0022     struct netfs_io_request *rreq;
0023     int ret;
0024 
0025     rreq = kzalloc(sizeof(struct netfs_io_request), GFP_KERNEL);
0026     if (!rreq)
0027         return ERR_PTR(-ENOMEM);
0028 
0029     rreq->start = start;
0030     rreq->len   = len;
0031     rreq->origin    = origin;
0032     rreq->netfs_ops = ctx->ops;
0033     rreq->mapping   = mapping;
0034     rreq->inode = inode;
0035     rreq->i_size    = i_size_read(inode);
0036     rreq->debug_id  = atomic_inc_return(&debug_ids);
0037     INIT_LIST_HEAD(&rreq->subrequests);
0038     refcount_set(&rreq->ref, 1);
0039     __set_bit(NETFS_RREQ_IN_PROGRESS, &rreq->flags);
0040     if (rreq->netfs_ops->init_request) {
0041         ret = rreq->netfs_ops->init_request(rreq, file);
0042         if (ret < 0) {
0043             kfree(rreq);
0044             return ERR_PTR(ret);
0045         }
0046     }
0047 
0048     netfs_stat(&netfs_n_rh_rreq);
0049     return rreq;
0050 }
0051 
0052 void netfs_get_request(struct netfs_io_request *rreq, enum netfs_rreq_ref_trace what)
0053 {
0054     int r;
0055 
0056     __refcount_inc(&rreq->ref, &r);
0057     trace_netfs_rreq_ref(rreq->debug_id, r + 1, what);
0058 }
0059 
0060 void netfs_clear_subrequests(struct netfs_io_request *rreq, bool was_async)
0061 {
0062     struct netfs_io_subrequest *subreq;
0063 
0064     while (!list_empty(&rreq->subrequests)) {
0065         subreq = list_first_entry(&rreq->subrequests,
0066                       struct netfs_io_subrequest, rreq_link);
0067         list_del(&subreq->rreq_link);
0068         netfs_put_subrequest(subreq, was_async,
0069                      netfs_sreq_trace_put_clear);
0070     }
0071 }
0072 
0073 static void netfs_free_request(struct work_struct *work)
0074 {
0075     struct netfs_io_request *rreq =
0076         container_of(work, struct netfs_io_request, work);
0077 
0078     trace_netfs_rreq(rreq, netfs_rreq_trace_free);
0079     netfs_clear_subrequests(rreq, false);
0080     if (rreq->netfs_ops->free_request)
0081         rreq->netfs_ops->free_request(rreq);
0082     if (rreq->cache_resources.ops)
0083         rreq->cache_resources.ops->end_operation(&rreq->cache_resources);
0084     kfree(rreq);
0085     netfs_stat_d(&netfs_n_rh_rreq);
0086 }
0087 
0088 void netfs_put_request(struct netfs_io_request *rreq, bool was_async,
0089                enum netfs_rreq_ref_trace what)
0090 {
0091     unsigned int debug_id = rreq->debug_id;
0092     bool dead;
0093     int r;
0094 
0095     dead = __refcount_dec_and_test(&rreq->ref, &r);
0096     trace_netfs_rreq_ref(debug_id, r - 1, what);
0097     if (dead) {
0098         if (was_async) {
0099             rreq->work.func = netfs_free_request;
0100             if (!queue_work(system_unbound_wq, &rreq->work))
0101                 BUG();
0102         } else {
0103             netfs_free_request(&rreq->work);
0104         }
0105     }
0106 }
0107 
0108 /*
0109  * Allocate and partially initialise an I/O request structure.
0110  */
0111 struct netfs_io_subrequest *netfs_alloc_subrequest(struct netfs_io_request *rreq)
0112 {
0113     struct netfs_io_subrequest *subreq;
0114 
0115     subreq = kzalloc(sizeof(struct netfs_io_subrequest), GFP_KERNEL);
0116     if (subreq) {
0117         INIT_LIST_HEAD(&subreq->rreq_link);
0118         refcount_set(&subreq->ref, 2);
0119         subreq->rreq = rreq;
0120         netfs_get_request(rreq, netfs_rreq_trace_get_subreq);
0121         netfs_stat(&netfs_n_rh_sreq);
0122     }
0123 
0124     return subreq;
0125 }
0126 
0127 void netfs_get_subrequest(struct netfs_io_subrequest *subreq,
0128               enum netfs_sreq_ref_trace what)
0129 {
0130     int r;
0131 
0132     __refcount_inc(&subreq->ref, &r);
0133     trace_netfs_sreq_ref(subreq->rreq->debug_id, subreq->debug_index, r + 1,
0134                  what);
0135 }
0136 
0137 static void netfs_free_subrequest(struct netfs_io_subrequest *subreq,
0138                   bool was_async)
0139 {
0140     struct netfs_io_request *rreq = subreq->rreq;
0141 
0142     trace_netfs_sreq(subreq, netfs_sreq_trace_free);
0143     kfree(subreq);
0144     netfs_stat_d(&netfs_n_rh_sreq);
0145     netfs_put_request(rreq, was_async, netfs_rreq_trace_put_subreq);
0146 }
0147 
0148 void netfs_put_subrequest(struct netfs_io_subrequest *subreq, bool was_async,
0149               enum netfs_sreq_ref_trace what)
0150 {
0151     unsigned int debug_index = subreq->debug_index;
0152     unsigned int debug_id = subreq->rreq->debug_id;
0153     bool dead;
0154     int r;
0155 
0156     dead = __refcount_dec_and_test(&subreq->ref, &r);
0157     trace_netfs_sreq_ref(debug_id, debug_index, r - 1, what);
0158     if (dead)
0159         netfs_free_subrequest(subreq, was_async);
0160 }