+static unsigned nrs_tbf_id_hop_hash(struct cfs_hash *hs, const void *key,
+ unsigned mask)
+{
+ return cfs_hash_djb2_hash(key, sizeof(struct tbf_id), mask);
+}
+
+static int nrs_tbf_id_hop_keycmp(const void *key, struct hlist_node *hnode)
+{
+ const struct tbf_id *opc = key;
+ enum nrs_tbf_flag ntf;
+ struct nrs_tbf_client *cli = hlist_entry(hnode, struct nrs_tbf_client,
+ tc_hnode);
+ ntf = opc->ti_type & cli->tc_id.ti_type;
+ if ((ntf & NRS_TBF_FLAG_UID) && opc->ti_uid != cli->tc_id.ti_uid)
+ return 0;
+
+ if ((ntf & NRS_TBF_FLAG_GID) && opc->ti_gid != cli->tc_id.ti_gid)
+ return 0;
+
+ return 1;
+}
+
+static void *nrs_tbf_id_hop_key(struct hlist_node *hnode)
+{
+ struct nrs_tbf_client *cli = hlist_entry(hnode,
+ struct nrs_tbf_client,
+ tc_hnode);
+ return &cli->tc_id;
+}
+
+static void nrs_tbf_id_hop_get(struct cfs_hash *hs, struct hlist_node *hnode)
+{
+ struct nrs_tbf_client *cli = hlist_entry(hnode,
+ struct nrs_tbf_client,
+ tc_hnode);
+
+ atomic_inc(&cli->tc_ref);
+}
+
+static void nrs_tbf_id_hop_put(struct cfs_hash *hs, struct hlist_node *hnode)
+{
+ struct nrs_tbf_client *cli = hlist_entry(hnode,
+ struct nrs_tbf_client,
+ tc_hnode);
+
+ atomic_dec(&cli->tc_ref);
+}
+
+static void
+nrs_tbf_id_hop_exit(struct cfs_hash *hs, struct hlist_node *hnode)
+
+{
+ struct nrs_tbf_client *cli = hlist_entry(hnode,
+ struct nrs_tbf_client,
+ tc_hnode);
+
+ LASSERT(atomic_read(&cli->tc_ref) == 0);
+ nrs_tbf_cli_fini(cli);
+}
+
+static struct cfs_hash_ops nrs_tbf_id_hash_ops = {
+ .hs_hash = nrs_tbf_id_hop_hash,
+ .hs_keycmp = nrs_tbf_id_hop_keycmp,
+ .hs_key = nrs_tbf_id_hop_key,
+ .hs_object = nrs_tbf_hop_object,
+ .hs_get = nrs_tbf_id_hop_get,
+ .hs_put = nrs_tbf_id_hop_put,
+ .hs_put_locked = nrs_tbf_id_hop_put,
+ .hs_exit = nrs_tbf_id_hop_exit,
+};
+
+static int
+nrs_tbf_id_startup(struct ptlrpc_nrs_policy *policy,
+ struct nrs_tbf_head *head)
+{
+ struct nrs_tbf_cmd start;
+ int rc;
+
+ head->th_cli_hash = cfs_hash_create("nrs_tbf_id_hash",
+ NRS_TBF_NID_BITS,
+ NRS_TBF_NID_BITS,
+ NRS_TBF_NID_BKT_BITS, 0,
+ CFS_HASH_MIN_THETA,
+ CFS_HASH_MAX_THETA,
+ &nrs_tbf_id_hash_ops,
+ CFS_HASH_RW_BKTLOCK);
+ if (head->th_cli_hash == NULL)
+ return -ENOMEM;
+
+ memset(&start, 0, sizeof(start));
+ start.u.tc_start.ts_ids_str = "*";
+ start.u.tc_start.ts_rpc_rate = tbf_rate;
+ start.u.tc_start.ts_rule_flags = NTRS_DEFAULT;
+ start.tc_name = NRS_TBF_DEFAULT_RULE;
+ INIT_LIST_HEAD(&start.u.tc_start.ts_ids);
+ rc = nrs_tbf_rule_start(policy, head, &start);
+ if (rc) {
+ cfs_hash_putref(head->th_cli_hash);
+ head->th_cli_hash = NULL;
+ }
+
+ return rc;
+}
+
+static struct nrs_tbf_client *
+nrs_tbf_id_cli_find(struct nrs_tbf_head *head,
+ struct ptlrpc_request *req)
+{
+ struct tbf_id id;
+
+ LASSERT(head->th_type_flag == NRS_TBF_FLAG_UID ||
+ head->th_type_flag == NRS_TBF_FLAG_GID);
+
+ nrs_tbf_id_cli_set(req, &id, head->th_type_flag);
+ return cfs_hash_lookup(head->th_cli_hash, &id);
+}
+
+static struct nrs_tbf_client *
+nrs_tbf_id_cli_findadd(struct nrs_tbf_head *head,
+ struct nrs_tbf_client *cli)
+{
+ return cfs_hash_findadd_unique(head->th_cli_hash, &cli->tc_id,
+ &cli->tc_hnode);
+}
+
+static void
+nrs_tbf_uid_cli_init(struct nrs_tbf_client *cli,
+ struct ptlrpc_request *req)
+{
+ nrs_tbf_id_cli_set(req, &cli->tc_id, NRS_TBF_FLAG_UID);
+}
+
+static void
+nrs_tbf_gid_cli_init(struct nrs_tbf_client *cli,
+ struct ptlrpc_request *req)
+{
+ nrs_tbf_id_cli_set(req, &cli->tc_id, NRS_TBF_FLAG_GID);
+}
+
+static int
+nrs_tbf_id_list_match(struct list_head *id_list, struct tbf_id id)
+{
+ struct nrs_tbf_id *nti_id;
+ enum nrs_tbf_flag flag;
+
+ list_for_each_entry(nti_id, id_list, nti_linkage) {
+ flag = id.ti_type & nti_id->nti_id.ti_type;
+ if (!flag)
+ continue;
+
+ if ((flag & NRS_TBF_FLAG_UID) &&
+ (id.ti_uid != nti_id->nti_id.ti_uid))
+ continue;
+
+ if ((flag & NRS_TBF_FLAG_GID) &&
+ (id.ti_gid != nti_id->nti_id.ti_gid))
+ continue;
+
+ return 1;
+ }
+ return 0;
+}
+
+static int
+nrs_tbf_id_rule_match(struct nrs_tbf_rule *rule,
+ struct nrs_tbf_client *cli)
+{
+ return nrs_tbf_id_list_match(&rule->tr_ids, cli->tc_id);
+}
+
+static void nrs_tbf_id_cmd_fini(struct nrs_tbf_cmd *cmd)
+{
+ nrs_tbf_id_list_free(&cmd->u.tc_start.ts_ids);
+
+ if (cmd->u.tc_start.ts_ids_str)
+ OBD_FREE(cmd->u.tc_start.ts_ids_str,
+ strlen(cmd->u.tc_start.ts_ids_str) + 1);
+}
+
+static int
+nrs_tbf_id_list_parse(char *str, int len, struct list_head *id_list,
+ enum nrs_tbf_flag tif)
+{
+ struct cfs_lstr src;
+ struct cfs_lstr res;
+ int rc = 0;
+ struct tbf_id id = { 0 };
+ ENTRY;
+
+ if (tif != NRS_TBF_FLAG_UID && tif != NRS_TBF_FLAG_GID)
+ RETURN(-EINVAL);
+
+ src.ls_str = str;
+ src.ls_len = len;
+ INIT_LIST_HEAD(id_list);
+ while (src.ls_str) {
+ struct nrs_tbf_id *nti_id;
+
+ if (cfs_gettok(&src, ' ', &res) == 0)
+ GOTO(out, rc = -EINVAL);
+
+ id.ti_type = tif;
+ if (tif == NRS_TBF_FLAG_UID) {
+ if (!cfs_str2num_check(res.ls_str, res.ls_len,
+ &id.ti_uid, 0, (u32)~0U))
+ GOTO(out, rc = -EINVAL);
+ } else {
+ if (!cfs_str2num_check(res.ls_str, res.ls_len,
+ &id.ti_gid, 0, (u32)~0U))
+ GOTO(out, rc = -EINVAL);
+ }
+
+ OBD_ALLOC_PTR(nti_id);
+ if (nti_id == NULL)
+ GOTO(out, rc = -ENOMEM);
+
+ nti_id->nti_id = id;
+ list_add_tail(&nti_id->nti_linkage, id_list);
+ }
+out:
+ if (rc)
+ nrs_tbf_id_list_free(id_list);
+ RETURN(rc);
+}
+
+static int nrs_tbf_ug_id_parse(struct nrs_tbf_cmd *cmd, char *id)
+{
+ struct cfs_lstr src;
+ int rc;
+ enum nrs_tbf_flag tif;
+
+ tif = cmd->u.tc_start.ts_valid_type;
+
+ src.ls_str = id;
+ src.ls_len = strlen(id);
+
+ rc = nrs_tbf_check_id_value(&src,
+ tif == NRS_TBF_FLAG_UID ? "uid" : "gid");
+ if (rc)
+ return rc;
+
+ OBD_ALLOC(cmd->u.tc_start.ts_ids_str, src.ls_len + 1);
+ if (cmd->u.tc_start.ts_ids_str == NULL)
+ return -ENOMEM;
+
+ strlcpy(cmd->u.tc_start.ts_ids_str, src.ls_str, src.ls_len + 1);
+
+ rc = nrs_tbf_id_list_parse(cmd->u.tc_start.ts_ids_str,
+ strlen(cmd->u.tc_start.ts_ids_str),
+ &cmd->u.tc_start.ts_ids, tif);
+ if (rc)
+ nrs_tbf_id_cmd_fini(cmd);
+
+ return rc;
+}
+
+static int
+nrs_tbf_id_rule_init(struct ptlrpc_nrs_policy *policy,
+ struct nrs_tbf_rule *rule,
+ struct nrs_tbf_cmd *start)
+{
+ struct nrs_tbf_head *head = rule->tr_head;
+ int rc = 0;
+ enum nrs_tbf_flag tif = head->th_type_flag;
+ int ids_len = strlen(start->u.tc_start.ts_ids_str) + 1;
+
+ LASSERT(start->u.tc_start.ts_ids_str);
+ INIT_LIST_HEAD(&rule->tr_ids);
+
+ OBD_ALLOC(rule->tr_ids_str, ids_len);
+ if (rule->tr_ids_str == NULL)
+ return -ENOMEM;
+
+ strlcpy(rule->tr_ids_str, start->u.tc_start.ts_ids_str,
+ ids_len);
+
+ if (!list_empty(&start->u.tc_start.ts_ids)) {
+ rc = nrs_tbf_id_list_parse(rule->tr_ids_str,
+ strlen(rule->tr_ids_str),
+ &rule->tr_ids, tif);
+ if (rc)
+ CERROR("%ss {%s} illegal\n",
+ tif == NRS_TBF_FLAG_UID ? "uid" : "gid",
+ rule->tr_ids_str);
+ }
+ if (rc) {
+ OBD_FREE(rule->tr_ids_str, ids_len);
+ rule->tr_ids_str = NULL;
+ }
+ return rc;
+}
+
+static int
+nrs_tbf_id_rule_dump(struct nrs_tbf_rule *rule, struct seq_file *m)
+{
+ seq_printf(m, "%s {%s} %llu, ref %d\n", rule->tr_name,
+ rule->tr_ids_str, rule->tr_rpc_rate,
+ atomic_read(&rule->tr_ref) - 1);
+ return 0;
+}
+
+static void nrs_tbf_id_rule_fini(struct nrs_tbf_rule *rule)
+{
+ nrs_tbf_id_list_free(&rule->tr_ids);
+ if (rule->tr_ids_str != NULL)
+ OBD_FREE(rule->tr_ids_str, strlen(rule->tr_ids_str) + 1);
+}
+
+struct nrs_tbf_ops nrs_tbf_uid_ops = {
+ .o_name = NRS_TBF_TYPE_UID,
+ .o_startup = nrs_tbf_id_startup,
+ .o_cli_find = nrs_tbf_id_cli_find,
+ .o_cli_findadd = nrs_tbf_id_cli_findadd,
+ .o_cli_put = nrs_tbf_nid_cli_put,
+ .o_cli_init = nrs_tbf_uid_cli_init,
+ .o_rule_init = nrs_tbf_id_rule_init,
+ .o_rule_dump = nrs_tbf_id_rule_dump,
+ .o_rule_match = nrs_tbf_id_rule_match,
+ .o_rule_fini = nrs_tbf_id_rule_fini,
+};
+
+struct nrs_tbf_ops nrs_tbf_gid_ops = {
+ .o_name = NRS_TBF_TYPE_GID,
+ .o_startup = nrs_tbf_id_startup,
+ .o_cli_find = nrs_tbf_id_cli_find,
+ .o_cli_findadd = nrs_tbf_id_cli_findadd,
+ .o_cli_put = nrs_tbf_nid_cli_put,
+ .o_cli_init = nrs_tbf_gid_cli_init,
+ .o_rule_init = nrs_tbf_id_rule_init,
+ .o_rule_dump = nrs_tbf_id_rule_dump,
+ .o_rule_match = nrs_tbf_id_rule_match,
+ .o_rule_fini = nrs_tbf_id_rule_fini,
+};
+