Skip to content

Commit e44ef4e

Browse files
ayalevin123Saeed Mahameed
authored andcommitted
devlink: Hang reporter's dump method on a dumpit cb
The devlink health reporter provides a dump method on an error. Dump may contain a large amount of data, in this case doit cb isn't sufficient. This is because the user side is blocking and doesn't allow draining of the socket until the socket runs out of buffers. Using dumpit cb is the correct way to go. Please note that thankfully the dump op is not yet implemented in any driver and therefore this change is not breaking userspace. Fixes: 35455e2 ("devlink: Add health dump {get,clear} commands") Signed-off-by: Aya Levin <[email protected]> Acked-by: Jiri Pirko <[email protected]> Signed-off-by: Saeed Mahameed <[email protected]>
1 parent a842fe1 commit e44ef4e

File tree

1 file changed

+98
-20
lines changed

1 file changed

+98
-20
lines changed

net/core/devlink.c

Lines changed: 98 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4518,6 +4518,35 @@ static int devlink_fmsg_snd(struct devlink_fmsg *fmsg,
45184518
return err;
45194519
}
45204520

4521+
static int devlink_fmsg_dumpit(struct devlink_fmsg *fmsg, struct sk_buff *skb,
4522+
struct netlink_callback *cb,
4523+
enum devlink_command cmd)
4524+
{
4525+
int index = cb->args[0];
4526+
int tmp_index = index;
4527+
void *hdr;
4528+
int err;
4529+
4530+
hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
4531+
&devlink_nl_family, NLM_F_ACK | NLM_F_MULTI, cmd);
4532+
if (!hdr) {
4533+
err = -EMSGSIZE;
4534+
goto nla_put_failure;
4535+
}
4536+
4537+
err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
4538+
if ((err && err != -EMSGSIZE) || tmp_index == index)
4539+
goto nla_put_failure;
4540+
4541+
cb->args[0] = index;
4542+
genlmsg_end(skb, hdr);
4543+
return skb->len;
4544+
4545+
nla_put_failure:
4546+
genlmsg_cancel(skb, hdr);
4547+
return err;
4548+
}
4549+
45214550
struct devlink_health_reporter {
45224551
struct list_head list;
45234552
void *priv;
@@ -4750,17 +4779,16 @@ int devlink_health_report(struct devlink_health_reporter *reporter,
47504779
EXPORT_SYMBOL_GPL(devlink_health_report);
47514780

47524781
static struct devlink_health_reporter *
4753-
devlink_health_reporter_get_from_info(struct devlink *devlink,
4754-
struct genl_info *info)
4782+
devlink_health_reporter_get_from_attrs(struct devlink *devlink,
4783+
struct nlattr **attrs)
47554784
{
47564785
struct devlink_health_reporter *reporter;
47574786
char *reporter_name;
47584787

4759-
if (!info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME])
4788+
if (!attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME])
47604789
return NULL;
47614790

4762-
reporter_name =
4763-
nla_data(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
4791+
reporter_name = nla_data(attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
47644792
mutex_lock(&devlink->reporters_lock);
47654793
reporter = devlink_health_reporter_find_by_name(devlink, reporter_name);
47664794
if (reporter)
@@ -4769,6 +4797,48 @@ devlink_health_reporter_get_from_info(struct devlink *devlink,
47694797
return reporter;
47704798
}
47714799

4800+
static struct devlink_health_reporter *
4801+
devlink_health_reporter_get_from_info(struct devlink *devlink,
4802+
struct genl_info *info)
4803+
{
4804+
return devlink_health_reporter_get_from_attrs(devlink, info->attrs);
4805+
}
4806+
4807+
static struct devlink_health_reporter *
4808+
devlink_health_reporter_get_from_cb(struct netlink_callback *cb)
4809+
{
4810+
struct devlink_health_reporter *reporter;
4811+
struct devlink *devlink;
4812+
struct nlattr **attrs;
4813+
int err;
4814+
4815+
attrs = kmalloc_array(DEVLINK_ATTR_MAX + 1, sizeof(*attrs), GFP_KERNEL);
4816+
if (!attrs)
4817+
return NULL;
4818+
4819+
err = nlmsg_parse_deprecated(cb->nlh,
4820+
GENL_HDRLEN + devlink_nl_family.hdrsize,
4821+
attrs, DEVLINK_ATTR_MAX,
4822+
devlink_nl_family.policy, cb->extack);
4823+
if (err)
4824+
goto free;
4825+
4826+
mutex_lock(&devlink_mutex);
4827+
devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
4828+
if (IS_ERR(devlink))
4829+
goto unlock;
4830+
4831+
reporter = devlink_health_reporter_get_from_attrs(devlink, attrs);
4832+
mutex_unlock(&devlink_mutex);
4833+
kfree(attrs);
4834+
return reporter;
4835+
unlock:
4836+
mutex_unlock(&devlink_mutex);
4837+
free:
4838+
kfree(attrs);
4839+
return NULL;
4840+
}
4841+
47724842
static void
47734843
devlink_health_reporter_put(struct devlink_health_reporter *reporter)
47744844
{
@@ -5004,32 +5074,40 @@ static int devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff *skb,
50045074
return err;
50055075
}
50065076

5007-
static int devlink_nl_cmd_health_reporter_dump_get_doit(struct sk_buff *skb,
5008-
struct genl_info *info)
5077+
static int
5078+
devlink_nl_cmd_health_reporter_dump_get_dumpit(struct sk_buff *skb,
5079+
struct netlink_callback *cb)
50095080
{
5010-
struct devlink *devlink = info->user_ptr[0];
50115081
struct devlink_health_reporter *reporter;
5082+
u64 start = cb->args[0];
50125083
int err;
50135084

5014-
reporter = devlink_health_reporter_get_from_info(devlink, info);
5085+
reporter = devlink_health_reporter_get_from_cb(cb);
50155086
if (!reporter)
50165087
return -EINVAL;
50175088

50185089
if (!reporter->ops->dump) {
5019-
devlink_health_reporter_put(reporter);
5020-
return -EOPNOTSUPP;
5090+
err = -EOPNOTSUPP;
5091+
goto out;
50215092
}
5022-
50235093
mutex_lock(&reporter->dump_lock);
5024-
err = devlink_health_do_dump(reporter, NULL);
5025-
if (err)
5026-
goto out;
5027-
5028-
err = devlink_fmsg_snd(reporter->dump_fmsg, info,
5029-
DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET, 0);
5094+
if (!start) {
5095+
err = devlink_health_do_dump(reporter, NULL);
5096+
if (err)
5097+
goto unlock;
5098+
cb->args[1] = reporter->dump_ts;
5099+
}
5100+
if (!reporter->dump_fmsg || cb->args[1] != reporter->dump_ts) {
5101+
NL_SET_ERR_MSG_MOD(cb->extack, "Dump trampled, please retry");
5102+
err = -EAGAIN;
5103+
goto unlock;
5104+
}
50305105

5031-
out:
5106+
err = devlink_fmsg_dumpit(reporter->dump_fmsg, skb, cb,
5107+
DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET);
5108+
unlock:
50325109
mutex_unlock(&reporter->dump_lock);
5110+
out:
50335111
devlink_health_reporter_put(reporter);
50345112
return err;
50355113
}
@@ -5366,7 +5444,7 @@ static const struct genl_ops devlink_nl_ops[] = {
53665444
{
53675445
.cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
53685446
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
5369-
.doit = devlink_nl_cmd_health_reporter_dump_get_doit,
5447+
.dumpit = devlink_nl_cmd_health_reporter_dump_get_dumpit,
53705448
.flags = GENL_ADMIN_PERM,
53715449
.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
53725450
DEVLINK_NL_FLAG_NO_LOCK,

0 commit comments

Comments
 (0)