Whamcloud - gitweb
land v0.9.1 on HEAD, in preparation for a 1.0.x branch
[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         spin_unlock(&cli->cl_loi_list_lock);
141
142         return count;
143 }
144
145 int osc_rd_cur_dirty_bytes(char *page, char **start, off_t off, int count,
146                            int *eof, void *data)
147 {
148         struct obd_device *dev = data;
149         struct client_obd *cli = &dev->u.cli;
150         int rc;
151
152         spin_lock(&cli->cl_loi_list_lock);
153         rc = snprintf(page, count, LPU64"\n", cli->cl_dirty);
154         spin_unlock(&cli->cl_loi_list_lock);
155         return rc;
156 }
157
158 int osc_rd_create_low_wm(char *page, char **start, off_t off, int count,
159                          int *eof, void *data)
160 {
161         struct obd_device *obd = data;
162         struct obd_export *exp;
163
164         if (obd == NULL || list_empty(&obd->obd_exports))
165                 return 0;
166
167         spin_lock(&obd->obd_dev_lock);
168         exp = list_entry(obd->obd_exports.next, struct obd_export,
169                          exp_obd_chain);
170         spin_unlock(&obd->obd_dev_lock);
171
172         return snprintf(page, count, "%d\n",
173                         exp->exp_osc_data.oed_oscc.oscc_kick_barrier);
174 }
175
176 int osc_wr_create_low_wm(struct file *file, const char *buffer,
177                          unsigned long count, void *data)
178 {
179         struct obd_device *obd = data;
180         struct obd_export *exp;
181         int val, rc;
182
183         if (obd == NULL || list_empty(&obd->obd_exports))
184                 return 0;
185
186         rc = lprocfs_write_helper(buffer, count, &val);
187         if (rc)
188                 return rc;
189
190         if (val < 0)
191                 return -ERANGE;
192
193         spin_lock(&obd->obd_dev_lock);
194         exp = list_entry(obd->obd_exports.next, struct obd_export,
195                          exp_obd_chain);
196         exp->exp_osc_data.oed_oscc.oscc_kick_barrier = val;
197         spin_unlock(&obd->obd_dev_lock);
198
199         return count;
200 }
201
202 int osc_rd_create_count(char *page, char **start, off_t off, int count,
203                         int *eof, void *data)
204 {
205         struct obd_device *obd = data;
206         struct obd_export *exp;
207
208         if (obd == NULL || list_empty(&obd->obd_exports))
209                 return 0;
210
211         spin_lock(&obd->obd_dev_lock);
212         exp = list_entry(obd->obd_exports.next, struct obd_export,
213                          exp_obd_chain);
214         spin_unlock(&obd->obd_dev_lock);
215
216         return snprintf(page, count, "%d\n",
217                         exp->exp_osc_data.oed_oscc.oscc_grow_count);
218 }
219
220 int osc_wr_create_count(struct file *file, const char *buffer,
221                         unsigned long count, void *data)
222 {
223         struct obd_device *obd = data;
224         struct obd_export *exp;
225         int val, rc;
226
227         if (obd == NULL || list_empty(&obd->obd_exports))
228                 return 0;
229
230         rc = lprocfs_write_helper(buffer, count, &val);
231         if (rc)
232                 return rc;
233
234         if (val < 0)
235                 return -ERANGE;
236
237         spin_lock(&obd->obd_dev_lock);
238         exp = list_entry(obd->obd_exports.next, struct obd_export,
239                          exp_obd_chain);
240         exp->exp_osc_data.oed_oscc.oscc_grow_count = val;
241         spin_unlock(&obd->obd_dev_lock);
242
243         return count;
244 }
245
246 int osc_rd_prealloc_next_id(char *page, char **start, off_t off, int count,
247                             int *eof, void *data)
248 {
249         struct obd_device *obd = data;
250         struct obd_export *exp;
251
252         if (obd == NULL || list_empty(&obd->obd_exports))
253                 return 0;
254
255         spin_lock(&obd->obd_dev_lock);
256         exp = list_entry(obd->obd_exports.next, struct obd_export,
257                          exp_obd_chain);
258         spin_unlock(&obd->obd_dev_lock);
259
260         return snprintf(page, count, LPU64"\n",
261                         exp->exp_osc_data.oed_oscc.oscc_next_id);
262 }
263
264 int osc_rd_prealloc_last_id(char *page, char **start, off_t off, int count,
265                             int *eof, void *data)
266 {
267         struct obd_device *obd = data;
268         struct obd_export *exp;
269
270         if (obd == NULL || list_empty(&obd->obd_exports))
271                 return 0;
272
273         spin_lock(&obd->obd_dev_lock);
274         exp = list_entry(obd->obd_exports.next, struct obd_export,
275                          exp_obd_chain);
276         spin_unlock(&obd->obd_dev_lock);
277
278         return snprintf(page, count, LPU64"\n",
279                         exp->exp_osc_data.oed_oscc.oscc_last_id);
280 }
281
282 static struct lprocfs_vars lprocfs_obd_vars[] = {
283         { "uuid",            lprocfs_rd_uuid,        0, 0 },
284         { "blocksize",       lprocfs_rd_blksize,     0, 0 },
285         { "kbytestotal",     lprocfs_rd_kbytestotal, 0, 0 },
286         { "kbytesfree",      lprocfs_rd_kbytesfree,  0, 0 },
287         { "filestotal",      lprocfs_rd_filestotal,  0, 0 },
288         { "filesfree",       lprocfs_rd_filesfree,   0, 0 },
289         //{ "filegroups",      lprocfs_rd_filegroups,  0, 0 },
290         { "ost_server_uuid", lprocfs_rd_server_uuid, 0, 0 },
291         { "ost_conn_uuid",   lprocfs_rd_conn_uuid, 0, 0 },
292         { "max_pages_per_rpc", osc_rd_max_pages_per_rpc, 
293                                osc_wr_max_pages_per_rpc, 0 },
294         { "max_rpcs_in_flight", osc_rd_max_rpcs_in_flight, 
295                                 osc_wr_max_rpcs_in_flight, 0 },
296         { "max_dirty_mb", osc_rd_max_dirty_mb, osc_wr_max_dirty_mb, 0 },
297         { "cur_dirty_bytes", osc_rd_cur_dirty_bytes, 0, 0 },
298         {"create_low_watermark", osc_rd_create_low_wm, osc_wr_create_low_wm, 0},
299         { "create_count", osc_rd_create_count, osc_wr_create_count, 0 },
300         { "prealloc_next_id", osc_rd_prealloc_next_id, 0, 0 },
301         { "prealloc_last_id", osc_rd_prealloc_last_id, 0, 0 },
302         { 0 }
303 };
304
305 static struct lprocfs_vars lprocfs_module_vars[] = {
306         { "num_refs",        lprocfs_rd_numrefs,     0, 0 },
307         { 0 }
308 };
309
310 void lproc_osc_hist(struct osc_histogram *oh, unsigned int value)
311 {
312         unsigned long flags;
313
314         if (value >= OSC_HIST_MAX)
315                 value = OSC_HIST_MAX - 1;
316
317         spin_lock_irqsave(&oh->oh_lock, flags);
318         oh->oh_buckets[value]++;
319         spin_unlock_irqrestore(&oh->oh_lock, flags);
320 }
321
322 void lproc_osc_hist_pow2(struct osc_histogram *oh, unsigned int value)
323 {
324         unsigned int pow;
325
326         for (pow = 0; ((1 << pow) < value) && (pow <= OSC_HIST_MAX); pow++)
327                 ;
328
329         lproc_osc_hist(oh, pow);
330 }
331
332 static unsigned long lproc_oh_sum(struct osc_histogram *oh)
333 {
334         unsigned long ret = 0;
335         int i;
336
337         for (i = 0; i < OSC_HIST_MAX; i++)
338                 ret +=  oh->oh_buckets[i];
339         return ret;
340 }
341
342 static void lproc_clear_oh(struct osc_histogram *oh)
343 {
344         unsigned long flags;
345         spin_lock_irqsave(&oh->oh_lock, flags);
346         memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
347         spin_unlock_irqrestore(&oh->oh_lock, flags);
348 }
349
350 #define pct(a,b) (b ? a * 100 / b : 0)
351
352 static int osc_rpc_stats_seq_show(struct seq_file *seq, void *v)
353 {
354         struct timeval now;
355         struct obd_device *dev = seq->private;
356         struct client_obd *cli = &dev->u.cli;
357         unsigned long flags;
358         unsigned long read_tot = 0, write_tot = 0, read_cum, write_cum;
359         int i, rpcs, r, w;
360
361         do_gettimeofday(&now);
362
363         spin_lock_irqsave(&cli->cl_loi_list_lock, flags);
364
365         rpcs = cli->cl_brw_in_flight;
366         r = cli->cl_pending_r_pages;
367         w = cli->cl_pending_w_pages;
368                                                                                 
369         seq_printf(seq, "snapshot_time:         %lu:%lu (secs:usecs)\n",
370                    now.tv_sec, now.tv_usec);
371         seq_printf(seq, "RPCs in flight:        %d\n", rpcs);
372         seq_printf(seq, "pending write pages:   %d\n", w);
373         seq_printf(seq, "pending read pages:   %d\n", r);
374
375         seq_printf(seq, "\n\t\t\tread\t\t\twrite\n");
376         seq_printf(seq, "pages per rpc         rpcs   %% cum %% |");
377         seq_printf(seq, "       rpcs   %% cum %%\n");
378
379         read_tot = lproc_oh_sum(&cli->cl_read_page_hist);
380         write_tot = lproc_oh_sum(&cli->cl_write_page_hist);
381
382         read_cum = 0;
383         write_cum = 0;
384         for (i = 0; i < OSC_HIST_MAX; i++) {
385                 unsigned long r = cli->cl_read_page_hist.oh_buckets[i];
386                 unsigned long w = cli->cl_write_page_hist.oh_buckets[i];
387                 read_cum += r;
388                 write_cum += w;
389                 seq_printf(seq, "%d:\t\t%10lu %3lu %3lu   | %10lu %3lu %3lu\n", 
390                                  1 << i, r, pct(r, read_tot), 
391                                  pct(read_cum, read_tot), w, 
392                                  pct(w, write_tot),
393                                  pct(write_cum, write_tot));
394                 if (read_cum == read_tot && write_cum == write_tot)
395                         break;
396         }
397
398         seq_printf(seq, "\n\t\t\tread\t\t\twrite\n");
399         seq_printf(seq, "rpcs in flight        rpcs   %% cum %% |");
400         seq_printf(seq, "       rpcs   %% cum %%\n");
401
402         read_tot = lproc_oh_sum(&cli->cl_read_rpc_hist);
403         write_tot = lproc_oh_sum(&cli->cl_write_rpc_hist);
404
405         read_cum = 0;
406         write_cum = 0;
407         for (i = 0; i < OSC_HIST_MAX; i++) {
408                 unsigned long r = cli->cl_read_rpc_hist.oh_buckets[i];
409                 unsigned long w = cli->cl_write_rpc_hist.oh_buckets[i];
410                 read_cum += r;
411                 write_cum += w;
412                 seq_printf(seq, "%d:\t\t%10lu %3lu %3lu   | %10lu %3lu %3lu\n", 
413                                  i, r, pct(r, read_tot), 
414                                  pct(read_cum, read_tot), w, 
415                                  pct(w, write_tot),
416                                  pct(write_cum, write_tot));
417                 if (read_cum == read_tot && write_cum == write_tot)
418                         break;
419         }
420
421         spin_unlock_irqrestore(&cli->cl_loi_list_lock, flags);
422
423         return 0;
424 }
425 #undef pct
426
427 static void *osc_rpc_stats_seq_start(struct seq_file *p, loff_t *pos)
428 {
429         if (*pos == 0)
430                 return (void *)1;
431         return NULL;
432 }
433 static void *osc_rpc_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
434 {
435         ++*pos;
436         return NULL;
437 }
438 static void osc_rpc_stats_seq_stop(struct seq_file *p, void *v)
439 {
440 }
441 struct seq_operations osc_rpc_stats_seq_sops = {
442         .start = osc_rpc_stats_seq_start,
443         .stop = osc_rpc_stats_seq_stop,
444         .next = osc_rpc_stats_seq_next,
445         .show = osc_rpc_stats_seq_show,
446 };
447
448 static int osc_rpc_stats_seq_open(struct inode *inode, struct file *file)
449 {
450         struct proc_dir_entry *dp = inode->u.generic_ip;
451         struct seq_file *seq;
452         int rc;
453  
454         rc = seq_open(file, &osc_rpc_stats_seq_sops);
455         if (rc)
456                 return rc;
457         seq = file->private_data;
458         seq->private = dp->data;
459         return 0;
460 }
461
462 static ssize_t osc_rpc_stats_seq_write(struct file *file, const char *buf,
463                                        size_t len, loff_t *off)
464 {
465         struct seq_file *seq = file->private_data;
466         struct obd_device *dev = seq->private;
467         struct client_obd *cli = &dev->u.cli;
468
469         lproc_clear_oh(&cli->cl_read_rpc_hist);
470         lproc_clear_oh(&cli->cl_write_rpc_hist);
471         lproc_clear_oh(&cli->cl_read_page_hist);
472         lproc_clear_oh(&cli->cl_write_page_hist);
473
474         return len;
475 }
476
477 struct file_operations osc_rpc_stats_fops = {
478         .open    = osc_rpc_stats_seq_open,
479         .read    = seq_read,
480         .write   = osc_rpc_stats_seq_write,
481         .llseek  = seq_lseek,
482         .release = seq_release,
483 };
484
485 int lproc_osc_attach_seqstat(struct obd_device *dev)
486 {
487         struct proc_dir_entry *entry;
488         ENTRY;
489
490         entry = create_proc_entry("rpc_stats", 0444, dev->obd_proc_entry);
491         if (entry == NULL)
492                 RETURN(-ENOMEM);
493         entry->proc_fops = &osc_rpc_stats_fops;
494         entry->data = dev;
495
496         RETURN(0);
497 }
498
499
500 #endif /* LPROCFS */
501 LPROCFS_INIT_VARS(osc,lprocfs_module_vars, lprocfs_obd_vars)