s4:dsdb: Fix stack use after scope in gkdi_create_root_key()
[samba.git] / source3 / modules / perfcount_onefs.c
1 /*
2  * Unix SMB/CIFS implementation.
3  * Support for OneFS protocol statistics / 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 #include "smbd/smbd.h"
23 #include <sys/isi_stats_protocol.h>
24 #include <sys/isi_stats_client.h>
25 #include <sys/isi_stats_cifs.h>
26
27 extern struct current_user current_user;
28
29 struct onefs_op_counter {
30         struct isp_op_delta iod;
31         struct onefs_op_counter *next;
32         struct onefs_op_counter *prev;
33 };
34
35 struct onefs_stats_context {
36         bool alloced;
37         struct isp_op_delta iod;
38
39         /* ANDX commands stats stored here */
40         struct onefs_op_counter *ops_chain;
41 };
42
43 const char *onefs_stat_debug(struct isp_op_delta *iod);
44
45 struct onefs_stats_context g_context;
46
47 static void onefs_smb_statistics_end(struct smb_perfcount_data *pcd);
48
49 struct isp_op_delta *onefs_stats_get_op_delta(struct onefs_stats_context *ctxt)
50 {
51         /* operate on head of chain */
52         if (ctxt->ops_chain) {
53 #ifdef ONEFS_PERF_DEBUG
54                 DEBUG(0,("************* CHAINED *****\n"));
55 #endif
56                 return &ctxt->ops_chain->iod;
57         } else
58                 return &ctxt->iod;
59 }
60
61 /* statistics operations */
62 static void onefs_smb_statistics_start(struct smb_perfcount_data *pcd)
63 {
64
65 #ifdef ONEFS_PERF_DEBUG
66         if (g_context.iod.op) {
67                 DEBUG(0,("**************** OP Collision! %s(%d) \n",
68                         onefs_stat_debug(&g_context.iod), g_context.iod.op));
69         }
70
71 #endif
72
73         ISP_OP_BEG(&g_context.iod, ISP_PROTO_CIFS, 0);
74
75         if (g_context.iod.enabled)
76                 pcd->context = &g_context;
77         else
78                 pcd->context = NULL;
79
80
81 }
82
83 static void onefs_smb_statistics_add(struct smb_perfcount_data *pcd)
84 {
85         struct onefs_op_counter *oc;
86         struct onefs_stats_context *ctxt = pcd->context;
87
88         /* not enabled */
89         if (pcd->context == NULL)
90                 return;
91
92         oc = SMB_MALLOC_P(struct onefs_op_counter);
93
94         if (oc == NULL)
95                 return;
96
97 #ifdef ONEFS_PERF_DEBUG
98         DEBUG(0,("*********** add chained op \n"));
99 #endif
100
101         DLIST_ADD(ctxt->ops_chain, oc);
102         ISP_OP_BEG(&oc->iod, ISP_PROTO_CIFS, 0);
103 }
104
105 static void onefs_smb_statistics_set_op(struct smb_perfcount_data *pcd, int op)
106 {
107         struct onefs_stats_context *ctxt = pcd->context;
108         struct isp_op_delta *iod;
109
110         /* not enabled */
111         if (pcd->context == NULL)
112                 return;
113
114         iod = onefs_stats_get_op_delta(ctxt);
115         iod->op = isp_cifs_op_id(op);
116
117 #ifdef ONEFS_PERF_DEBUG
118         DEBUG(0,("***********SET op %s(%d)\n", onefs_stat_debug(iod), op));
119 #endif
120         /* no reply required */
121         if (op == SMBntcancel)
122                 onefs_smb_statistics_end(pcd);
123
124 }
125
126 static void onefs_smb_statistics_set_subop(struct smb_perfcount_data *pcd,
127                                            int subop)
128 {
129         struct onefs_stats_context *ctxt = pcd->context;
130         struct isp_op_delta *iod;
131
132         /* not enabled */
133         if (pcd->context == NULL)
134                 return;
135
136         iod = onefs_stats_get_op_delta(ctxt);
137         iod->op = isp_cifs_sub_op_id(iod->op, subop);
138
139 #ifdef ONEFS_PERF_DEBUG
140         DEBUG(0,("********************  SET subop %s(%d)\n",
141                 onefs_stat_debug(iod), subop));
142 #endif
143
144         /*
145          * finalize this one - we don't need to know when it
146          * is set, but its useful as a counter
147          */
148         if (subop == NT_TRANSACT_NOTIFY_CHANGE)
149                 onefs_smb_statistics_end(pcd);
150 }
151
152 static void onefs_smb_statistics_set_ioctl(struct smb_perfcount_data *pcd,
153                                            int io_ctl)
154 {
155         struct onefs_stats_context *ctxt = pcd->context;
156         struct isp_op_delta *iod;
157
158         /* not enabled */
159         if (pcd->context == NULL)
160                 return;
161
162         /* we only monitor shadow copy */
163         if (io_ctl != FSCTL_GET_SHADOW_COPY_DATA)
164                 return;
165
166         iod = onefs_stats_get_op_delta(ctxt);
167         iod->op = isp_cifs_sub_op_id(iod->op, ISP_CIFS_NTRN_IOCTL_FGSCD);
168 #ifdef ONEFS_PERF_DEBUG
169         DEBUG(0,("********************  SET ioctl %s(%d)\n",
170                 onefs_stat_debug(iod), io_ctl));
171 #endif
172 }
173
174 static void onefs_smb_statistics_set_msglen_in(struct smb_perfcount_data *pcd,
175                                                uint64_t in_bytes)
176 {
177         struct onefs_stats_context *ctxt = pcd->context;
178         struct isp_op_delta *iod;
179
180         /* not enabled */
181         if (pcd->context == NULL)
182                 return;
183
184         iod = onefs_stats_get_op_delta(ctxt);
185         iod->in_bytes = in_bytes;
186 }
187
188 static void onefs_smb_statistics_set_msglen_out(struct smb_perfcount_data *pcd,
189                                                 uint64_t out_bytes)
190 {
191         struct onefs_stats_context *ctxt = pcd->context;
192
193         /* not enabled */
194         if (pcd->context == NULL)
195                 return;
196
197         if (ctxt->ops_chain)
198                 ctxt->ops_chain->iod.out_bytes = out_bytes;
199
200         ctxt->iod.out_bytes = out_bytes;
201 }
202
203 static int onefs_copy_perfcount_context(struct onefs_stats_context *ctxt,
204                                         struct onefs_stats_context **dest)
205 {
206         struct onefs_stats_context *new_ctxt;
207
208         /* make an alloc'd copy of the data */
209         new_ctxt = SMB_MALLOC_P(struct onefs_stats_context);
210         if (!new_ctxt) {
211                 return -1;
212         }
213
214         memcpy(new_ctxt, ctxt, sizeof(struct onefs_stats_context));
215         new_ctxt->alloced = True;
216         *dest = new_ctxt;
217         return 0;
218 }
219
220 static void onefs_smb_statistics_copy_context(struct smb_perfcount_data *pcd,
221                                               struct smb_perfcount_data *dest)
222 {
223         struct onefs_stats_context *ctxt = pcd->context;
224         struct onefs_stats_context *new_ctxt;
225         int ret;
226
227         /* not enabled */
228         if (pcd->context == NULL)
229                 return;
230
231 #ifdef ONEFS_PERF_DEBUG
232         DEBUG(0,("********  COPYING op %s(%d)\n",
233                 onefs_stat_debug(&ctxt->iod), ctxt->iod.op));
234 #endif
235
236         ret = onefs_copy_perfcount_context(ctxt, &new_ctxt);
237         if (ret)
238                 return;
239
240         /* instrumentation */
241         if (ctxt == &g_context)
242                 ZERO_STRUCT(g_context);
243
244         dest->context = new_ctxt;
245 }
246
247 /*
248  * For perf reasons, we usually use the global - sometimes, though,
249  * when an operation is deferred, we need to alloc a copy.
250  */
251 static void onefs_smb_statistics_defer_op(struct smb_perfcount_data *pcd,
252                                           struct smb_perfcount_data *def_pcd)
253 {
254         struct onefs_stats_context *ctxt = pcd->context;
255         struct onefs_stats_context *deferred_ctxt;
256         int ret;
257
258         /* not enabled */
259         if (pcd->context == NULL)
260                 return;
261
262         /* already allocated ? */
263         if (ctxt->alloced)
264         {
265                 def_pcd->context = ctxt;
266                 pcd->context = NULL;
267                 return;
268         }
269
270 #ifdef ONEFS_PERF_DEBUG
271         DEBUG(0,("********  DEFERRING op %s(%d)\n",
272                 onefs_stat_debug(&ctxt->iod), ctxt->iod.op));
273 #endif
274
275         ret = onefs_copy_perfcount_context(ctxt, &deferred_ctxt);
276         if (ret)
277                 return;
278
279         def_pcd->context = (void*) deferred_ctxt;
280
281         /* instrumentation */
282         if (ctxt == &g_context)
283                 ZERO_STRUCT(g_context);
284
285         if (pcd != def_pcd)
286                 pcd->context = NULL;
287 }
288
289 static void onefs_smb_statistics_end(struct smb_perfcount_data *pcd)
290 {
291         struct onefs_stats_context *ctxt = pcd->context;
292         struct onefs_op_counter *tmp;
293         uint64_t uid;
294
295         static in_addr_t rem_addr = 0;
296         static in_addr_t loc_addr = 0;
297
298         /* not enabled */
299         if (pcd->context == NULL)
300                 return;
301
302         uid = current_user.ut.uid ? current_user.ut.uid : ISC_UNKNOWN_CLIENT_ID;
303
304         /* get address info once, doesn't change for process */
305         if (rem_addr == 0) {
306
307 #error Isilon, please remove this after testing the code below
308
309                 char *addr;
310
311                 addr = talloc_sub_basic(talloc_tos(), "", "", "%I");
312                 if (addr != NULL) {
313                         rem_addr = interpret_addr(addr);
314                         TALLOC_FREE(addr);
315                 } else {
316                         rem_addr = ISC_MASKED_ADDR;
317                 }
318
319                 addr = talloc_sub_basic(talloc_tos(), "", "", "%i");
320                 if (addr != NULL) {
321                         loc_addr = interpret_addr(addr);
322                         TALLOC_FREE(addr);
323                 } else {
324                         loc_addr = ISC_MASKED_ADDR;
325                 }
326         }
327
328         /*
329          * bug here - we aren't getting the outlens right,
330          * when dealing w/ chained requests.
331          */
332         for (tmp = ctxt->ops_chain; tmp; tmp = tmp->next) {
333                 tmp->iod.out_bytes = ctxt->iod.out_bytes;
334                 isc_cookie_init(&tmp->iod.cookie, rem_addr, loc_addr, uid);
335                 ISP_OP_END(&tmp->iod);
336 #ifdef ONEFS_PERF_DEBUG
337                 DEBUG(0,("********  Finalized CHAIN op %s uid %llu in:%llu"
338                         ", out:%llu\n",
339                         onefs_stat_debug(&tmp->iod), uid,
340                         tmp->iod.in_bytes, tmp->iod.out_bytes));
341 #endif
342                 SAFE_FREE(DLIST_PREV(tmp));
343         }
344
345         isc_cookie_init(&ctxt->iod.cookie, rem_addr, loc_addr, uid);
346         ISP_OP_END(&ctxt->iod);
347 #ifdef ONEFS_PERF_DEBUG
348         DEBUG(0,("********  Finalized op %s uid %llu in:%llu, out:%llu\n",
349                 onefs_stat_debug(&ctxt->iod), uid,
350                 ctxt->iod.in_bytes, ctxt->iod.out_bytes));
351 #endif
352
353         if (ctxt->alloced)
354                 SAFE_FREE(ctxt);
355         else
356                 ZERO_STRUCTP(ctxt);
357
358         pcd->context = NULL;
359 }
360
361
362 static struct smb_perfcount_handlers onefs_pc_handlers = {
363         onefs_smb_statistics_start,
364         onefs_smb_statistics_add,
365         onefs_smb_statistics_set_op,
366         onefs_smb_statistics_set_subop,
367         onefs_smb_statistics_set_ioctl,
368         onefs_smb_statistics_set_msglen_in,
369         onefs_smb_statistics_set_msglen_out,
370         onefs_smb_statistics_copy_context,
371         onefs_smb_statistics_defer_op,
372         onefs_smb_statistics_end
373 };
374
375 NTSTATUS perfcount_onefs_init(void)
376 {
377         return smb_register_perfcounter(SMB_PERFCOUNTER_INTERFACE_VERSION,
378                                         "pc_onefs", &onefs_pc_handlers);
379 }
380
381 #ifdef ONEFS_PERF_DEBUG
382 /* debug helper */
383 struct op_debug {
384         int type;
385         const char *name;
386 };
387
388 struct op_debug op_debug_table[] = {
389         { 0x00, "mkdir"}, { 0x01, "rmdir"}, { 0x02, "open"}, { 0x03, "create"},
390         { 0x04, "close"}, { 0x05, "flush"}, { 0x06, "unlink"}, { 0x07, "mv"},
391         { 0x08, "getatr"}, { 0x09, "setatr"}, { 0x0a, "read"}, { 0x0b, "write"},
392         { 0x0c, "lock"}, { 0x0d, "unlock"}, { 0x0e, "ctemp"}, { 0x0f, "mknew"},
393         { 0x10, "chkpth"}, { 0x11, "exit"}, { 0x12, "lseek"}, { 0x13, "lockread"},
394         { 0x14, "writeunlock"}, { 0x1a, "readbraw"}, { 0x1b, "readbmpx"},
395         { 0x1c, "readbs"}, { 0x1d, "writebraw"}, { 0x1e, "writebmpx"},
396         { 0x1f, "writebs"}, { 0x20, "writec"}, { 0x22, "setattre"},
397         { 0x23, "getattre"}, { 0x24, "lockingx"}, { 0x25, "trans"},
398         { 0x26, "transs"}, { 0x27, "ioctl"}, { 0x28, "ioctls"}, { 0x29, "copy"},
399         { 0x2a, "move"}, { 0x2b, "echo"}, { 0x2c, "writeclose"}, { 0x2d, "openx"},
400         { 0x2e, "readx"}, { 0x2f, "writex"}, { 0x34, "findclose"},
401         { 0x35, "findnclose"}, { 0x70, "tcon"}, { 0x71, "tdis"},
402         { 0x72, "negprot"}, { 0x73, "sesssetupx"}, { 0x74, "ulogoffx"},
403         { 0x75, "tconx"}, { 0x80, "dskattr"}, { 0x81, "search"},
404         { 0x82, "ffirst"}, { 0x83, "funique"}, { 0x84, "fclose"},
405         { 0x400, "nttrans"},{ 0x500, "nttranss"},
406         { 0xa2, "ntcreatex"}, { 0xa4, "ntcancel"}, { 0xa5, "ntrename"},
407         { 0xc0, "splopen"}, { 0xc1, "splwr"}, { 0xc2, "splclose"},
408         { 0xc3, "splretq"}, { 0xd0, "sends"}, { 0xd1, "sendb"},
409         { 0xd2, "fwdname"}, { 0xd3, "cancelf"}, { 0xd4, "getmac"},
410         { 0xd5, "sendstrt"}, { 0xd6, "sendend"}, { 0xd7, "sendtxt"},
411         { ISP_CIFS_INVALID_OP, "unknown"},
412         { ISP_CIFS_TRNS2 + 0x00,  "trans2:open"},
413         { ISP_CIFS_TRNS2 + 0x01,  "trans2:findfirst"},
414         { ISP_CIFS_TRNS2 + 0x02,  "trans2:findnext"},
415         { ISP_CIFS_TRNS2 + 0x03,  "trans2:qfsinfo"},
416         { ISP_CIFS_TRNS2 + 0x04,  "trans2:setfsinfo"},
417         { ISP_CIFS_TRNS2 + 0x05,  "trans2:qpathinfo"},
418         { ISP_CIFS_TRNS2 + 0x06,  "trans2:setpathinfo"},
419         { ISP_CIFS_TRNS2 + 0x07,  "trans2:qfileinfo"},
420         { ISP_CIFS_TRNS2 + 0x08,  "trans2:setfileinfo"},
421         { ISP_CIFS_TRNS2 + 0x0a,  "trans2:ioctl"},
422         { ISP_CIFS_TRNS2 + 0x0b,  "trans2:findnotifyfirst"},
423         { ISP_CIFS_TRNS2 + 0x0c,  "trans2:findnotifynext"},
424         { ISP_CIFS_TRNS2 + 0x0d,  "trans2:mkdir"},
425         { ISP_CIFS_TRNS2 + 0x10,  "trans2:get_dfs_ref"},
426         { ISP_CIFS_TRNS2 + ISP_CIFS_SUBOP_UNKNOWN, "trans2:unknown"},
427         { ISP_CIFS_TRNSS2 +0x00, "transs2:open"},
428         { ISP_CIFS_TRNSS2 +0x01, "transs2:findfirst"},
429         { ISP_CIFS_TRNSS2 +0x02, "transs2:findnext"},
430         { ISP_CIFS_TRNSS2 +0x03, "transs2:qfsinfo"},
431         { ISP_CIFS_TRNSS2 +0x04, "transs2:setfsinfo"},
432         { ISP_CIFS_TRNSS2 +0x05, "transs2:qpathinfo"},
433         { ISP_CIFS_TRNSS2 +0x06, "transs2:setpathinfo"},
434         { ISP_CIFS_TRNSS2 +0x07, "transs2:qfileinfo"},
435         { ISP_CIFS_TRNSS2 +0x08, "transs2:setfileinfo"},
436         { ISP_CIFS_TRNSS2 +0x0a, "transs2:ioctl"},
437         { ISP_CIFS_TRNSS2 +0x0b, "transs2:findnotifyfirst"},
438         { ISP_CIFS_TRNSS2 +0x0c, "transs2:findnotifynext"},
439         { ISP_CIFS_TRNSS2 +0x0d, "transs2:mkdir"},
440         { ISP_CIFS_TRNSS2 +0x10, "transs2:get_dfs_referral"},
441         { ISP_CIFS_TRNSS2 + ISP_CIFS_SUBOP_UNKNOWN, "transs2:unknown"},
442         { ISP_CIFS_NTRNS + 0x1, "nttrans:create"},
443         { ISP_CIFS_NTRNS + 0x2, "nttrans:ioctl"},
444         { ISP_CIFS_NTRNS + 0x3, "nttrans:set_security_desc"},
445         { ISP_CIFS_NTRNS + 0x4, "nttrans:notify_change"},
446         { ISP_CIFS_NTRNS + 0x5, "nttrans:rename"},
447         { ISP_CIFS_NTRNS + 0x6, "nttrans:qry_security_desc"},
448         { ISP_CIFS_NTRNS + 0x7, "nttrans:get_user_quota"},
449         { ISP_CIFS_NTRNS + 0x8, "nttrans:set_user_quota"},
450         { ISP_CIFS_NTRNS + ISP_CIFS_NTRN_IOCTL_FGSCD,
451                 "nttrans:ioctl:get_shadow_copy_data"},
452         { ISP_CIFS_NTRNS + ISP_CIFS_SUBOP_UNKNOWN,
453                 "nttrans:unknown"},
454         { ISP_CIFS_NTRNSS + 0x1, "nttranss:create"},
455         { ISP_CIFS_NTRNSS + 0x2, "nttranss:ioctl"},
456         { ISP_CIFS_NTRNSS + 0x3, "nttranss:set_security_desc"},
457         { ISP_CIFS_NTRNSS + 0x4, "nttranss:notify_change"},
458         { ISP_CIFS_NTRNSS + 0x5, "nttranss:rename"},
459         { ISP_CIFS_NTRNSS + 0x6, "nttranss:qry_security_desc"},
460         { ISP_CIFS_NTRNSS + 0x7, "nttranss:get_user_quota"},
461         { ISP_CIFS_NTRNSS + 0x8, "nttranss:set_user_quota"},
462         { ISP_CIFS_NTRNSS + ISP_CIFS_NTRN_IOCTL_FGSCD,
463                 "nttranss:ioctl:get_shadow_copy_data"},
464         { ISP_CIFS_NTRNSS + ISP_CIFS_SUBOP_UNKNOWN,
465                 "nttranss:unknown"},
466 };
467
468 int op_debug_table_count = sizeof(op_debug_table) / sizeof(op_debug_table[0]);
469
470 const char *onefs_stat_debug(struct isp_op_delta *iod)
471 {
472         int i;
473         const char *unk = "unknown";
474         for (i=0; i < op_debug_table_count;i++) {
475                 if (iod->op == op_debug_table[i].type)
476                         return op_debug_table[i].name;
477         }
478
479         return unk;
480 }
481 #endif