1 |
/* $MidnightBSD$ */ |
2 |
/*- |
3 |
* Copyright (c) 2009-2010 Fabio Checconi |
4 |
* Copyright (c) 2009-2010 Luigi Rizzo, Universita` di Pisa |
5 |
* All rights reserved. |
6 |
* |
7 |
* Redistribution and use in source and binary forms, with or without |
8 |
* modification, are permitted provided that the following conditions |
9 |
* are met: |
10 |
* 1. Redistributions of source code must retain the above copyright |
11 |
* notice, this list of conditions and the following disclaimer. |
12 |
* 2. Redistributions in binary form must reproduce the above copyright |
13 |
* notice, this list of conditions and the following disclaimer in the |
14 |
* documentation and/or other materials provided with the distribution. |
15 |
* |
16 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND |
17 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
18 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
19 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE |
20 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
21 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
22 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
23 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
24 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
25 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
26 |
* SUCH DAMAGE. |
27 |
*/ |
28 |
|
29 |
/* |
30 |
* $Id$ |
31 |
* $FreeBSD: stable/10/sys/geom/sched/gs_scheduler.h 218909 2011-02-21 09:01:34Z brucec $ |
32 |
* |
33 |
* Prototypes for GEOM-based disk scheduling algorithms. |
34 |
* See g_sched.c for generic documentation. |
35 |
* |
36 |
* This file is used by the kernel modules implementing the various |
37 |
* scheduling algorithms. They should provide all the methods |
38 |
* defined in struct g_gsched, and also invoke the macro |
39 |
* DECLARE_GSCHED_MODULE |
40 |
* which registers the scheduling algorithm with the geom_sched module. |
41 |
* |
42 |
* The various scheduling algorithms do not need to know anything |
43 |
* about geom, they only need to handle the 'bio' requests they |
44 |
* receive, pass them down when needed, and use the locking interface |
45 |
* defined below. |
46 |
*/ |
47 |
|
48 |
#ifndef _G_GSCHED_H_ |
49 |
#define _G_GSCHED_H_ |
50 |
|
51 |
#ifdef _KERNEL |
52 |
#include <sys/param.h> |
53 |
#include <sys/kernel.h> |
54 |
#include <sys/ktr.h> |
55 |
#include <sys/module.h> |
56 |
#include <sys/queue.h> |
57 |
#include <geom/geom.h> |
58 |
#include "g_sched.h" |
59 |
|
60 |
/* |
61 |
* This is the interface exported to scheduling modules. |
62 |
* |
63 |
* gs_init() is called when our scheduling algorithm |
64 |
* starts being used by a geom 'sched' |
65 |
* |
66 |
* gs_fini() is called when the algorithm is released. |
67 |
* |
68 |
* gs_start() is called when a new request comes in. It should |
69 |
* enqueue the request and return 0 if success, or return non-zero |
70 |
* in case of failure (meaning the request is passed down). |
71 |
* The scheduler can use bio->bio_caller1 to store a non-null |
72 |
* pointer meaning the request is under its control. |
73 |
* |
74 |
* gs_next() is called in a loop by g_sched_dispatch(), right after |
75 |
* gs_start(), or on timeouts or 'done' events. It should return |
76 |
* immediately, either a pointer to the bio to be served or NULL |
77 |
* if no bio should be served now. If force is specified, a |
78 |
* work-conserving behavior is expected. |
79 |
* |
80 |
* gs_done() is called when a request under service completes. |
81 |
* In turn the scheduler may decide to call the dispatch loop |
82 |
* to serve other pending requests (or make sure there is a pending |
83 |
* timeout to avoid stalls). |
84 |
* |
85 |
* gs_init_class() is called when a new client (as determined by |
86 |
* the classifier) starts being used. |
87 |
* |
88 |
* gs_hash_unref() is called right before the class hashtable is |
89 |
* destroyed; after this call, the scheduler is supposed to hold no |
90 |
* more references to the elements in the table. |
91 |
*/ |
92 |
|
93 |
/* Forward declarations for prototypes. */ |
94 |
struct g_geom; |
95 |
struct g_sched_class; |
96 |
|
97 |
typedef void *gs_init_t (struct g_geom *geom); |
98 |
typedef void gs_fini_t (void *data); |
99 |
typedef int gs_start_t (void *data, struct bio *bio); |
100 |
typedef void gs_done_t (void *data, struct bio *bio); |
101 |
typedef struct bio *gs_next_t (void *data, int force); |
102 |
typedef int gs_init_class_t (void *data, void *priv); |
103 |
typedef void gs_fini_class_t (void *data, void *priv); |
104 |
typedef void gs_hash_unref_t (void *data); |
105 |
|
106 |
struct g_gsched { |
107 |
const char *gs_name; |
108 |
int gs_refs; |
109 |
int gs_priv_size; |
110 |
|
111 |
gs_init_t *gs_init; |
112 |
gs_fini_t *gs_fini; |
113 |
gs_start_t *gs_start; |
114 |
gs_done_t *gs_done; |
115 |
gs_next_t *gs_next; |
116 |
g_dumpconf_t *gs_dumpconf; |
117 |
|
118 |
gs_init_class_t *gs_init_class; |
119 |
gs_fini_class_t *gs_fini_class; |
120 |
gs_hash_unref_t *gs_hash_unref; |
121 |
|
122 |
LIST_ENTRY(g_gsched) glist; |
123 |
}; |
124 |
|
125 |
#define KTR_GSCHED KTR_SPARE4 |
126 |
|
127 |
MALLOC_DECLARE(M_GEOM_SCHED); |
128 |
|
129 |
/* |
130 |
* Basic classification mechanism. Each request is associated to |
131 |
* a g_sched_class, and each scheduler has the opportunity to set |
132 |
* its own private data for the given (class, geom) pair. The |
133 |
* private data have a base type of g_sched_private, and are |
134 |
* extended at the end with the actual private fields of each |
135 |
* scheduler. |
136 |
*/ |
137 |
struct g_sched_class { |
138 |
int gsc_refs; |
139 |
int gsc_expire; |
140 |
u_long gsc_key; |
141 |
LIST_ENTRY(g_sched_class) gsc_clist; |
142 |
|
143 |
void *gsc_priv[0]; |
144 |
}; |
145 |
|
146 |
/* |
147 |
* Manipulate the classifier's data. g_sched_get_class() gets a reference |
148 |
* to the class corresponding to bp in gp, allocating and initializing |
149 |
* it if necessary. g_sched_put_class() releases the reference. |
150 |
* The returned value points to the private data for the class. |
151 |
*/ |
152 |
void *g_sched_get_class(struct g_geom *gp, struct bio *bp); |
153 |
void g_sched_put_class(struct g_geom *gp, void *priv); |
154 |
|
155 |
static inline struct g_sched_class * |
156 |
g_sched_priv2class(void *priv) |
157 |
{ |
158 |
|
159 |
return ((struct g_sched_class *)((u_long)priv - |
160 |
offsetof(struct g_sched_class, gsc_priv))); |
161 |
} |
162 |
|
163 |
static inline void |
164 |
g_sched_priv_ref(void *priv) |
165 |
{ |
166 |
struct g_sched_class *gsc; |
167 |
|
168 |
gsc = g_sched_priv2class(priv); |
169 |
gsc->gsc_refs++; |
170 |
} |
171 |
|
172 |
/* |
173 |
* Locking interface. When each operation registered with the |
174 |
* scheduler is invoked, a per-instance lock is taken to protect |
175 |
* the data associated with it. If the scheduler needs something |
176 |
* else to access the same data (e.g., a callout) it must use |
177 |
* these functions. |
178 |
*/ |
179 |
void g_sched_lock(struct g_geom *gp); |
180 |
void g_sched_unlock(struct g_geom *gp); |
181 |
|
182 |
/* |
183 |
* Restart request dispatching. Must be called with the per-instance |
184 |
* mutex held. |
185 |
*/ |
186 |
void g_sched_dispatch(struct g_geom *geom); |
187 |
|
188 |
/* |
189 |
* Simple gathering of statistical data, used by schedulers to collect |
190 |
* info on process history. Just keep an exponential average of the |
191 |
* samples, with some extra bits of precision. |
192 |
*/ |
193 |
struct g_savg { |
194 |
uint64_t gs_avg; |
195 |
unsigned int gs_smpl; |
196 |
}; |
197 |
|
198 |
static inline void |
199 |
g_savg_add_sample(struct g_savg *ss, uint64_t sample) |
200 |
{ |
201 |
|
202 |
/* EMA with alpha = 0.125, fixed point, 3 bits of precision. */ |
203 |
ss->gs_avg = sample + ss->gs_avg - (ss->gs_avg >> 3); |
204 |
ss->gs_smpl = 1 + ss->gs_smpl - (ss->gs_smpl >> 3); |
205 |
} |
206 |
|
207 |
static inline int |
208 |
g_savg_valid(struct g_savg *ss) |
209 |
{ |
210 |
|
211 |
/* We want at least 8 samples to deem an average as valid. */ |
212 |
return (ss->gs_smpl > 7); |
213 |
} |
214 |
|
215 |
static inline uint64_t |
216 |
g_savg_read(struct g_savg *ss) |
217 |
{ |
218 |
|
219 |
return (ss->gs_avg / ss->gs_smpl); |
220 |
} |
221 |
|
222 |
/* |
223 |
* Declaration of a scheduler module. |
224 |
*/ |
225 |
int g_gsched_modevent(module_t mod, int cmd, void *arg); |
226 |
|
227 |
#define DECLARE_GSCHED_MODULE(name, gsched) \ |
228 |
static moduledata_t name##_mod = { \ |
229 |
#name, \ |
230 |
g_gsched_modevent, \ |
231 |
gsched, \ |
232 |
}; \ |
233 |
DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); \ |
234 |
MODULE_DEPEND(name, geom_sched, 0, 0, 0); |
235 |
|
236 |
#endif /* _KERNEL */ |
237 |
|
238 |
#endif /* _G_GSCHED_H_ */ |