Merge tag '6.6-rc-smb3-client-fixes-part2' of git://git.samba.org/sfrench/cifs-2.6
[sfrench/cifs-2.6.git] / kernel / trace / trace_events_filter.c
index 1e14f801685a8f83ad09f08d9b7739f214435be0..33264e510d161f5c78fdd464e45b6f966dd765d9 100644 (file)
@@ -68,7 +68,9 @@ enum filter_pred_fn {
        FILTER_PRED_FN_PCHAR_USER,
        FILTER_PRED_FN_PCHAR,
        FILTER_PRED_FN_CPU,
+       FILTER_PRED_FN_CPU_CPUMASK,
        FILTER_PRED_FN_CPUMASK,
+       FILTER_PRED_FN_CPUMASK_CPU,
        FILTER_PRED_FN_FUNCTION,
        FILTER_PRED_FN_,
        FILTER_PRED_TEST_VISITED,
@@ -665,6 +667,25 @@ do_filter_cpumask(int op, const struct cpumask *mask, const struct cpumask *cmp)
 /* Optimisation of do_filter_cpumask() for scalar fields */
 static inline int
 do_filter_scalar_cpumask(int op, unsigned int cpu, const struct cpumask *mask)
+{
+       /*
+        * Per the weight-of-one cpumask optimisations, the mask passed in this
+        * function has a weight >= 2, so it is never equal to a single scalar.
+        */
+       switch (op) {
+       case OP_EQ:
+               return false;
+       case OP_NE:
+               return true;
+       case OP_BAND:
+               return cpumask_test_cpu(cpu, mask);
+       default:
+               return 0;
+       }
+}
+
+static inline int
+do_filter_cpumask_scalar(int op, const struct cpumask *mask, unsigned int cpu)
 {
        switch (op) {
        case OP_EQ:
@@ -937,6 +958,14 @@ static int filter_pred_cpu(struct filter_pred *pred, void *event)
        }
 }
 
+/* Filter predicate for current CPU vs user-provided cpumask */
+static int filter_pred_cpu_cpumask(struct filter_pred *pred, void *event)
+{
+       int cpu = raw_smp_processor_id();
+
+       return do_filter_scalar_cpumask(pred->op, cpu, pred->mask);
+}
+
 /* Filter predicate for cpumask field vs user-provided cpumask */
 static int filter_pred_cpumask(struct filter_pred *pred, void *event)
 {
@@ -948,6 +977,17 @@ static int filter_pred_cpumask(struct filter_pred *pred, void *event)
        return do_filter_cpumask(pred->op, mask, cmp);
 }
 
+/* Filter predicate for cpumask field vs user-provided scalar  */
+static int filter_pred_cpumask_cpu(struct filter_pred *pred, void *event)
+{
+       u32 item = *(u32 *)(event + pred->offset);
+       int loc = item & 0xffff;
+       const struct cpumask *mask = (event + loc);
+       unsigned int cpu = pred->val;
+
+       return do_filter_cpumask_scalar(pred->op, mask, cpu);
+}
+
 /* Filter predicate for COMM. */
 static int filter_pred_comm(struct filter_pred *pred, void *event)
 {
@@ -1320,7 +1360,7 @@ int filter_assign_type(const char *type)
                        return FILTER_DYN_STRING;
                if (strstr(type, "cpumask_t"))
                        return FILTER_CPUMASK;
-               }
+       }
 
        if (strstr(type, "__rel_loc") && strstr(type, "char"))
                return FILTER_RDYN_STRING;
@@ -1440,8 +1480,12 @@ static int filter_pred_fn_call(struct filter_pred *pred, void *event)
                return filter_pred_pchar(pred, event);
        case FILTER_PRED_FN_CPU:
                return filter_pred_cpu(pred, event);
+       case FILTER_PRED_FN_CPU_CPUMASK:
+               return filter_pred_cpu_cpumask(pred, event);
        case FILTER_PRED_FN_CPUMASK:
                return filter_pred_cpumask(pred, event);
+       case FILTER_PRED_FN_CPUMASK_CPU:
+               return filter_pred_cpumask_cpu(pred, event);
        case FILTER_PRED_FN_FUNCTION:
                return filter_pred_function(pred, event);
        case FILTER_PRED_TEST_VISITED:
@@ -1655,10 +1699,12 @@ static int parse_pred(const char *str, void *data,
 
        } else if (!strncmp(str + i, "CPUS", 4)) {
                unsigned int maskstart;
+               bool single;
                char *tmp;
 
                switch (field->filter_type) {
                case FILTER_CPUMASK:
+               case FILTER_CPU:
                case FILTER_OTHER:
                        break;
                default:
@@ -1685,7 +1731,9 @@ static int parse_pred(const char *str, void *data,
                maskstart = i;
 
                /* Walk the cpulist until closing } */
-               for (; str[i] && str[i] != '}'; i++);
+               for (; str[i] && str[i] != '}'; i++)
+                       ;
+
                if (str[i] != '}') {
                        parse_error(pe, FILT_ERR_MISSING_BRACE_CLOSE, pos + i);
                        goto err_free;
@@ -1698,22 +1746,58 @@ static int parse_pred(const char *str, void *data,
 
                /* Copy the cpulist between { and } */
                tmp = kmalloc((i - maskstart) + 1, GFP_KERNEL);
-               strscpy(tmp, str + maskstart, (i - maskstart) + 1);
+               if (!tmp)
+                       goto err_mem;
 
+               strscpy(tmp, str + maskstart, (i - maskstart) + 1);
                pred->mask = kzalloc(cpumask_size(), GFP_KERNEL);
-               if (!pred->mask)
+               if (!pred->mask) {
+                       kfree(tmp);
                        goto err_mem;
+               }
 
                /* Now parse it */
                if (cpulist_parse(tmp, pred->mask)) {
+                       kfree(tmp);
                        parse_error(pe, FILT_ERR_INVALID_CPULIST, pos + i);
                        goto err_free;
                }
+               kfree(tmp);
 
                /* Move along */
                i++;
+
+               /*
+                * Optimisation: if the user-provided mask has a weight of one
+                * then we can treat it as a scalar input.
+                */
+               single = cpumask_weight(pred->mask) == 1;
+               if (single) {
+                       pred->val = cpumask_first(pred->mask);
+                       kfree(pred->mask);
+                       pred->mask = NULL;
+               }
+
                if (field->filter_type == FILTER_CPUMASK) {
-                       pred->fn_num = FILTER_PRED_FN_CPUMASK;
+                       pred->fn_num = single ?
+                               FILTER_PRED_FN_CPUMASK_CPU :
+                               FILTER_PRED_FN_CPUMASK;
+               } else if (field->filter_type == FILTER_CPU) {
+                       if (single) {
+                               if (pred->op == OP_BAND)
+                                       pred->op = OP_EQ;
+
+                               pred->fn_num = FILTER_PRED_FN_CPU;
+                       } else {
+                               pred->fn_num = FILTER_PRED_FN_CPU_CPUMASK;
+                       }
+               } else if (single) {
+                       if (pred->op == OP_BAND)
+                               pred->op = OP_EQ;
+
+                       pred->fn_num = select_comparison_fn(pred->op, field->size, false);
+                       if (pred->op == OP_NE)
+                               pred->not = 1;
                } else {
                        switch (field->size) {
                        case 8: