diff options
-rw-r--r-- | fs/quota/netlink.c | 17 | ||||
-rw-r--r-- | include/uapi/linux/genetlink.h | 1 | ||||
-rw-r--r-- | net/netlink/genetlink.c | 10 |
3 files changed, 24 insertions, 4 deletions
diff --git a/fs/quota/netlink.c b/fs/quota/netlink.c index 16e8abb7709b..aa22fe03b76c 100644 --- a/fs/quota/netlink.c +++ b/fs/quota/netlink.c | |||
@@ -11,13 +11,23 @@ | |||
11 | 11 | ||
12 | /* Netlink family structure for quota */ | 12 | /* Netlink family structure for quota */ |
13 | static struct genl_family quota_genl_family = { | 13 | static struct genl_family quota_genl_family = { |
14 | .id = GENL_ID_GENERATE, | 14 | /* |
15 | * Needed due to multicast group ID abuse - old code assumed | ||
16 | * the family ID was also a valid multicast group ID (which | ||
17 | * isn't true) and userspace might thus rely on it. Assign a | ||
18 | * static ID for this group to make dealing with that easier. | ||
19 | */ | ||
20 | .id = GENL_ID_VFS_DQUOT, | ||
15 | .hdrsize = 0, | 21 | .hdrsize = 0, |
16 | .name = "VFS_DQUOT", | 22 | .name = "VFS_DQUOT", |
17 | .version = 1, | 23 | .version = 1, |
18 | .maxattr = QUOTA_NL_A_MAX, | 24 | .maxattr = QUOTA_NL_A_MAX, |
19 | }; | 25 | }; |
20 | 26 | ||
27 | static struct genl_multicast_group quota_mcgrp = { | ||
28 | .name = "events", | ||
29 | }; | ||
30 | |||
21 | /** | 31 | /** |
22 | * quota_send_warning - Send warning to userspace about exceeded quota | 32 | * quota_send_warning - Send warning to userspace about exceeded quota |
23 | * @type: The quota type: USRQQUOTA, GRPQUOTA,... | 33 | * @type: The quota type: USRQQUOTA, GRPQUOTA,... |
@@ -78,7 +88,7 @@ void quota_send_warning(struct kqid qid, dev_t dev, | |||
78 | goto attr_err_out; | 88 | goto attr_err_out; |
79 | genlmsg_end(skb, msg_head); | 89 | genlmsg_end(skb, msg_head); |
80 | 90 | ||
81 | genlmsg_multicast(skb, 0, quota_genl_family.id, GFP_NOFS); | 91 | genlmsg_multicast(skb, 0, quota_mcgrp.id, GFP_NOFS); |
82 | return; | 92 | return; |
83 | attr_err_out: | 93 | attr_err_out: |
84 | printk(KERN_ERR "VFS: Not enough space to compose quota message!\n"); | 94 | printk(KERN_ERR "VFS: Not enough space to compose quota message!\n"); |
@@ -92,6 +102,9 @@ static int __init quota_init(void) | |||
92 | if (genl_register_family("a_genl_family) != 0) | 102 | if (genl_register_family("a_genl_family) != 0) |
93 | printk(KERN_ERR | 103 | printk(KERN_ERR |
94 | "VFS: Failed to create quota netlink interface.\n"); | 104 | "VFS: Failed to create quota netlink interface.\n"); |
105 | if (genl_register_mc_group("a_genl_family, "a_mcgrp)) | ||
106 | printk(KERN_ERR | ||
107 | "VFS: Failed to register quota mcast group.\n"); | ||
95 | return 0; | 108 | return 0; |
96 | }; | 109 | }; |
97 | 110 | ||
diff --git a/include/uapi/linux/genetlink.h b/include/uapi/linux/genetlink.h index c880a417d8a9..1af72d8228e0 100644 --- a/include/uapi/linux/genetlink.h +++ b/include/uapi/linux/genetlink.h | |||
@@ -27,6 +27,7 @@ struct genlmsghdr { | |||
27 | */ | 27 | */ |
28 | #define GENL_ID_GENERATE 0 | 28 | #define GENL_ID_GENERATE 0 |
29 | #define GENL_ID_CTRL NLMSG_MIN_TYPE | 29 | #define GENL_ID_CTRL NLMSG_MIN_TYPE |
30 | #define GENL_ID_VFS_DQUOT (NLMSG_MIN_TYPE + 1) | ||
30 | 31 | ||
31 | /************************************************************************** | 32 | /************************************************************************** |
32 | * Controller | 33 | * Controller |
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 353909d46dda..bee91a7527a5 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c | |||
@@ -69,8 +69,11 @@ static struct list_head family_ht[GENL_FAM_TAB_SIZE]; | |||
69 | * abuses the API and thinks it can statically use group 1. | 69 | * abuses the API and thinks it can statically use group 1. |
70 | * That group will typically conflict with other groups that | 70 | * That group will typically conflict with other groups that |
71 | * any proper users use. | 71 | * any proper users use. |
72 | * Bit 17 is marked as already used since the VFS quota code | ||
73 | * also abused this API and relied on family == group ID, we | ||
74 | * cater to that by giving it a static family and group ID. | ||
72 | */ | 75 | */ |
73 | static unsigned long mc_group_start = 0x3; | 76 | static unsigned long mc_group_start = 0x3 | BIT(GENL_ID_VFS_DQUOT); |
74 | static unsigned long *mc_groups = &mc_group_start; | 77 | static unsigned long *mc_groups = &mc_group_start; |
75 | static unsigned long mc_groups_longs = 1; | 78 | static unsigned long mc_groups_longs = 1; |
76 | 79 | ||
@@ -130,7 +133,8 @@ static u16 genl_generate_id(void) | |||
130 | int i; | 133 | int i; |
131 | 134 | ||
132 | for (i = 0; i <= GENL_MAX_ID - GENL_MIN_ID; i++) { | 135 | for (i = 0; i <= GENL_MAX_ID - GENL_MIN_ID; i++) { |
133 | if (!genl_family_find_byid(id_gen_idx)) | 136 | if (id_gen_idx != GENL_ID_VFS_DQUOT && |
137 | !genl_family_find_byid(id_gen_idx)) | ||
134 | return id_gen_idx; | 138 | return id_gen_idx; |
135 | if (++id_gen_idx > GENL_MAX_ID) | 139 | if (++id_gen_idx > GENL_MAX_ID) |
136 | id_gen_idx = GENL_MIN_ID; | 140 | id_gen_idx = GENL_MIN_ID; |
@@ -169,6 +173,8 @@ int genl_register_mc_group(struct genl_family *family, | |||
169 | id = GENL_ID_CTRL; | 173 | id = GENL_ID_CTRL; |
170 | else if (strcmp(family->name, "NET_DM") == 0) | 174 | else if (strcmp(family->name, "NET_DM") == 0) |
171 | id = 1; | 175 | id = 1; |
176 | else if (strcmp(family->name, "VFS_DQUOT") == 0) | ||
177 | id = GENL_ID_VFS_DQUOT; | ||
172 | else | 178 | else |
173 | id = find_first_zero_bit(mc_groups, | 179 | id = find_first_zero_bit(mc_groups, |
174 | mc_groups_longs * BITS_PER_LONG); | 180 | mc_groups_longs * BITS_PER_LONG); |