extern int lprocfs_write_helper(const char *buffer, unsigned long count,
int *val);
+int lprocfs_obd_seq_create(struct obd_device *dev, char *name, mode_t mode,
+ struct file_operations *seq_fops, void *data);
+struct obd_histogram;
+void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value);
+void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value);
+void lprocfs_oh_clear(struct obd_histogram *oh);
+unsigned long lprocfs_oh_sum(struct obd_histogram *oh);
/* lprocfs_status.c: counter read/write functions */
extern int lprocfs_counter_read(char *page, char **start, off_t off,
wait_queue_head_t osic_waitq;
};
+/* if we find more consumers this could be generalized */
+#define OBD_HIST_MAX 32
+struct obd_histogram {
+ spinlock_t oh_lock;
+ unsigned long oh_buckets[OBD_HIST_MAX];
+};
+
/* Individual type definitions */
struct ost_server_data;
__u64 *fo_last_objids; //last created object ID for groups
struct semaphore fo_alloc_lock;
+
+ struct obd_histogram fo_r_pages;
+ struct obd_histogram fo_w_pages;
+ struct obd_histogram fo_r_discont_pages;
+ struct obd_histogram fo_w_discont_pages;
+ struct obd_histogram fo_r_discont_blocks;
+ struct obd_histogram fo_w_discont_blocks;
};
struct mds_server_data;
-/* if we find more consumers this could be generalized */
-#define OSC_HIST_MAX 32
-struct osc_histogram {
- spinlock_t oh_lock;
- unsigned long oh_buckets[OSC_HIST_MAX];
-};
-
struct mdc_rpc_lock;
struct client_obd {
struct obd_import *cl_import;
int cl_pending_r_pages;
int cl_max_pages_per_rpc;
int cl_max_rpcs_in_flight;
- struct osc_histogram cl_read_rpc_hist;
- struct osc_histogram cl_write_rpc_hist;
- struct osc_histogram cl_read_page_hist;
- struct osc_histogram cl_write_page_hist;
+ struct obd_histogram cl_read_rpc_hist;
+ struct obd_histogram cl_write_rpc_hist;
+ struct obd_histogram cl_read_page_hist;
+ struct obd_histogram cl_write_page_hist;
struct mdc_rpc_lock *cl_rpc_lock;
struct mdc_rpc_lock *cl_setattr_lock;
return 0;
}
+int lprocfs_obd_seq_create(struct obd_device *dev, char *name, mode_t mode,
+ struct file_operations *seq_fops, void *data)
+{
+ struct proc_dir_entry *entry;
+ ENTRY;
+
+ entry = create_proc_entry(name, mode, dev->obd_proc_entry);
+ if (entry == NULL)
+ RETURN(-ENOMEM);
+ entry->proc_fops = seq_fops;
+ entry->data = data;
+
+ RETURN(0);
+}
+EXPORT_SYMBOL(lprocfs_obd_seq_create);
+
+void lprocfs_oh_tally(struct obd_histogram *oh, unsigned int value)
+{
+ unsigned long flags;
+
+ if (value >= OBD_HIST_MAX)
+ value = OBD_HIST_MAX - 1;
+
+ spin_lock_irqsave(&oh->oh_lock, flags);
+ oh->oh_buckets[value]++;
+ spin_unlock_irqrestore(&oh->oh_lock, flags);
+}
+EXPORT_SYMBOL(lprocfs_oh_tally);
+
+void lprocfs_oh_tally_log2(struct obd_histogram *oh, unsigned int value)
+{
+ unsigned int val;
+
+ for (val = 0; ((1 << val) < value) && (val <= OBD_HIST_MAX); val++)
+ ;
+
+ lprocfs_oh_tally(oh, val);
+}
+EXPORT_SYMBOL(lprocfs_oh_tally_log2);
+
+unsigned long lprocfs_oh_sum(struct obd_histogram *oh)
+{
+ unsigned long ret = 0;
+ int i;
+
+ for (i = 0; i < OBD_HIST_MAX; i++)
+ ret += oh->oh_buckets[i];
+ return ret;
+}
+EXPORT_SYMBOL(lprocfs_oh_sum);
+
+void lprocfs_oh_clear(struct obd_histogram *oh)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&oh->oh_lock, flags);
+ memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
+ spin_unlock_irqrestore(&oh->oh_lock, flags);
+}
+EXPORT_SYMBOL(lprocfs_oh_clear);
#endif /* LPROCFS*/
spin_lock_init(&filter->fo_objidlock);
INIT_LIST_HEAD(&filter->fo_export_list);
sema_init(&filter->fo_alloc_lock, 1);
+ spin_lock_init(&filter->fo_r_pages.oh_lock);
+ spin_lock_init(&filter->fo_w_pages.oh_lock);
+ spin_lock_init(&filter->fo_r_discont_pages.oh_lock);
+ spin_lock_init(&filter->fo_w_discont_pages.oh_lock);
+ spin_lock_init(&filter->fo_r_discont_blocks.oh_lock);
+ spin_lock_init(&filter->fo_w_discont_blocks.oh_lock);
obd->obd_namespace = ldlm_namespace_new("filter-tgt",
LDLM_NAMESPACE_SERVER);
LPROCFS_CNTR_AVGMINMAX, "read_bytes", "bytes");
lprocfs_counter_init(obd->obd_stats, LPROC_FILTER_WRITE_BYTES,
LPROCFS_CNTR_AVGMINMAX, "write_bytes", "bytes");
- return rc;
+
+ return lproc_filter_attach_seqstat(obd);
}
static int filter_detach(struct obd_device *dev)
int filter_san_preprw(int cmd, struct obd_export *, struct obdo *, int objcount,
struct obd_ioobj *, int niocount, struct niobuf_remote *);
+#ifdef __KERNEL__
+void filter_tally_write(struct filter_obd *filter, struct page **pages,
+ int nr_pages, unsigned long *blocks,
+ int blocks_per_page);
+void filter_tally_read(struct filter_obd *filter, struct niobuf_local *lnb,
+ int niocount);
+int lproc_filter_attach_seqstat(struct obd_device *dev);
+#else
+static inline filter_tally_write(struct filter_obd *filter,
+ struct page **pages, int nr_pages,
+ unsigned long *blocks, int blocks_per_page) {}
+static inline void filter_tally_read(struct filter_obd *filter,
+ struct niobuf_local *lnb, int niocount)
+ {}
+static inline lproc_filter_attach_seqstat(struct obd_device *dev) {}
+#endif
+
#endif
CDEBUG(D_INFO, "finish_page_read: %lu jiffies\n",
(jiffies - now));
+ filter_tally_read(&exp->exp_obd->u.filter, res, niocount);
+
EXIT;
cleanup:
}
up(&exp->exp_obd->u.filter.fo_alloc_lock);
+ filter_tally_write(&obd->u.filter, iobuf->maplist, iobuf->nr_pages,
+ iobuf->blocks, blocks_per_page);
+
if (attr->ia_size > inode->i_size)
attr->ia_valid |= ATTR_SIZE;
rc = fsfilt_setattr(obd, dchild, oti->oti_handle, attr, 0);
#include <linux/version.h>
#include <linux/lprocfs_status.h>
#include <linux/obd.h>
+#include <linux/seq_file.h>
#include "filter_internal.h"
{ 0 }
};
+void filter_tally_write(struct filter_obd *filter, struct page **pages,
+ int nr_pages, unsigned long *blocks, int blocks_per_page)
+{
+ struct page *last_page = NULL;
+ unsigned long *last_block = NULL;
+ unsigned long discont_pages = 0;
+ unsigned long discont_blocks = 0;
+ int i;
+
+ if (nr_pages == 0)
+ return;
+
+ lprocfs_oh_tally_log2(&filter->fo_w_pages, nr_pages);
+
+ while (nr_pages-- > 0) {
+ if (last_page && (*pages)->index != (last_page->index + 1))
+ discont_pages++;
+ last_page = *pages;
+ pages++;
+ for (i = 0; i < blocks_per_page; i++) {
+ if (last_block && *blocks != (*last_block + 1))
+ discont_blocks++;
+ last_block = blocks++;
+ }
+ }
+
+ lprocfs_oh_tally(&filter->fo_w_discont_pages, discont_pages);
+ lprocfs_oh_tally(&filter->fo_w_discont_blocks, discont_blocks);
+}
+
+void filter_tally_read(struct filter_obd *filter, struct niobuf_local *lnb,
+ int niocount)
+{
+ struct niobuf_local *end;
+ struct page *last_page = NULL;
+ unsigned long discont_pages = 0;
+ unsigned long discont_blocks = 0;
+
+ if (niocount == 0)
+ return;
+
+ for (end = lnb + niocount; lnb < end && lnb->page; lnb++) {
+ struct page *page = lnb->page;
+ if (last_page) {
+ if (page->index != (last_page->index + 1))
+ discont_pages++;
+ /* XXX not so smart for now */
+ if ((page->buffers && last_page->buffers) &&
+ (page->buffers->b_blocknr !=
+ (last_page->buffers->b_blocknr + 1)))
+ discont_blocks++;
+ }
+ last_page = page;
+ }
+
+ lprocfs_oh_tally_log2(&filter->fo_r_pages, niocount);
+ lprocfs_oh_tally(&filter->fo_r_discont_pages, discont_pages);
+ lprocfs_oh_tally(&filter->fo_r_discont_blocks, discont_blocks);
+}
+
+#define pct(a,b) (b ? a * 100 / b : 0)
+
+static int filter_brw_stats_seq_show(struct seq_file *seq, void *v)
+{
+ struct timeval now;
+ struct obd_device *dev = seq->private;
+ struct filter_obd *filter = &dev->u.filter;
+ unsigned long read_tot = 0, write_tot = 0, read_cum, write_cum;
+ int i;
+
+ do_gettimeofday(&now);
+
+ /* this sampling races with updates */
+
+ seq_printf(seq, "snapshot_time: %lu:%lu (secs:usecs)\n",
+ now.tv_sec, now.tv_usec);
+
+ seq_printf(seq, "\n\t\t\tread\t\t\twrite\n");
+ seq_printf(seq, "pages per brw brws %% cum %% |");
+ seq_printf(seq, " rpcs %% cum %%\n");
+
+ read_tot = lprocfs_oh_sum(&filter->fo_r_pages);
+ write_tot = lprocfs_oh_sum(&filter->fo_w_pages);
+
+ read_cum = 0;
+ write_cum = 0;
+ for (i = 0; i < OBD_HIST_MAX; i++) {
+ unsigned long r = filter->fo_r_pages.oh_buckets[i];
+ unsigned long w = filter->fo_w_pages.oh_buckets[i];
+ read_cum += r;
+ write_cum += w;
+ seq_printf(seq, "%d:\t\t%10lu %3lu %3lu | %10lu %3lu %3lu\n",
+ 1 << i, r, pct(r, read_tot),
+ pct(read_cum, read_tot), w,
+ pct(w, write_tot),
+ pct(write_cum, write_tot));
+ if (read_cum == read_tot && write_cum == write_tot)
+ break;
+ }
+
+ seq_printf(seq, "\n\t\t\tread\t\t\twrite\n");
+ seq_printf(seq, "discont pages rpcs %% cum %% |");
+ seq_printf(seq, " rpcs %% cum %%\n");
+
+ read_tot = lprocfs_oh_sum(&filter->fo_r_discont_pages);
+ write_tot = lprocfs_oh_sum(&filter->fo_w_discont_pages);
+
+ read_cum = 0;
+ write_cum = 0;
+
+ for (i = 0; i < OBD_HIST_MAX; i++) {
+ unsigned long r = filter->fo_r_discont_pages.oh_buckets[i];
+ unsigned long w = filter->fo_w_discont_pages.oh_buckets[i];
+ read_cum += r;
+ write_cum += w;
+ seq_printf(seq, "%d:\t\t%10lu %3lu %3lu | %10lu %3lu %3lu\n",
+ i, r, pct(r, read_tot),
+ pct(read_cum, read_tot), w,
+ pct(w, write_tot),
+ pct(write_cum, write_tot));
+ if (read_cum == read_tot && write_cum == write_tot)
+ break;
+ }
+
+ seq_printf(seq, "\n\t\t\tread\t\t\twrite\n");
+ seq_printf(seq, "discont blocks rpcs %% cum %% |");
+ seq_printf(seq, " rpcs %% cum %%\n");
+
+ read_tot = lprocfs_oh_sum(&filter->fo_r_discont_blocks);
+ write_tot = lprocfs_oh_sum(&filter->fo_w_discont_blocks);
+
+ read_cum = 0;
+ write_cum = 0;
+ for (i = 0; i < OBD_HIST_MAX; i++) {
+ unsigned long r = filter->fo_r_discont_blocks.oh_buckets[i];
+ unsigned long w = filter->fo_w_discont_blocks.oh_buckets[i];
+ read_cum += r;
+ write_cum += w;
+ seq_printf(seq, "%d:\t\t%10lu %3lu %3lu | %10lu %3lu %3lu\n",
+ i, r, pct(r, read_tot),
+ pct(read_cum, read_tot), w,
+ pct(w, write_tot),
+ pct(write_cum, write_tot));
+ if (read_cum == read_tot && write_cum == write_tot)
+ break;
+ }
+
+ return 0;
+}
+#undef pct
+
+static void *filter_brw_stats_seq_start(struct seq_file *p, loff_t *pos)
+{
+ if (*pos == 0)
+ return (void *)1;
+ return NULL;
+}
+static void *filter_brw_stats_seq_next(struct seq_file *p, void *v, loff_t *pos)
+{
+ ++*pos;
+ return NULL;
+}
+static void filter_brw_stats_seq_stop(struct seq_file *p, void *v)
+{
+}
+struct seq_operations filter_brw_stats_seq_sops = {
+ .start = filter_brw_stats_seq_start,
+ .stop = filter_brw_stats_seq_stop,
+ .next = filter_brw_stats_seq_next,
+ .show = filter_brw_stats_seq_show,
+};
+
+static int filter_brw_stats_seq_open(struct inode *inode, struct file *file)
+{
+ struct proc_dir_entry *dp = inode->u.generic_ip;
+ struct seq_file *seq;
+ int rc;
+
+ rc = seq_open(file, &filter_brw_stats_seq_sops);
+ if (rc)
+ return rc;
+ seq = file->private_data;
+ seq->private = dp->data;
+ return 0;
+}
+
+static ssize_t filter_brw_stats_seq_write(struct file *file, const char *buf,
+ size_t len, loff_t *off)
+{
+ struct seq_file *seq = file->private_data;
+ struct obd_device *dev = seq->private;
+ struct filter_obd *filter = &dev->u.filter;
+
+ lprocfs_oh_clear(&filter->fo_r_pages);
+ lprocfs_oh_clear(&filter->fo_w_pages);
+ lprocfs_oh_clear(&filter->fo_r_discont_pages);
+ lprocfs_oh_clear(&filter->fo_w_discont_pages);
+ lprocfs_oh_clear(&filter->fo_r_discont_blocks);
+ lprocfs_oh_clear(&filter->fo_w_discont_blocks);
+
+ return len;
+}
+
+struct file_operations filter_brw_stats_fops = {
+ .open = filter_brw_stats_seq_open,
+ .read = seq_read,
+ .write = filter_brw_stats_seq_write,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+int lproc_filter_attach_seqstat(struct obd_device *dev)
+{
+ return lprocfs_obd_seq_create(dev, "brw_stats", 0444,
+ &filter_brw_stats_fops, dev);
+}
+
+
+
#endif /* LPROCFS */
LPROCFS_INIT_VARS(filter,lprocfs_module_vars, lprocfs_obd_vars)
{ 0 }
};
-void lproc_osc_hist(struct osc_histogram *oh, unsigned int value)
-{
- unsigned long flags;
-
- if (value >= OSC_HIST_MAX)
- value = OSC_HIST_MAX - 1;
-
- spin_lock_irqsave(&oh->oh_lock, flags);
- oh->oh_buckets[value]++;
- spin_unlock_irqrestore(&oh->oh_lock, flags);
-}
-
-void lproc_osc_hist_pow2(struct osc_histogram *oh, unsigned int value)
-{
- unsigned int pow;
-
- for (pow = 0; ((1 << pow) < value) && (pow <= OSC_HIST_MAX); pow++)
- ;
-
- lproc_osc_hist(oh, pow);
-}
-
-static unsigned long lproc_oh_sum(struct osc_histogram *oh)
-{
- unsigned long ret = 0;
- int i;
-
- for (i = 0; i < OSC_HIST_MAX; i++)
- ret += oh->oh_buckets[i];
- return ret;
-}
-
-static void lproc_clear_oh(struct osc_histogram *oh)
-{
- unsigned long flags;
- spin_lock_irqsave(&oh->oh_lock, flags);
- memset(oh->oh_buckets, 0, sizeof(oh->oh_buckets));
- spin_unlock_irqrestore(&oh->oh_lock, flags);
-}
-
#define pct(a,b) (b ? a * 100 / b : 0)
static int osc_rpc_stats_seq_show(struct seq_file *seq, void *v)
seq_printf(seq, "pages per rpc rpcs %% cum %% |");
seq_printf(seq, " rpcs %% cum %%\n");
- read_tot = lproc_oh_sum(&cli->cl_read_page_hist);
- write_tot = lproc_oh_sum(&cli->cl_write_page_hist);
+ read_tot = lprocfs_oh_sum(&cli->cl_read_page_hist);
+ write_tot = lprocfs_oh_sum(&cli->cl_write_page_hist);
read_cum = 0;
write_cum = 0;
- for (i = 0; i < OSC_HIST_MAX; i++) {
+ for (i = 0; i < OBD_HIST_MAX; i++) {
unsigned long r = cli->cl_read_page_hist.oh_buckets[i];
unsigned long w = cli->cl_write_page_hist.oh_buckets[i];
read_cum += r;
seq_printf(seq, "rpcs in flight rpcs %% cum %% |");
seq_printf(seq, " rpcs %% cum %%\n");
- read_tot = lproc_oh_sum(&cli->cl_read_rpc_hist);
- write_tot = lproc_oh_sum(&cli->cl_write_rpc_hist);
+ read_tot = lprocfs_oh_sum(&cli->cl_read_rpc_hist);
+ write_tot = lprocfs_oh_sum(&cli->cl_write_rpc_hist);
read_cum = 0;
write_cum = 0;
- for (i = 0; i < OSC_HIST_MAX; i++) {
+ for (i = 0; i < OBD_HIST_MAX; i++) {
unsigned long r = cli->cl_read_rpc_hist.oh_buckets[i];
unsigned long w = cli->cl_write_rpc_hist.oh_buckets[i];
read_cum += r;
struct obd_device *dev = seq->private;
struct client_obd *cli = &dev->u.cli;
- lproc_clear_oh(&cli->cl_read_rpc_hist);
- lproc_clear_oh(&cli->cl_write_rpc_hist);
- lproc_clear_oh(&cli->cl_read_page_hist);
- lproc_clear_oh(&cli->cl_write_page_hist);
+ lprocfs_oh_clear(&cli->cl_read_rpc_hist);
+ lprocfs_oh_clear(&cli->cl_write_rpc_hist);
+ lprocfs_oh_clear(&cli->cl_read_page_hist);
+ lprocfs_oh_clear(&cli->cl_write_page_hist);
return len;
}
int lproc_osc_attach_seqstat(struct obd_device *dev)
{
- struct proc_dir_entry *entry;
- ENTRY;
-
- entry = create_proc_entry("rpc_stats", 0444, dev->obd_proc_entry);
- if (entry == NULL)
- RETURN(-ENOMEM);
- entry->proc_fops = &osc_rpc_stats_fops;
- entry->data = dev;
-
- RETURN(0);
+ return lprocfs_obd_seq_create(dev, "rpc_stats", 0444,
+ &osc_rpc_stats_fops, dev);
}
#include <portals/lib-types.h> /* for PTL_MTU and PTL_MD_MAX_PAGES */
+
/* bug 1578: negotiate BRW_MAX_SIZE with the OST, instead of hard-coding it */
#define OSC_BRW_MAX_SIZE PTL_MTU
#define OSC_BRW_MAX_IOV PTL_MD_MAX_PAGES
void osc_adjust_cache(struct client_obd *cli);
#ifdef __KERNEL__
-
int lproc_osc_attach_seqstat(struct obd_device *dev);
-void lproc_osc_hist(struct osc_histogram *oh, unsigned int value);
-void lproc_osc_hist_pow2(struct osc_histogram *oh, unsigned int value);
-
-#else /* !__KERNEL__ */
-
-#define lproc_osc_attach_seqstat(dev) (0)
-#define lproc_osc_hist(o,v) do{}while(0)
-#define lproc_osc_hist_pow2(o, v) do{}while(0)
-
+#else
+static inline int lproc_osc_attach_seqstat(struct obd_device *dev) {}
#endif
#endif /* OSC_INTERNAL_H */
INIT_LIST_HEAD(&rpc_list);
if (cmd == OBD_BRW_READ)
- lproc_osc_hist_pow2(&cli->cl_read_page_hist, page_count);
+ lprocfs_oh_tally_log2(&cli->cl_read_page_hist, page_count);
else
- lproc_osc_hist_pow2(&cli->cl_write_page_hist, page_count);
+ lprocfs_oh_tally_log2(&cli->cl_write_page_hist, page_count);
spin_lock(&cli->cl_loi_list_lock);
if (cmd == OBD_BRW_READ)
- lproc_osc_hist(&cli->cl_read_rpc_hist, cli->cl_brw_in_flight);
+ lprocfs_oh_tally(&cli->cl_read_rpc_hist, cli->cl_brw_in_flight);
else
- lproc_osc_hist(&cli->cl_write_rpc_hist, cli->cl_brw_in_flight);
+ lprocfs_oh_tally(&cli->cl_write_rpc_hist,
+ cli->cl_brw_in_flight);
cli->cl_brw_in_flight++;
CDEBUG(D_INODE, "req %p: %d pages, aa %p. now %d in flight\n", request,