Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

genetlink: introduce per-sock family private storage

Introduce an xarray for Generic netlink family to store per-socket
private. Initialize this xarray only if family uses per-socket privs.

Introduce genl_sk_priv_get() to get the socket priv pointer for a family
and initialize it in case it does not exist.
Introduce __genl_sk_priv_get() to obtain socket priv pointer for a
family under RCU read lock.

Allow family to specify the priv size, init() and destroy() callbacks.

Signed-off-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Jiri Pirko and committed by
Paolo Abeni
a7311324 5648de0b

+154 -1
+11
include/net/genetlink.h
··· 51 51 * @split_ops: the split do/dump form of operation definition 52 52 * @n_split_ops: number of entries in @split_ops, not that with split do/dump 53 53 * ops the number of entries is not the same as number of commands 54 + * @sock_priv_size: the size of per-socket private memory 55 + * @sock_priv_init: the per-socket private memory initializer 56 + * @sock_priv_destroy: the per-socket private memory destructor 54 57 * 55 58 * Attribute policies (the combination of @policy and @maxattr fields) 56 59 * can be attached at the family level or at the operation level. ··· 87 84 const struct genl_multicast_group *mcgrps; 88 85 struct module *module; 89 86 87 + size_t sock_priv_size; 88 + void (*sock_priv_init)(void *priv); 89 + void (*sock_priv_destroy)(void *priv); 90 + 90 91 /* private: internal use only */ 91 92 /* protocol family identifier */ 92 93 int id; 93 94 /* starting number of multicast group IDs in this family */ 94 95 unsigned int mcgrp_offset; 96 + /* list of per-socket privs */ 97 + struct xarray *sock_privs; 95 98 }; 96 99 97 100 /** ··· 307 298 return !info->nlhdr; 308 299 } 309 300 301 + void *__genl_sk_priv_get(struct genl_family *family, struct sock *sk); 302 + void *genl_sk_priv_get(struct genl_family *family, struct sock *sk); 310 303 int genl_register_family(struct genl_family *family); 311 304 int genl_unregister_family(const struct genl_family *family); 312 305 void genl_notify(const struct genl_family *family, struct sk_buff *skb,
+143 -1
net/netlink/genetlink.c
··· 631 631 return 0; 632 632 } 633 633 634 + static void *genl_sk_priv_alloc(struct genl_family *family) 635 + { 636 + void *priv; 637 + 638 + priv = kzalloc(family->sock_priv_size, GFP_KERNEL); 639 + if (!priv) 640 + return ERR_PTR(-ENOMEM); 641 + 642 + if (family->sock_priv_init) 643 + family->sock_priv_init(priv); 644 + 645 + return priv; 646 + } 647 + 648 + static void genl_sk_priv_free(const struct genl_family *family, void *priv) 649 + { 650 + if (family->sock_priv_destroy) 651 + family->sock_priv_destroy(priv); 652 + kfree(priv); 653 + } 654 + 655 + static int genl_sk_privs_alloc(struct genl_family *family) 656 + { 657 + if (!family->sock_priv_size) 658 + return 0; 659 + 660 + family->sock_privs = kzalloc(sizeof(*family->sock_privs), GFP_KERNEL); 661 + if (!family->sock_privs) 662 + return -ENOMEM; 663 + xa_init(family->sock_privs); 664 + return 0; 665 + } 666 + 667 + static void genl_sk_privs_free(const struct genl_family *family) 668 + { 669 + unsigned long id; 670 + void *priv; 671 + 672 + if (!family->sock_priv_size) 673 + return; 674 + 675 + xa_for_each(family->sock_privs, id, priv) 676 + genl_sk_priv_free(family, priv); 677 + 678 + xa_destroy(family->sock_privs); 679 + kfree(family->sock_privs); 680 + } 681 + 682 + static void genl_sk_priv_free_by_sock(struct genl_family *family, 683 + struct sock *sk) 684 + { 685 + void *priv; 686 + 687 + if (!family->sock_priv_size) 688 + return; 689 + priv = xa_erase(family->sock_privs, (unsigned long) sk); 690 + if (!priv) 691 + return; 692 + genl_sk_priv_free(family, priv); 693 + } 694 + 695 + static void genl_release(struct sock *sk, unsigned long *groups) 696 + { 697 + struct genl_family *family; 698 + unsigned int id; 699 + 700 + down_read(&cb_lock); 701 + 702 + idr_for_each_entry(&genl_fam_idr, family, id) 703 + genl_sk_priv_free_by_sock(family, sk); 704 + 705 + up_read(&cb_lock); 706 + } 707 + 708 + /** 709 + * __genl_sk_priv_get - Get family private pointer for socket, if exists 710 + * 711 + * @family: family 712 + * @sk: socket 713 + * 714 + * Lookup a private memory for a Generic netlink family and specified socket. 715 + * 716 + * Caller should make sure this is called in RCU read locked section. 717 + * 718 + * Return: valid pointer on success, otherwise negative error value 719 + * encoded by ERR_PTR(), NULL in case priv does not exist. 720 + */ 721 + void *__genl_sk_priv_get(struct genl_family *family, struct sock *sk) 722 + { 723 + if (WARN_ON_ONCE(!family->sock_privs)) 724 + return ERR_PTR(-EINVAL); 725 + return xa_load(family->sock_privs, (unsigned long) sk); 726 + } 727 + 728 + /** 729 + * genl_sk_priv_get - Get family private pointer for socket 730 + * 731 + * @family: family 732 + * @sk: socket 733 + * 734 + * Lookup a private memory for a Generic netlink family and specified socket. 735 + * Allocate the private memory in case it was not already done. 736 + * 737 + * Return: valid pointer on success, otherwise negative error value 738 + * encoded by ERR_PTR(). 739 + */ 740 + void *genl_sk_priv_get(struct genl_family *family, struct sock *sk) 741 + { 742 + void *priv, *old_priv; 743 + 744 + priv = __genl_sk_priv_get(family, sk); 745 + if (priv) 746 + return priv; 747 + 748 + /* priv for the family does not exist so far, create it. */ 749 + 750 + priv = genl_sk_priv_alloc(family); 751 + if (IS_ERR(priv)) 752 + return ERR_CAST(priv); 753 + 754 + old_priv = xa_cmpxchg(family->sock_privs, (unsigned long) sk, NULL, 755 + priv, GFP_KERNEL); 756 + if (old_priv) { 757 + genl_sk_priv_free(family, priv); 758 + if (xa_is_err(old_priv)) 759 + return ERR_PTR(xa_err(old_priv)); 760 + /* Race happened, priv for the socket was already inserted. */ 761 + return old_priv; 762 + } 763 + return priv; 764 + } 765 + 634 766 /** 635 767 * genl_register_family - register a generic netlink family 636 768 * @family: generic netlink family ··· 791 659 goto errout_locked; 792 660 } 793 661 662 + err = genl_sk_privs_alloc(family); 663 + if (err) 664 + goto errout_locked; 665 + 794 666 /* 795 667 * Sadly, a few cases need to be special-cased 796 668 * due to them having previously abused the API ··· 815 679 start, end + 1, GFP_KERNEL); 816 680 if (family->id < 0) { 817 681 err = family->id; 818 - goto errout_locked; 682 + goto errout_sk_privs_free; 819 683 } 820 684 821 685 err = genl_validate_assign_mc_groups(family); ··· 834 698 835 699 errout_remove: 836 700 idr_remove(&genl_fam_idr, family->id); 701 + errout_sk_privs_free: 702 + genl_sk_privs_free(family); 837 703 errout_locked: 838 704 genl_unlock_all(); 839 705 return err; ··· 866 728 up_write(&cb_lock); 867 729 wait_event(genl_sk_destructing_waitq, 868 730 atomic_read(&genl_sk_destructing_cnt) == 0); 731 + 732 + genl_sk_privs_free(family); 733 + 869 734 genl_unlock(); 870 735 871 736 genl_ctrl_event(CTRL_CMD_DELFAMILY, family, NULL, 0); ··· 1849 1708 .input = genl_rcv, 1850 1709 .flags = NL_CFG_F_NONROOT_RECV, 1851 1710 .bind = genl_bind, 1711 + .release = genl_release, 1852 1712 }; 1853 1713 1854 1714 /* we'll bump the group number right afterwards */