All of lore.kernel.org
 help / color / mirror / Atom feed
From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
To: Jeff Xie <xiehuan09@gmail.com>
Cc: rostedt@goodmis.org, mingo@redhat.com, mhiramat@kernel.org,
	zanussi@kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v10 1/4] trace: Add trace any kernel object
Date: Sun, 22 May 2022 00:25:41 +0900	[thread overview]
Message-ID: <20220522002541.85a32eecd48cfee550d9a47c@kernel.org> (raw)
In-Reply-To: <20220512170008.1301613-2-xiehuan09@gmail.com>

Hi Jeff,

On Fri, 13 May 2022 01:00:05 +0800
Jeff Xie <xiehuan09@gmail.com> wrote:

> Introduce objtrace trigger to get the call flow by tracing any kernel
> object in the function parameter.
> 
> The objtrace trigger makes a list of the target object address from
> the given event parameter, and records all kernel function calls
> which has the object address in its parameter.

Thank you for updating this. Please read my comments below

[...]
> +
> +static bool object_exist(void *obj, struct trace_array *tr)
> +{
> +	int i, max;
> +	struct objtrace_data *obj_data;
> +
> +	obj_data = get_obj_data(tr);
> +	if (!obj_data)
> +		return false;
> +
> +	max = atomic_read(&obj_data->num_traced_obj);

max = READ_ONCE(&obj_data->num_traced_obj);
 (see below)

> +	smp_rmb();
> +	for (i = 0; i < max; i++) {
> +		if (obj_data->traced_obj[i].obj == obj)
> +			return true;
> +	}
> +	return false;
> +}
> +
> +static bool object_empty(struct trace_array *tr)
> +{
> +	struct objtrace_data *obj_data;
> +
> +	obj_data = get_obj_data(tr);
> +	if (!obj_data)
> +		return false;
> +
> +	return !atomic_read(&obj_data->num_traced_obj);

return !READ_ONCE(&obj_data->num_traced_obj);
 (see below)

> +}
> +
> +static void set_trace_object(void *obj, struct trace_array *tr)
> +{
> +	unsigned long flags;
> +	struct object_instance *obj_ins;
> +	struct objtrace_data *obj_data;
> +
> +	if (in_nmi())
> +		return;
> +
> +	if (!obj && object_exist(obj, tr))
> +		return;
> +
> +	obj_data = get_obj_data(tr);
> +	if (!obj_data)
> +		return;
> +
> +	/* only this place has write operations */
> +	raw_spin_lock_irqsave(&obj_data->obj_data_lock, flags);
> +	if (atomic_read(&obj_data->num_traced_obj) == MAX_TRACED_OBJECT) {

Since obj_data->num_traced_obj update is protected by obj_data->obj_data_lock,
you don't need atomic operation. What you need is using READ_ONCE() to
access the num_traced_obj outside of this protected area.

> +		trace_array_printk_buf(tr->array_buffer.buffer, _THIS_IP_,
> +				"object_pool is full, can't trace object:0x%px\n", obj);
> +		goto out;
> +	}
> +	obj_ins = &obj_data->traced_obj[atomic_read(&obj_data->num_traced_obj)];
> +	obj_ins->obj = obj;
> +	obj_ins->tr = tr;
> +	/* make sure the num_traced_obj update always appears after traced_obj update */
> +	smp_wmb();
> +	atomic_inc(&obj_data->num_traced_obj);
> +out:
> +	raw_spin_unlock_irqrestore(&obj_data->obj_data_lock, flags);
> +}
> +
[...]
> +
> +static int
> +event_object_trigger_parse(struct event_command *cmd_ops,
> +		       struct trace_event_file *file,
> +		       char *glob, char *cmd, char *param_and_filter)
> +{
> +	struct event_trigger_data *trigger_data;
> +	struct objtrace_trigger_data *obj_data;
> +	struct ftrace_event_field *field;
> +	char *objtrace_cmd, *arg;
> +	char *param, *filter;
> +	int ret;
> +	bool remove;
> +
> +	remove = event_trigger_check_remove(glob);
> +
> +	/*
> +	 * separate the param and the filter:
> +	 * objtrace:add:OBJ[:COUNT] [if filter]
> +	 */
> +	ret = event_trigger_separate_filter(param_and_filter, &param, &filter, true);
> +	if (ret)
> +		return ret;
> +
> +	objtrace_cmd = strsep(&param, ":");
> +	if (!objtrace_cmd || strcmp(objtrace_cmd, "add")) {
> +		pr_err("error objtrace command\n");
> +		return -EINVAL;
> +	}
> +
> +	arg = strsep(&param, ":");
> +	if (!arg)
> +		return -EINVAL;
> +
> +	field = trace_find_event_field(file->event_call, arg);
> +	if (!field)
> +		return -EINVAL;
> +
> +	if (field->size != sizeof(void *)) {
> +		pr_err("the size of the %s should be:%ld\n", field->name, sizeof(void *));
> +		return -EINVAL;
> +	}
> +
> +	if (remove && !field_exist(file, cmd_ops, field->name))
> +		return -EINVAL;

This may return -ENOENT.

> +
> +	obj_data = kzalloc(sizeof(*obj_data), GFP_KERNEL);
> +	if (!obj_data)
> +		return -ENOMEM;
> +
> +	obj_data->field = field;
> +	obj_data->tr = file->tr;
> +	snprintf(obj_data->objtrace_cmd, OBJTRACE_CMD_LEN, objtrace_cmd);

If objtrace_cmd is fixed command string, can you make this a flag, like
OBJTRACE_CMD_ADD.

> +
> +	trigger_data = event_trigger_alloc(cmd_ops, cmd, param, obj_data);
> +	if (!trigger_data) {
> +		kfree(obj_data);
> +		return -ENOMEM;
> +	}
> +	if (remove) {
> +		event_trigger_unregister(cmd_ops, file, glob+1, trigger_data);
> +		kfree(obj_data);
> +		kfree(trigger_data);
> +		return 0;
> +	}
> +
> +	ret = event_trigger_parse_num(param, trigger_data);
> +	if (ret)
> +		goto out_free;
> +
> +	ret = event_trigger_set_filter(cmd_ops, file, filter, trigger_data);
> +	if (ret < 0)
> +		goto out_free;
> +
> +	ret = event_trigger_register(cmd_ops, file, glob, trigger_data);
> +	if (ret)
> +		goto out_free;
> +
> +	return ret;
> +
> + out_free:
> +	event_trigger_reset_filter(cmd_ops, trigger_data);
> +	kfree(obj_data);
> +	kfree(trigger_data);
> +	return ret;
> +}
> +
> +static struct event_command trigger_object_cmd = {
> +	.name			= "objtrace",
> +	.trigger_type		= ETT_TRACE_OBJECT,
> +	.flags			= EVENT_CMD_FL_NEEDS_REC,
> +	.parse			= event_object_trigger_parse,
> +	.reg			= register_trigger,
> +	.unreg			= unregister_trigger,
> +	.get_trigger_ops	= objecttrace_get_trigger_ops,
> +	.set_filter		= set_trigger_filter,
> +};
> +
> +__init int register_trigger_object_cmd(void)
> +{
> +	int ret;
> +
> +	ret = register_event_command(&trigger_object_cmd);
> +	WARN_ON(ret < 0);
> +
> +	return ret;
> +}
> +
> +int allocate_objtrace_data(struct trace_array *tr)
> +{
> +	struct objtrace_data *obj_data;
> +	struct ftrace_ops *fops;
> +
> +	obj_data = kzalloc(sizeof(*obj_data), GFP_KERNEL);
> +	if (!obj_data)
> +		return -ENOMEM;
> +
> +	tr->obj_data = obj_data;

I suggest to move this line after initializing all field in
the obj_data.

> +	obj_data->tr = tr;
> +	fops = &obj_data->fops;
> +	fops->func = trace_object_events_call;
> +	fops->flags = FTRACE_OPS_FL_SAVE_REGS;
> +	fops->private = tr;
> +
> +	raw_spin_lock(&obj_data->obj_data_lock);

You don't need to lock this spinlock becuase this data structure
is not used yet. Also, you need to initialize the lock with
__RAW_SPIN_LOCK_UNLOCKED() macro.

> +	list_add(&obj_data->head, &obj_data_head);
> +	raw_spin_unlock(&obj_data->obj_data_lock);
> +	return 0;
> +}


Thank you,


-- 
Masami Hiramatsu <mhiramat@kernel.org>

  parent reply	other threads:[~2022-05-21 15:25 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-05-12 17:00 [PATCH v10 0/4] trace: Introduce objtrace trigger to trace the kernel object Jeff Xie
2022-05-12 17:00 ` [PATCH v10 1/4] trace: Add trace any " Jeff Xie
2022-05-13  2:01   ` kernel test robot
2022-05-18 13:48     ` Masami Hiramatsu
2022-05-18 13:48       ` Masami Hiramatsu
2022-05-18 14:17       ` Jeff Xie
2022-05-18 14:17         ` Jeff Xie
2022-05-26 23:42         ` Masami Hiramatsu
2022-05-26 23:42           ` Masami Hiramatsu
2022-05-27 12:00           ` Jeff Xie
2022-05-27 12:00             ` Jeff Xie
2022-05-13  4:50   ` kernel test robot
2022-05-21 15:25   ` Masami Hiramatsu [this message]
2022-05-21 17:25     ` Jeff Xie
2022-05-12 17:00 ` [PATCH v10 2/4] trace/objtrace: Get the value of the object Jeff Xie
2022-05-22 14:22   ` Masami Hiramatsu
2022-05-23  1:12     ` Jeff Xie
2022-05-31  7:13     ` Jeff Xie
2022-06-01 15:13       ` Masami Hiramatsu
2022-06-02 16:23         ` Jeff Xie
2022-05-12 17:00 ` [PATCH v10 3/4] trace/objtrace: Add testcases for objtrace Jeff Xie
2022-05-12 17:00 ` [PATCH v10 4/4] trace/objtrace: Add documentation " Jeff Xie

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220522002541.85a32eecd48cfee550d9a47c@kernel.org \
    --to=mhiramat@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=rostedt@goodmis.org \
    --cc=xiehuan09@gmail.com \
    --cc=zanussi@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.