1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License version 2 for more details.  A copy is
14  * included in the COPYING file that accompanied this code.
15 
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2011 Intel Corporation
24  *
25  * Copyright 2012 Xyratex Technology Limited
26  */
27 /*
28  * lustre/ptlrpc/nrs_fifo.c
29  *
30  * Network Request Scheduler (NRS) FIFO policy
31  *
32  * Handles RPCs in a FIFO manner, as received from the network. This policy is
33  * a logical wrapper around previous, non-NRS functionality. It is used as the
34  * default and fallback policy for all types of RPCs on all PTLRPC service
35  * partitions, for both regular and high-priority NRS heads. Default here means
36  * the policy is the one enabled at PTLRPC service partition startup time, and
37  * fallback means the policy is used to handle RPCs that are not handled
38  * successfully or are not handled at all by any primary policy that may be
39  * enabled on a given NRS head.
40  *
41  * Author: Liang Zhen <liang@whamcloud.com>
42  * Author: Nikitas Angelinas <nikitas_angelinas@xyratex.com>
43  */
44 /**
45  * \addtogoup nrs
46  * @{
47  */
48 
49 #define DEBUG_SUBSYSTEM S_RPC
50 #include "../include/obd_support.h"
51 #include "../include/obd_class.h"
52 #include "../../include/linux/libcfs/libcfs.h"
53 #include "ptlrpc_internal.h"
54 
55 /**
56  * \name fifo
57  *
58  * The FIFO policy is a logical wrapper around previous, non-NRS functionality.
59  * It schedules RPCs in the same order as they are queued from LNet.
60  *
61  * @{
62  */
63 
64 #define NRS_POL_NAME_FIFO	"fifo"
65 
66 /**
67  * Is called before the policy transitions into
68  * ptlrpc_nrs_pol_state::NRS_POL_STATE_STARTED; allocates and initializes a
69  * policy-specific private data structure.
70  *
71  * \param[in] policy The policy to start
72  *
73  * \retval -ENOMEM OOM error
74  * \retval  0	   success
75  *
76  * \see nrs_policy_register()
77  * \see nrs_policy_ctl()
78  */
nrs_fifo_start(struct ptlrpc_nrs_policy * policy)79 static int nrs_fifo_start(struct ptlrpc_nrs_policy *policy)
80 {
81 	struct nrs_fifo_head *head;
82 
83 	head = kzalloc_node(sizeof(*head), GFP_NOFS,
84 			    cfs_cpt_spread_node(nrs_pol2cptab(policy),
85 						nrs_pol2cptid(policy)));
86 	if (head == NULL)
87 		return -ENOMEM;
88 
89 	INIT_LIST_HEAD(&head->fh_list);
90 	policy->pol_private = head;
91 	return 0;
92 }
93 
94 /**
95  * Is called before the policy transitions into
96  * ptlrpc_nrs_pol_state::NRS_POL_STATE_STOPPED; deallocates the policy-specific
97  * private data structure.
98  *
99  * \param[in] policy The policy to stop
100  *
101  * \see nrs_policy_stop0()
102  */
nrs_fifo_stop(struct ptlrpc_nrs_policy * policy)103 static void nrs_fifo_stop(struct ptlrpc_nrs_policy *policy)
104 {
105 	struct nrs_fifo_head *head = policy->pol_private;
106 
107 	LASSERT(head != NULL);
108 	LASSERT(list_empty(&head->fh_list));
109 
110 	kfree(head);
111 }
112 
113 /**
114  * Is called for obtaining a FIFO policy resource.
115  *
116  * \param[in]  policy	  The policy on which the request is being asked for
117  * \param[in]  nrq	  The request for which resources are being taken
118  * \param[in]  parent	  Parent resource, unused in this policy
119  * \param[out] resp	  Resources references are placed in this array
120  * \param[in]  moving_req Signifies limited caller context; unused in this
121  *			  policy
122  *
123  * \retval 1 The FIFO policy only has a one-level resource hierarchy, as since
124  *	     it implements a simple scheduling algorithm in which request
125  *	     priority is determined on the request arrival order, it does not
126  *	     need to maintain a set of resources that would otherwise be used
127  *	     to calculate a request's priority.
128  *
129  * \see nrs_resource_get_safe()
130  */
nrs_fifo_res_get(struct ptlrpc_nrs_policy * policy,struct ptlrpc_nrs_request * nrq,const struct ptlrpc_nrs_resource * parent,struct ptlrpc_nrs_resource ** resp,bool moving_req)131 static int nrs_fifo_res_get(struct ptlrpc_nrs_policy *policy,
132 			    struct ptlrpc_nrs_request *nrq,
133 			    const struct ptlrpc_nrs_resource *parent,
134 			    struct ptlrpc_nrs_resource **resp, bool moving_req)
135 {
136 	/**
137 	 * Just return the resource embedded inside nrs_fifo_head, and end this
138 	 * resource hierarchy reference request.
139 	 */
140 	*resp = &((struct nrs_fifo_head *)policy->pol_private)->fh_res;
141 	return 1;
142 }
143 
144 /**
145  * Called when getting a request from the FIFO policy for handling, or just
146  * peeking; removes the request from the policy when it is to be handled.
147  *
148  * \param[in] policy The policy
149  * \param[in] peek   When set, signifies that we just want to examine the
150  *		     request, and not handle it, so the request is not removed
151  *		     from the policy.
152  * \param[in] force  Force the policy to return a request; unused in this
153  *		     policy
154  *
155  * \retval The request to be handled; this is the next request in the FIFO
156  *	   queue
157  *
158  * \see ptlrpc_nrs_req_get_nolock()
159  * \see nrs_request_get()
160  */
161 static
nrs_fifo_req_get(struct ptlrpc_nrs_policy * policy,bool peek,bool force)162 struct ptlrpc_nrs_request *nrs_fifo_req_get(struct ptlrpc_nrs_policy *policy,
163 					    bool peek, bool force)
164 {
165 	struct nrs_fifo_head *head = policy->pol_private;
166 	struct ptlrpc_nrs_request *nrq;
167 
168 	nrq = unlikely(list_empty(&head->fh_list)) ? NULL :
169 	      list_entry(head->fh_list.next, struct ptlrpc_nrs_request,
170 			     nr_u.fifo.fr_list);
171 
172 	if (likely(!peek && nrq != NULL)) {
173 		struct ptlrpc_request *req = container_of(nrq,
174 							  struct ptlrpc_request,
175 							  rq_nrq);
176 
177 		list_del_init(&nrq->nr_u.fifo.fr_list);
178 
179 		CDEBUG(D_RPCTRACE, "NRS start %s request from %s, seq: %llu\n",
180 		       policy->pol_desc->pd_name, libcfs_id2str(req->rq_peer),
181 		       nrq->nr_u.fifo.fr_sequence);
182 	}
183 
184 	return nrq;
185 }
186 
187 /**
188  * Adds request \a nrq to \a policy's list of queued requests
189  *
190  * \param[in] policy The policy
191  * \param[in] nrq    The request to add
192  *
193  * \retval 0 success; nrs_request_enqueue() assumes this function will always
194  *		      succeed
195  */
nrs_fifo_req_add(struct ptlrpc_nrs_policy * policy,struct ptlrpc_nrs_request * nrq)196 static int nrs_fifo_req_add(struct ptlrpc_nrs_policy *policy,
197 			    struct ptlrpc_nrs_request *nrq)
198 {
199 	struct nrs_fifo_head *head;
200 
201 	head = container_of(nrs_request_resource(nrq), struct nrs_fifo_head,
202 			    fh_res);
203 	/**
204 	 * Only used for debugging
205 	 */
206 	nrq->nr_u.fifo.fr_sequence = head->fh_sequence++;
207 	list_add_tail(&nrq->nr_u.fifo.fr_list, &head->fh_list);
208 
209 	return 0;
210 }
211 
212 /**
213  * Removes request \a nrq from \a policy's list of queued requests.
214  *
215  * \param[in] policy The policy
216  * \param[in] nrq    The request to remove
217  */
nrs_fifo_req_del(struct ptlrpc_nrs_policy * policy,struct ptlrpc_nrs_request * nrq)218 static void nrs_fifo_req_del(struct ptlrpc_nrs_policy *policy,
219 			     struct ptlrpc_nrs_request *nrq)
220 {
221 	LASSERT(!list_empty(&nrq->nr_u.fifo.fr_list));
222 	list_del_init(&nrq->nr_u.fifo.fr_list);
223 }
224 
225 /**
226  * Prints a debug statement right before the request \a nrq stops being
227  * handled.
228  *
229  * \param[in] policy The policy handling the request
230  * \param[in] nrq    The request being handled
231  *
232  * \see ptlrpc_server_finish_request()
233  * \see ptlrpc_nrs_req_stop_nolock()
234  */
nrs_fifo_req_stop(struct ptlrpc_nrs_policy * policy,struct ptlrpc_nrs_request * nrq)235 static void nrs_fifo_req_stop(struct ptlrpc_nrs_policy *policy,
236 			      struct ptlrpc_nrs_request *nrq)
237 {
238 	struct ptlrpc_request *req = container_of(nrq, struct ptlrpc_request,
239 						  rq_nrq);
240 
241 	CDEBUG(D_RPCTRACE, "NRS stop %s request from %s, seq: %llu\n",
242 	       policy->pol_desc->pd_name, libcfs_id2str(req->rq_peer),
243 	       nrq->nr_u.fifo.fr_sequence);
244 }
245 
246 /**
247  * FIFO policy operations
248  */
249 static const struct ptlrpc_nrs_pol_ops nrs_fifo_ops = {
250 	.op_policy_start	= nrs_fifo_start,
251 	.op_policy_stop		= nrs_fifo_stop,
252 	.op_res_get		= nrs_fifo_res_get,
253 	.op_req_get		= nrs_fifo_req_get,
254 	.op_req_enqueue		= nrs_fifo_req_add,
255 	.op_req_dequeue		= nrs_fifo_req_del,
256 	.op_req_stop		= nrs_fifo_req_stop,
257 };
258 
259 /**
260  * FIFO policy configuration
261  */
262 struct ptlrpc_nrs_pol_conf nrs_conf_fifo = {
263 	.nc_name		= NRS_POL_NAME_FIFO,
264 	.nc_ops			= &nrs_fifo_ops,
265 	.nc_compat		= nrs_policy_compat_all,
266 	.nc_flags		= PTLRPC_NRS_FL_FALLBACK |
267 				  PTLRPC_NRS_FL_REG_START
268 };
269 
270 /** @} fifo */
271 
272 /** @} nrs */
273