aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-06-20 07:40:46 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-06-22 16:09:45 -0400
commit670dc2833d144375eac36ad74111495a825a9288 (patch)
tree12d5d3a925da562a6ba0497c47f4b55c71ff545b
parentc1c3daee97498f5d74bfd23531cfe23c8e14a619 (diff)
netlink: advertise incomplete dumps
Consider the following situation: * a dump that would show 8 entries, four in the first round, and four in the second * between the first and second rounds, 6 entries are removed * now the second round will not show any entry, and even if there is a sequence/generation counter the application will not know To solve this problem, add a new flag NLM_F_DUMP_INTR to the netlink header that indicates the dump wasn't consistent, this flag can also be set on the MSG_DONE message that terminates the dump, and as such above situation can be detected. To achieve this, add a sequence counter to the netlink callback struct. Of course, netlink code still needs to use this new functionality. The correct way to do that is to always set cb->seq when a dumpit callback is invoked and call nl_dump_check_consistent() for each new message. The core code will also call this function for the final MSG_DONE message. To make it usable with generic netlink, a new function genlmsg_nlhdr() is needed to obtain the netlink header from the genetlink user header. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Acked-by: David S. Miller <davem@davemloft.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--include/linux/netlink.h2
-rw-r--r--include/net/genetlink.h32
-rw-r--r--include/net/netlink.h24
-rw-r--r--net/netlink/af_netlink.c2
4 files changed, 60 insertions, 0 deletions
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index 4c4ac3f3ce5a..8d1bcec5cc06 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -48,6 +48,7 @@ struct nlmsghdr {
48#define NLM_F_MULTI 2 /* Multipart message, terminated by NLMSG_DONE */ 48#define NLM_F_MULTI 2 /* Multipart message, terminated by NLMSG_DONE */
49#define NLM_F_ACK 4 /* Reply with ack, with zero or error code */ 49#define NLM_F_ACK 4 /* Reply with ack, with zero or error code */
50#define NLM_F_ECHO 8 /* Echo this request */ 50#define NLM_F_ECHO 8 /* Echo this request */
51#define NLM_F_DUMP_INTR 16 /* Dump was inconsistent due to sequence change */
51 52
52/* Modifiers to GET request */ 53/* Modifiers to GET request */
53#define NLM_F_ROOT 0x100 /* specify tree root */ 54#define NLM_F_ROOT 0x100 /* specify tree root */
@@ -221,6 +222,7 @@ struct netlink_callback {
221 struct netlink_callback *cb); 222 struct netlink_callback *cb);
222 int (*done)(struct netlink_callback *cb); 223 int (*done)(struct netlink_callback *cb);
223 int family; 224 int family;
225 unsigned int prev_seq, seq;
224 long args[6]; 226 long args[6];
225}; 227};
226 228
diff --git a/include/net/genetlink.h b/include/net/genetlink.h
index d420f28b6d60..82d8d09faa44 100644
--- a/include/net/genetlink.h
+++ b/include/net/genetlink.h
@@ -160,6 +160,38 @@ static inline void *genlmsg_put(struct sk_buff *skb, u32 pid, u32 seq,
160} 160}
161 161
162/** 162/**
163 * genlmsg_nlhdr - Obtain netlink header from user specified header
164 * @user_hdr: user header as returned from genlmsg_put()
165 * @family: generic netlink family
166 *
167 * Returns pointer to netlink header.
168 */
169static inline struct nlmsghdr *genlmsg_nlhdr(void *user_hdr,
170 struct genl_family *family)
171{
172 return (struct nlmsghdr *)((char *)user_hdr -
173 family->hdrsize -
174 GENL_HDRLEN -
175 NLMSG_HDRLEN);
176}
177
178/**
179 * genl_dump_check_consistent - check if sequence is consistent and advertise if not
180 * @cb: netlink callback structure that stores the sequence number
181 * @user_hdr: user header as returned from genlmsg_put()
182 * @family: generic netlink family
183 *
184 * Cf. nl_dump_check_consistent(), this just provides a wrapper to make it
185 * simpler to use with generic netlink.
186 */
187static inline void genl_dump_check_consistent(struct netlink_callback *cb,
188 void *user_hdr,
189 struct genl_family *family)
190{
191 nl_dump_check_consistent(cb, genlmsg_nlhdr(user_hdr, family));
192}
193
194/**
163 * genlmsg_put_reply - Add generic netlink header to a reply message 195 * genlmsg_put_reply - Add generic netlink header to a reply message
164 * @skb: socket buffer holding the message 196 * @skb: socket buffer holding the message
165 * @info: receiver info 197 * @info: receiver info
diff --git a/include/net/netlink.h b/include/net/netlink.h
index 02740a94f108..98c185441bee 100644
--- a/include/net/netlink.h
+++ b/include/net/netlink.h
@@ -638,6 +638,30 @@ static inline int nlmsg_unicast(struct sock *sk, struct sk_buff *skb, u32 pid)
638 nlmsg_ok(pos, rem); \ 638 nlmsg_ok(pos, rem); \
639 pos = nlmsg_next(pos, &(rem))) 639 pos = nlmsg_next(pos, &(rem)))
640 640
641/**
642 * nl_dump_check_consistent - check if sequence is consistent and advertise if not
643 * @cb: netlink callback structure that stores the sequence number
644 * @nlh: netlink message header to write the flag to
645 *
646 * This function checks if the sequence (generation) number changed during dump
647 * and if it did, advertises it in the netlink message header.
648 *
649 * The correct way to use it is to set cb->seq to the generation counter when
650 * all locks for dumping have been acquired, and then call this function for
651 * each message that is generated.
652 *
653 * Note that due to initialisation concerns, 0 is an invalid sequence number
654 * and must not be used by code that uses this functionality.
655 */
656static inline void
657nl_dump_check_consistent(struct netlink_callback *cb,
658 struct nlmsghdr *nlh)
659{
660 if (cb->prev_seq && cb->seq != cb->prev_seq)
661 nlh->nlmsg_flags |= NLM_F_DUMP_INTR;
662 cb->prev_seq = cb->seq;
663}
664
641/************************************************************************** 665/**************************************************************************
642 * Netlink Attributes 666 * Netlink Attributes
643 **************************************************************************/ 667 **************************************************************************/
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 6ef64adf7362..a7ec8512f552 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1693,6 +1693,8 @@ static int netlink_dump(struct sock *sk)
1693 if (!nlh) 1693 if (!nlh)
1694 goto errout_skb; 1694 goto errout_skb;
1695 1695
1696 nl_dump_check_consistent(cb, nlh);
1697
1696 memcpy(nlmsg_data(nlh), &len, sizeof(len)); 1698 memcpy(nlmsg_data(nlh), &len, sizeof(len));
1697 1699
1698 if (sk_filter(sk, skb)) 1700 if (sk_filter(sk, skb))