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