memcpy(rule->tr_name, start->tc_name, strlen(start->tc_name));
rule->tr_rpc_rate = start->u.tc_start.ts_rpc_rate;
+ rule->tr_flags = start->u.tc_start.ts_rule_flags;
rule->tr_nsecs = NSEC_PER_SEC;
do_div(rule->tr_nsecs, rule->tr_rpc_rate);
rule->tr_depth = tbf_depth;
head->th_rule = rule;
}
+ CDEBUG(D_RPCTRACE, "TBF starts rule@%p rate %llu gen %llu\n",
+ rule, rule->tr_rpc_rate, rule->tr_generation);
+
return 0;
}
cli1 = container_of(e1, struct nrs_tbf_client, tc_node);
cli2 = container_of(e2, struct nrs_tbf_client, tc_node);
- if (cli1->tc_check_time + cli1->tc_nsecs <
- cli2->tc_check_time + cli2->tc_nsecs)
+ if (cli1->tc_deadline < cli2->tc_deadline)
return 1;
- else if (cli1->tc_check_time + cli1->tc_nsecs >
- cli2->tc_check_time + cli2->tc_nsecs)
+ else if (cli1->tc_deadline > cli2->tc_deadline)
return 0;
if (cli1->tc_check_time < cli2->tc_check_time)
}
static int
-nrs_tbf_jobid_list_add(const struct cfs_lstr *id, struct list_head *jobid_list)
+nrs_tbf_jobid_list_add(struct cfs_lstr *id, struct list_head *jobid_list)
{
struct nrs_tbf_jobid *jobid;
+ struct cfs_lstr res;
+ int rc;
OBD_ALLOC(jobid, sizeof(struct nrs_tbf_jobid));
if (jobid == NULL)
}
memcpy(jobid->tj_id, id->ls_str, id->ls_len);
+ rc = cfs_gettok(id, '*', &res);
+ if (rc == 0)
+ jobid->tj_match_flag = NRS_TBF_MATCH_FULL;
+ else
+ jobid->tj_match_flag = NRS_TBF_MATCH_WILDCARD;
+
list_add_tail(&jobid->tj_linkage, jobid_list);
return 0;
}
+static bool
+cfs_match_wildcard(const char *pattern, const char *content)
+{
+ if (*pattern == '\0' && *content == '\0')
+ return true;
+
+ if (*pattern == '*' && *(pattern + 1) != '\0' && *content == '\0')
+ return false;
+
+ while (*pattern == *content) {
+ pattern++;
+ content++;
+ if (*pattern == '\0' && *content == '\0')
+ return true;
+
+ if (*pattern == '*' && *(pattern + 1) != '\0' &&
+ *content == '\0')
+ return false;
+ }
+
+ if (*pattern == '*')
+ return (cfs_match_wildcard(pattern + 1, content) ||
+ cfs_match_wildcard(pattern, content + 1));
+
+ return false;
+}
+
+static inline bool
+nrs_tbf_jobid_match(const struct nrs_tbf_jobid *jobid, const char *id)
+{
+ if (jobid->tj_match_flag == NRS_TBF_MATCH_FULL)
+ return strcmp(jobid->tj_id, id) == 0;
+
+ if (jobid->tj_match_flag == NRS_TBF_MATCH_WILDCARD)
+ return cfs_match_wildcard(jobid->tj_id, id);
+
+ return false;
+}
+
static int
nrs_tbf_jobid_list_match(struct list_head *jobid_list, char *id)
{
struct nrs_tbf_jobid *jobid;
list_for_each_entry(jobid, jobid_list, tj_linkage) {
- if (strcmp(id, jobid->tj_id) == 0)
+ if (nrs_tbf_jobid_match(jobid, id))
return 1;
}
return 0;
cli->tc_rule->tr_flags & NTRS_STOPPING) {
struct nrs_tbf_rule *rule;
+ CDEBUG(D_RPCTRACE,
+ "TBF class@%p rate %llu sequence %d, "
+ "rule flags %d, head sequence %d\n",
+ cli, cli->tc_rpc_rate,
+ cli->tc_rule_sequence,
+ cli->tc_rule->tr_flags,
+ atomic_read(&head->th_rule_sequence));
rule = nrs_tbf_rule_match(head, cli);
- if (rule != cli->tc_rule)
+ if (rule != cli->tc_rule) {
nrs_tbf_cli_reset(head, rule, cli);
- else
+ } else {
+ if (cli->tc_rule_generation != rule->tr_generation)
+ nrs_tbf_cli_reset_value(head, cli);
nrs_tbf_rule_put(rule);
+ }
} else if (cli->tc_rule_generation !=
cli->tc_rule->tr_generation) {
nrs_tbf_cli_reset_value(head, cli);
struct ptlrpc_nrs_request,
nr_u.tbf.tr_list);
} else {
+ struct nrs_tbf_rule *rule = cli->tc_rule;
__u64 now = ktime_to_ns(ktime_get());
__u64 passed;
__u64 ntoken;
__u64 deadline;
+ __u64 old_resid = 0;
deadline = cli->tc_check_time +
cli->tc_nsecs;
passed = now - cli->tc_check_time;
ntoken = passed * cli->tc_rpc_rate;
do_div(ntoken, NSEC_PER_SEC);
+
ntoken += cli->tc_ntoken;
- if (ntoken > cli->tc_depth)
+ if (rule->tr_flags & NTRS_REALTIME) {
+ LASSERT(cli->tc_nsecs_resid < cli->tc_nsecs);
+ old_resid = cli->tc_nsecs_resid;
+ cli->tc_nsecs_resid += passed % cli->tc_nsecs;
+ if (cli->tc_nsecs_resid > cli->tc_nsecs) {
+ ntoken++;
+ cli->tc_nsecs_resid -= cli->tc_nsecs;
+ }
+ } else if (ntoken > cli->tc_depth)
ntoken = cli->tc_depth;
+
if (ntoken > 0) {
struct ptlrpc_request *req;
nrq = list_entry(cli->tc_list.next,
&cli->tc_node);
cli->tc_in_heap = false;
} else {
+ if (!(rule->tr_flags & NTRS_REALTIME))
+ cli->tc_deadline = now + cli->tc_nsecs;
cfs_binheap_relocate(head->th_binheap,
&cli->tc_node);
}
CDEBUG(D_RPCTRACE,
- "NRS start %s request from %s, "
- "seq: %llu\n",
- policy->pol_desc->pd_name,
- libcfs_id2str(req->rq_peer),
- nrq->nr_u.tbf.tr_sequence);
+ "TBF dequeues: class@%p rate %llu gen %llu "
+ "token %llu, rule@%p rate %llu gen %llu\n",
+ cli, cli->tc_rpc_rate,
+ cli->tc_rule_generation, cli->tc_ntoken,
+ cli->tc_rule, cli->tc_rule->tr_rpc_rate,
+ cli->tc_rule->tr_generation);
} else {
ktime_t time;
+ if (rule->tr_flags & NTRS_REALTIME) {
+ cli->tc_deadline = deadline;
+ cli->tc_nsecs_resid = old_resid;
+ cfs_binheap_relocate(head->th_binheap,
+ &cli->tc_node);
+ if (node != cfs_binheap_root(head->th_binheap))
+ return nrs_tbf_req_get(policy,
+ peek, force);
+ }
policy->pol_nrs->nrs_throttling = 1;
head->th_deadline = deadline;
time = ktime_set(0, 0);
struct nrs_tbf_head, th_res);
if (list_empty(&cli->tc_list)) {
LASSERT(!cli->tc_in_heap);
+ cli->tc_deadline = cli->tc_check_time + cli->tc_nsecs;
rc = cfs_binheap_insert(head->th_binheap, &cli->tc_node);
if (rc == 0) {
cli->tc_in_heap = true;
list_add_tail(&nrq->nr_u.tbf.tr_list,
&cli->tc_list);
if (policy->pol_nrs->nrs_throttling) {
- __u64 deadline = cli->tc_check_time +
- cli->tc_nsecs;
+ __u64 deadline = cli->tc_deadline;
if ((head->th_deadline > deadline) &&
(hrtimer_try_to_cancel(&head->th_timer)
>= 0)) {
list_add_tail(&nrq->nr_u.tbf.tr_list,
&cli->tc_list);
}
+
+ if (rc == 0)
+ CDEBUG(D_RPCTRACE,
+ "TBF enqueues: class@%p rate %llu gen %llu "
+ "token %llu, rule@%p rate %llu gen %llu\n",
+ cli, cli->tc_rpc_rate,
+ cli->tc_rule_generation, cli->tc_ntoken,
+ cli->tc_rule, cli->tc_rule->tr_rpc_rate,
+ cli->tc_rule->tr_generation);
+
return rc;
}
cmd->u.tc_change.tc_next_name = val;
else
return -EINVAL;
+ } else if (strcmp(key, "realtime") == 0) {
+ unsigned long realtime;
+
+ rc = kstrtoul(val, 10, &realtime);
+ if (rc)
+ return rc;
+
+ if (realtime > 0)
+ cmd->u.tc_start.ts_rule_flags |= NTRS_REALTIME;
} else {
return -EINVAL;
}