Whamcloud - gitweb
r=zab,phil
[fs/lustre-release.git] / lustre / osc / lproc_osc.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (C) 2002, 2003 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/version.h>
25 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
26 #include <asm/statfs.h>
27 #endif
28 #include <linux/obd_class.h>
29 #include <linux/lprocfs_status.h>
30 #include <linux/seq_file.h>
31 #include "osc_internal.h"
32
33 #ifndef LPROCFS
34 static struct lprocfs_vars lprocfs_obd_vars[]  = { {0} };
35 static struct lprocfs_vars lprocfs_module_vars[] = { {0} };
36 #else
37
38 #define OSC_MAX_RIF_MAX 32
39 #define OSC_MAX_DIRTY_MB_MAX 4096 /* totally arbitrary */
40
41 int osc_rd_max_pages_per_rpc(char *page, char **start, off_t off, int count,
42                              int *eof, void *data)
43 {
44         struct obd_device *dev = data;
45         struct client_obd *cli = &dev->u.cli;
46         int rc;
47
48         spin_lock(&cli->cl_loi_list_lock);
49         rc = snprintf(page, count, "%d\n", cli->cl_max_pages_per_rpc);
50         spin_unlock(&cli->cl_loi_list_lock);
51         return rc;
52 }
53
54 int osc_wr_max_pages_per_rpc(struct file *file, const char *buffer,
55                              unsigned long count, void *data)
56 {
57         struct obd_device *dev = data;
58         struct client_obd *cli = &dev->u.cli;
59         int val, rc;
60
61         rc = lprocfs_write_helper(buffer, count, &val);
62         if (rc)
63                 return rc;
64
65         if (val < 1 || val > PTL_MD_MAX_PAGES)
66                 return -ERANGE;
67
68         spin_lock(&cli->cl_loi_list_lock);
69         cli->cl_max_pages_per_rpc = val;
70         spin_unlock(&cli->cl_loi_list_lock);
71
72         return count;
73 }
74
75 int osc_rd_max_rpcs_in_flight(char *page, char **start, off_t off, int count,
76                               int *eof, void *data)
77 {
78         struct obd_device *dev = data;
79         struct client_obd *cli = &dev->u.cli;
80         int rc;
81
82         spin_lock(&cli->cl_loi_list_lock);
83         rc = snprintf(page, count, "%d\n", cli->cl_max_rpcs_in_flight);
84         spin_unlock(&cli->cl_loi_list_lock);
85         return rc;
86 }
87
88 int osc_wr_max_rpcs_in_flight(struct file *file, const char *buffer,
89                               unsigned long count, void *data)
90 {
91         struct obd_device *dev = data;
92         struct client_obd *cli = &dev->u.cli;
93         int val, rc;
94
95         rc = lprocfs_write_helper(buffer, count, &val);
96         if (rc)
97                 return rc;
98
99         if (val < 1 || val > OSC_MAX_RIF_MAX)
100                 return -ERANGE;
101
102         spin_lock(&cli->cl_loi_list_lock);
103         cli->cl_max_rpcs_in_flight = val;
104         spin_unlock(&cli->cl_loi_list_lock);
105
106         return count;
107 }
108
109 int osc_rd_max_dirty_mb(char *page, char **start, off_t off, int count,
110                         int *eof, void *data)
111 {
112         struct obd_device *dev = data;
113         struct client_obd *cli = &dev->u.cli;
114         int val;
115         int rc;
116
117         spin_lock(&cli->cl_loi_list_lock);
118         val = cli->cl_dirty_max >> 20;
119         rc = snprintf(page, count, "%d\n", val);
120         spin_unlock(&cli->cl_loi_list_lock);
121         return rc;
122 }
123
124 int osc_wr_max_dirty_mb(struct file *file, const char *buffer,
125                         unsigned long count, void *data)
126 {
127         struct obd_device *dev = data;
128         struct client_obd *cli = &dev->u.cli;
129         int val, rc;
130
131         rc = lprocfs_write_helper(buffer, count, &val);
132         if (rc)
133                 return rc;
134
135         if (val < 0 || val > OSC_MAX_DIRTY_MB_MAX)
136                 return -ERANGE;
137
138         spin_lock(&cli->cl_loi_list_lock);
139         cli->cl_dirty_max = (obd_count)val * 1024 * 1024;
140         osc_adjust_cache(cli);
141         spin_unlock(&cli->cl_loi_list_lock);
142
143         return count;
144 }
145
146 int osc_rd_cur_dirty_bytes(char *page, char **start, off_t off, int count,
147                            int *eof, void *data)
148 {
149         struct obd_device *dev = data;
150         struct client_obd *cli = &dev->u.cli;
151         int rc;
152
153         spin_lock(&cli->cl_loi_list_lock);
154         rc = snprintf(page, count, LPU64"\n", cli->cl_dirty);
155         spin_unlock(&cli->cl_loi_list_lock);
156         return rc;
157 }
158
159 int osc_rd_create_low_wm(char *page, char **start, off_t off, int count,
160                          int *eof, void *data)
161 {
162         struct obd_device *obd = data;
163         struct obd_export *exp;
164
165         if (obd == NULL || list_empty(&obd->obd_exports))
166                 return 0;
167
168         spin_lock(&obd->obd_dev_lock);
169         exp = list_entry(obd->obd_exports.next, struct obd_export,
170                          exp_obd_chain);
171         spin_unlock(&obd->obd_dev_lock);
172
173         return snprintf(page, count, "%d\n",
174                         exp->exp_osc_data.oed_oscc.oscc_kick_barrier);
175 }
176
177 int osc_wr_create_low_wm(struct file *file, const char *buffer,
178                          unsigned long count, void *data)
179 {
180         struct obd_device *obd = data;
181         struct obd_export *exp;
182         int val, rc;
183
184         if (obd == NULL || list_empty(&obd->obd_exports))
185                 return 0;
186
187         rc = lprocfs_write_helper(buffer, count, &val);
188         if (rc)
189                 return rc;
190
191         if (val < 0)
192                 return -ERANGE;
193
194         spin_lock(&obd->obd_dev_lock);
195         exp = list_entry(obd->obd_exports.next, struct obd_export,
196                          exp_obd_chain);
197         exp->exp_osc_data.oed_oscc.oscc_kick_barrier = val;
198         spin_unlock(&obd->obd_dev_lock);
199
200         return count;
201 }
202
203 int osc_rd_create_count(char *page, char **start, off_t off, int count,
204                         int *eof, void *data)
205 {
206         struct obd_device *obd = data;
207         struct obd_export *exp;
208
209         if (obd == NULL || list_empty(&obd->obd_exports))
210                 return 0;
211
212         spin_lock(&obd->obd_dev_lock);
213         exp = list_entry(obd->obd_exports.next, struct obd_export,
214                          exp_obd_chain);
215         spin_unlock(&obd->obd_dev_lock);
216
217         return snprintf(page, count, "%d\n",
218                         exp->exp_osc_data.oed_oscc.oscc_grow_count);
219 }
220
221 int osc_wr_create_count(struct file *file, const char *buffer,
222                         unsigned long count, void *data)
223 {
224         struct obd_device *obd = data;
225         struct obd_export *exp;
226         int val, rc;
227
228         if (obd == NULL || list_empty(&obd->obd_exports))
229                 return 0;
230
231         rc = lprocfs_write_helper(buffer, count, &val);
232         if (rc)
233                 return rc;
234
235         if (val < 0)
236                 return -ERANGE;
237
238         spin_lock(&obd->obd_dev_lock);
239         exp = list_entry(obd->obd_exports.next, struct obd_export,
240                          exp_obd_chain);
241         exp->exp_osc_data.oed_oscc.oscc_grow_count = val;
242         spin_unlock(&obd->obd_dev_lock);
243
244         return count;
245 }
246
247 int osc_rd_prealloc_next_id(char *page, char **start, off_t off, int count,
248                             int *eof, void *data)
249 {
250         struct obd_device *obd = data;
251         struct obd_export *exp;
252
253         if (obd == NULL || list_empty(&obd->obd_exports))
254                 return 0;
255
256         spin_lock(&obd->obd_dev_lock);
257         exp = list_entry(obd->obd_exports.next, struct obd_export,
258                          exp_obd_chain);
259         spin_unlock(&obd->obd_dev_lock);
260
261         return snprintf(page, count, LPU64"\n",
262                         exp->exp_osc_data.oed_oscc.oscc_next_id);
263 }
264
265 int osc_rd_prealloc_last_id(char *page, char **start, off_t off, int count,
266                             int *eof, void *data)
267 {
268         struct obd_device *obd = data;
269         struct obd_export *exp;
270
271         if (obd == NULL || list_empty(&obd->obd_exports))
272                 return 0;
273
274         spin_lock(&obd->obd_dev_lock);
275         exp = list_entry(obd->obd_exports.next, struct obd_export,
276                          exp_obd_chain);
277         spin_unlock(&obd->obd_dev_lock);
278
279         return snprintf(page, count, LPU64"\n",
280                         exp->exp_osc_data.oed_oscc.oscc_last_id);
281 }
282
283 static struct lprocfs_vars lprocfs_obd_vars[] = {
284         { "uuid",            lprocfs_rd_uuid,        0, 0 },
285         { "blocksize",       lprocfs_rd_blksize,     0, 0 },
286         { "kbytestotal",     lprocfs_rd_kbytestotal, 0, 0 },
287         { "kbytesfree",      lprocfs_rd_kbytesfree,  0, 0 },
288         { "filestotal",      lprocfs_rd_filestotal,  0, 0 },
289         { "filesfree",       lprocfs_rd_filesfree,   0, 0 },
290         //{ "filegroups",      lprocfs_rd_filegroups,  0, 0 },
291         { "ost_server_uuid", lprocfs_rd_server_uuid, 0, 0 },
292         { "ost_conn_uuid",   lprocfs_rd_conn_uuid, 0, 0 },
293         { "max_pages_per_rpc", osc_rd_max_pages_per_rpc, 
294                                osc_wr_max_pages_per_rpc, 0 },
295         { "max_rpcs_in_flight", osc_rd_max_rpcs_in_flight, 
296                                 osc_wr_max_rpcs_in_flight, 0 },
297         { "max_dirty_mb", osc_rd_max_dirty_mb, osc_wr_max_dirty_mb, 0 },
298         { "cur_dirty_bytes", osc_rd_cur_dirty_bytes, 0, 0 },
299         {"create_low_watermark", osc_rd_create_low_wm, osc_wr_create_low_wm, 0},
300         { "create_count", osc_rd_create_count, osc_wr_create_count, 0 },
301         { "prealloc_next_id", osc_rd_prealloc_next_id, 0, 0 },
302         { "prealloc_last_id", osc_rd_prealloc_last_id, 0, 0 },
303         { 0 }
304 };
305
306 static struct lprocfs_vars lprocfs_module_vars[] = {
307         { "num_refs",        lprocfs_rd_numrefs,     0, 0 },
308         { 0 }
309 };
310
311 void lproc_osc_hist(struct osc_histogram *oh, unsigned int value)
312 {
313         unsigned long flags;
314
315         if (value >= OSC_HIST_MAX)
316                 value = OSC_HIST_MAX - 1;
317
318         spin_lock_irqsave(&oh->oh_lock, flags);
319         oh->oh_buckets[value]++;
320         spin_unlock_irqrestore(&oh->oh_lock, flags);
321 }
322
323 void lproc_osc_hist_pow2(struct osc_histogram *oh, unsigned int value)
324 {
325         unsigned int pow;
326
327         for (pow = 0; ((1 << pow) < value) && (pow <= OSC_HIST_MAX); pow++)
328                 ;
329
330         lproc_osc_hist(oh, pow);
331 }
332
333 static unsigned long lproc_oh_sum(struct osc_histogram *oh)
334 {
335         unsigned long ret = 0;
336         int i;
337
338         for (i = 0; i < OSC_HIST_MAX; i++)
339                 ret +=  oh->oh_buckets[i];
340         return ret;
341 }
342
343 static void lproc_clear_oh(struct osc_histogram *oh)
344 {
345         unsigned long flags;
346         spin_lock_irqsave(&oh->oh_lock, flags);
347         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
348         spin_unlock_irqrestore(&oh->oh_lock, flags);
349 }
350
351 #define pct(a,b) (b ? a * 100 / b : 0)
352
353 static int osc_rpc_stats_seq_show(struct seq_file *seq, void *v)
354 {
355         struct timeval now;
356         struct obd_device *dev = seq->private;
357         struct client_obd *cli = &dev->u.cli;
358         unsigned long flags;
359         unsigned long read_tot = 0, write_tot = 0, read_cum, write_cum;
360         int i, rpcs, r, w;
361
362         do_gettimeofday(&now);
363
364         spin_lock_irqsave(&cli->cl_loi_list_lock, flags);
365
366         rpcs = cli->cl_brw_in_flight;
367         r = cli->cl_pending_r_pages;
368         w = cli->cl_pending_w_pages;
369                                                                                 
370         seq_printf(seq, "snapshot_time:         %lu:%lu (secs:usecs)\n",
371                    now.tv_sec, now.tv_usec);
372         seq_printf(seq, "RPCs in flight:        %d\n", rpcs);
373         seq_printf(seq, "pending write pages:   %d\n", w);
374         seq_printf(seq, "pending read pages:   %d\n", r);
375
376         seq_printf(seq, "\n\t\t\tread\t\t\twrite\n");
377         seq_printf(seq, "pages per rpc         rpcs   %% cum %% |");
378         seq_printf(seq, "       rpcs   %% cum %%\n");
379
380         read_tot = lproc_oh_sum(&cli->cl_read_page_hist);
381         write_tot = lproc_oh_sum(&cli->cl_write_page_hist);
382
383         read_cum = 0;
384         write_cum = 0;
385         for (i = 0; i < OSC_HIST_MAX; i++) {
386                 unsigned long r = cli->cl_read_page_hist.oh_buckets[i];
387                 unsigned long w = cli->cl_write_page_hist.oh_buckets[i];
388                 read_cum += r;
389                 write_cum += w;
390                 seq_printf(seq, "%d:\t\t%10lu %3lu %3lu   | %10lu %3lu %3lu\n", 
391                                  1 << i, r, pct(r, read_tot), 
392                                  pct(read_cum, read_tot), w, 
393                                  pct(w, write_tot),
394                                  pct(write_cum, write_tot));
395                 if (read_cum == read_tot && write_cum == write_tot)
396                         break;
397         }
398
399         seq_printf(seq, "\n\t\t\tread\t\t\twrite\n");
400         seq_printf(seq, "rpcs in flight        rpcs   %% cum %% |");
401         seq_printf(seq, "       rpcs   %% cum %%\n");
402
403         read_tot = lproc_oh_sum(&cli->cl_read_rpc_hist);
404         write_tot = lproc_oh_sum(&cli->cl_write_rpc_hist);
405
406         read_cum = 0;
407         write_cum = 0;
408         for (i = 0; i < OSC_HIST_MAX; i++) {
409                 unsigned long r = cli->cl_read_rpc_hist.oh_buckets[i];
410                 unsigned long w = cli->cl_write_rpc_hist.oh_buckets[i];
411                 read_cum += r;
412                 write_cum += w;
413                 seq_printf(seq, "%d:\t\t%10lu %3lu %3lu   | %10lu %3lu %3lu\n", 
414                                  i, r, pct(r, read_tot), 
415                                  pct(read_cum, read_tot), w, 
416                                  pct(w, write_tot),
417                                  pct(write_cum, write_tot));
418                 if (read_cum == read_tot && write_cum == write_tot)
419                         break;
420         }
421
422         spin_unlock_irqrestore(&cli->cl_loi_list_lock, flags);
423
424         return 0;
425 }
426 #undef pct
427
428 static void *osc_rpc_stats_seq_start(struct seq_file *p, loff_t *pos)
429 {
430         if (*pos == 0)
431                 return (void *)1;
432         return NULL;
433 }
434 static void *osc_rpc_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
435 {
436         ++*pos;
437         return NULL;
438 }
439 static void osc_rpc_stats_seq_stop(struct seq_file *p, void *v)
440 {
441 }
442 struct seq_operations osc_rpc_stats_seq_sops = {
443         .start = osc_rpc_stats_seq_start,
444         .stop = osc_rpc_stats_seq_stop,
445         .next = osc_rpc_stats_seq_next,
446         .show = osc_rpc_stats_seq_show,
447 };
448
449 static int osc_rpc_stats_seq_open(struct inode *inode, struct file *file)
450 {
451         struct proc_dir_entry *dp = inode->u.generic_ip;
452         struct seq_file *seq;
453         int rc;
454  
455         rc = seq_open(file, &osc_rpc_stats_seq_sops);
456         if (rc)
457                 return rc;
458         seq = file->private_data;
459         seq->private = dp->data;
460         return 0;
461 }
462
463 static ssize_t osc_rpc_stats_seq_write(struct file *file, const char *buf,
464                                        size_t len, loff_t *off)
465 {
466         struct seq_file *seq = file->private_data;
467         struct obd_device *dev = seq->private;
468         struct client_obd *cli = &dev->u.cli;
469
470         lproc_clear_oh(&cli->cl_read_rpc_hist);
471         lproc_clear_oh(&cli->cl_write_rpc_hist);
472         lproc_clear_oh(&cli->cl_read_page_hist);
473         lproc_clear_oh(&cli->cl_write_page_hist);
474
475         return len;
476 }
477
478 struct file_operations osc_rpc_stats_fops = {
479         .open    = osc_rpc_stats_seq_open,
480         .read    = seq_read,
481         .write   = osc_rpc_stats_seq_write,
482         .llseek  = seq_lseek,
483         .release = seq_release,
484 };
485
486 int lproc_osc_attach_seqstat(struct obd_device *dev)
487 {
488         struct proc_dir_entry *entry;
489         ENTRY;
490
491         entry = create_proc_entry("rpc_stats", 0444, dev->obd_proc_entry);
492         if (entry == NULL)
493                 RETURN(-ENOMEM);
494         entry->proc_fops = &osc_rpc_stats_fops;
495         entry->data = dev;
496
497         RETURN(0);
498 }
499
500
501 #endif /* LPROCFS */
502 LPROCFS_INIT_VARS(osc,lprocfs_module_vars, lprocfs_obd_vars)