Whamcloud - gitweb
a10a273c756b84f14e34c3af7cb6ecac25c8625d
[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 #define pct(a,b) (b ? a * 100 / b : 0)
312
313 static int osc_rpc_stats_seq_show(struct seq_file *seq, void *v)
314 {
315         struct timeval now;
316         struct obd_device *dev = seq->private;
317         struct client_obd *cli = &dev->u.cli;
318         unsigned long flags;
319         unsigned long read_tot = 0, write_tot = 0, read_cum, write_cum;
320         int i, rpcs, r, w;
321
322         do_gettimeofday(&now);
323
324         spin_lock_irqsave(&cli->cl_loi_list_lock, flags);
325
326         rpcs = cli->cl_brw_in_flight;
327         r = cli->cl_pending_r_pages;
328         w = cli->cl_pending_w_pages;
329                                                                                 
330         seq_printf(seq, "snapshot_time:         %lu:%lu (secs:usecs)\n",
331                    now.tv_sec, now.tv_usec);
332         seq_printf(seq, "RPCs in flight:        %d\n", rpcs);
333         seq_printf(seq, "pending write pages:   %d\n", w);
334         seq_printf(seq, "pending read pages:   %d\n", r);
335
336         seq_printf(seq, "\n\t\t\tread\t\t\twrite\n");
337         seq_printf(seq, "pages per rpc         rpcs   %% cum %% |");
338         seq_printf(seq, "       rpcs   %% cum %%\n");
339
340         read_tot = lprocfs_oh_sum(&cli->cl_read_page_hist);
341         write_tot = lprocfs_oh_sum(&cli->cl_write_page_hist);
342
343         read_cum = 0;
344         write_cum = 0;
345         for (i = 0; i < OBD_HIST_MAX; i++) {
346                 unsigned long r = cli->cl_read_page_hist.oh_buckets[i];
347                 unsigned long w = cli->cl_write_page_hist.oh_buckets[i];
348                 read_cum += r;
349                 write_cum += w;
350                 seq_printf(seq, "%d:\t\t%10lu %3lu %3lu   | %10lu %3lu %3lu\n", 
351                                  1 << i, r, pct(r, read_tot), 
352                                  pct(read_cum, read_tot), w, 
353                                  pct(w, write_tot),
354                                  pct(write_cum, write_tot));
355                 if (read_cum == read_tot && write_cum == write_tot)
356                         break;
357         }
358
359         seq_printf(seq, "\n\t\t\tread\t\t\twrite\n");
360         seq_printf(seq, "rpcs in flight        rpcs   %% cum %% |");
361         seq_printf(seq, "       rpcs   %% cum %%\n");
362
363         read_tot = lprocfs_oh_sum(&cli->cl_read_rpc_hist);
364         write_tot = lprocfs_oh_sum(&cli->cl_write_rpc_hist);
365
366         read_cum = 0;
367         write_cum = 0;
368         for (i = 0; i < OBD_HIST_MAX; i++) {
369                 unsigned long r = cli->cl_read_rpc_hist.oh_buckets[i];
370                 unsigned long w = cli->cl_write_rpc_hist.oh_buckets[i];
371                 read_cum += r;
372                 write_cum += w;
373                 seq_printf(seq, "%d:\t\t%10lu %3lu %3lu   | %10lu %3lu %3lu\n", 
374                                  i, r, pct(r, read_tot), 
375                                  pct(read_cum, read_tot), w, 
376                                  pct(w, write_tot),
377                                  pct(write_cum, write_tot));
378                 if (read_cum == read_tot && write_cum == write_tot)
379                         break;
380         }
381
382         spin_unlock_irqrestore(&cli->cl_loi_list_lock, flags);
383
384         return 0;
385 }
386 #undef pct
387
388 static void *osc_rpc_stats_seq_start(struct seq_file *p, loff_t *pos)
389 {
390         if (*pos == 0)
391                 return (void *)1;
392         return NULL;
393 }
394 static void *osc_rpc_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
395 {
396         ++*pos;
397         return NULL;
398 }
399 static void osc_rpc_stats_seq_stop(struct seq_file *p, void *v)
400 {
401 }
402 struct seq_operations osc_rpc_stats_seq_sops = {
403         .start = osc_rpc_stats_seq_start,
404         .stop = osc_rpc_stats_seq_stop,
405         .next = osc_rpc_stats_seq_next,
406         .show = osc_rpc_stats_seq_show,
407 };
408
409 static int osc_rpc_stats_seq_open(struct inode *inode, struct file *file)
410 {
411         struct proc_dir_entry *dp = inode->u.generic_ip;
412         struct seq_file *seq;
413         int rc;
414  
415         rc = seq_open(file, &osc_rpc_stats_seq_sops);
416         if (rc)
417                 return rc;
418         seq = file->private_data;
419         seq->private = dp->data;
420         return 0;
421 }
422
423 static ssize_t osc_rpc_stats_seq_write(struct file *file, const char *buf,
424                                        size_t len, loff_t *off)
425 {
426         struct seq_file *seq = file->private_data;
427         struct obd_device *dev = seq->private;
428         struct client_obd *cli = &dev->u.cli;
429
430         lprocfs_oh_clear(&cli->cl_read_rpc_hist);
431         lprocfs_oh_clear(&cli->cl_write_rpc_hist);
432         lprocfs_oh_clear(&cli->cl_read_page_hist);
433         lprocfs_oh_clear(&cli->cl_write_page_hist);
434
435         return len;
436 }
437
438 struct file_operations osc_rpc_stats_fops = {
439         .open    = osc_rpc_stats_seq_open,
440         .read    = seq_read,
441         .write   = osc_rpc_stats_seq_write,
442         .llseek  = seq_lseek,
443         .release = seq_release,
444 };
445
446 int lproc_osc_attach_seqstat(struct obd_device *dev)
447 {
448         return lprocfs_obd_seq_create(dev, "rpc_stats", 0444, 
449                                       &osc_rpc_stats_fops, dev);
450 }
451
452
453 #endif /* LPROCFS */
454 LPROCFS_INIT_VARS(osc,lprocfs_module_vars, lprocfs_obd_vars)