| @@ -3597,6 +3597,507 @@ out: · 3596 unmodified lines |
| 3597 | return 0; | 3597 | return 0; |
| 3598 | } | 3598 | } |
| 3599 | | 3599 | |
| | 3600 | #define DEVLINK_HEALTH_BUFFER_SIZE (4096 - GENL_HDRLEN) |
| | 3601 | #define DEVLINK_HEALTH_BUFFER_DATA_SIZE (DEVLINK_HEALTH_BUFFER_SIZE / 2) |
| | 3602 | #define DEVLINK_HEALTH_SIZE_TO_BUFFERS(size) DIV_ROUND_UP(size, DEVLINK_HEALTH_BUFFER_DATA_SIZE) |
| | 3603 | #define DEVLINK_HEALTH_BUFFER_MAX_CHUNK 1024 |
| | 3604 | |
| | 3605 | struct devlink_health_buffer { |
| | 3606 | void *data; |
| | 3607 | u64 offset; |
| | 3608 | u64 bytes_left; |
| | 3609 | u64 bytes_left_metadata; |
| | 3610 | u64 max_nested_depth; |
| | 3611 | u64 curr_nest; |
| | 3612 | }; |
| | 3613 | |
| | 3614 | struct devlink_health_buffer_desc { |
| | 3615 | int attrtype; |
| | 3616 | u16 len; |
| | 3617 | u8 nla_type; |
| | 3618 | u8 nest_end; |
| | 3619 | int value[0]; |
| | 3620 | }; |
| | 3621 | |
| | 3622 | static void |
| | 3623 | devlink_health_buffers_reset(struct devlink_health_buffer **buffers_list, |
| | 3624 | u64 num_of_buffers) |
| | 3625 | { |
| | 3626 | u64 i; |
| | 3627 | |
| | 3628 | for (i = 0; i < num_of_buffers; i++) { |
| | 3629 | memset(buffers_list[i]->data, 0, DEVLINK_HEALTH_BUFFER_SIZE); |
| | 3630 | buffers_list[i]->offset = 0; |
| | 3631 | buffers_list[i]->bytes_left = DEVLINK_HEALTH_BUFFER_DATA_SIZE; |
| | 3632 | buffers_list[i]->bytes_left_metadata = |
| | 3633 | DEVLINK_HEALTH_BUFFER_DATA_SIZE; |
| | 3634 | buffers_list[i]->max_nested_depth = 0; |
| | 3635 | buffers_list[i]->curr_nest = 0; |
| | 3636 | } |
| | 3637 | } |
| | 3638 | |
| | 3639 | static void |
| | 3640 | devlink_health_buffers_destroy(struct devlink_health_buffer **buffers_list, |
| | 3641 | u64 size); |
| | 3642 | |
| | 3643 | static struct devlink_health_buffer ** |
| | 3644 | devlink_health_buffers_create(u64 size) |
| | 3645 | { |
| | 3646 | struct devlink_health_buffer **buffers_list; |
| | 3647 | u64 num_of_buffers = DEVLINK_HEALTH_SIZE_TO_BUFFERS(size); |
| | 3648 | u64 i; |
| | 3649 | |
| | 3650 | buffers_list = kcalloc(num_of_buffers, |
| | 3651 | sizeof(struct devlink_health_buffer *), |
| | 3652 | GFP_KERNEL); |
| | 3653 | if (!buffers_list) |
| | 3654 | return NULL; |
| | 3655 | |
| | 3656 | for (i = 0; i < num_of_buffers; i++) { |
| | 3657 | struct devlink_health_buffer *buffer; |
| | 3658 | void *data; |
| | 3659 | |
| | 3660 | buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); |
| | 3661 | data = kzalloc(DEVLINK_HEALTH_BUFFER_SIZE, GFP_KERNEL); |
| | 3662 | if (!buffer || !data) { |
| | 3663 | kfree(buffer); |
| | 3664 | kfree(data); |
| | 3665 | goto buffers_cleanup; |
| | 3666 | } |
| | 3667 | buffers_list[i] = buffer; |
| | 3668 | buffer->data = data; |
| | 3669 | } |
| | 3670 | devlink_health_buffers_reset(buffers_list, num_of_buffers); |
| | 3671 | |
| | 3672 | return buffers_list; |
| | 3673 | |
| | 3674 | buffers_cleanup: |
| | 3675 | devlink_health_buffers_destroy(buffers_list, --i); |
| | 3676 | kfree(buffers_list); |
| | 3677 | return NULL; |
| | 3678 | } |
| | 3679 | |
| | 3680 | static void |
| | 3681 | devlink_health_buffers_destroy(struct devlink_health_buffer **buffers_list, |
| | 3682 | u64 num_of_buffers) |
| | 3683 | { |
| | 3684 | u64 i; |
| | 3685 | |
| | 3686 | for (i = 0; i < num_of_buffers; i++) { |
| | 3687 | kfree(buffers_list[i]->data); |
| | 3688 | kfree(buffers_list[i]); |
| | 3689 | } |
| | 3690 | } |
| | 3691 | |
| | 3692 | void |
| | 3693 | devlink_health_buffer_offset_inc(struct devlink_health_buffer *buffer, |
| | 3694 | int len) |
| | 3695 | { |
| | 3696 | buffer->offset += len; |
| | 3697 | } |
| | 3698 | |
| | 3699 | /* In order to store a nest, need two descriptors, for start and end */ |
| | 3700 | #define DEVLINK_HEALTH_BUFFER_NEST_SIZE (sizeof(struct devlink_health_buffer_desc) * 2) |
| | 3701 | |
| | 3702 | int devlink_health_buffer_verify_len(struct devlink_health_buffer *buffer, |
| | 3703 | int len, int metadata_len) |
| | 3704 | { |
| | 3705 | if (len > DEVLINK_HEALTH_BUFFER_DATA_SIZE) |
| | 3706 | return -EINVAL; |
| | 3707 | |
| | 3708 | if (buffer->bytes_left < len || |
| | 3709 | buffer->bytes_left_metadata < metadata_len) |
| | 3710 | return -ENOMEM; |
| | 3711 | |
| | 3712 | return 0; |
| | 3713 | } |
| | 3714 | |
| | 3715 | static struct devlink_health_buffer_desc * |
| | 3716 | devlink_health_buffer_get_desc_from_offset(struct devlink_health_buffer *buffer) |
| | 3717 | { |
| | 3718 | return buffer->data + buffer->offset; |
| | 3719 | } |
| | 3720 | |
| | 3721 | int |
| | 3722 | devlink_health_buffer_nest_start(struct devlink_health_buffer *buffer, |
| | 3723 | int attrtype) |
| | 3724 | { |
| | 3725 | struct devlink_health_buffer_desc *desc; |
| | 3726 | int err; |
| | 3727 | |
| | 3728 | err = devlink_health_buffer_verify_len(buffer, 0, |
| | 3729 | DEVLINK_HEALTH_BUFFER_NEST_SIZE); |
| | 3730 | if (err) |
| | 3731 | return err; |
| | 3732 | |
| | 3733 | if (attrtype != DEVLINK_ATTR_HEALTH_BUFFER_OBJECT && |
| | 3734 | attrtype != DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_PAIR && |
| | 3735 | attrtype != DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_VALUE && |
| | 3736 | attrtype != DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_VALUE_ARRAY) |
| | 3737 | return -EINVAL; |
| | 3738 | |
| | 3739 | desc = devlink_health_buffer_get_desc_from_offset(buffer); |
| | 3740 | |
| | 3741 | desc->attrtype = attrtype; |
| | 3742 | buffer->bytes_left_metadata -= DEVLINK_HEALTH_BUFFER_NEST_SIZE; |
| | 3743 | devlink_health_buffer_offset_inc(buffer, sizeof(*desc)); |
| | 3744 | |
| | 3745 | buffer->curr_nest++; |
| | 3746 | buffer->max_nested_depth = max(buffer->max_nested_depth, |
| | 3747 | buffer->curr_nest); |
| | 3748 | |
| | 3749 | return 0; |
| | 3750 | } |
| | 3751 | EXPORT_SYMBOL_GPL(devlink_health_buffer_nest_start); |
| | 3752 | |
| | 3753 | enum devlink_health_buffer_nest_end_cancel { |
| | 3754 | DEVLINK_HEALTH_BUFFER_NEST_END = 1, |
| | 3755 | DEVLINK_HEALTH_BUFFER_NEST_CANCEL, |
| | 3756 | }; |
| | 3757 | |
| | 3758 | static void |
| | 3759 | devlink_health_buffer_nest_end_cancel(struct devlink_health_buffer *buffer, |
| | 3760 | enum devlink_health_buffer_nest_end_cancel nest) |
| | 3761 | { |
| | 3762 | struct devlink_health_buffer_desc *desc; |
| | 3763 | |
| | 3764 | WARN_ON(!buffer->curr_nest); |
| | 3765 | buffer->curr_nest--; |
| | 3766 | |
| | 3767 | desc = devlink_health_buffer_get_desc_from_offset(buffer); |
| | 3768 | desc->nest_end = nest; |
| | 3769 | devlink_health_buffer_offset_inc(buffer, sizeof(*desc)); |
| | 3770 | } |
| | 3771 | |
| | 3772 | void devlink_health_buffer_nest_end(struct devlink_health_buffer *buffer) |
| | 3773 | { |
| | 3774 | devlink_health_buffer_nest_end_cancel(buffer, |
| | 3775 | DEVLINK_HEALTH_BUFFER_NEST_END); |
| | 3776 | } |
| | 3777 | EXPORT_SYMBOL_GPL(devlink_health_buffer_nest_end); |
| | 3778 | |
| | 3779 | void devlink_health_buffer_nest_cancel(struct devlink_health_buffer *buffer) |
| | 3780 | { |
| | 3781 | devlink_health_buffer_nest_end_cancel(buffer, |
| | 3782 | DEVLINK_HEALTH_BUFFER_NEST_CANCEL); |
| | 3783 | } |
| | 3784 | EXPORT_SYMBOL_GPL(devlink_health_buffer_nest_cancel); |
| | 3785 | |
| | 3786 | int |
| | 3787 | devlink_health_buffer_put_object_name(struct devlink_health_buffer *buffer, |
| | 3788 | char *name) |
| | 3789 | { |
| | 3790 | struct devlink_health_buffer_desc *desc; |
| | 3791 | int err; |
| | 3792 | |
| | 3793 | err = devlink_health_buffer_verify_len(buffer, strlen(name) + 1, |
| | 3794 | sizeof(*desc)); |
| | 3795 | if (err) |
| | 3796 | return err; |
| | 3797 | |
| | 3798 | desc = devlink_health_buffer_get_desc_from_offset(buffer); |
| | 3799 | desc->attrtype = DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_NAME; |
| | 3800 | desc->nla_type = NLA_NUL_STRING; |
| | 3801 | desc->len = strlen(name) + 1; |
| | 3802 | memcpy(&desc->value, name, desc->len); |
| | 3803 | devlink_health_buffer_offset_inc(buffer, sizeof(*desc) + desc->len); |
| | 3804 | |
| | 3805 | buffer->bytes_left_metadata -= sizeof(*desc); |
| | 3806 | buffer->bytes_left -= (strlen(name) + 1); |
| | 3807 | |
| | 3808 | return 0; |
| | 3809 | } |
| | 3810 | EXPORT_SYMBOL_GPL(devlink_health_buffer_put_object_name); |
| | 3811 | |
| | 3812 | static int |
| | 3813 | devlink_health_buffer_put_value(struct devlink_health_buffer *buffer, |
| | 3814 | u8 nla_type, void *value, int len) |
| | 3815 | { |
| | 3816 | struct devlink_health_buffer_desc *desc; |
| | 3817 | int err; |
| | 3818 | |
| | 3819 | err = devlink_health_buffer_verify_len(buffer, len, sizeof(*desc)); |
| | 3820 | if (err) |
| | 3821 | return err; |
| | 3822 | |
| | 3823 | desc = devlink_health_buffer_get_desc_from_offset(buffer); |
| | 3824 | desc->attrtype = DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_VALUE_DATA; |
| | 3825 | desc->nla_type = nla_type; |
| | 3826 | desc->len = len; |
| | 3827 | memcpy(&desc->value, value, len); |
| | 3828 | devlink_health_buffer_offset_inc(buffer, sizeof(*desc) + desc->len); |
| | 3829 | |
| | 3830 | buffer->bytes_left_metadata -= sizeof(*desc); |
| | 3831 | buffer->bytes_left -= len; |
| | 3832 | |
| | 3833 | return 0; |
| | 3834 | } |
| | 3835 | |
| | 3836 | int |
| | 3837 | devlink_health_buffer_put_value_u8(struct devlink_health_buffer *buffer, |
| | 3838 | u8 value) |
| | 3839 | { |
| | 3840 | int err; |
| | 3841 | |
| | 3842 | err = devlink_health_buffer_put_value(buffer, NLA_U8, &value, |
| | 3843 | sizeof(value)); |
| | 3844 | if (err) |
| | 3845 | return err; |
| | 3846 | |
| | 3847 | return 0; |
| | 3848 | } |
| | 3849 | EXPORT_SYMBOL_GPL(devlink_health_buffer_put_value_u8); |
| | 3850 | |
| | 3851 | int |
| | 3852 | devlink_health_buffer_put_value_u32(struct devlink_health_buffer *buffer, |
| | 3853 | u32 value) |
| | 3854 | { |
| | 3855 | int err; |
| | 3856 | |
| | 3857 | err = devlink_health_buffer_put_value(buffer, NLA_U32, &value, |
| | 3858 | sizeof(value)); |
| | 3859 | if (err) |
| | 3860 | return err; |
| | 3861 | |
| | 3862 | return 0; |
| | 3863 | } |
| | 3864 | EXPORT_SYMBOL_GPL(devlink_health_buffer_put_value_u32); |
| | 3865 | |
| | 3866 | int |
| | 3867 | devlink_health_buffer_put_value_u64(struct devlink_health_buffer *buffer, |
| | 3868 | u64 value) |
| | 3869 | { |
| | 3870 | int err; |
| | 3871 | |
| | 3872 | err = devlink_health_buffer_put_value(buffer, NLA_U64, &value, |
| | 3873 | sizeof(value)); |
| | 3874 | if (err) |
| | 3875 | return err; |
| | 3876 | |
| | 3877 | return 0; |
| | 3878 | } |
| | 3879 | EXPORT_SYMBOL_GPL(devlink_health_buffer_put_value_u64); |
| | 3880 | |
| | 3881 | int |
| | 3882 | devlink_health_buffer_put_value_string(struct devlink_health_buffer *buffer, |
| | 3883 | char *name) |
| | 3884 | { |
| | 3885 | int err; |
| | 3886 | |
| | 3887 | if (strlen(name) + 1 > DEVLINK_HEALTH_BUFFER_MAX_CHUNK) |
| | 3888 | return -EINVAL; |
| | 3889 | |
| | 3890 | err = devlink_health_buffer_put_value(buffer, NLA_NUL_STRING, name, |
| | 3891 | strlen(name) + 1); |
| | 3892 | if (err) |
| | 3893 | return err; |
| | 3894 | |
| | 3895 | return 0; |
| | 3896 | } |
| | 3897 | EXPORT_SYMBOL_GPL(devlink_health_buffer_put_value_string); |
| | 3898 | |
| | 3899 | int |
| | 3900 | devlink_health_buffer_put_value_data(struct devlink_health_buffer *buffer, |
| | 3901 | void *data, int len) |
| | 3902 | { |
| | 3903 | int err; |
| | 3904 | |
| | 3905 | if (len > DEVLINK_HEALTH_BUFFER_MAX_CHUNK) |
| | 3906 | return -EINVAL; |
| | 3907 | |
| | 3908 | err = devlink_health_buffer_put_value(buffer, NLA_BINARY, data, len); |
| | 3909 | if (err) |
| | 3910 | return err; |
| | 3911 | |
| | 3912 | return 0; |
| | 3913 | } |
| | 3914 | EXPORT_SYMBOL_GPL(devlink_health_buffer_put_value_data); |
| | 3915 | |
| | 3916 | static int |
| | 3917 | devlink_health_buffer_fill_data(struct sk_buff *skb, |
| | 3918 | struct devlink_health_buffer_desc *desc) |
| | 3919 | { |
| | 3920 | int err = -EINVAL; |
| | 3921 | |
| | 3922 | switch (desc->nla_type) { |
| | 3923 | case NLA_U8: |
| | 3924 | err = nla_put_u8(skb, DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_VALUE_DATA, |
| | 3925 | *(u8 *)desc->value); |
| | 3926 | break; |
| | 3927 | case NLA_U32: |
| | 3928 | err = nla_put_u32(skb, DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_VALUE_DATA, |
| | 3929 | *(u32 *)desc->value); |
| | 3930 | break; |
| | 3931 | case NLA_U64: |
| | 3932 | err = nla_put_u64_64bit(skb, |
| | 3933 | DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_VALUE_DATA, |
| | 3934 | *(u64 *)desc->value, DEVLINK_ATTR_PAD); |
| | 3935 | break; |
| | 3936 | case NLA_NUL_STRING: |
| | 3937 | err = nla_put_string(skb, |
| | 3938 | DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_VALUE_DATA, |
| | 3939 | (char *)&desc->value); |
| | 3940 | break; |
| | 3941 | case NLA_BINARY: |
| | 3942 | err = nla_put(skb, DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_VALUE_DATA, |
| | 3943 | desc->len, (void *)&desc->value); |
| | 3944 | break; |
| | 3945 | } |
| | 3946 | |
| | 3947 | return err; |
| | 3948 | } |
| | 3949 | |
| | 3950 | static int |
| | 3951 | devlink_health_buffer_fill_type(struct sk_buff *skb, |
| | 3952 | struct devlink_health_buffer_desc *desc) |
| | 3953 | { |
| | 3954 | int err = -EINVAL; |
| | 3955 | |
| | 3956 | switch (desc->nla_type) { |
| | 3957 | case NLA_U8: |
| | 3958 | err = nla_put_u8(skb, DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_VALUE_TYPE, |
| | 3959 | NLA_U8); |
| | 3960 | break; |
| | 3961 | case NLA_U32: |
| | 3962 | err = nla_put_u8(skb, DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_VALUE_TYPE, |
| | 3963 | NLA_U32); |
| | 3964 | break; |
| | 3965 | case NLA_U64: |
| | 3966 | err = nla_put_u8(skb, DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_VALUE_TYPE, |
| | 3967 | NLA_U64); |
| | 3968 | break; |
| | 3969 | case NLA_NUL_STRING: |
| | 3970 | err = nla_put_u8(skb, DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_VALUE_TYPE, |
| | 3971 | NLA_NUL_STRING); |
| | 3972 | break; |
| | 3973 | case NLA_BINARY: |
| | 3974 | err = nla_put_u8(skb, DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_VALUE_TYPE, |
| | 3975 | NLA_BINARY); |
| | 3976 | break; |
| | 3977 | } |
| | 3978 | |
| | 3979 | return err; |
| | 3980 | } |
| | 3981 | |
| | 3982 | static inline struct devlink_health_buffer_desc * |
| | 3983 | devlink_health_buffer_get_next_desc(struct devlink_health_buffer_desc *desc) |
| | 3984 | { |
| | 3985 | return (void *)&desc->value + desc->len; |
| | 3986 | } |
| | 3987 | |
| | 3988 | static int |
| | 3989 | devlink_health_buffer_prepare_skb(struct sk_buff *skb, |
| | 3990 | struct devlink_health_buffer *buffer) |
| | 3991 | { |
| | 3992 | struct devlink_health_buffer_desc *last_desc, *desc; |
| | 3993 | struct nlattr **buffer_nlattr; |
| | 3994 | int err; |
| | 3995 | int i = 0; |
| | 3996 | |
| | 3997 | buffer_nlattr = kcalloc(buffer->max_nested_depth, |
| | 3998 | sizeof(*buffer_nlattr), GFP_KERNEL); |
| | 3999 | if (!buffer_nlattr) |
| | 4000 | return -EINVAL; |
| | 4001 | |
| | 4002 | last_desc = devlink_health_buffer_get_desc_from_offset(buffer); |
| | 4003 | desc = buffer->data; |
| | 4004 | while (desc != last_desc) { |
| | 4005 | switch (desc->attrtype) { |
| | 4006 | case DEVLINK_ATTR_HEALTH_BUFFER_OBJECT: |
| | 4007 | case DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_PAIR: |
| | 4008 | case DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_VALUE: |
| | 4009 | case DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_VALUE_ARRAY: |
| | 4010 | buffer_nlattr[i] = nla_nest_start(skb, desc->attrtype); |
| | 4011 | if (!buffer_nlattr[i]) |
| | 4012 | goto nla_put_failure; |
| | 4013 | i++; |
| | 4014 | break; |
| | 4015 | case DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_VALUE_DATA: |
| | 4016 | err = devlink_health_buffer_fill_data(skb, desc); |
| | 4017 | if (err) |
| | 4018 | goto nla_put_failure; |
| | 4019 | err = devlink_health_buffer_fill_type(skb, desc); |
| | 4020 | if (err) |
| | 4021 | goto nla_put_failure; |
| | 4022 | break; |
| | 4023 | case DEVLINK_ATTR_HEALTH_BUFFER_OBJECT_NAME: |
| | 4024 | err = nla_put_string(skb, desc->attrtype, |
| | 4025 | (char *)&desc->value); |
| | 4026 | if (err) |
| | 4027 | goto nla_put_failure; |
| | 4028 | break; |
| | 4029 | default: |
| | 4030 | WARN_ON(!desc->nest_end); |
| | 4031 | WARN_ON(i <= 0); |
| | 4032 | if (desc->nest_end == DEVLINK_HEALTH_BUFFER_NEST_END) |
| | 4033 | nla_nest_end(skb, buffer_nlattr[--i]); |
| | 4034 | else |
| | 4035 | nla_nest_cancel(skb, buffer_nlattr[--i]); |
| | 4036 | break; |
| | 4037 | } |
| | 4038 | desc = devlink_health_buffer_get_next_desc(desc); |
| | 4039 | } |
| | 4040 | |
| | 4041 | return 0; |
| | 4042 | |
| | 4043 | nla_put_failure: |
| | 4044 | kfree(buffer_nlattr); |
| | 4045 | return err; |
| | 4046 | } |
| | 4047 | |
| | 4048 | static int |
| | 4049 | devlink_health_buffer_snd(struct genl_info *info, |
| | 4050 | enum devlink_command cmd, int flags, |
| | 4051 | struct devlink_health_buffer **buffers_array, |
| | 4052 | u64 num_of_buffers) |
| | 4053 | { |
| | 4054 | struct sk_buff *skb; |
| | 4055 | struct nlmsghdr *nlh; |
| | 4056 | void *hdr; |
| | 4057 | int err; |
| | 4058 | u64 i; |
| | 4059 | |
| | 4060 | for (i = 0; i < num_of_buffers; i++) { |
| | 4061 | /* Skip buffer if driver did not fill it up with any data */ |
| | 4062 | if (!buffers_array[i]->offset) |
| | 4063 | continue; |
| | 4064 | |
| | 4065 | skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); |
| | 4066 | if (!skb) |
| | 4067 | return -ENOMEM; |
| | 4068 | |
| | 4069 | hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq, |
| | 4070 | &devlink_nl_family, NLM_F_MULTI, cmd); |
| | 4071 | if (!hdr) |
| | 4072 | goto nla_put_failure; |
| | 4073 | |
| | 4074 | err = devlink_health_buffer_prepare_skb(skb, buffers_array[i]); |
| | 4075 | if (err) |
| | 4076 | goto nla_put_failure; |
| | 4077 | |
| | 4078 | genlmsg_end(skb, hdr); |
| | 4079 | err = genlmsg_reply(skb, info); |
| | 4080 | if (err) |
| | 4081 | return err; |
| | 4082 | } |
| | 4083 | |
| | 4084 | skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL); |
| | 4085 | if (!skb) |
| | 4086 | return -ENOMEM; |
| | 4087 | nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq, |
| | 4088 | NLMSG_DONE, 0, flags | NLM_F_MULTI); |
| | 4089 | err = genlmsg_reply(skb, info); |
| | 4090 | if (err) |
| | 4091 | return err; |
| | 4092 | |
| | 4093 | return 0; |
| | 4094 | |
| | 4095 | nla_put_failure: |
| | 4096 | err = -EIO; |
| | 4097 | nlmsg_free(skb); |
| | 4098 | return err; |
| | 4099 | } |
| | 4100 | |
| 3600 | static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = { | 4101 | static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = { |
| 3601 | [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING }, | 4102 | [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING }, |
| 3602 | [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING }, | 4103 | [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING }, |