@@ -701,12 +701,12 @@ struct ll_sb_info {
struct cl_device *ll_cl;
/* Statistics */
- struct ll_rw_extents_info ll_rw_extents_info;
+ struct ll_rw_extents_info *ll_rw_extents_info;
int ll_extent_process_count;
unsigned int ll_offset_process_count;
+ struct ll_rw_process_info *ll_rw_process_info;
+ struct ll_rw_process_info *ll_rw_offset_info;
ktime_t ll_process_stats_init;
- struct ll_rw_process_info ll_rw_process_info[LL_PROCESS_HIST_MAX];
- struct ll_rw_process_info ll_rw_offset_info[LL_OFFSET_HIST_MAX];
unsigned int ll_rw_offset_entry_count;
int ll_stats_track_id;
enum stats_track_type ll_stats_track_type;
@@ -997,6 +997,7 @@ int cl_get_grouplock(struct cl_object *obj, unsigned long gid, int nonblock,
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);
+void ll_free_rw_stats_info(struct ll_sb_info *sbi);
enum {
LPROC_LL_READ_BYTES,
@@ -85,7 +85,6 @@ static struct ll_sb_info *ll_init_sbi(void)
unsigned long lru_page_max;
struct sysinfo si;
int rc;
- int i;
sbi = kzalloc(sizeof(*sbi), GFP_NOFS);
if (!sbi)
@@ -161,14 +160,6 @@ static struct ll_sb_info *ll_init_sbi(void)
set_bit(LL_SBI_LRU_RESIZE, sbi->ll_flags);
set_bit(LL_SBI_LAZYSTATFS, sbi->ll_flags);
- for (i = 0; i <= LL_PROCESS_HIST_MAX; i++) {
- struct per_process_info *pp_ext;
-
- pp_ext = &sbi->ll_rw_extents_info.pp_extents[i];
- spin_lock_init(&pp_ext->pp_r_hist.oh_lock);
- spin_lock_init(&pp_ext->pp_w_hist.oh_lock);
- }
-
/* metadata statahead is enabled by default */
sbi->ll_sa_running_max = LL_SA_RUNNING_DEF;
sbi->ll_sa_max = LL_SA_RPC_DEF;
@@ -241,6 +232,7 @@ static void ll_free_sbi(struct super_block *sb)
kvfree(items);
sbi->ll_foreign_symlink_upcall_items = NULL;
}
+ ll_free_rw_stats_info(sbi);
pcc_super_fini(&sbi->ll_pcc_super);
kfree(sbi);
}
@@ -1924,15 +1924,16 @@ void ll_debugfs_unregister_super(struct super_block *sb)
lprocfs_free_stats(&sbi->ll_stats);
}
-static void ll_display_extents_info(struct ll_rw_extents_info *io_extents,
+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 = &io_extents->pp_extents[which];
+ struct per_process_info *pp_info;
+ pp_info = &rw_extents->pp_extents[which];
read_cum = 0;
write_cum = 0;
start = 0;
@@ -1968,39 +1969,103 @@ static void ll_display_extents_info(struct ll_rw_extents_info *io_extents,
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) {
- seq_puts(seq, "disabled\n"
- "write anything in this file to activate, then '0' or 'disabled' to deactivate\n");
+ if (!sbi->ll_rw_stats_on || !rw_extents) {
+ seq_puts(seq, "disabled\n write anything in this file to activate, then '0' or 'disabled' 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;
+
+ rw_extents = kzalloc(sizeof(*rw_extents), GFP_KERNEL);
+ 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)
+ kfree(rw_extents);
+
+ process = kzalloc(sizeof(*process) * LL_PROCESS_HIST_MAX,
+ GFP_KERNEL);
+ if (!process) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ offset = kzalloc(sizeof(*offset) * LL_OFFSET_HIST_MAX,
+ GFP_KERNEL);
+ if (!offset) {
+ rc = -ENOMEM;
+ goto out_free;
+ }
+
+ 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)
+ kfree(offset);
+ if (sbi->ll_rw_process_info != process) {
+out_free:
+ kfree(process);
+ }
+out:
+ return rc;
+}
+
+void ll_free_rw_stats_info(struct ll_sb_info *sbi)
+{
+ kfree(sbi->ll_rw_extents_info);
+ sbi->ll_rw_extents_info = NULL;
+ kfree(sbi->ll_rw_offset_info);
+ sbi->ll_rw_offset_info = NULL;
+ kfree(sbi->ll_rw_process_info);
+ 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;
@@ -2009,19 +2074,31 @@ static ssize_t ll_rw_extents_stats_pp_seq_write(struct file *file,
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;
}
@@ -2030,22 +2107,22 @@ static ssize_t ll_rw_extents_stats_pp_seq_write(struct file *file,
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) {
- seq_puts(seq, "disabled\n"
- "write anything in this file to activate, then '0' or 'disabled' to deactivate\n");
+ if (!sbi->ll_rw_stats_on || !rw_extents) {
+ seq_puts(seq, "disabled\n write anything in this file to activate, then '0' or 'disabled' 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;
@@ -2057,7 +2134,7 @@ static ssize_t ll_rw_extents_stats_seq_write(struct file *file,
{
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;
@@ -2066,17 +2143,27 @@ static ssize_t ll_rw_extents_stats_seq_write(struct file *file,
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);
@@ -2094,17 +2181,21 @@ void ll_rw_stats_tally(struct ll_sb_info *sbi, pid_t pid,
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;
+ 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;
spin_lock(&sbi->ll_pp_extent_lock);
+ 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 (io_extents->pp_extents[i].pid == pid) {
+ if (rw_extents->pp_extents[i].pid == pid) {
cur = i;
break;
}
@@ -2115,24 +2206,29 @@ void ll_rw_stats_tally(struct ll_sb_info *sbi, pid_t pid,
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->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);
+ 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) {
@@ -2143,8 +2239,7 @@ void ll_rw_stats_tally(struct ll_sb_info *sbi, pid_t pid,
process[i].rw_largest_extent = count;
process[i].rw_offset = 0;
process[i].rw_last_file = file;
- spin_unlock(&sbi->ll_process_lock);
- return;
+ goto out_unlock;
}
if (process[i].rw_last_file_pos != pos) {
*off_count =
@@ -2173,8 +2268,7 @@ void ll_rw_stats_tally(struct ll_sb_info *sbi, pid_t pid,
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;
+ goto out_unlock;
}
}
*process_count = (*process_count + 1) % LL_PROCESS_HIST_MAX;
@@ -2186,14 +2280,16 @@ void ll_rw_stats_tally(struct ll_sb_info *sbi, pid_t pid,
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) {
@@ -2204,12 +2300,13 @@ static int ll_rw_offset_stats_seq_show(struct seq_file *seq, void *v)
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",
@@ -2221,8 +2318,10 @@ static int ll_rw_offset_stats_seq_show(struct seq_file *seq, void *v)
(unsigned long)offset[i].rw_largest_extent,
offset[i].rw_offset);
}
+
/* 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",
@@ -2245,8 +2344,6 @@ static ssize_t ll_rw_offset_stats_seq_write(struct file *file,
{
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)
@@ -2254,19 +2351,28 @@ static ssize_t ll_rw_offset_stats_seq_write(struct file *file,
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;