[SCSI] target: add initial statistics
[linux-3.10.git] / drivers / target / target_core_fabric_configfs.c
index b65d1c8e774050562e440db8a1dce40255b0591f..07ab5a3bb8e8d56a97a76c3c21af3fa8a8e96792 100644 (file)
@@ -4,10 +4,10 @@
  * This file contains generic fabric module configfs infrastructure for
  * TCM v4.x code
  *
- * Copyright (c) 2010 Rising Tide Systems
- * Copyright (c) 2010 Linux-iSCSI.org
+ * Copyright (c) 2010,2011 Rising Tide Systems
+ * Copyright (c) 2010,2011 Linux-iSCSI.org
  *
- * Copyright (c) 2010 Nicholas A. Bellinger <nab@linux-iscsi.org>
+ * Copyright (c) Nicholas A. Bellinger <nab@linux-iscsi.org>
 *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -48,6 +48,7 @@
 #include "target_core_alua.h"
 #include "target_core_hba.h"
 #include "target_core_pr.h"
+#include "target_core_stat.h"
 
 #define TF_CIT_SETUP(_name, _item_ops, _group_ops, _attrs)             \
 static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) \
@@ -241,6 +242,32 @@ TF_CIT_SETUP(tpg_mappedlun, &target_fabric_mappedlun_item_ops, NULL,
 
 /* End of tfc_tpg_mappedlun_cit */
 
+/* Start of tfc_tpg_mappedlun_port_cit */
+
+static struct config_group *target_core_mappedlun_stat_mkdir(
+       struct config_group *group,
+       const char *name)
+{
+       return ERR_PTR(-ENOSYS);
+}
+
+static void target_core_mappedlun_stat_rmdir(
+       struct config_group *group,
+       struct config_item *item)
+{
+       return;
+}
+
+static struct configfs_group_operations target_fabric_mappedlun_stat_group_ops = {
+       .make_group             = target_core_mappedlun_stat_mkdir,
+       .drop_item              = target_core_mappedlun_stat_rmdir,
+};
+
+TF_CIT_SETUP(tpg_mappedlun_stat, NULL, &target_fabric_mappedlun_stat_group_ops,
+               NULL);
+
+/* End of tfc_tpg_mappedlun_port_cit */
+
 /* Start of tfc_tpg_nacl_attrib_cit */
 
 CONFIGFS_EATTR_OPS(target_fabric_nacl_attrib, se_node_acl, acl_attrib_group);
@@ -294,6 +321,7 @@ static struct config_group *target_fabric_make_mappedlun(
        struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
        struct se_lun_acl *lacl;
        struct config_item *acl_ci;
+       struct config_group *lacl_cg = NULL, *ml_stat_grp = NULL;
        char *buf;
        unsigned long mapped_lun;
        int ret = 0;
@@ -330,15 +358,42 @@ static struct config_group *target_fabric_make_mappedlun(
 
        lacl = core_dev_init_initiator_node_lun_acl(se_tpg, mapped_lun,
                        config_item_name(acl_ci), &ret);
-       if (!(lacl))
+       if (!(lacl)) {
+               ret = -EINVAL;
                goto out;
+       }
+
+       lacl_cg = &lacl->se_lun_group;
+       lacl_cg->default_groups = kzalloc(sizeof(struct config_group) * 2,
+                               GFP_KERNEL);
+       if (!lacl_cg->default_groups) {
+               printk(KERN_ERR "Unable to allocate lacl_cg->default_groups\n");
+               ret = -ENOMEM;
+               goto out;
+       }
 
        config_group_init_type_name(&lacl->se_lun_group, name,
                        &TF_CIT_TMPL(tf)->tfc_tpg_mappedlun_cit);
+       config_group_init_type_name(&lacl->ml_stat_grps.stat_group,
+                       "statistics", &TF_CIT_TMPL(tf)->tfc_tpg_mappedlun_stat_cit);
+       lacl_cg->default_groups[0] = &lacl->ml_stat_grps.stat_group;
+       lacl_cg->default_groups[1] = NULL;
+
+       ml_stat_grp = &ML_STAT_GRPS(lacl)->stat_group;
+       ml_stat_grp->default_groups = kzalloc(sizeof(struct config_group) * 3,
+                               GFP_KERNEL);
+       if (!ml_stat_grp->default_groups) {
+               printk(KERN_ERR "Unable to allocate ml_stat_grp->default_groups\n");
+               ret = -ENOMEM;
+               goto out;
+       }
+       target_stat_setup_mappedlun_default_groups(lacl);
 
        kfree(buf);
        return &lacl->se_lun_group;
 out:
+       if (lacl_cg)
+               kfree(lacl_cg->default_groups);
        kfree(buf);
        return ERR_PTR(ret);
 }
@@ -347,6 +402,28 @@ static void target_fabric_drop_mappedlun(
        struct config_group *group,
        struct config_item *item)
 {
+       struct se_lun_acl *lacl = container_of(to_config_group(item),
+                       struct se_lun_acl, se_lun_group);
+       struct config_item *df_item;
+       struct config_group *lacl_cg = NULL, *ml_stat_grp = NULL;
+       int i;
+
+       ml_stat_grp = &ML_STAT_GRPS(lacl)->stat_group;
+       for (i = 0; ml_stat_grp->default_groups[i]; i++) {
+               df_item = &ml_stat_grp->default_groups[i]->cg_item;
+               ml_stat_grp->default_groups[i] = NULL;
+               config_item_put(df_item);
+       }
+       kfree(ml_stat_grp->default_groups);
+
+       lacl_cg = &lacl->se_lun_group;
+       for (i = 0; lacl_cg->default_groups[i]; i++) {
+               df_item = &lacl_cg->default_groups[i]->cg_item;
+               lacl_cg->default_groups[i] = NULL;
+               config_item_put(df_item);
+       }
+       kfree(lacl_cg->default_groups);
+
        config_item_put(item);
 }
 
@@ -376,6 +453,15 @@ TF_CIT_SETUP(tpg_nacl_base, &target_fabric_nacl_base_item_ops,
 
 /* End of tfc_tpg_nacl_base_cit */
 
+/* Start of tfc_node_fabric_stats_cit */
+/*
+ * This is used as a placeholder for struct se_node_acl->acl_fabric_stat_group
+ * to allow fabrics access to ->acl_fabric_stat_group->default_groups[]
+ */
+TF_CIT_SETUP(tpg_nacl_stat, NULL, NULL, NULL);
+
+/* End of tfc_wwn_fabric_stats_cit */
+
 /* Start of tfc_tpg_nacl_cit */
 
 static struct config_group *target_fabric_make_nodeacl(
@@ -402,7 +488,8 @@ static struct config_group *target_fabric_make_nodeacl(
        nacl_cg->default_groups[0] = &se_nacl->acl_attrib_group;
        nacl_cg->default_groups[1] = &se_nacl->acl_auth_group;
        nacl_cg->default_groups[2] = &se_nacl->acl_param_group;
-       nacl_cg->default_groups[3] = NULL;
+       nacl_cg->default_groups[3] = &se_nacl->acl_fabric_stat_group;
+       nacl_cg->default_groups[4] = NULL;
 
        config_group_init_type_name(&se_nacl->acl_group, name,
                        &TF_CIT_TMPL(tf)->tfc_tpg_nacl_base_cit);
@@ -412,6 +499,9 @@ static struct config_group *target_fabric_make_nodeacl(
                        &TF_CIT_TMPL(tf)->tfc_tpg_nacl_auth_cit);
        config_group_init_type_name(&se_nacl->acl_param_group, "param",
                        &TF_CIT_TMPL(tf)->tfc_tpg_nacl_param_cit);
+       config_group_init_type_name(&se_nacl->acl_fabric_stat_group,
+                       "fabric_statistics",
+                       &TF_CIT_TMPL(tf)->tfc_tpg_nacl_stat_cit);
 
        return &se_nacl->acl_group;
 }
@@ -758,6 +848,31 @@ TF_CIT_SETUP(tpg_port, &target_fabric_port_item_ops, NULL, target_fabric_port_at
 
 /* End of tfc_tpg_port_cit */
 
+/* Start of tfc_tpg_port_stat_cit */
+
+static struct config_group *target_core_port_stat_mkdir(
+       struct config_group *group,
+       const char *name)
+{
+       return ERR_PTR(-ENOSYS);
+}
+
+static void target_core_port_stat_rmdir(
+       struct config_group *group,
+       struct config_item *item)
+{
+       return;
+}
+
+static struct configfs_group_operations target_fabric_port_stat_group_ops = {
+       .make_group             = target_core_port_stat_mkdir,
+       .drop_item              = target_core_port_stat_rmdir,
+};
+
+TF_CIT_SETUP(tpg_port_stat, NULL, &target_fabric_port_stat_group_ops, NULL);
+
+/* End of tfc_tpg_port_stat_cit */
+
 /* Start of tfc_tpg_lun_cit */
 
 static struct config_group *target_fabric_make_lun(
@@ -768,7 +883,9 @@ static struct config_group *target_fabric_make_lun(
        struct se_portal_group *se_tpg = container_of(group,
                        struct se_portal_group, tpg_lun_group);
        struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf;
+       struct config_group *lun_cg = NULL, *port_stat_grp = NULL;
        unsigned long unpacked_lun;
+       int errno;
 
        if (strstr(name, "lun_") != name) {
                printk(KERN_ERR "Unable to locate \'_\" in"
@@ -782,16 +899,64 @@ static struct config_group *target_fabric_make_lun(
        if (!(lun))
                return ERR_PTR(-EINVAL);
 
+       lun_cg = &lun->lun_group;
+       lun_cg->default_groups = kzalloc(sizeof(struct config_group) * 2,
+                               GFP_KERNEL);
+       if (!lun_cg->default_groups) {
+               printk(KERN_ERR "Unable to allocate lun_cg->default_groups\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
        config_group_init_type_name(&lun->lun_group, name,
                        &TF_CIT_TMPL(tf)->tfc_tpg_port_cit);
+       config_group_init_type_name(&lun->port_stat_grps.stat_group,
+                       "statistics", &TF_CIT_TMPL(tf)->tfc_tpg_port_stat_cit);
+       lun_cg->default_groups[0] = &lun->port_stat_grps.stat_group;
+       lun_cg->default_groups[1] = NULL;
+
+       port_stat_grp = &PORT_STAT_GRP(lun)->stat_group;
+       port_stat_grp->default_groups =  kzalloc(sizeof(struct config_group) * 3,
+                               GFP_KERNEL);
+       if (!port_stat_grp->default_groups) {
+               printk(KERN_ERR "Unable to allocate port_stat_grp->default_groups\n");
+               errno = -ENOMEM;
+               goto out;
+       }
+       target_stat_setup_port_default_groups(lun);
 
        return &lun->lun_group;
+out:
+       if (lun_cg)
+               kfree(lun_cg->default_groups);
+       return ERR_PTR(errno);
 }
 
 static void target_fabric_drop_lun(
        struct config_group *group,
        struct config_item *item)
 {
+       struct se_lun *lun = container_of(to_config_group(item),
+                               struct se_lun, lun_group);
+       struct config_item *df_item;
+       struct config_group *lun_cg, *port_stat_grp;
+       int i;
+
+       port_stat_grp = &PORT_STAT_GRP(lun)->stat_group;
+       for (i = 0; port_stat_grp->default_groups[i]; i++) {
+               df_item = &port_stat_grp->default_groups[i]->cg_item;
+               port_stat_grp->default_groups[i] = NULL;
+               config_item_put(df_item);
+       }
+       kfree(port_stat_grp->default_groups);
+
+       lun_cg = &lun->lun_group;
+       for (i = 0; lun_cg->default_groups[i]; i++) {
+               df_item = &lun_cg->default_groups[i]->cg_item;
+               lun_cg->default_groups[i] = NULL;
+               config_item_put(df_item);
+       }
+       kfree(lun_cg->default_groups);
+
        config_item_put(item);
 }
 
@@ -946,6 +1111,15 @@ TF_CIT_SETUP(tpg, &target_fabric_tpg_item_ops, &target_fabric_tpg_group_ops,
 
 /* End of tfc_tpg_cit */
 
+/* Start of tfc_wwn_fabric_stats_cit */
+/*
+ * This is used as a placeholder for struct se_wwn->fabric_stat_group
+ * to allow fabrics access to ->fabric_stat_group->default_groups[]
+ */
+TF_CIT_SETUP(wwn_fabric_stats, NULL, NULL, NULL);
+
+/* End of tfc_wwn_fabric_stats_cit */
+
 /* Start of tfc_wwn_cit */
 
 static struct config_group *target_fabric_make_wwn(
@@ -966,8 +1140,17 @@ static struct config_group *target_fabric_make_wwn(
                return ERR_PTR(-EINVAL);
 
        wwn->wwn_tf = tf;
+       /*
+        * Setup default groups from pre-allocated wwn->wwn_default_groups
+        */
+       wwn->wwn_group.default_groups = wwn->wwn_default_groups;
+       wwn->wwn_group.default_groups[0] = &wwn->fabric_stat_group;
+       wwn->wwn_group.default_groups[1] = NULL;
+
        config_group_init_type_name(&wwn->wwn_group, name,
                        &TF_CIT_TMPL(tf)->tfc_tpg_cit);
+       config_group_init_type_name(&wwn->fabric_stat_group, "fabric_statistics",
+                       &TF_CIT_TMPL(tf)->tfc_wwn_fabric_stats_cit);
 
        return &wwn->wwn_group;
 }
@@ -976,6 +1159,18 @@ static void target_fabric_drop_wwn(
        struct config_group *group,
        struct config_item *item)
 {
+       struct se_wwn *wwn = container_of(to_config_group(item),
+                               struct se_wwn, wwn_group);
+       struct config_item *df_item;
+       struct config_group *cg = &wwn->wwn_group;
+       int i;
+
+       for (i = 0; cg->default_groups[i]; i++) {
+               df_item = &cg->default_groups[i]->cg_item;
+               cg->default_groups[i] = NULL;
+               config_item_put(df_item);
+       }
+
        config_item_put(item);
 }
 
@@ -1015,9 +1210,11 @@ int target_fabric_setup_cits(struct target_fabric_configfs *tf)
 {
        target_fabric_setup_discovery_cit(tf);
        target_fabric_setup_wwn_cit(tf);
+       target_fabric_setup_wwn_fabric_stats_cit(tf);
        target_fabric_setup_tpg_cit(tf);
        target_fabric_setup_tpg_base_cit(tf);
        target_fabric_setup_tpg_port_cit(tf);
+       target_fabric_setup_tpg_port_stat_cit(tf);
        target_fabric_setup_tpg_lun_cit(tf);
        target_fabric_setup_tpg_np_cit(tf);
        target_fabric_setup_tpg_np_base_cit(tf);
@@ -1028,7 +1225,9 @@ int target_fabric_setup_cits(struct target_fabric_configfs *tf)
        target_fabric_setup_tpg_nacl_attrib_cit(tf);
        target_fabric_setup_tpg_nacl_auth_cit(tf);
        target_fabric_setup_tpg_nacl_param_cit(tf);
+       target_fabric_setup_tpg_nacl_stat_cit(tf);
        target_fabric_setup_tpg_mappedlun_cit(tf);
+       target_fabric_setup_tpg_mappedlun_stat_cit(tf);
 
        return 0;
 }