}
#undef MAX_STRING_SIZE
-static void ll_display_extents_info(struct ll_rw_extents_info *io_extents,
- struct seq_file *seq, int which)
-{
- unsigned long read_tot = 0, write_tot = 0, read_cum, write_cum;
- unsigned long start, end, r, w;
- char *unitp = "KMGTPEZY";
- int i, units = 10;
- struct per_process_info *pp_info = &io_extents->pp_extents[which];
-
- read_cum = 0;
- write_cum = 0;
- start = 0;
-
- for(i = 0; i < LL_HIST_MAX; i++) {
- read_tot += pp_info->pp_r_hist.oh_buckets[i];
- write_tot += pp_info->pp_w_hist.oh_buckets[i];
- }
+static void ll_display_extents_info(struct ll_rw_extents_info *rw_extents,
+ struct seq_file *seq, int which)
+{
+ unsigned long read_tot = 0, write_tot = 0, read_cum, write_cum;
+ unsigned long start, end, r, w;
+ char *unitp = "KMGTPEZY";
+ int i, units = 10;
+ struct per_process_info *pp_info;
+
+ pp_info = &rw_extents->pp_extents[which];
+ read_cum = 0;
+ write_cum = 0;
+ start = 0;
+
+ for (i = 0; i < LL_HIST_MAX; i++) {
+ read_tot += pp_info->pp_r_hist.oh_buckets[i];
+ write_tot += pp_info->pp_w_hist.oh_buckets[i];
+ }
- for(i = 0; i < LL_HIST_MAX; i++) {
+ for (i = 0; i < LL_HIST_MAX; i++) {
r = pp_info->pp_r_hist.oh_buckets[i];
w = pp_info->pp_w_hist.oh_buckets[i];
read_cum += r;
static int ll_rw_extents_stats_pp_seq_show(struct seq_file *seq, void *v)
{
struct ll_sb_info *sbi = seq->private;
- struct ll_rw_extents_info *io_extents = &sbi->ll_rw_extents_info;
+ struct ll_rw_extents_info *rw_extents = sbi->ll_rw_extents_info;
int k;
- if (!sbi->ll_rw_stats_on) {
+ if (!sbi->ll_rw_stats_on || !rw_extents) {
seq_puts(seq, "disabled\n write anything to this file to activate, then '0' or 'disable' to deactivate\n");
return 0;
}
- lprocfs_stats_header(seq, ktime_get(), io_extents->pp_init, 25, ":", 1);
+
+ spin_lock(&sbi->ll_pp_extent_lock);
+ lprocfs_stats_header(seq, ktime_get(), rw_extents->pp_init, 25, ":", 1);
seq_printf(seq, "%15s %19s | %20s\n", " ", "read", "write");
seq_printf(seq, "%13s %14s %4s %4s | %14s %4s %4s\n",
- "extents", "calls", "%", "cum%",
- "calls", "%", "cum%");
- spin_lock(&sbi->ll_pp_extent_lock);
+ "extents", "calls", "%", "cum%", "calls", "%", "cum%");
+
for (k = 0; k < LL_PROCESS_HIST_MAX; k++) {
- if (io_extents->pp_extents[k].pid != 0) {
+ if (rw_extents->pp_extents[k].pid != 0) {
seq_printf(seq, "\nPID: %d\n",
- io_extents->pp_extents[k].pid);
- ll_display_extents_info(io_extents, seq, k);
+ rw_extents->pp_extents[k].pid);
+ ll_display_extents_info(rw_extents, seq, k);
}
}
spin_unlock(&sbi->ll_pp_extent_lock);
return 0;
}
+static int alloc_rw_stats_info(struct ll_sb_info *sbi)
+{
+ struct ll_rw_extents_info *rw_extents;
+ struct ll_rw_process_info *offset;
+ struct ll_rw_process_info *process;
+ int i, rc = 0;
+
+ OBD_ALLOC(rw_extents, sizeof(*rw_extents));
+ if (!rw_extents)
+ return -ENOMEM;
+
+ for (i = 0; i <= LL_PROCESS_HIST_MAX; i++) {
+ spin_lock_init(&rw_extents->pp_extents[i].pp_r_hist.oh_lock);
+ spin_lock_init(&rw_extents->pp_extents[i].pp_w_hist.oh_lock);
+ }
+
+ spin_lock(&sbi->ll_pp_extent_lock);
+ if (!sbi->ll_rw_extents_info)
+ sbi->ll_rw_extents_info = rw_extents;
+ spin_unlock(&sbi->ll_pp_extent_lock);
+ /* another writer allocated the struct before we got the lock */
+ if (sbi->ll_rw_extents_info != rw_extents)
+ OBD_FREE(rw_extents, sizeof(*rw_extents));
+
+ OBD_ALLOC(process, sizeof(*process) * LL_PROCESS_HIST_MAX);
+ if (!process)
+ GOTO(out, rc = -ENOMEM);
+ OBD_ALLOC(offset, sizeof(*offset) * LL_OFFSET_HIST_MAX);
+ if (!offset)
+ GOTO(out_free, rc = -ENOMEM);
+
+ spin_lock(&sbi->ll_process_lock);
+ if (!sbi->ll_rw_process_info)
+ sbi->ll_rw_process_info = process;
+ if (!sbi->ll_rw_offset_info)
+ sbi->ll_rw_offset_info = offset;
+ spin_unlock(&sbi->ll_process_lock);
+
+ /* another writer allocated the structs before we got the lock */
+ if (sbi->ll_rw_offset_info != offset)
+ OBD_FREE(offset, sizeof(*offset) * LL_OFFSET_HIST_MAX);
+ if (sbi->ll_rw_process_info != process) {
+out_free:
+ OBD_FREE(process, sizeof(*process) * LL_PROCESS_HIST_MAX);
+ }
+
+out:
+ return rc;
+}
+
+void ll_free_rw_stats_info(struct ll_sb_info *sbi)
+{
+ if (sbi->ll_rw_extents_info) {
+ OBD_FREE(sbi->ll_rw_extents_info,
+ sizeof(*sbi->ll_rw_extents_info));
+ sbi->ll_rw_extents_info = NULL;
+ }
+ if (sbi->ll_rw_offset_info) {
+ OBD_FREE(sbi->ll_rw_offset_info,
+ sizeof(*sbi->ll_rw_offset_info) * LL_OFFSET_HIST_MAX);
+ sbi->ll_rw_offset_info = NULL;
+ }
+ if (sbi->ll_rw_process_info) {
+ OBD_FREE(sbi->ll_rw_process_info,
+ sizeof(*sbi->ll_rw_process_info) * LL_PROCESS_HIST_MAX);
+ sbi->ll_rw_process_info = NULL;
+ }
+}
+
static ssize_t ll_rw_extents_stats_pp_seq_write(struct file *file,
const char __user *buf,
- size_t len,
- loff_t *off)
+ size_t len, loff_t *off)
{
struct seq_file *seq = file->private_data;
struct ll_sb_info *sbi = seq->private;
- struct ll_rw_extents_info *io_extents = &sbi->ll_rw_extents_info;
+ struct ll_rw_extents_info *rw_extents;
int i;
__s64 value;
value = ll_stats_pid_write(buf, len);
- if (value == 0)
+ if (value == 0) {
sbi->ll_rw_stats_on = 0;
- else
+ } else {
+ if (!sbi->ll_rw_extents_info) {
+ int rc = alloc_rw_stats_info(sbi);
+
+ if (rc)
+ return rc;
+ }
sbi->ll_rw_stats_on = 1;
+ }
+
spin_lock(&sbi->ll_pp_extent_lock);
- io_extents->pp_init = ktime_get();
- for (i = 0; i < LL_PROCESS_HIST_MAX; i++) {
- io_extents->pp_extents[i].pid = 0;
- lprocfs_oh_clear(&io_extents->pp_extents[i].pp_r_hist);
- lprocfs_oh_clear(&io_extents->pp_extents[i].pp_w_hist);
+ rw_extents = sbi->ll_rw_extents_info;
+ if (rw_extents) {
+ rw_extents->pp_init = ktime_get();
+ for (i = 0; i < LL_PROCESS_HIST_MAX; i++) {
+ rw_extents->pp_extents[i].pid = 0;
+ lprocfs_oh_clear(&rw_extents->pp_extents[i].pp_r_hist);
+ lprocfs_oh_clear(&rw_extents->pp_extents[i].pp_w_hist);
+ }
}
spin_unlock(&sbi->ll_pp_extent_lock);
+
return len;
}
static int ll_rw_extents_stats_seq_show(struct seq_file *seq, void *v)
{
struct ll_sb_info *sbi = seq->private;
- struct ll_rw_extents_info *io_extents = &sbi->ll_rw_extents_info;
+ struct ll_rw_extents_info *rw_extents = sbi->ll_rw_extents_info;
- if (!sbi->ll_rw_stats_on) {
+ if (!sbi->ll_rw_stats_on || !rw_extents) {
seq_puts(seq, "disabled\n write anything to this file to activate, then '0' or 'disable' to deactivate\n");
return 0;
}
- lprocfs_stats_header(seq, ktime_get(), io_extents->pp_init, 25, ":", 1);
+ spin_lock(&sbi->ll_lock);
+ lprocfs_stats_header(seq, ktime_get(), rw_extents->pp_init, 25, ":", 1);
seq_printf(seq, "%15s %19s | %20s\n", " ", "read", "write");
seq_printf(seq, "%13s %14s %4s %4s | %14s %4s %4s\n",
"extents", "calls", "%", "cum%",
"calls", "%", "cum%");
- spin_lock(&sbi->ll_lock);
- ll_display_extents_info(io_extents, seq, LL_PROCESS_HIST_MAX);
+
+ ll_display_extents_info(rw_extents, seq, LL_PROCESS_HIST_MAX);
spin_unlock(&sbi->ll_lock);
return 0;
{
struct seq_file *seq = file->private_data;
struct ll_sb_info *sbi = seq->private;
- struct ll_rw_extents_info *io_extents = &sbi->ll_rw_extents_info;
+ struct ll_rw_extents_info *rw_extents;
int i;
__s64 value;
value = ll_stats_pid_write(buf, len);
- if (value == 0)
+ if (value == 0) {
sbi->ll_rw_stats_on = 0;
- else
+ } else {
+ if (!sbi->ll_rw_extents_info) {
+ int rc = alloc_rw_stats_info(sbi);
+
+ if (rc)
+ return rc;
+ }
sbi->ll_rw_stats_on = 1;
+ }
spin_lock(&sbi->ll_pp_extent_lock);
- io_extents->pp_init = ktime_get();
- for (i = 0; i <= LL_PROCESS_HIST_MAX; i++) {
- io_extents->pp_extents[i].pid = 0;
- lprocfs_oh_clear(&io_extents->pp_extents[i].pp_r_hist);
- lprocfs_oh_clear(&io_extents->pp_extents[i].pp_w_hist);
+ rw_extents = sbi->ll_rw_extents_info;
+ if (rw_extents) {
+ rw_extents->pp_init = ktime_get();
+ for (i = 0; i <= LL_PROCESS_HIST_MAX; i++) {
+ rw_extents->pp_extents[i].pid = 0;
+ lprocfs_oh_clear(&rw_extents->pp_extents[i].pp_r_hist);
+ lprocfs_oh_clear(&rw_extents->pp_extents[i].pp_w_hist);
+ }
}
spin_unlock(&sbi->ll_pp_extent_lock);
LDEBUGFS_SEQ_FOPS(ll_rw_extents_stats);
void ll_rw_stats_tally(struct ll_sb_info *sbi, pid_t pid,
- struct ll_file_data *file, loff_t pos,
- size_t count, int rw)
+ struct ll_file_data *file, loff_t pos,
+ size_t count, int rw)
{
- int i, cur = -1;
- struct ll_rw_process_info *process;
- struct ll_rw_process_info *offset;
- int *off_count = &sbi->ll_rw_offset_entry_count;
- int *process_count = &sbi->ll_offset_process_count;
- struct ll_rw_extents_info *io_extents = &sbi->ll_rw_extents_info;
+ int i, cur = -1;
+ struct ll_rw_process_info *process;
+ struct ll_rw_process_info *offset;
+ int *off_count = &sbi->ll_rw_offset_entry_count;
+ int *process_count = &sbi->ll_offset_process_count;
+ struct ll_rw_extents_info *rw_extents;
- if(!sbi->ll_rw_stats_on)
- return;
- process = sbi->ll_rw_process_info;
- offset = sbi->ll_rw_offset_info;
+ if (!sbi->ll_rw_stats_on)
+ return;
spin_lock(&sbi->ll_pp_extent_lock);
- /* Extent statistics */
- for(i = 0; i < LL_PROCESS_HIST_MAX; i++) {
- if(io_extents->pp_extents[i].pid == pid) {
- cur = i;
- break;
- }
- }
-
- if (cur == -1) {
- /* new process */
- sbi->ll_extent_process_count =
- (sbi->ll_extent_process_count + 1) % LL_PROCESS_HIST_MAX;
- cur = sbi->ll_extent_process_count;
- io_extents->pp_extents[cur].pid = pid;
- lprocfs_oh_clear(&io_extents->pp_extents[cur].pp_r_hist);
- lprocfs_oh_clear(&io_extents->pp_extents[cur].pp_w_hist);
- }
+ rw_extents = sbi->ll_rw_extents_info;
+ if (!rw_extents) {
+ spin_unlock(&sbi->ll_pp_extent_lock);
+ return;
+ }
+
+ /* Extent statistics */
+ for (i = 0; i < LL_PROCESS_HIST_MAX; i++) {
+ if (rw_extents->pp_extents[i].pid == pid) {
+ cur = i;
+ break;
+ }
+ }
+
+ if (cur == -1) {
+ /* new process */
+ sbi->ll_extent_process_count =
+ (sbi->ll_extent_process_count + 1) % LL_PROCESS_HIST_MAX;
+ cur = sbi->ll_extent_process_count;
+ rw_extents->pp_extents[cur].pid = pid;
+ lprocfs_oh_clear(&rw_extents->pp_extents[cur].pp_r_hist);
+ lprocfs_oh_clear(&rw_extents->pp_extents[cur].pp_w_hist);
+ }
for (i = 0; (count >= 1 << (LL_HIST_START + i)) &&
(i < (LL_HIST_MAX - 1)); i++);
if (rw == 0) {
- io_extents->pp_extents[cur].pp_r_hist.oh_buckets[i]++;
- io_extents->pp_extents[LL_PROCESS_HIST_MAX].pp_r_hist.oh_buckets[i]++;
+ rw_extents->pp_extents[cur].pp_r_hist.oh_buckets[i]++;
+ rw_extents->pp_extents[LL_PROCESS_HIST_MAX].pp_r_hist.oh_buckets[i]++;
} else {
- io_extents->pp_extents[cur].pp_w_hist.oh_buckets[i]++;
- io_extents->pp_extents[LL_PROCESS_HIST_MAX].pp_w_hist.oh_buckets[i]++;
+ rw_extents->pp_extents[cur].pp_w_hist.oh_buckets[i]++;
+ rw_extents->pp_extents[LL_PROCESS_HIST_MAX].pp_w_hist.oh_buckets[i]++;
}
spin_unlock(&sbi->ll_pp_extent_lock);
spin_lock(&sbi->ll_process_lock);
- /* Offset statistics */
- for (i = 0; i < LL_PROCESS_HIST_MAX; i++) {
- if (process[i].rw_pid == pid) {
- if (process[i].rw_last_file != file) {
- process[i].rw_range_start = pos;
- process[i].rw_last_file_pos = pos + count;
- process[i].rw_smallest_extent = count;
- process[i].rw_largest_extent = count;
- process[i].rw_offset = 0;
- process[i].rw_last_file = file;
- spin_unlock(&sbi->ll_process_lock);
- return;
- }
+ process = sbi->ll_rw_process_info;
+ offset = sbi->ll_rw_offset_info;
+ if (!process || !offset)
+ goto out_unlock;
+
+ /* Offset statistics */
+ for (i = 0; i < LL_PROCESS_HIST_MAX; i++) {
+ if (process[i].rw_pid == pid) {
+ if (process[i].rw_last_file != file) {
+ process[i].rw_range_start = pos;
+ process[i].rw_last_file_pos = pos + count;
+ process[i].rw_smallest_extent = count;
+ process[i].rw_largest_extent = count;
+ process[i].rw_offset = 0;
+ process[i].rw_last_file = file;
+ goto out_unlock;
+ }
if (process[i].rw_last_file_pos != pos) {
*off_count =
(*off_count + 1) % LL_OFFSET_HIST_MAX;
process[i].rw_offset = pos -
process[i].rw_last_file_pos;
}
- if(process[i].rw_smallest_extent > count)
- process[i].rw_smallest_extent = count;
- if(process[i].rw_largest_extent < count)
- process[i].rw_largest_extent = count;
- process[i].rw_last_file_pos = pos + count;
- spin_unlock(&sbi->ll_process_lock);
- return;
- }
- }
- *process_count = (*process_count + 1) % LL_PROCESS_HIST_MAX;
- process[*process_count].rw_pid = pid;
- process[*process_count].rw_op = rw;
- process[*process_count].rw_range_start = pos;
- process[*process_count].rw_last_file_pos = pos + count;
- process[*process_count].rw_smallest_extent = count;
- process[*process_count].rw_largest_extent = count;
- process[*process_count].rw_offset = 0;
- process[*process_count].rw_last_file = file;
+ if (process[i].rw_smallest_extent > count)
+ process[i].rw_smallest_extent = count;
+ if (process[i].rw_largest_extent < count)
+ process[i].rw_largest_extent = count;
+ process[i].rw_last_file_pos = pos + count;
+ goto out_unlock;
+ }
+ }
+ *process_count = (*process_count + 1) % LL_PROCESS_HIST_MAX;
+ process[*process_count].rw_pid = pid;
+ process[*process_count].rw_op = rw;
+ process[*process_count].rw_range_start = pos;
+ process[*process_count].rw_last_file_pos = pos + count;
+ process[*process_count].rw_smallest_extent = count;
+ process[*process_count].rw_largest_extent = count;
+ process[*process_count].rw_offset = 0;
+ process[*process_count].rw_last_file = file;
+
+out_unlock:
spin_unlock(&sbi->ll_process_lock);
}
static int ll_rw_offset_stats_seq_show(struct seq_file *seq, void *v)
{
struct ll_sb_info *sbi = seq->private;
- struct ll_rw_process_info *offset = sbi->ll_rw_offset_info;
- struct ll_rw_process_info *process = sbi->ll_rw_process_info;
+ struct ll_rw_process_info *offset;
+ struct ll_rw_process_info *process;
int i;
if (!sbi->ll_rw_stats_on) {
spin_lock(&sbi->ll_process_lock);
lprocfs_stats_header(seq, ktime_get(), sbi->ll_process_stats_init, 25,
":", true);
-
seq_printf(seq, "%3s %10s %14s %14s %17s %17s %14s\n",
"R/W", "PID", "RANGE START", "RANGE END",
"SMALLEST EXTENT", "LARGEST EXTENT", "OFFSET");
/* We stored the discontiguous offsets here; print them first */
- for (i = 0; i < LL_OFFSET_HIST_MAX; i++) {
+ offset = sbi->ll_rw_offset_info;
+ for (i = 0; offset && i < LL_OFFSET_HIST_MAX; i++) {
if (offset[i].rw_pid != 0)
seq_printf(seq,
"%3c %10d %14llu %14llu %17lu %17lu %14lld\n",
}
/* Then print the current offsets for each process */
- for (i = 0; i < LL_PROCESS_HIST_MAX; i++) {
+ process = sbi->ll_rw_process_info;
+ for (i = 0; process && i < LL_PROCESS_HIST_MAX; i++) {
if (process[i].rw_pid != 0)
seq_printf(seq,
"%3c %10d %14llu %14llu %17lu %17lu %14lld\n",
{
struct seq_file *seq = file->private_data;
struct ll_sb_info *sbi = seq->private;
- struct ll_rw_process_info *process_info = sbi->ll_rw_process_info;
- struct ll_rw_process_info *offset_info = sbi->ll_rw_offset_info;
__s64 value;
if (len == 0)
value = ll_stats_pid_write(buf, len);
- if (value == 0)
+ if (value == 0) {
sbi->ll_rw_stats_on = 0;
- else
+ } else {
+ if (!sbi->ll_rw_process_info || !sbi->ll_rw_offset_info) {
+ int rc = alloc_rw_stats_info(sbi);
+
+ if (rc)
+ return rc;
+ }
sbi->ll_rw_stats_on = 1;
+ }
spin_lock(&sbi->ll_process_lock);
sbi->ll_offset_process_count = 0;
sbi->ll_rw_offset_entry_count = 0;
sbi->ll_process_stats_init = ktime_get();
- memset(process_info, 0, sizeof(struct ll_rw_process_info) *
- LL_PROCESS_HIST_MAX);
- memset(offset_info, 0, sizeof(struct ll_rw_process_info) *
- LL_OFFSET_HIST_MAX);
+ if (sbi->ll_rw_process_info)
+ memset(sbi->ll_rw_process_info, 0,
+ sizeof(struct ll_rw_process_info) * LL_PROCESS_HIST_MAX);
+ if (sbi->ll_rw_offset_info)
+ memset(sbi->ll_rw_offset_info, 0,
+ sizeof(struct ll_rw_process_info) * LL_OFFSET_HIST_MAX);
spin_unlock(&sbi->ll_process_lock);
return len;