+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;
+ }
+}
+