Whamcloud - gitweb
Land b1_4_smallfix onto b1_4 (20041216_1438)
[fs/lustre-release.git] / lustre / ptlrpc / lproc_ptlrpc.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (C) 2002 Cluster File Systems, Inc.
5  *
6  *   This file is part of Lustre, http://www.lustre.org.
7  *
8  *   Lustre is free software; you can redistribute it and/or
9  *   modify it under the terms of version 2 of the GNU General Public
10  *   License as published by the Free Software Foundation.
11  *
12  *   Lustre 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 Lustre; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  */
22 #define DEBUG_SUBSYSTEM S_CLASS
23
24 #include <linux/obd_support.h>
25 #include <linux/obd.h>
26 #include <linux/lprocfs_status.h>
27 #include <linux/lustre_idl.h>
28 #include <linux/lustre_net.h>
29 #include <linux/obd_class.h>
30 #include <linux/seq_file.h>
31 #include "ptlrpc_internal.h"
32
33
34 struct ll_rpc_opcode {
35      __u32       opcode;
36      const char *opname;
37 } ll_rpc_opcode_table[LUSTRE_MAX_OPCODES] = {
38         { OST_REPLY,        "ost_reply" },
39         { OST_GETATTR,      "ost_getattr" },
40         { OST_SETATTR,      "ost_setattr" },
41         { OST_READ,         "ost_read" },
42         { OST_WRITE,        "ost_write" },
43         { OST_CREATE ,      "ost_create" },
44         { OST_DESTROY,      "ost_destroy" },
45         { OST_GET_INFO,     "ost_get_info" },
46         { OST_CONNECT,      "ost_connect" },
47         { OST_DISCONNECT,   "ost_disconnect" },
48         { OST_PUNCH,        "ost_punch" },
49         { OST_OPEN,         "ost_open" },
50         { OST_CLOSE,        "ost_close" },
51         { OST_STATFS,       "ost_statfs" },
52         { OST_SAN_READ,     "ost_san_read" },
53         { OST_SAN_WRITE,    "ost_san_write" },
54         { OST_SYNC,         "ost_sync" },
55         { OST_SET_INFO,     "ost_set_info" },
56         { MDS_GETATTR,      "mds_getattr" },
57         { MDS_GETATTR_NAME, "mds_getattr_name" },
58         { MDS_CLOSE,        "mds_close" },
59         { MDS_REINT,        "mds_reint" },
60         { MDS_READPAGE,     "mds_readpage" },
61         { MDS_CONNECT,      "mds_connect" },
62         { MDS_DISCONNECT,   "mds_disconnect" },
63         { MDS_GETSTATUS,    "mds_getstatus" },
64         { MDS_STATFS,       "mds_statfs" },
65         { MDS_PIN,          "mds_pin" },
66         { MDS_UNPIN,        "mds_unpin" },
67         { MDS_SYNC,         "mds_sync" },
68         { MDS_DONE_WRITING, "mds_done_writing" },
69         { LDLM_ENQUEUE,     "ldlm_enqueue" },
70         { LDLM_CONVERT,     "ldlm_convert" },
71         { LDLM_CANCEL,      "ldlm_cancel" },
72         { LDLM_BL_CALLBACK, "ldlm_bl_callback" },
73         { LDLM_CP_CALLBACK, "ldlm_cp_callback" },
74         { LDLM_GL_CALLBACK, "ldlm_gl_callback" },
75         { PTLBD_QUERY,      "ptlbd_query" },
76         { PTLBD_READ,       "ptlbd_read" },
77         { PTLBD_WRITE,      "ptlbd_write" },
78         { PTLBD_FLUSH,      "ptlbd_flush" },
79         { PTLBD_CONNECT,    "ptlbd_connect" },
80         { PTLBD_DISCONNECT, "ptlbd_disconnect" },
81         { OBD_PING,         "obd_ping" },
82         { OBD_LOG_CANCEL,   "llog_origin_handle_cancel"},
83 };
84
85 const char* ll_opcode2str(__u32 opcode)
86 {
87         /* When one of the assertions below fail, chances are that:
88          *     1) A new opcode was added in lustre_idl.h, but was
89          *        is missing from the table above.
90          * or  2) The opcode space was renumbered or rearranged,
91          *        and the opcode_offset() function in
92          *        ptlrpc_internals.h needs to be modified.
93          */
94         __u32 offset = opcode_offset(opcode);
95         LASSERT(offset < LUSTRE_MAX_OPCODES);
96         LASSERT(ll_rpc_opcode_table[offset].opcode == opcode);
97         return ll_rpc_opcode_table[offset].opname;
98 }
99
100 #ifndef LPROCFS
101 void ptlrpc_lprocfs_register_service(struct obd_device *obddev,
102                                      struct ptlrpc_service *svc) { return ; }
103 void ptlrpc_lprocfs_unregister_service(struct ptlrpc_service *svc) { return; }
104 #else
105
106 void ptlrpc_lprocfs_register(struct proc_dir_entry *root, char *dir,
107                              char *name, struct proc_dir_entry **procroot_ret,
108                              struct lprocfs_stats **stats_ret)
109 {
110         struct proc_dir_entry *svc_procroot;
111         struct lprocfs_stats *svc_stats;
112         int i, rc;
113         unsigned int svc_counter_config = LPROCFS_CNTR_AVGMINMAX |
114                                           LPROCFS_CNTR_STDDEV;
115
116         LASSERT(*procroot_ret == NULL);
117         LASSERT(*stats_ret == NULL);
118
119         svc_stats = lprocfs_alloc_stats(PTLRPC_LAST_CNTR + LUSTRE_MAX_OPCODES);
120         if (svc_stats == NULL)
121                 return;
122
123         if (dir) {
124                 svc_procroot = lprocfs_register(dir, root, NULL, NULL);
125                 if (IS_ERR(svc_procroot)) {
126                         lprocfs_free_stats(svc_stats);
127                         return;
128                 }
129         } else {
130                 svc_procroot = root;
131         }
132
133         lprocfs_counter_init(svc_stats, PTLRPC_REQWAIT_CNTR,
134                              svc_counter_config, "req_waittime", "usec");
135         lprocfs_counter_init(svc_stats, PTLRPC_REQQDEPTH_CNTR,
136                              svc_counter_config, "req_qdepth", "reqs");
137         lprocfs_counter_init(svc_stats, PTLRPC_REQACTIVE_CNTR,
138                              svc_counter_config, "req_active", "reqs");
139         lprocfs_counter_init(svc_stats, PTLRPC_REQBUF_AVAIL_CNTR,
140                              svc_counter_config, "reqbuf_avail", "bufs");
141         for (i = 0; i < LUSTRE_MAX_OPCODES; i++) {
142                 __u32 opcode = ll_rpc_opcode_table[i].opcode;
143                 lprocfs_counter_init(svc_stats, PTLRPC_LAST_CNTR + i,
144                                      svc_counter_config, ll_opcode2str(opcode),
145                                      "usec");
146         }
147
148         rc = lprocfs_register_stats(svc_procroot, name, svc_stats);
149         if (rc < 0) {
150                 if (dir)
151                         lprocfs_remove(svc_procroot);
152                 lprocfs_free_stats(svc_stats);
153         } else {
154                 if (dir)
155                         *procroot_ret = svc_procroot;
156                 *stats_ret = svc_stats;
157         }
158 }
159
160 static int
161 ptlrpc_lprocfs_read_req_history_len(char *page, char **start, off_t off,
162                                     int count, int *eof, void *data)
163 {
164         struct ptlrpc_service *svc = data;
165         
166         *eof = 1;
167         return snprintf(page, count, "%d\n", svc->srv_n_history_rqbds);
168 }
169
170 static int
171 ptlrpc_lprocfs_read_req_history_max(char *page, char **start, off_t off,
172                                     int count, int *eof, void *data)
173 {
174         struct ptlrpc_service *svc = data;
175         
176         *eof = 1;
177         return snprintf(page, count, "%d\n", svc->srv_max_history_rqbds);
178 }
179
180 static int
181 ptlrpc_lprocfs_write_req_history_max(struct file *file, const char *buffer,
182                                      unsigned long count, void *data)
183 {
184         struct ptlrpc_service *svc = data;
185         int                    bufpages;
186         unsigned long          flags;
187         int                    val;
188         int                    rc = lprocfs_write_helper(buffer, count, &val);
189         
190         if (rc < 0)
191                 return rc;
192
193         if (val < 0)
194                 return -ERANGE;
195
196         /* This sanity check is more of an insanity check; we can still
197          * hose a kernel by allowing the request history to grow too
198          * far. */
199         bufpages = (svc->srv_buf_size + PAGE_SIZE - 1)/PAGE_SIZE;
200         if (val > num_physpages/(2*bufpages))
201                 return -ERANGE;
202         
203         spin_lock_irqsave(&svc->srv_lock, flags);
204         svc->srv_max_history_rqbds = val;
205         spin_unlock_irqrestore(&svc->srv_lock, flags);
206  
207         return count;
208 }
209
210 struct ptlrpc_srh_iterator {
211         __u64                  srhi_seq;
212         struct ptlrpc_request *srhi_req;
213 };
214
215 int
216 ptlrpc_lprocfs_svc_req_history_seek(struct ptlrpc_service *svc,
217                                     struct ptlrpc_srh_iterator *srhi,
218                                     __u64 seq)
219 {
220         struct list_head      *e;
221         struct ptlrpc_request *req;
222
223         if (srhi->srhi_req != NULL &&
224             srhi->srhi_seq > svc->srv_request_max_cull_seq &&
225             srhi->srhi_seq <= seq) {
226                 /* If srhi_req was set previously, hasn't been culled and
227                  * we're searching for a seq on or after it (i.e. more
228                  * recent), search from it onwards. 
229                  * Since the service history is LRU (i.e. culled reqs will
230                  * be near the head), we shouldn't have to do long
231                  * re-scans */
232                 LASSERT (srhi->srhi_seq == srhi->srhi_req->rq_history_seq);
233                 LASSERT (!list_empty(&svc->srv_request_history));
234                 e = &srhi->srhi_req->rq_history_list;
235         } else {
236                 /* search from start */
237                 e = svc->srv_request_history.next;
238         }
239
240         while (e != &svc->srv_request_history) {
241                 req = list_entry(e, struct ptlrpc_request, rq_history_list);
242                 
243                 if (req->rq_history_seq >= seq) {
244                         srhi->srhi_seq = req->rq_history_seq;
245                         srhi->srhi_req = req;
246                         return 0;
247                 }
248                 e = e->next;
249         }
250         
251         return -ENOENT;
252 }
253
254 static void *
255 ptlrpc_lprocfs_svc_req_history_start(struct seq_file *s, loff_t *pos)
256 {
257         struct ptlrpc_service       *svc = s->private;
258         struct ptlrpc_srh_iterator  *srhi;
259         unsigned long                flags;
260         int                          rc;
261
262         OBD_ALLOC(srhi, sizeof(*srhi));
263         if (srhi == NULL)
264                 return NULL;
265
266         srhi->srhi_seq = 0;
267         srhi->srhi_req = NULL;
268         
269         spin_lock_irqsave(&svc->srv_lock, flags);
270         rc = ptlrpc_lprocfs_svc_req_history_seek(svc, srhi, *pos);
271         spin_unlock_irqrestore(&svc->srv_lock, flags);
272         
273         if (rc == 0) {
274                 *pos = srhi->srhi_seq;
275                 return srhi;
276         }
277         
278         OBD_FREE(srhi, sizeof(*srhi));
279         return NULL;
280 }
281
282 static void
283 ptlrpc_lprocfs_svc_req_history_stop(struct seq_file *s, void *iter)
284 {
285         struct ptlrpc_srh_iterator *srhi = iter;
286
287         if (srhi != NULL)
288                 OBD_FREE(srhi, sizeof(*srhi));
289 }
290
291 static void *
292 ptlrpc_lprocfs_svc_req_history_next(struct seq_file *s, 
293                                     void *iter, loff_t *pos)
294 {
295         struct ptlrpc_service       *svc = s->private;
296         struct ptlrpc_srh_iterator  *srhi = iter;
297         unsigned long                flags;
298         int                          rc;
299
300         spin_lock_irqsave(&svc->srv_lock, flags);
301         rc = ptlrpc_lprocfs_svc_req_history_seek(svc, srhi, *pos + 1);
302         spin_unlock_irqrestore(&svc->srv_lock, flags);
303
304         if (rc != 0) {
305                 OBD_FREE(srhi, sizeof(*srhi));
306                 return NULL;
307         }
308
309         *pos = srhi->srhi_seq;
310         return srhi;
311 }
312
313 static int ptlrpc_lprocfs_svc_req_history_show(struct seq_file *s, void *iter)
314 {
315         struct ptlrpc_service      *svc = s->private;
316         struct ptlrpc_srh_iterator *srhi = iter;
317         struct ptlrpc_request      *req;
318         unsigned long               flags;
319         int                         rc;
320
321         spin_lock_irqsave(&svc->srv_lock, flags);
322
323         rc = ptlrpc_lprocfs_svc_req_history_seek(svc, srhi, srhi->srhi_seq);
324
325         if (rc == 0) {
326                 req = srhi->srhi_req;
327
328                 /* Print common req fields.
329                  * CAVEAT EMPTOR: we're racing with the service handler
330                  * here.  The request could contain any old crap, so you
331                  * must be just as careful as the service's request
332                  * parser. Currently I only print stuff here I know is OK
333                  * to look at coz it was set up in request_in_callback()!!! */
334                 seq_printf(s, LPD64":%s:%s:"LPD64":%d:%s ",
335                            req->rq_history_seq,
336                            req->rq_peer.peer_ni->pni_name, req->rq_peerstr,
337                            req->rq_xid, req->rq_reqlen,ptlrpc_rqphase2str(req));
338
339                 if (svc->srv_request_history_print_fn == NULL)
340                         seq_printf(s, "\n");
341                 else
342                         svc->srv_request_history_print_fn(s, srhi->srhi_req);
343         }
344
345         spin_unlock_irqrestore(&svc->srv_lock, flags);
346
347         return rc;
348 }
349
350 static int
351 ptlrpc_lprocfs_svc_req_history_open(struct inode *inode, struct file *file)
352 {
353         static struct seq_operations sops = {
354                 .start = ptlrpc_lprocfs_svc_req_history_start,
355                 .stop  = ptlrpc_lprocfs_svc_req_history_stop,
356                 .next  = ptlrpc_lprocfs_svc_req_history_next,
357                 .show  = ptlrpc_lprocfs_svc_req_history_show,
358         };
359         struct proc_dir_entry *dp = PDE(inode);
360         struct seq_file       *seqf;
361         int                    rc;
362
363         rc = seq_open(file, &sops);
364
365         if (rc == 0) {
366                 seqf = file->private_data;
367                 seqf->private = dp->data;
368         }
369
370         return rc;
371 }
372
373 void ptlrpc_lprocfs_register_service(struct proc_dir_entry *entry,
374                                      struct ptlrpc_service *svc)
375 {
376         struct lprocfs_vars lproc_vars[] = {
377                 {.name       = "req_buffer_history_len", 
378                  .write_fptr = NULL,
379                  .read_fptr  = ptlrpc_lprocfs_read_req_history_len, 
380                  .data       = svc},
381                 {.name       = "req_buffer_history_max",
382                  .write_fptr = ptlrpc_lprocfs_write_req_history_max,
383                  .read_fptr  = ptlrpc_lprocfs_read_req_history_max, 
384                  .data       = svc},
385                 {NULL}
386         };
387         static struct file_operations req_history_fops = {
388                 .owner       = THIS_MODULE,
389                 .open        = ptlrpc_lprocfs_svc_req_history_open,
390                 .read        = seq_read,
391                 .llseek      = seq_lseek,
392                 .release     = seq_release,
393         };
394         struct proc_dir_entry *req_history;
395
396         ptlrpc_lprocfs_register(entry, svc->srv_name,
397                                 "stats", &svc->srv_procroot,
398                                 &svc->srv_stats);
399         
400         if (svc->srv_procroot == NULL)
401                 return;
402
403         lprocfs_add_vars(svc->srv_procroot, lproc_vars, NULL);
404
405         req_history = create_proc_entry("req_history", 0400, 
406                                         svc->srv_procroot);
407         if (req_history != NULL) {
408                 req_history->data = svc;
409                 req_history->proc_fops = &req_history_fops;
410         }
411 }
412
413 void ptlrpc_lprocfs_register_obd(struct obd_device *obddev)
414 {
415         ptlrpc_lprocfs_register(obddev->obd_proc_entry, NULL, "stats",
416                                 &obddev->obd_svc_procroot,
417                                 &obddev->obd_svc_stats);
418 }
419
420 void ptlrpc_lprocfs_rpc_sent(struct ptlrpc_request *req)
421 {
422         struct lprocfs_stats *svc_stats;
423         int opc =  opcode_offset(req->rq_reqmsg->opc);
424
425         svc_stats = req->rq_import->imp_obd->obd_svc_stats;
426         if (svc_stats == NULL || opc <= 0)
427                 return;
428         LASSERT(opc < LUSTRE_MAX_OPCODES);
429         lprocfs_counter_add(svc_stats, opc + PTLRPC_LAST_CNTR, 0);
430 }
431
432 void ptlrpc_lprocfs_unregister_service(struct ptlrpc_service *svc)
433 {
434         if (svc->srv_procroot != NULL) {
435                 lprocfs_remove(svc->srv_procroot);
436                 svc->srv_procroot = NULL;
437         }
438         if (svc->srv_stats) {
439                 lprocfs_free_stats(svc->srv_stats);
440                 svc->srv_stats = NULL;
441         }
442 }
443
444 void ptlrpc_lprocfs_unregister_obd(struct obd_device *obd)
445 {
446         if (obd->obd_svc_procroot) {
447                 lprocfs_remove(obd->obd_svc_procroot);
448                 obd->obd_svc_procroot = NULL;
449         }
450         if (obd->obd_svc_stats) {
451                 lprocfs_free_stats(obd->obd_svc_stats);
452                 obd->obd_svc_stats = NULL;
453         }
454 }
455
456 int lprocfs_wr_evict_client(struct file *file, const char *buffer,
457                             unsigned long count, void *data)
458 {
459         struct obd_device *obd = data;
460         struct obd_export *doomed_exp = NULL;
461         struct obd_uuid doomed;
462         struct list_head *p;
463         char tmpbuf[sizeof(doomed)];
464
465         sscanf(buffer, "%40s", tmpbuf);
466         obd_str2uuid(&doomed, tmpbuf);
467
468         spin_lock(&obd->obd_dev_lock);
469         list_for_each(p, &obd->obd_exports) {
470                 doomed_exp = list_entry(p, struct obd_export, exp_obd_chain);
471                 if (obd_uuid_equals(&doomed, &doomed_exp->exp_client_uuid)) {
472                         class_export_get(doomed_exp);
473                         break;
474                 }
475                 doomed_exp = NULL;
476         }
477         spin_unlock(&obd->obd_dev_lock);
478
479         if (doomed_exp == NULL) {
480                 CERROR("can't disconnect %s: no export found\n", doomed.uuid);
481         } else {
482                 CERROR("evicting %s at adminstrative request\n", doomed.uuid);
483                 ptlrpc_fail_export(doomed_exp);
484                 class_export_put(doomed_exp);
485         }
486         return count;
487 }
488 EXPORT_SYMBOL(lprocfs_wr_evict_client);
489 #endif /* LPROCFS */