/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- perfcount_test_add_counters
- perfcount_test_dump_id
- smb_subop_name
- perfcount_test_dump_counter
- perfcount_test_dump_counters
- perfcount_test_start
- perfcount_test_add
- perfcount_test_set_op
- perfcount_test_set_subop
- perfcount_test_set_ioctl
- perfcount_test_set_msglen_in
- perfcount_test_set_msglen_out
- perfcount_test_copy_context
- perfcount_test_defer_op
- perfcount_test_set_client
- perfcount_test_end
- perfcount_test_init
1 /*
2 * Unix SMB/CIFS implementation.
3 * Test module for perfcounters
4 *
5 * Copyright (C) Todd Stecher 2008
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22
23 #define PARM_PC_TEST_TYPE "pc_test"
24 #define PARM_DUMPON_COUNT "count"
25 #define PARM_DUMPON_COUNT_DEFAULT 50
26
27 struct perfcount_test_identity {
28 uid_t uid;
29 char *user;
30 char *domain;
31 };
32
33 struct perfcount_test_counter {
34 int op;
35 int sub_op;
36 int ioctl;
37 uint64_t bytes_in;
38 uint64_t bytes_out;
39 int count;
40
41 struct perfcount_test_counter *next;
42 struct perfcount_test_counter *prev;
43 };
44
45 struct perfcount_test_context {
46
47 /* wip: identity */
48 struct perfcount_test_identity *id;
49 struct perfcount_test_counter *ops;
50 };
51
52 #define MAX_OP 256
53 struct perfcount_test_counter *g_list[MAX_OP];
54
55 int count;
56
57 /* determine frequency of dumping results */
58 int count_mod = 1;
59
60 static void perfcount_test_add_counters(struct perfcount_test_context *ctxt)
/* [<][>][^][v][top][bottom][index][help] */
61 {
62 struct perfcount_test_counter *head;
63 struct perfcount_test_counter *ptc;
64 struct perfcount_test_counter *tmp;
65 bool found;
66
67 for (ptc = ctxt->ops; ptc != NULL; ) {
68
69 found = false;
70
71 if (ptc->op > MAX_OP)
72 continue;
73
74 for (head = g_list[ptc->op]; head != NULL; head = head->next) {
75 if ((ptc->sub_op == head->sub_op) &&
76 (ptc->ioctl == head->ioctl)) {
77 head->bytes_in += ptc->bytes_in;
78 head->bytes_out += ptc->bytes_out;
79 head->count++;
80 tmp = ptc->next;
81 DLIST_REMOVE(ctxt->ops, ptc);
82 SAFE_FREE(ptc);
83 ptc = tmp;
84 found = true;
85 break;
86 }
87 }
88
89 /* not in global tracking list - add it */
90 if (!found) {
91 tmp = ptc->next;
92 DLIST_REMOVE(ctxt->ops, ptc);
93 ptc->count = 1;
94 DLIST_ADD(g_list[ptc->op], ptc);
95 ptc = tmp;
96 }
97 }
98
99 }
100
101 #if 0
102
103 static void perfcount_test_dump_id(struct perfcount_test_identity *id, int lvl)
/* [<][>][^][v][top][bottom][index][help] */
104 {
105 if (!id)
106 return;
107
108 DEBUG(lvl,("uid - %d\n", id->uid));
109 DEBUG(lvl,("user - %s\n", id->user));
110 DEBUG(lvl,("domain - %s\n", id->domain));
111 }
112
113 #endif
114
115 static const char *trans_subop_table[] = {
116 "unknown", "trans:create", "trans:ioctl", "trans:set sd",
117 "trans:change notify", "trans: rename", "trans:get sd",
118 "trans:get quota", "trans:set quota"
119 };
120
121 static const char *trans2_subop_table[] = {
122 "trans2:open", "trans2:find first", "trans2:find next",
123 "trans2:q fsinfo", "trans2:set fsinfo", "trans2:q path info",
124 "trans2:set pathinfo", "trans2:fs ctl", "trans2: io ctl",
125 "trans2:find notify first", "trans2:find notify next",
126 "trans2:mkdir", "trans2:sess setup", "trans2:get dfs referral",
127 "trans2:report dfs inconsistent"
128 };
129
130 static const char *smb_subop_name(int op, int subop)
/* [<][>][^][v][top][bottom][index][help] */
131 {
132 /* trans */
133 if (op == 0x25) {
134 if (subop > sizeof(trans_subop_table) /
135 sizeof(trans_subop_table[0])) {
136 return "unknown";
137 }
138 return trans_subop_table[subop];
139 } else if (op == 0x32) {
140 if (subop > sizeof(trans2_subop_table) /
141 sizeof(trans2_subop_table[0])) {
142 return "unknown";
143 }
144 return trans2_subop_table[subop];
145 }
146
147 return "unknown";
148 }
149
150 static void perfcount_test_dump_counter(struct perfcount_test_counter *ptc,
/* [<][>][^][v][top][bottom][index][help] */
151 int lvl)
152 {
153 DEBUG(lvl, ("OP: %s\n", smb_fn_name(ptc->op)));
154 if (ptc->sub_op > 0) {
155 DEBUG(lvl, ("SUBOP: %s\n",
156 smb_subop_name(ptc->op, ptc->sub_op)));
157 }
158
159 if (ptc->ioctl > 0) {
160 DEBUG(lvl, ("IOCTL: %d\n", ptc->ioctl));
161 }
162
163 DEBUG(lvl, ("Count: %d\n\n", ptc->count));
164 }
165
166 static void perfcount_test_dump_counters(void)
/* [<][>][^][v][top][bottom][index][help] */
167 {
168 int i;
169 struct perfcount_test_counter *head;
170
171 count_mod = lp_parm_int(0, PARM_PC_TEST_TYPE, PARM_DUMPON_COUNT,
172 PARM_DUMPON_COUNT_DEFAULT);
173
174 if ((count++ % count_mod) != 0)
175 return;
176
177 DEBUG(0,("##### Dumping Performance Counters #####\n"));
178
179 for (i=0; i < 256; i++) {
180 for (head = g_list[i]; head != NULL; head = head->next) {
181 perfcount_test_dump_counter(head, 0);
182 head->prev = NULL;
183 SAFE_FREE(head->prev);
184 }
185 SAFE_FREE(head);
186 }
187 }
188
189 /* operations */
190 static void perfcount_test_start(struct smb_perfcount_data *pcd)
/* [<][>][^][v][top][bottom][index][help] */
191 {
192 struct perfcount_test_context *ctxt;
193 struct perfcount_test_counter *ctr;
194 /*
195 * there shouldn't already be a context here - if so,
196 * there's an unbalanced call to start / end.
197 */
198 if (pcd->context) {
199 DEBUG(0,("perfcount_test_start - starting "
200 "initialized context - %p\n", pcd));
201 return;
202 }
203
204 ctxt = SMB_MALLOC_P(struct perfcount_test_context);
205 if (!ctxt)
206 return;
207
208 ZERO_STRUCTP(ctxt);
209
210 /* create 'default' context */
211 ctr = SMB_MALLOC_P(struct perfcount_test_counter);
212 if (!ctr) {
213 SAFE_FREE(ctxt);
214 return;
215 }
216
217 ZERO_STRUCTP(ctr);
218 ctr->op = ctr->sub_op = ctr->ioctl = -1;
219 DLIST_ADD(ctxt->ops, ctr);
220
221 pcd->context = (void*)ctxt;
222 }
223
224 static void perfcount_test_add(struct smb_perfcount_data *pcd)
/* [<][>][^][v][top][bottom][index][help] */
225 {
226 struct perfcount_test_context *ctxt =
227 (struct perfcount_test_context *)pcd->context;
228 struct perfcount_test_counter *ctr;
229
230 if (pcd->context == NULL)
231 return;
232
233 ctr = SMB_MALLOC_P(struct perfcount_test_counter);
234 if (!ctr) {
235 return;
236 }
237
238 DLIST_ADD(ctxt->ops, ctr);
239
240 }
241
242 static void perfcount_test_set_op(struct smb_perfcount_data *pcd, int op)
/* [<][>][^][v][top][bottom][index][help] */
243 {
244 struct perfcount_test_context *ctxt =
245 (struct perfcount_test_context *)pcd->context;
246
247 if (pcd->context == NULL)
248 return;
249
250 ctxt->ops->op = op;
251 }
252
253 static void perfcount_test_set_subop(struct smb_perfcount_data *pcd, int sub_op)
/* [<][>][^][v][top][bottom][index][help] */
254 {
255 struct perfcount_test_context *ctxt =
256 (struct perfcount_test_context *)pcd->context;
257
258 if (pcd->context == NULL)
259 return;
260
261 ctxt->ops->sub_op = sub_op;
262 }
263
264 static void perfcount_test_set_ioctl(struct smb_perfcount_data *pcd, int io_ctl)
/* [<][>][^][v][top][bottom][index][help] */
265 {
266 struct perfcount_test_context *ctxt =
267 (struct perfcount_test_context *)pcd->context;
268 if (pcd->context == NULL)
269 return;
270
271 ctxt->ops->ioctl = io_ctl;
272 }
273
274 static void perfcount_test_set_msglen_in(struct smb_perfcount_data *pcd,
/* [<][>][^][v][top][bottom][index][help] */
275 uint64_t bytes_in)
276 {
277 struct perfcount_test_context *ctxt =
278 (struct perfcount_test_context *)pcd->context;
279 if (pcd->context == NULL)
280 return;
281
282 ctxt->ops->bytes_in = bytes_in;
283 }
284
285 static void perfcount_test_set_msglen_out(struct smb_perfcount_data *pcd,
/* [<][>][^][v][top][bottom][index][help] */
286 uint64_t bytes_out)
287 {
288 struct perfcount_test_context *ctxt =
289 (struct perfcount_test_context *)pcd->context;
290
291 if (pcd->context == NULL)
292 return;
293
294 ctxt->ops->bytes_out = bytes_out;
295 }
296
297 static void perfcount_test_copy_context(struct smb_perfcount_data *pcd,
/* [<][>][^][v][top][bottom][index][help] */
298 struct smb_perfcount_data *new_pcd)
299 {
300 struct perfcount_test_context *ctxt =
301 (struct perfcount_test_context *)pcd->context;
302 struct perfcount_test_context *new_ctxt;
303
304 struct perfcount_test_counter *ctr;
305 struct perfcount_test_counter *new_ctr;
306
307 if (pcd->context == NULL)
308 return;
309
310 new_ctxt = SMB_MALLOC_P(struct perfcount_test_context);
311 if (!new_ctxt) {
312 return;
313 }
314
315 memcpy(new_ctxt, ctxt, sizeof(struct perfcount_test_context));
316
317 for (ctr = ctxt->ops; ctr != NULL; ctr = ctr->next) {
318 new_ctr = SMB_MALLOC_P(struct perfcount_test_counter);
319 if (!new_ctr) {
320 goto error;
321 }
322
323 memcpy(new_ctr, ctr, sizeof(struct perfcount_test_counter));
324 new_ctr->next = NULL;
325 new_ctr->prev = NULL;
326 DLIST_ADD(new_ctxt->ops, new_ctr);
327 }
328
329 new_pcd->context = new_ctxt;
330 return;
331
332 error:
333
334 for (ctr = new_ctxt->ops; ctr != NULL; ) {
335 new_ctr = ctr->next;
336 SAFE_FREE(ctr);
337 ctr = new_ctr;
338 }
339
340 SAFE_FREE(new_ctxt);
341 }
342
343 /*
344 * For perf reasons, its best to use some global state
345 * when an operation is deferred, we need to alloc a copy.
346 */
347 static void perfcount_test_defer_op(struct smb_perfcount_data *pcd,
/* [<][>][^][v][top][bottom][index][help] */
348 struct smb_perfcount_data *def_pcd)
349 {
350 /* we don't do anything special to deferred ops */
351 return;
352 }
353
354 static void perfcount_test_set_client(struct smb_perfcount_data *pcd,
/* [<][>][^][v][top][bottom][index][help] */
355 uid_t uid, const char *user,
356 const char *domain)
357 {
358 /* WIP */
359 return;
360 }
361
362 static void perfcount_test_end(struct smb_perfcount_data *pcd)
/* [<][>][^][v][top][bottom][index][help] */
363 {
364 struct perfcount_test_context *ctxt =
365 (struct perfcount_test_context *)pcd->context;
366 if (pcd->context == NULL)
367 return;
368
369 /* @bug - we don't store outbytes right for chained cmds */
370 perfcount_test_add_counters(ctxt);
371 perfcount_test_dump_counters();
372 pcd->context = NULL;
373 SAFE_FREE(ctxt);
374 }
375
376
377 static struct smb_perfcount_handlers perfcount_test_handlers = {
378 perfcount_test_start,
379 perfcount_test_add,
380 perfcount_test_set_op,
381 perfcount_test_set_subop,
382 perfcount_test_set_ioctl,
383 perfcount_test_set_msglen_in,
384 perfcount_test_set_msglen_out,
385 perfcount_test_set_client,
386 perfcount_test_copy_context,
387 perfcount_test_defer_op,
388 perfcount_test_end
389 };
390
391 NTSTATUS perfcount_test_init(void)
/* [<][>][^][v][top][bottom][index][help] */
392 {
393 return smb_register_perfcounter(SMB_PERFCOUNTER_INTERFACE_VERSION,
394 "pc_test", &perfcount_test_handlers);
395 }