Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright (c) 2019 Mellanox Technologies. All rights reserved */
0003 
0004 #include <linux/debugfs.h>
0005 #include <linux/err.h>
0006 #include <linux/kernel.h>
0007 #include <linux/slab.h>
0008 
0009 #include "netdevsim.h"
0010 
0011 static int
0012 nsim_dev_empty_reporter_dump(struct devlink_health_reporter *reporter,
0013                  struct devlink_fmsg *fmsg, void *priv_ctx,
0014                  struct netlink_ext_ack *extack)
0015 {
0016     return 0;
0017 }
0018 
0019 static int
0020 nsim_dev_empty_reporter_diagnose(struct devlink_health_reporter *reporter,
0021                  struct devlink_fmsg *fmsg,
0022                  struct netlink_ext_ack *extack)
0023 {
0024     return 0;
0025 }
0026 
0027 static const
0028 struct devlink_health_reporter_ops nsim_dev_empty_reporter_ops = {
0029     .name = "empty",
0030     .dump = nsim_dev_empty_reporter_dump,
0031     .diagnose = nsim_dev_empty_reporter_diagnose,
0032 };
0033 
0034 struct nsim_dev_dummy_reporter_ctx {
0035     char *break_msg;
0036 };
0037 
0038 static int
0039 nsim_dev_dummy_reporter_recover(struct devlink_health_reporter *reporter,
0040                 void *priv_ctx,
0041                 struct netlink_ext_ack *extack)
0042 {
0043     struct nsim_dev_health *health = devlink_health_reporter_priv(reporter);
0044     struct nsim_dev_dummy_reporter_ctx *ctx = priv_ctx;
0045 
0046     if (health->fail_recover) {
0047         /* For testing purposes, user set debugfs fail_recover
0048          * value to true. Fail right away.
0049          */
0050         NL_SET_ERR_MSG_MOD(extack, "User setup the recover to fail for testing purposes");
0051         return -EINVAL;
0052     }
0053     if (ctx) {
0054         kfree(health->recovered_break_msg);
0055         health->recovered_break_msg = kstrdup(ctx->break_msg,
0056                               GFP_KERNEL);
0057         if (!health->recovered_break_msg)
0058             return -ENOMEM;
0059     }
0060     return 0;
0061 }
0062 
0063 static int nsim_dev_dummy_fmsg_put(struct devlink_fmsg *fmsg, u32 binary_len)
0064 {
0065     char *binary;
0066     int err;
0067     int i;
0068 
0069     err = devlink_fmsg_bool_pair_put(fmsg, "test_bool", true);
0070     if (err)
0071         return err;
0072     err = devlink_fmsg_u8_pair_put(fmsg, "test_u8", 1);
0073     if (err)
0074         return err;
0075     err = devlink_fmsg_u32_pair_put(fmsg, "test_u32", 3);
0076     if (err)
0077         return err;
0078     err = devlink_fmsg_u64_pair_put(fmsg, "test_u64", 4);
0079     if (err)
0080         return err;
0081     err = devlink_fmsg_string_pair_put(fmsg, "test_string", "somestring");
0082     if (err)
0083         return err;
0084 
0085     binary = kmalloc(binary_len, GFP_KERNEL | __GFP_NOWARN);
0086     if (!binary)
0087         return -ENOMEM;
0088     get_random_bytes(binary, binary_len);
0089     err = devlink_fmsg_binary_pair_put(fmsg, "test_binary", binary, binary_len);
0090     kfree(binary);
0091     if (err)
0092         return err;
0093 
0094     err = devlink_fmsg_pair_nest_start(fmsg, "test_nest");
0095     if (err)
0096         return err;
0097     err = devlink_fmsg_obj_nest_start(fmsg);
0098     if (err)
0099         return err;
0100     err = devlink_fmsg_bool_pair_put(fmsg, "nested_test_bool", false);
0101     if (err)
0102         return err;
0103     err = devlink_fmsg_u8_pair_put(fmsg, "nested_test_u8", false);
0104     if (err)
0105         return err;
0106     err = devlink_fmsg_obj_nest_end(fmsg);
0107     if (err)
0108         return err;
0109     err = devlink_fmsg_pair_nest_end(fmsg);
0110     if (err)
0111         return err;
0112 
0113     err = devlink_fmsg_arr_pair_nest_end(fmsg);
0114     if (err)
0115         return err;
0116 
0117     err = devlink_fmsg_arr_pair_nest_start(fmsg, "test_u32_array");
0118     if (err)
0119         return err;
0120     for (i = 0; i < 10; i++) {
0121         err = devlink_fmsg_u32_put(fmsg, i);
0122         if (err)
0123             return err;
0124     }
0125     err = devlink_fmsg_arr_pair_nest_end(fmsg);
0126     if (err)
0127         return err;
0128 
0129     err = devlink_fmsg_arr_pair_nest_start(fmsg, "test_array_of_objects");
0130     if (err)
0131         return err;
0132     for (i = 0; i < 10; i++) {
0133         err = devlink_fmsg_obj_nest_start(fmsg);
0134         if (err)
0135             return err;
0136         err = devlink_fmsg_bool_pair_put(fmsg,
0137                          "in_array_nested_test_bool",
0138                          false);
0139         if (err)
0140             return err;
0141         err = devlink_fmsg_u8_pair_put(fmsg,
0142                            "in_array_nested_test_u8",
0143                            i);
0144         if (err)
0145             return err;
0146         err = devlink_fmsg_obj_nest_end(fmsg);
0147         if (err)
0148             return err;
0149     }
0150     return devlink_fmsg_arr_pair_nest_end(fmsg);
0151 }
0152 
0153 static int
0154 nsim_dev_dummy_reporter_dump(struct devlink_health_reporter *reporter,
0155                  struct devlink_fmsg *fmsg, void *priv_ctx,
0156                  struct netlink_ext_ack *extack)
0157 {
0158     struct nsim_dev_health *health = devlink_health_reporter_priv(reporter);
0159     struct nsim_dev_dummy_reporter_ctx *ctx = priv_ctx;
0160     int err;
0161 
0162     if (ctx) {
0163         err = devlink_fmsg_string_pair_put(fmsg, "break_message",
0164                            ctx->break_msg);
0165         if (err)
0166             return err;
0167     }
0168     return nsim_dev_dummy_fmsg_put(fmsg, health->binary_len);
0169 }
0170 
0171 static int
0172 nsim_dev_dummy_reporter_diagnose(struct devlink_health_reporter *reporter,
0173                  struct devlink_fmsg *fmsg,
0174                  struct netlink_ext_ack *extack)
0175 {
0176     struct nsim_dev_health *health = devlink_health_reporter_priv(reporter);
0177     int err;
0178 
0179     if (health->recovered_break_msg) {
0180         err = devlink_fmsg_string_pair_put(fmsg,
0181                            "recovered_break_message",
0182                            health->recovered_break_msg);
0183         if (err)
0184             return err;
0185     }
0186     return nsim_dev_dummy_fmsg_put(fmsg, health->binary_len);
0187 }
0188 
0189 static const
0190 struct devlink_health_reporter_ops nsim_dev_dummy_reporter_ops = {
0191     .name = "dummy",
0192     .recover = nsim_dev_dummy_reporter_recover,
0193     .dump = nsim_dev_dummy_reporter_dump,
0194     .diagnose = nsim_dev_dummy_reporter_diagnose,
0195 };
0196 
0197 static ssize_t nsim_dev_health_break_write(struct file *file,
0198                        const char __user *data,
0199                        size_t count, loff_t *ppos)
0200 {
0201     struct nsim_dev_health *health = file->private_data;
0202     struct nsim_dev_dummy_reporter_ctx ctx;
0203     char *break_msg;
0204     int err;
0205 
0206     break_msg = memdup_user_nul(data, count);
0207     if (IS_ERR(break_msg))
0208         return PTR_ERR(break_msg);
0209 
0210     if (break_msg[count - 1] == '\n')
0211         break_msg[count - 1] = '\0';
0212 
0213     ctx.break_msg = break_msg;
0214     err = devlink_health_report(health->dummy_reporter, break_msg, &ctx);
0215     if (err)
0216         goto out;
0217 
0218 out:
0219     kfree(break_msg);
0220     return err ?: count;
0221 }
0222 
0223 static const struct file_operations nsim_dev_health_break_fops = {
0224     .open = simple_open,
0225     .write = nsim_dev_health_break_write,
0226     .llseek = generic_file_llseek,
0227     .owner = THIS_MODULE,
0228 };
0229 
0230 int nsim_dev_health_init(struct nsim_dev *nsim_dev, struct devlink *devlink)
0231 {
0232     struct nsim_dev_health *health = &nsim_dev->health;
0233     int err;
0234 
0235     health->empty_reporter =
0236         devlink_health_reporter_create(devlink,
0237                            &nsim_dev_empty_reporter_ops,
0238                            0, health);
0239     if (IS_ERR(health->empty_reporter))
0240         return PTR_ERR(health->empty_reporter);
0241 
0242     health->dummy_reporter =
0243         devlink_health_reporter_create(devlink,
0244                            &nsim_dev_dummy_reporter_ops,
0245                            0, health);
0246     if (IS_ERR(health->dummy_reporter)) {
0247         err = PTR_ERR(health->dummy_reporter);
0248         goto err_empty_reporter_destroy;
0249     }
0250 
0251     health->ddir = debugfs_create_dir("health", nsim_dev->ddir);
0252     if (IS_ERR(health->ddir)) {
0253         err = PTR_ERR(health->ddir);
0254         goto err_dummy_reporter_destroy;
0255     }
0256 
0257     health->recovered_break_msg = NULL;
0258     debugfs_create_file("break_health", 0200, health->ddir, health,
0259                 &nsim_dev_health_break_fops);
0260     health->binary_len = 16;
0261     debugfs_create_u32("binary_len", 0600, health->ddir,
0262                &health->binary_len);
0263     health->fail_recover = false;
0264     debugfs_create_bool("fail_recover", 0600, health->ddir,
0265                 &health->fail_recover);
0266     return 0;
0267 
0268 err_dummy_reporter_destroy:
0269     devlink_health_reporter_destroy(health->dummy_reporter);
0270 err_empty_reporter_destroy:
0271     devlink_health_reporter_destroy(health->empty_reporter);
0272     return err;
0273 }
0274 
0275 void nsim_dev_health_exit(struct nsim_dev *nsim_dev)
0276 {
0277     struct nsim_dev_health *health = &nsim_dev->health;
0278 
0279     debugfs_remove_recursive(health->ddir);
0280     kfree(health->recovered_break_msg);
0281     devlink_health_reporter_destroy(health->dummy_reporter);
0282     devlink_health_reporter_destroy(health->empty_reporter);
0283 }