Whamcloud - gitweb
Branch HEAD
[fs/lustre-release.git] / lustre / obdclass / lprocfs_status.c
index 3801243..608af88 100644 (file)
@@ -116,6 +116,21 @@ int lprocfs_add_simple(struct proc_dir_entry *root, char *name,
         return 0;
 }
 
+struct proc_dir_entry *lprocfs_add_symlink(const char *name,
+                        struct proc_dir_entry *parent, const char *dest)
+{
+        struct proc_dir_entry *entry;
+
+        if (parent == NULL || dest == NULL)
+                return NULL;
+
+        entry = proc_symlink(name, parent, dest);
+        if (entry == NULL)
+                CERROR("LprocFS: Could not create symbolic link from %s to %s",
+                        name, dest);
+        return entry;
+}
+
 static ssize_t lprocfs_fops_read(struct file *f, char __user *buf,
                                  size_t size, loff_t *ppos)
 {
@@ -288,13 +303,13 @@ void lprocfs_remove(struct proc_dir_entry **rooth)
         struct proc_dir_entry *rm_entry;
         struct proc_dir_entry *parent;
 
-        if (!root) 
+        if (!root)
                 return;
         *rooth = NULL;
 
         parent = root->parent;
         LASSERT(parent != NULL);
+
         while (1) {
                 while (temp->subdir != NULL)
                         temp = temp->subdir;
@@ -312,13 +327,19 @@ void lprocfs_remove(struct proc_dir_entry **rooth)
                  * by _lprocfs_lock. */
                 down_write(&_lprocfs_lock);
                 rm_entry->data = NULL;
-                remove_proc_entry(rm_entry->name, rm_entry->parent);
+                remove_proc_entry(rm_entry->name, temp);
                 up_write(&_lprocfs_lock);
                 if (temp == parent)
                         break;
         }
 }
 
+void lprocfs_remove_proc_entry(const char *name, struct proc_dir_entry *parent)
+{
+        LASSERT(parent != NULL);
+        remove_proc_entry(name, parent);
+}
+
 struct proc_dir_entry *lprocfs_register(const char *name,
                                         struct proc_dir_entry *parent,
                                         struct lprocfs_vars *list, void *data)
@@ -681,22 +702,64 @@ int lprocfs_obd_cleanup(struct obd_device *obd)
 {
         if (!obd) 
                 return -EINVAL;
-        if (obd->obd_proc_exports) {
+        if (obd->obd_proc_exports_entry) {
                 /* Should be no exports left */
-                LASSERT(obd->obd_proc_exports->subdir == NULL);
-                lprocfs_remove(&obd->obd_proc_exports);
+                LASSERT(obd->obd_proc_exports_entry->subdir == NULL);
+                lprocfs_remove(&obd->obd_proc_exports_entry);
         }
         lprocfs_remove(&obd->obd_proc_entry);
         return 0;
 }
 
+void lprocfs_free_client_stats(void *obj, void *data)
+{
+        struct nid_stat *client_stat = obj;
+
+        CDEBUG(D_CONFIG, "stat %p - data %p/%p/%p\n", client_stat,
+               client_stat->nid_proc, client_stat->nid_stats,
+               client_stat->nid_brw_stats);
+
+        LASSERTF(client_stat->nid_exp_ref_count == 0, "count %d\n",
+                 client_stat->nid_exp_ref_count);
+
+        hlist_del_init(&client_stat->nid_hash);
+        list_del(&client_stat->nid_list);
+
+        if (client_stat->nid_proc)
+                lprocfs_remove(&client_stat->nid_proc);
+
+        if (client_stat->nid_stats)
+                lprocfs_free_stats(&client_stat->nid_stats);
+
+        if (client_stat->nid_brw_stats)
+                OBD_FREE(client_stat->nid_brw_stats, sizeof(struct brw_stats));
+
+        OBD_FREE(client_stat, sizeof(*client_stat));
+        return;
+
+}
+
+void lprocfs_free_per_client_stats(struct obd_device *obd)
+{
+        struct nid_stat *stat;
+        ENTRY;
+
+        /* we need extra list - because hash_exit called to early */
+        while(!list_empty(&obd->obd_nid_stats)) {
+                stat = list_entry(obd->obd_nid_stats.next,
+                                  struct nid_stat, nid_list);
+                lprocfs_free_client_stats(stat, NULL);
+        }
+
+        EXIT;
+}
+
 struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
                                           enum lprocfs_stats_flags flags)
 {
         struct lprocfs_stats *stats;
-        struct lprocfs_percpu *percpu;
         unsigned int percpusize;
-        unsigned int i;
+        unsigned int i, j;
         unsigned int num_cpu;
 
         if (num == 0)
@@ -719,12 +782,20 @@ struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
                 stats->ls_flags = 0;
         }
 
-        percpusize = offsetof(typeof(*percpu), lp_cntr[num]);
+        percpusize = offsetof(struct lprocfs_percpu, lp_cntr[num]);
         if (num_cpu > 1)
                 percpusize = L1_CACHE_ALIGN(percpusize);
 
-        stats->ls_percpu_size = num_cpu * percpusize;
-        OBD_ALLOC(stats->ls_percpu[0], stats->ls_percpu_size);
+        for (i = 0; i < num_cpu; i++) {
+                OBD_ALLOC(stats->ls_percpu[i], percpusize);
+                if (stats->ls_percpu[i] == NULL) {
+                        for (j = 0; j < i; j++) {
+                                OBD_FREE(stats->ls_percpu[j], percpusize);
+                                stats->ls_percpu[j] = NULL;
+                        }
+                        break;
+                }
+        }
         if (stats->ls_percpu[0] == NULL) {
                 OBD_FREE(stats, offsetof(typeof(*stats),
                                          ls_percpu[num_cpu]));
@@ -732,10 +803,6 @@ struct lprocfs_stats *lprocfs_alloc_stats(unsigned int num,
         }
 
         stats->ls_num = num;
-        for (i = 1; i < num_cpu; i++)
-                stats->ls_percpu[i] = (void *)(stats->ls_percpu[i - 1]) +
-                        percpusize;
-
         return stats;
 }
 
@@ -743,6 +810,8 @@ void lprocfs_free_stats(struct lprocfs_stats **statsh)
 {
         struct lprocfs_stats *stats = *statsh;
         unsigned int num_cpu;
+        unsigned int percpusize;
+        unsigned int i;
 
         if (stats == NULL || stats->ls_num == 0)
                 return;
@@ -753,7 +822,11 @@ void lprocfs_free_stats(struct lprocfs_stats **statsh)
         else
                 num_cpu = num_possible_cpus();
 
-        OBD_FREE(stats->ls_percpu[0], stats->ls_percpu_size);
+        percpusize = offsetof(struct lprocfs_percpu, lp_cntr[stats->ls_num]);
+        if (num_cpu > 1)
+                percpusize = L1_CACHE_ALIGN(percpusize);
+        for (i = 0; i < num_cpu; i++)
+                OBD_FREE(stats->ls_percpu[i], percpusize);
         OBD_FREE(stats, offsetof(typeof(*stats), ls_percpu[num_cpu]));
 }
 
@@ -766,12 +839,12 @@ void lprocfs_clear_stats(struct lprocfs_stats *stats)
         num_cpu = lprocfs_stats_lock(stats, LPROCFS_GET_NUM_CPU);
 
         for (i = 0; i < num_cpu; i++) {
-                for (j = 0; j < stats->ls_num; j++) {        
+                for (j = 0; j < stats->ls_num; j++) {
                         percpu_cntr = &(stats->ls_percpu[i])->lp_cntr[j];
                         atomic_inc(&percpu_cntr->lc_cntl.la_entry);
                         percpu_cntr->lc_count = 0;
                         percpu_cntr->lc_sum = 0;
-                        percpu_cntr->lc_min = ~(__u64)0;
+                        percpu_cntr->lc_min = LC_MIN_INIT;
                         percpu_cntr->lc_max = 0;
                         percpu_cntr->lc_sumsquare = 0;
                         atomic_inc(&percpu_cntr->lc_cntl.la_exit);
@@ -817,7 +890,7 @@ static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
 {
        struct lprocfs_stats *stats = p->private;
        struct lprocfs_counter  *cntr = v;
-       struct lprocfs_counter  t, ret = { .lc_min = ~(__u64)0 };
+       struct lprocfs_counter  t, ret = { .lc_min = LC_MIN_INIT };
        int i, idx, rc;
        unsigned int num_cpu;
 
@@ -859,18 +932,18 @@ static int lprocfs_stats_seq_show(struct seq_file *p, void *v)
                ret.lc_sumsquare += t.lc_sumsquare;
        }
 
-       rc = seq_printf(p, "%-25s "LPU64" samples [%s]", cntr->lc_name,
+       rc = seq_printf(p, "%-25s "LPD64" samples [%s]", cntr->lc_name,
                        ret.lc_count, cntr->lc_units);
        if (rc < 0)
                goto out;
 
        if ((cntr->lc_config & LPROCFS_CNTR_AVGMINMAX) && (ret.lc_count > 0)) {
-               rc = seq_printf(p, " "LPU64" "LPU64" "LPU64,
+               rc = seq_printf(p, " "LPD64" "LPD64" "LPD64,
                                ret.lc_min, ret.lc_max, ret.lc_sum);
                if (rc < 0)
                        goto out;
                if (cntr->lc_config & LPROCFS_CNTR_STDDEV)
-                       rc = seq_printf(p, " "LPU64, ret.lc_sumsquare);
+                       rc = seq_printf(p, " "LPD64, ret.lc_sumsquare);
                if (rc < 0)
                        goto out;
        }
@@ -942,7 +1015,7 @@ void lprocfs_counter_init(struct lprocfs_stats *stats, int index,
                 c->lc_config = conf;
                 c->lc_count = 0;
                 c->lc_sum = 0;
-                c->lc_min = ~(__u64)0;
+                c->lc_min = LC_MIN_INIT;
                 c->lc_max = 0;
                 c->lc_name = name;
                 c->lc_units = units;
@@ -1166,90 +1239,170 @@ int lprocfs_exp_rd_nid(char *page, char **start, off_t off, int count,
         return snprintf(page, count, "%s\n", obd_export_nid2str(exp));
 }
 
+struct exp_uuid_cb_data {
+        char                   *page;
+        int                     count;
+        int                    *eof;
+        int                    *len;
+};
+
+void lprocfs_exp_print_uuid(void *obj, void *cb_data)
+{
+        struct obd_export *exp = (struct obd_export *)obj;
+        struct exp_uuid_cb_data *data = (struct exp_uuid_cb_data *)cb_data;
+
+        if (exp->exp_nid_stats)
+                *data->len += snprintf((data->page + *data->len),
+                                       data->count, "%s\n",
+                                       obd_uuid2str(&exp->exp_client_uuid));
+}
+
 int lprocfs_exp_rd_uuid(char *page, char **start, off_t off, int count,
-                         int *eof,  void *data)
+                        int *eof,  void *data)
+{
+        struct nid_stat *stats = (struct nid_stat *)data;
+        struct exp_uuid_cb_data cb_data;
+        struct obd_device *obd = stats->nid_obd;
+        int len = 0;
+
+        *eof = 1;
+        page[0] = '\0';
+        LASSERT(obd != NULL);
+
+        cb_data.page = page;
+        cb_data.count = count;
+        cb_data.eof = eof;
+        cb_data.len = &len;
+        lustre_hash_bucket_iterate(obd->obd_nid_hash_body,
+                                   &stats->nid, lprocfs_exp_print_uuid,
+                                   &cb_data);
+        return (*cb_data.len);
+}
+
+int lprocfs_nid_stats_clear_read(char *page, char **start, off_t off,
+                                        int count, int *eof,  void *data)
 {
-        struct obd_export *exp = (struct obd_export*)data;
-        LASSERT(exp != NULL);
         *eof = 1;
-        return snprintf(page, count, "%s\n", 
-                        obd_uuid2str(&exp->exp_client_uuid));
+        return snprintf(page, count, "%s\n",
+                        "Write into this file to clear all nid stats and "
+                        "stale nid entries");
 }
-        
-int lprocfs_exp_setup(struct obd_export *exp)
+EXPORT_SYMBOL(lprocfs_nid_stats_clear_read);
+
+void lprocfs_nid_stats_clear_write_cb(void *obj, void *data)
 {
-        char name[sizeof (exp->exp_client_uuid.uuid) + 3];
-        int i = 1, rc;
+        struct nid_stat *client_stat = obj;
+        int i;
+        if(client_stat->nid_exp_ref_count == 1) {
+                hlist_del_init(&client_stat->nid_hash);
+                lprocfs_free_client_stats(client_stat, data);
+                OBD_FREE(client_stat, sizeof(struct nid_stat));
+                EXIT;
+                return;
+        }
+
+        /* we has reference to object - only clear data*/
+        if (client_stat->nid_stats) {
+                lprocfs_clear_stats(client_stat->nid_stats);
+        }
+        if (client_stat->nid_brw_stats) {
+                for (i = 0; i < BRW_LAST; i++)
+                        lprocfs_oh_clear(&client_stat->nid_brw_stats->hist[i]);
+        }
+        EXIT;
+        return;
+}
+
+int lprocfs_nid_stats_clear_write(struct file *file, const char *buffer,
+                                         unsigned long count, void *data)
+{
+        struct obd_device *obd = (struct obd_device *)data;
+        lustre_hash_iterate_all(obd->obd_nid_stats_hash_body,
+                                lprocfs_free_client_stats, NULL);
+        return count;
+}
+EXPORT_SYMBOL(lprocfs_nid_stats_clear_write);
+
+int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid)
+{
+        int rc = 0;
+        struct nid_stat *tmp = NULL, *tmp1;
+        struct obd_device *obd = NULL;
         ENTRY;
-        if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports)
+
+        *newnid = 0;
+
+        if (!exp || !exp->exp_obd || !exp->exp_obd->obd_proc_exports_entry ||
+            !exp->exp_obd->obd_nid_stats_hash_body)
                 RETURN(-EINVAL);
-        mutex_down(&exp->exp_obd->obd_proc_exp_sem);
-        sprintf(name, "%s", (char *)exp->exp_client_uuid.uuid);
-        while (lprocfs_srch(exp->exp_obd->obd_proc_exports, name)) {
-                /* We might add a new export before deleting the old one during 
-                   an eviction (recovery-small 19a). Suckage. We
-                   could block, or come up with a new name, or just give up. */
-                if (++i > 9) 
-                        GOTO(out, rc = -EEXIST);
-                sprintf(name, "%s:%d", (char *)exp->exp_client_uuid.uuid, i);
-        }
 
-        /* Create a proc entry for this export */
-        exp->exp_proc = proc_mkdir(name, exp->exp_obd->obd_proc_exports);
-        if (!exp->exp_proc) {
-                CERROR("Error making export directory for %s\n", name);
-                GOTO(out, rc = -ENOMEM);
+       /* not test against zero because eric say:
+        * You may only test nid against another nid, or LNET_NID_ANY.  Anything else is
+        * nonsense.*/
+        if (!nid || *nid == LNET_NID_ANY)
+                RETURN(0);
+
+        obd = exp->exp_obd;
+
+        CDEBUG(D_CONFIG, "using hash %p\n", obd->obd_nid_stats_hash_body);
+
+        OBD_ALLOC(tmp, sizeof(struct nid_stat));
+        if (tmp == NULL)
+                RETURN(-ENOMEM);
+
+        tmp->nid = *nid;
+        tmp->nid_obd = exp->exp_obd;
+        tmp->nid_exp_ref_count = 1; /* need live in hash after destroy export */
+
+        tmp1= lustre_hash_findadd_unique(obd->obd_nid_stats_hash_body, nid,
+                                         &tmp->nid_hash);
+        CDEBUG(D_INFO, "Found stats %p for nid %s - ref %d\n",
+               tmp1, libcfs_nid2str(*nid), tmp->nid_exp_ref_count);
+
+        if (tmp1 != tmp) {
+                exp->exp_nid_stats = tmp1;
+                GOTO(destroy_new, rc = 0);
+        }
+        /* not found - create */
+        tmp->nid_proc = lprocfs_register(libcfs_nid2str(*nid),
+                                         obd->obd_proc_exports_entry, NULL, NULL);
+        if (!tmp->nid_proc) {
+                CERROR("Error making export directory for"
+                       " nid %s\n", libcfs_nid2str(*nid));
+                lustre_hash_delitem(obd->obd_nid_stats_hash_body, nid,
+                                    &tmp->nid_hash);
+                GOTO(destroy_new, rc = -ENOMEM);
         }
 
-        /* Always add nid and uuid */
-        rc = lprocfs_add_simple(exp->exp_proc, "nid",
-                                lprocfs_exp_rd_nid, NULL, exp);
-        if (rc)
-                GOTO(out, rc);
-        rc = lprocfs_add_simple(exp->exp_proc, "uuid",
-                                lprocfs_exp_rd_uuid, NULL, exp);
+        rc = lprocfs_add_simple(tmp->nid_proc, "uuid",
+                                lprocfs_exp_rd_uuid, NULL, tmp);
         if (rc)
-                GOTO(out, rc);
-        /* Always add ldlm stats */
-        exp->exp_ldlm_stats = lprocfs_alloc_stats(LDLM_LAST_OPC 
-                                                  - LDLM_FIRST_OPC, 0);
-        if (exp->exp_ldlm_stats == NULL) {
-                lprocfs_remove(&exp->exp_proc);
-                GOTO(out, rc = -ENOMEM);
-        }
+                CWARN("Error adding the uuid file\n");
 
-        lprocfs_counter_init(exp->exp_ldlm_stats, 
-                             LDLM_ENQUEUE - LDLM_FIRST_OPC,
-                             0, "ldlm_enqueue", "reqs");
-        lprocfs_counter_init(exp->exp_ldlm_stats, 
-                             LDLM_CONVERT - LDLM_FIRST_OPC,
-                             0, "ldlm_convert", "reqs");
-        lprocfs_counter_init(exp->exp_ldlm_stats, 
-                             LDLM_CANCEL - LDLM_FIRST_OPC,
-                             0, "ldlm_cancel", "reqs");
-        lprocfs_counter_init(exp->exp_ldlm_stats, 
-                             LDLM_BL_CALLBACK - LDLM_FIRST_OPC,
-                             0, "ldlm_bl_callback", "reqs");
-        lprocfs_counter_init(exp->exp_ldlm_stats, 
-                             LDLM_CP_CALLBACK - LDLM_FIRST_OPC,
-                             0, "ldlm_cp_callback", "reqs");
-        lprocfs_counter_init(exp->exp_ldlm_stats, 
-                             LDLM_GL_CALLBACK - LDLM_FIRST_OPC,
-                             0, "ldlm_gl_callback", "reqs");
-        lprocfs_register_stats(exp->exp_proc, "ldlm_stats",
-                               exp->exp_ldlm_stats);
-out:
-        mutex_up(&exp->exp_obd->obd_proc_exp_sem);
+        spin_lock(&obd->obd_nid_lock);
+        list_add(&tmp->nid_list, &obd->obd_nid_stats);
+        spin_unlock(&obd->obd_nid_lock);
+
+        exp->exp_nid_stats = tmp;
+        *newnid = 1;
+        RETURN(rc);
+
+destroy_new:
+        OBD_FREE(tmp, sizeof(struct nid_stat));
         RETURN(rc);
 }
 
 int lprocfs_exp_cleanup(struct obd_export *exp)
 {
-        mutex_down(&exp->exp_obd->obd_proc_exp_sem);
-        lprocfs_remove(&exp->exp_proc);
-        lprocfs_free_stats(&exp->exp_ops_stats);
-        lprocfs_free_stats(&exp->exp_ldlm_stats);
-        mutex_up(&exp->exp_obd->obd_proc_exp_sem);
+        struct nid_stat *stat = exp->exp_nid_stats;
+
+        if(!stat)
+                RETURN(0);
+
+        stat->nid_exp_ref_count--;
+        CDEBUG(D_INFO, "Put stat %p - %d\n", stat, stat->nid_exp_ref_count);
+
+        exp->exp_nid_stats = NULL;
         return 0;
 }
 
@@ -1558,8 +1711,8 @@ int lprocfs_obd_rd_recovery_status(char *page, char **start, off_t off,
                 goto out;
 
         if (lprocfs_obd_snprintf(&page, size, &len, "time remaining: %lu\n",
-                                 CURRENT_SECONDS >= obd->obd_recovery_end ? 0 :
-                                 obd->obd_recovery_end - CURRENT_SECONDS) <= 0)
+                                 cfs_time_current_sec() >= obd->obd_recovery_end ? 0 :
+                                 obd->obd_recovery_end - cfs_time_current_sec()) <= 0)
                 goto out;
 
         if(lprocfs_obd_snprintf(&page, size, &len, "connected_clients: %d/%d\n",
@@ -1622,9 +1775,13 @@ EXPORT_SYMBOL(lprocfs_obd_wr_recovery_maxtime);
 EXPORT_SYMBOL(lprocfs_register);
 EXPORT_SYMBOL(lprocfs_srch);
 EXPORT_SYMBOL(lprocfs_remove);
+EXPORT_SYMBOL(lprocfs_remove_proc_entry);
 EXPORT_SYMBOL(lprocfs_add_vars);
 EXPORT_SYMBOL(lprocfs_obd_setup);
 EXPORT_SYMBOL(lprocfs_obd_cleanup);
+EXPORT_SYMBOL(lprocfs_add_simple);
+EXPORT_SYMBOL(lprocfs_add_symlink);
+EXPORT_SYMBOL(lprocfs_free_per_client_stats);
 EXPORT_SYMBOL(lprocfs_alloc_stats);
 EXPORT_SYMBOL(lprocfs_free_stats);
 EXPORT_SYMBOL(lprocfs_clear_stats);