0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/slab.h>
0009 #include "internal.h"
0010
0011
0012
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
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 }