diff options
author | David Fries <David@Fries.net> | 2014-04-08 23:37:09 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-05-27 16:56:21 -0400 |
commit | 8a0427d192e6043834414210dd14cc1289daff18 (patch) | |
tree | 1e76812e3744b6946a815fb94f877cc31d11b302 | |
parent | 34470e0bfae223e3f22bd2bd6e0e1dac366c9290 (diff) |
w1: optional bundling of netlink kernel replies
Applications can submit a set of commands in one packet to the kernel,
and in some cases it is required such as reading the temperature
sensor results. This adds an option W1_CN_BUNDLE to the flags of
cn_msg to request the kernel to reply in one packet for efficiency.
The cn_msg flags now check for unknown flag values and return an error
if one is seen. See "Proper handling of unknown flags in system
calls" http://lwn.net/Articles/588444/
This corrects the ack values returned as per the protocol standard,
namely the original ack for status messages and seq + 1 for all others
such as the data returned from a read.
Some of the common variable names have been standardized as follows.
struct cn_msg *cn
struct w1_netlink_msg *msg
struct w1_netlink_cmd *cmd
struct w1_master *dev
When an argument and a function scope variable would collide, add req_
to the argument.
Signed-off-by: David Fries <David@Fries.net>
Acked-by: Evgeniy Polyakov <zbr@ioremap.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | Documentation/connector/connector.txt | 2 | ||||
-rw-r--r-- | Documentation/w1/w1.generic | 2 | ||||
-rw-r--r-- | Documentation/w1/w1.netlink | 13 | ||||
-rw-r--r-- | drivers/w1/w1.h | 8 | ||||
-rw-r--r-- | drivers/w1/w1_netlink.c | 649 | ||||
-rw-r--r-- | drivers/w1/w1_netlink.h | 36 |
6 files changed, 447 insertions, 263 deletions
diff --git a/Documentation/connector/connector.txt b/Documentation/connector/connector.txt index e56abdb21975..f6215f95149b 100644 --- a/Documentation/connector/connector.txt +++ b/Documentation/connector/connector.txt | |||
@@ -118,7 +118,7 @@ acknowledge number MUST be the same + 1. | |||
118 | If we receive a message and its sequence number is not equal to one we | 118 | If we receive a message and its sequence number is not equal to one we |
119 | are expecting, then it is a new message. If we receive a message and | 119 | are expecting, then it is a new message. If we receive a message and |
120 | its sequence number is the same as one we are expecting, but its | 120 | its sequence number is the same as one we are expecting, but its |
121 | acknowledge is not equal to the acknowledge number in the original | 121 | acknowledge is not equal to the sequence number in the original |
122 | message + 1, then it is a new message. | 122 | message + 1, then it is a new message. |
123 | 123 | ||
124 | Obviously, the protocol header contains the above id. | 124 | Obviously, the protocol header contains the above id. |
diff --git a/Documentation/w1/w1.generic b/Documentation/w1/w1.generic index a31c5a242973..b2033c64c7da 100644 --- a/Documentation/w1/w1.generic +++ b/Documentation/w1/w1.generic | |||
@@ -82,7 +82,7 @@ driver - (standard) symlink to the w1 driver | |||
82 | w1_master_add - Manually register a slave device | 82 | w1_master_add - Manually register a slave device |
83 | w1_master_attempts - the number of times a search was attempted | 83 | w1_master_attempts - the number of times a search was attempted |
84 | w1_master_max_slave_count | 84 | w1_master_max_slave_count |
85 | - the maximum slaves that may be attached to a master | 85 | - maximum number of slaves to search for at a time |
86 | w1_master_name - the name of the device (w1_bus_masterX) | 86 | w1_master_name - the name of the device (w1_bus_masterX) |
87 | w1_master_pullup - 5V strong pullup 0 enabled, 1 disabled | 87 | w1_master_pullup - 5V strong pullup 0 enabled, 1 disabled |
88 | w1_master_remove - Manually remove a slave device | 88 | w1_master_remove - Manually remove a slave device |
diff --git a/Documentation/w1/w1.netlink b/Documentation/w1/w1.netlink index 927a52cc0519..ef2727192d69 100644 --- a/Documentation/w1/w1.netlink +++ b/Documentation/w1/w1.netlink | |||
@@ -30,7 +30,7 @@ Protocol. | |||
30 | W1_SLAVE_CMD | 30 | W1_SLAVE_CMD |
31 | userspace command for slave device | 31 | userspace command for slave device |
32 | (read/write/touch) | 32 | (read/write/touch) |
33 | __u8 res - reserved | 33 | __u8 status - error indication from kernel |
34 | __u16 len - size of data attached to this header data | 34 | __u16 len - size of data attached to this header data |
35 | union { | 35 | union { |
36 | __u8 id[8]; - slave unique device id | 36 | __u8 id[8]; - slave unique device id |
@@ -44,10 +44,14 @@ Protocol. | |||
44 | __u8 cmd - command opcode. | 44 | __u8 cmd - command opcode. |
45 | W1_CMD_READ - read command | 45 | W1_CMD_READ - read command |
46 | W1_CMD_WRITE - write command | 46 | W1_CMD_WRITE - write command |
47 | W1_CMD_TOUCH - touch command | ||
48 | (write and sample data back to userspace) | ||
49 | W1_CMD_SEARCH - search command | 47 | W1_CMD_SEARCH - search command |
50 | W1_CMD_ALARM_SEARCH - alarm search command | 48 | W1_CMD_ALARM_SEARCH - alarm search command |
49 | W1_CMD_TOUCH - touch command | ||
50 | (write and sample data back to userspace) | ||
51 | W1_CMD_RESET - send bus reset | ||
52 | W1_CMD_SLAVE_ADD - add slave to kernel list | ||
53 | W1_CMD_SLAVE_REMOVE - remove slave from kernel list | ||
54 | W1_CMD_LIST_SLAVES - get slaves list from kernel | ||
51 | __u8 res - reserved | 55 | __u8 res - reserved |
52 | __u16 len - length of data for this command | 56 | __u16 len - length of data for this command |
53 | For read command data must be allocated like for write command | 57 | For read command data must be allocated like for write command |
@@ -87,8 +91,7 @@ format: | |||
87 | id0 ... idN | 91 | id0 ... idN |
88 | 92 | ||
89 | Each message is at most 4k in size, so if number of master devices | 93 | Each message is at most 4k in size, so if number of master devices |
90 | exceeds this, it will be split into several messages, | 94 | exceeds this, it will be split into several messages. |
91 | cn.seq will be increased for each one. | ||
92 | 95 | ||
93 | W1 search and alarm search commands. | 96 | W1 search and alarm search commands. |
94 | request: | 97 | request: |
diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h index 734dab7fc687..56a49ba41d83 100644 --- a/drivers/w1/w1.h +++ b/drivers/w1/w1.h | |||
@@ -203,7 +203,6 @@ enum w1_master_flags { | |||
203 | * @search_id: allows continuing a search | 203 | * @search_id: allows continuing a search |
204 | * @refcnt: reference count | 204 | * @refcnt: reference count |
205 | * @priv: private data storage | 205 | * @priv: private data storage |
206 | * @priv_size: size allocated | ||
207 | * @enable_pullup: allows a strong pullup | 206 | * @enable_pullup: allows a strong pullup |
208 | * @pullup_duration: time for the next strong pullup | 207 | * @pullup_duration: time for the next strong pullup |
209 | * @flags: one of w1_master_flags | 208 | * @flags: one of w1_master_flags |
@@ -214,7 +213,6 @@ enum w1_master_flags { | |||
214 | * @dev: sysfs device | 213 | * @dev: sysfs device |
215 | * @bus_master: io operations available | 214 | * @bus_master: io operations available |
216 | * @seq: sequence number used for netlink broadcasts | 215 | * @seq: sequence number used for netlink broadcasts |
217 | * @portid: destination for the current netlink command | ||
218 | */ | 216 | */ |
219 | struct w1_master | 217 | struct w1_master |
220 | { | 218 | { |
@@ -241,7 +239,6 @@ struct w1_master | |||
241 | atomic_t refcnt; | 239 | atomic_t refcnt; |
242 | 240 | ||
243 | void *priv; | 241 | void *priv; |
244 | int priv_size; | ||
245 | 242 | ||
246 | /** 5V strong pullup enabled flag, 1 enabled, zero disabled. */ | 243 | /** 5V strong pullup enabled flag, 1 enabled, zero disabled. */ |
247 | int enable_pullup; | 244 | int enable_pullup; |
@@ -260,11 +257,6 @@ struct w1_master | |||
260 | struct w1_bus_master *bus_master; | 257 | struct w1_bus_master *bus_master; |
261 | 258 | ||
262 | u32 seq; | 259 | u32 seq; |
263 | /* port id to send netlink responses to. The value is temporarily | ||
264 | * stored here while processing a message, set after locking the | ||
265 | * mutex, zero before unlocking the mutex. | ||
266 | */ | ||
267 | u32 portid; | ||
268 | }; | 260 | }; |
269 | 261 | ||
270 | /** | 262 | /** |
diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c index a02704a59321..351a2978ba72 100644 --- a/drivers/w1/w1_netlink.c +++ b/drivers/w1/w1_netlink.c | |||
@@ -29,51 +29,247 @@ | |||
29 | #include "w1_netlink.h" | 29 | #include "w1_netlink.h" |
30 | 30 | ||
31 | #if defined(CONFIG_W1_CON) && (defined(CONFIG_CONNECTOR) || (defined(CONFIG_CONNECTOR_MODULE) && defined(CONFIG_W1_MODULE))) | 31 | #if defined(CONFIG_W1_CON) && (defined(CONFIG_CONNECTOR) || (defined(CONFIG_CONNECTOR_MODULE) && defined(CONFIG_W1_MODULE))) |
32 | void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) | 32 | |
33 | #define MIN(a, b) (((a) < (b)) ? (a) : (b)) | ||
34 | |||
35 | /* Bundle together everything required to process a request in one memory | ||
36 | * allocation. | ||
37 | */ | ||
38 | struct w1_cb_block { | ||
39 | atomic_t refcnt; | ||
40 | u32 portid; /* Sending process port ID */ | ||
41 | /* maximum value for first_cn->len */ | ||
42 | u16 maxlen; | ||
43 | /* pointers to building up the reply message */ | ||
44 | struct cn_msg *first_cn; /* fixed once the structure is populated */ | ||
45 | struct cn_msg *cn; /* advances as cn_msg is appeneded */ | ||
46 | struct w1_netlink_msg *msg; /* advances as w1_netlink_msg is appened */ | ||
47 | struct w1_netlink_cmd *cmd; /* advances as cmds are appened */ | ||
48 | struct w1_netlink_msg *cur_msg; /* currently message being processed */ | ||
49 | /* copy of the original request follows */ | ||
50 | struct cn_msg request_cn; | ||
51 | /* followed by variable length: | ||
52 | * cn_msg, data (w1_netlink_msg and w1_netlink_cmd) | ||
53 | * one or more struct w1_cb_node | ||
54 | * reply first_cn, data (w1_netlink_msg and w1_netlink_cmd) | ||
55 | */ | ||
56 | }; | ||
57 | struct w1_cb_node { | ||
58 | struct w1_async_cmd async; | ||
59 | /* pointers within w1_cb_block and cn data */ | ||
60 | struct w1_cb_block *block; | ||
61 | struct w1_netlink_msg *msg; | ||
62 | struct w1_slave *sl; | ||
63 | struct w1_master *dev; | ||
64 | }; | ||
65 | |||
66 | /** | ||
67 | * w1_reply_len() - calculate current reply length, compare to maxlen | ||
68 | * @block: block to calculate | ||
69 | * | ||
70 | * Calculates the current message length including possible multiple | ||
71 | * cn_msg and data, excludes the first sizeof(struct cn_msg). Direclty | ||
72 | * compariable to maxlen and usable to send the message. | ||
73 | */ | ||
74 | static u16 w1_reply_len(struct w1_cb_block *block) | ||
75 | { | ||
76 | if (!block->cn) | ||
77 | return 0; | ||
78 | return (u8 *)block->cn - (u8 *)block->first_cn + block->cn->len; | ||
79 | } | ||
80 | |||
81 | static void w1_unref_block(struct w1_cb_block *block) | ||
82 | { | ||
83 | if (atomic_sub_return(1, &block->refcnt) == 0) { | ||
84 | u16 len = w1_reply_len(block); | ||
85 | if (len) { | ||
86 | cn_netlink_send_mult(block->first_cn, len, | ||
87 | block->portid, 0, GFP_KERNEL); | ||
88 | } | ||
89 | kfree(block); | ||
90 | } | ||
91 | } | ||
92 | |||
93 | /** | ||
94 | * w1_reply_make_space() - send message if needed to make space | ||
95 | * @block: block to make space on | ||
96 | * @space: how many bytes requested | ||
97 | * | ||
98 | * Verify there is enough room left for the caller to add "space" bytes to the | ||
99 | * message, if there isn't send the message and reset. | ||
100 | */ | ||
101 | static void w1_reply_make_space(struct w1_cb_block *block, u16 space) | ||
102 | { | ||
103 | u16 len = w1_reply_len(block); | ||
104 | if (len + space >= block->maxlen) { | ||
105 | cn_netlink_send_mult(block->first_cn, len, block->portid, 0, GFP_KERNEL); | ||
106 | block->first_cn->len = 0; | ||
107 | block->cn = NULL; | ||
108 | block->msg = NULL; | ||
109 | block->cmd = NULL; | ||
110 | } | ||
111 | } | ||
112 | |||
113 | /* Early send when replies aren't bundled. */ | ||
114 | static void w1_netlink_check_send(struct w1_cb_block *block) | ||
115 | { | ||
116 | if (!(block->request_cn.flags & W1_CN_BUNDLE) && block->cn) | ||
117 | w1_reply_make_space(block, block->maxlen); | ||
118 | } | ||
119 | |||
120 | /** | ||
121 | * w1_netlink_setup_msg() - prepare to write block->msg | ||
122 | * @block: block to operate on | ||
123 | * @ack: determines if cn can be reused | ||
124 | * | ||
125 | * block->cn will be setup with the correct ack, advancing if needed | ||
126 | * block->cn->len does not include space for block->msg | ||
127 | * block->msg advances but remains uninitialized | ||
128 | */ | ||
129 | static void w1_netlink_setup_msg(struct w1_cb_block *block, u32 ack) | ||
130 | { | ||
131 | if (block->cn && block->cn->ack == ack) { | ||
132 | block->msg = (struct w1_netlink_msg *)(block->cn->data + block->cn->len); | ||
133 | } else { | ||
134 | /* advance or set to data */ | ||
135 | if (block->cn) | ||
136 | block->cn = (struct cn_msg *)(block->cn->data + | ||
137 | block->cn->len); | ||
138 | else | ||
139 | block->cn = block->first_cn; | ||
140 | |||
141 | memcpy(block->cn, &block->request_cn, sizeof(*block->cn)); | ||
142 | block->cn->len = 0; | ||
143 | block->cn->ack = ack; | ||
144 | block->msg = (struct w1_netlink_msg *)block->cn->data; | ||
145 | } | ||
146 | } | ||
147 | |||
148 | /* Append cmd to msg, include cmd->data as well. This is because | ||
149 | * any following data goes with the command and in the case of a read is | ||
150 | * the results. | ||
151 | */ | ||
152 | static void w1_netlink_queue_cmd(struct w1_cb_block *block, | ||
153 | struct w1_netlink_cmd *cmd) | ||
154 | { | ||
155 | u32 space; | ||
156 | w1_reply_make_space(block, sizeof(struct cn_msg) + | ||
157 | sizeof(struct w1_netlink_msg) + sizeof(*cmd) + cmd->len); | ||
158 | |||
159 | /* There's a status message sent after each command, so no point | ||
160 | * in trying to bundle this cmd after an existing one, because | ||
161 | * there won't be one. Allocate and copy over a new cn_msg. | ||
162 | */ | ||
163 | w1_netlink_setup_msg(block, block->request_cn.seq + 1); | ||
164 | memcpy(block->msg, block->cur_msg, sizeof(*block->msg)); | ||
165 | block->cn->len += sizeof(*block->msg); | ||
166 | block->msg->len = 0; | ||
167 | block->cmd = (struct w1_netlink_cmd *)(block->msg->data); | ||
168 | |||
169 | space = sizeof(*cmd) + cmd->len; | ||
170 | if (block->cmd != cmd) | ||
171 | memcpy(block->cmd, cmd, space); | ||
172 | block->cn->len += space; | ||
173 | block->msg->len += space; | ||
174 | } | ||
175 | |||
176 | /* Append req_msg and req_cmd, no other commands and no data from req_cmd are | ||
177 | * copied. | ||
178 | */ | ||
179 | static void w1_netlink_queue_status(struct w1_cb_block *block, | ||
180 | struct w1_netlink_msg *req_msg, struct w1_netlink_cmd *req_cmd, | ||
181 | int error) | ||
33 | { | 182 | { |
34 | char buf[sizeof(struct cn_msg) + sizeof(struct w1_netlink_msg)]; | 183 | u16 space = sizeof(struct cn_msg) + sizeof(*req_msg) + sizeof(*req_cmd); |
35 | struct cn_msg *m = (struct cn_msg *)buf; | 184 | w1_reply_make_space(block, space); |
36 | struct w1_netlink_msg *w = (struct w1_netlink_msg *)(m+1); | 185 | w1_netlink_setup_msg(block, block->request_cn.ack); |
186 | |||
187 | memcpy(block->msg, req_msg, sizeof(*req_msg)); | ||
188 | block->cn->len += sizeof(*req_msg); | ||
189 | block->msg->len = 0; | ||
190 | block->msg->status = (u8)-error; | ||
191 | if (req_cmd) { | ||
192 | struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)block->msg->data; | ||
193 | memcpy(cmd, req_cmd, sizeof(*cmd)); | ||
194 | block->cn->len += sizeof(*cmd); | ||
195 | block->msg->len += sizeof(*cmd); | ||
196 | cmd->len = 0; | ||
197 | } | ||
198 | w1_netlink_check_send(block); | ||
199 | } | ||
37 | 200 | ||
38 | memset(buf, 0, sizeof(buf)); | 201 | /** |
202 | * w1_netlink_send_error() - sends the error message now | ||
203 | * @cn: original cn_msg | ||
204 | * @msg: original w1_netlink_msg | ||
205 | * @portid: where to send it | ||
206 | * @error: error status | ||
207 | * | ||
208 | * Use when a block isn't available to queue the message to and cn, msg | ||
209 | * might not be contiguous. | ||
210 | */ | ||
211 | static void w1_netlink_send_error(struct cn_msg *cn, struct w1_netlink_msg *msg, | ||
212 | int portid, int error) | ||
213 | { | ||
214 | struct { | ||
215 | struct cn_msg cn; | ||
216 | struct w1_netlink_msg msg; | ||
217 | } packet; | ||
218 | memcpy(&packet.cn, cn, sizeof(packet.cn)); | ||
219 | memcpy(&packet.msg, msg, sizeof(packet.msg)); | ||
220 | packet.cn.len = sizeof(packet.msg); | ||
221 | packet.msg.len = 0; | ||
222 | packet.msg.status = (u8)-error; | ||
223 | cn_netlink_send(&packet.cn, portid, 0, GFP_KERNEL); | ||
224 | } | ||
225 | |||
226 | /** | ||
227 | * w1_netlink_send() - sends w1 netlink notifications | ||
228 | * @dev: w1_master the even is associated with or for | ||
229 | * @msg: w1_netlink_msg message to be sent | ||
230 | * | ||
231 | * This are notifications generated from the kernel. | ||
232 | */ | ||
233 | void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) | ||
234 | { | ||
235 | struct { | ||
236 | struct cn_msg cn; | ||
237 | struct w1_netlink_msg msg; | ||
238 | } packet; | ||
239 | memset(&packet, 0, sizeof(packet)); | ||
39 | 240 | ||
40 | m->id.idx = CN_W1_IDX; | 241 | packet.cn.id.idx = CN_W1_IDX; |
41 | m->id.val = CN_W1_VAL; | 242 | packet.cn.id.val = CN_W1_VAL; |
42 | 243 | ||
43 | m->seq = dev->seq++; | 244 | packet.cn.seq = dev->seq++; |
44 | m->len = sizeof(struct w1_netlink_msg); | 245 | packet.cn.len = sizeof(*msg); |
45 | 246 | ||
46 | memcpy(w, msg, sizeof(struct w1_netlink_msg)); | 247 | memcpy(&packet.msg, msg, sizeof(*msg)); |
248 | packet.msg.len = 0; | ||
47 | 249 | ||
48 | cn_netlink_send(m, dev->portid, 0, GFP_KERNEL); | 250 | cn_netlink_send(&packet.cn, 0, 0, GFP_KERNEL); |
49 | } | 251 | } |
50 | 252 | ||
51 | static void w1_send_slave(struct w1_master *dev, u64 rn) | 253 | static void w1_send_slave(struct w1_master *dev, u64 rn) |
52 | { | 254 | { |
53 | struct cn_msg *msg = dev->priv; | 255 | struct w1_cb_block *block = dev->priv; |
54 | struct w1_netlink_msg *hdr = (struct w1_netlink_msg *)(msg + 1); | 256 | struct w1_netlink_cmd *cache_cmd = block->cmd; |
55 | struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)(hdr + 1); | ||
56 | int avail; | ||
57 | u64 *data; | 257 | u64 *data; |
58 | 258 | ||
59 | avail = dev->priv_size - cmd->len; | 259 | w1_reply_make_space(block, sizeof(*data)); |
60 | 260 | ||
61 | if (avail < 8) { | 261 | /* Add cmd back if the packet was sent */ |
62 | msg->ack++; | 262 | if (!block->cmd) { |
63 | cn_netlink_send(msg, dev->portid, 0, GFP_KERNEL); | 263 | cache_cmd->len = 0; |
64 | 264 | w1_netlink_queue_cmd(block, cache_cmd); | |
65 | msg->len = sizeof(struct w1_netlink_msg) + | ||
66 | sizeof(struct w1_netlink_cmd); | ||
67 | hdr->len = sizeof(struct w1_netlink_cmd); | ||
68 | cmd->len = 0; | ||
69 | } | 265 | } |
70 | 266 | ||
71 | data = (void *)(cmd + 1) + cmd->len; | 267 | data = (u64 *)(block->cmd->data + block->cmd->len); |
72 | 268 | ||
73 | *data = rn; | 269 | *data = rn; |
74 | cmd->len += 8; | 270 | block->cn->len += sizeof(*data); |
75 | hdr->len += 8; | 271 | block->msg->len += sizeof(*data); |
76 | msg->len += 8; | 272 | block->cmd->len += sizeof(*data); |
77 | } | 273 | } |
78 | 274 | ||
79 | static void w1_found_send_slave(struct w1_master *dev, u64 rn) | 275 | static void w1_found_send_slave(struct w1_master *dev, u64 rn) |
@@ -85,40 +281,15 @@ static void w1_found_send_slave(struct w1_master *dev, u64 rn) | |||
85 | } | 281 | } |
86 | 282 | ||
87 | /* Get the current slave list, or search (with or without alarm) */ | 283 | /* Get the current slave list, or search (with or without alarm) */ |
88 | static int w1_get_slaves(struct w1_master *dev, | 284 | static int w1_get_slaves(struct w1_master *dev, struct w1_netlink_cmd *req_cmd) |
89 | struct cn_msg *req_msg, struct w1_netlink_msg *req_hdr, | ||
90 | struct w1_netlink_cmd *req_cmd) | ||
91 | { | 285 | { |
92 | struct cn_msg *msg; | ||
93 | struct w1_netlink_msg *hdr; | ||
94 | struct w1_netlink_cmd *cmd; | ||
95 | struct w1_slave *sl; | 286 | struct w1_slave *sl; |
96 | 287 | ||
97 | msg = kzalloc(PAGE_SIZE, GFP_KERNEL); | 288 | req_cmd->len = 0; |
98 | if (!msg) | 289 | w1_netlink_queue_cmd(dev->priv, req_cmd); |
99 | return -ENOMEM; | ||
100 | |||
101 | msg->id = req_msg->id; | ||
102 | msg->seq = req_msg->seq; | ||
103 | msg->ack = 0; | ||
104 | msg->len = sizeof(struct w1_netlink_msg) + | ||
105 | sizeof(struct w1_netlink_cmd); | ||
106 | |||
107 | hdr = (struct w1_netlink_msg *)(msg + 1); | ||
108 | cmd = (struct w1_netlink_cmd *)(hdr + 1); | ||
109 | |||
110 | hdr->type = W1_MASTER_CMD; | ||
111 | hdr->id = req_hdr->id; | ||
112 | hdr->len = sizeof(struct w1_netlink_cmd); | ||
113 | |||
114 | cmd->cmd = req_cmd->cmd; | ||
115 | cmd->len = 0; | ||
116 | |||
117 | dev->priv = msg; | ||
118 | dev->priv_size = PAGE_SIZE - msg->len - sizeof(struct cn_msg); | ||
119 | 290 | ||
120 | if (req_cmd->cmd == W1_CMD_LIST_SLAVES) { | 291 | if (req_cmd->cmd == W1_CMD_LIST_SLAVES) { |
121 | __u64 rn; | 292 | u64 rn; |
122 | mutex_lock(&dev->list_mutex); | 293 | mutex_lock(&dev->list_mutex); |
123 | list_for_each_entry(sl, &dev->slist, w1_slave_entry) { | 294 | list_for_each_entry(sl, &dev->slist, w1_slave_entry) { |
124 | memcpy(&rn, &sl->reg_num, sizeof(rn)); | 295 | memcpy(&rn, &sl->reg_num, sizeof(rn)); |
@@ -126,73 +297,26 @@ static int w1_get_slaves(struct w1_master *dev, | |||
126 | } | 297 | } |
127 | mutex_unlock(&dev->list_mutex); | 298 | mutex_unlock(&dev->list_mutex); |
128 | } else { | 299 | } else { |
129 | w1_search_process_cb(dev, cmd->cmd == W1_CMD_ALARM_SEARCH ? | 300 | w1_search_process_cb(dev, req_cmd->cmd == W1_CMD_ALARM_SEARCH ? |
130 | W1_ALARM_SEARCH : W1_SEARCH, w1_found_send_slave); | 301 | W1_ALARM_SEARCH : W1_SEARCH, w1_found_send_slave); |
131 | } | 302 | } |
132 | 303 | ||
133 | msg->ack = 0; | ||
134 | cn_netlink_send(msg, dev->portid, 0, GFP_KERNEL); | ||
135 | |||
136 | dev->priv = NULL; | ||
137 | dev->priv_size = 0; | ||
138 | |||
139 | kfree(msg); | ||
140 | |||
141 | return 0; | 304 | return 0; |
142 | } | 305 | } |
143 | 306 | ||
144 | static int w1_send_read_reply(struct cn_msg *msg, struct w1_netlink_msg *hdr, | 307 | static int w1_process_command_io(struct w1_master *dev, |
145 | struct w1_netlink_cmd *cmd, u32 portid) | 308 | struct w1_netlink_cmd *cmd) |
146 | { | ||
147 | void *data; | ||
148 | struct w1_netlink_msg *h; | ||
149 | struct w1_netlink_cmd *c; | ||
150 | struct cn_msg *cm; | ||
151 | int err; | ||
152 | |||
153 | data = kzalloc(sizeof(struct cn_msg) + | ||
154 | sizeof(struct w1_netlink_msg) + | ||
155 | sizeof(struct w1_netlink_cmd) + | ||
156 | cmd->len, GFP_KERNEL); | ||
157 | if (!data) | ||
158 | return -ENOMEM; | ||
159 | |||
160 | cm = (struct cn_msg *)(data); | ||
161 | h = (struct w1_netlink_msg *)(cm + 1); | ||
162 | c = (struct w1_netlink_cmd *)(h + 1); | ||
163 | |||
164 | memcpy(cm, msg, sizeof(struct cn_msg)); | ||
165 | memcpy(h, hdr, sizeof(struct w1_netlink_msg)); | ||
166 | memcpy(c, cmd, sizeof(struct w1_netlink_cmd)); | ||
167 | |||
168 | cm->ack = msg->seq+1; | ||
169 | cm->len = sizeof(struct w1_netlink_msg) + | ||
170 | sizeof(struct w1_netlink_cmd) + cmd->len; | ||
171 | |||
172 | h->len = sizeof(struct w1_netlink_cmd) + cmd->len; | ||
173 | |||
174 | memcpy(c->data, cmd->data, c->len); | ||
175 | |||
176 | err = cn_netlink_send(cm, portid, 0, GFP_KERNEL); | ||
177 | |||
178 | kfree(data); | ||
179 | |||
180 | return err; | ||
181 | } | ||
182 | |||
183 | static int w1_process_command_io(struct w1_master *dev, struct cn_msg *msg, | ||
184 | struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) | ||
185 | { | 309 | { |
186 | int err = 0; | 310 | int err = 0; |
187 | 311 | ||
188 | switch (cmd->cmd) { | 312 | switch (cmd->cmd) { |
189 | case W1_CMD_TOUCH: | 313 | case W1_CMD_TOUCH: |
190 | w1_touch_block(dev, cmd->data, cmd->len); | 314 | w1_touch_block(dev, cmd->data, cmd->len); |
191 | w1_send_read_reply(msg, hdr, cmd, dev->portid); | 315 | w1_netlink_queue_cmd(dev->priv, cmd); |
192 | break; | 316 | break; |
193 | case W1_CMD_READ: | 317 | case W1_CMD_READ: |
194 | w1_read_block(dev, cmd->data, cmd->len); | 318 | w1_read_block(dev, cmd->data, cmd->len); |
195 | w1_send_read_reply(msg, hdr, cmd, dev->portid); | 319 | w1_netlink_queue_cmd(dev->priv, cmd); |
196 | break; | 320 | break; |
197 | case W1_CMD_WRITE: | 321 | case W1_CMD_WRITE: |
198 | w1_write_block(dev, cmd->data, cmd->len); | 322 | w1_write_block(dev, cmd->data, cmd->len); |
@@ -206,14 +330,13 @@ static int w1_process_command_io(struct w1_master *dev, struct cn_msg *msg, | |||
206 | } | 330 | } |
207 | 331 | ||
208 | static int w1_process_command_addremove(struct w1_master *dev, | 332 | static int w1_process_command_addremove(struct w1_master *dev, |
209 | struct cn_msg *msg, struct w1_netlink_msg *hdr, | ||
210 | struct w1_netlink_cmd *cmd) | 333 | struct w1_netlink_cmd *cmd) |
211 | { | 334 | { |
212 | struct w1_slave *sl; | 335 | struct w1_slave *sl; |
213 | int err = 0; | 336 | int err = 0; |
214 | struct w1_reg_num *id; | 337 | struct w1_reg_num *id; |
215 | 338 | ||
216 | if (cmd->len != 8) | 339 | if (cmd->len != sizeof(*id)) |
217 | return -EINVAL; | 340 | return -EINVAL; |
218 | 341 | ||
219 | id = (struct w1_reg_num *)cmd->data; | 342 | id = (struct w1_reg_num *)cmd->data; |
@@ -241,7 +364,6 @@ static int w1_process_command_addremove(struct w1_master *dev, | |||
241 | } | 364 | } |
242 | 365 | ||
243 | static int w1_process_command_master(struct w1_master *dev, | 366 | static int w1_process_command_master(struct w1_master *dev, |
244 | struct cn_msg *req_msg, struct w1_netlink_msg *req_hdr, | ||
245 | struct w1_netlink_cmd *req_cmd) | 367 | struct w1_netlink_cmd *req_cmd) |
246 | { | 368 | { |
247 | int err = -EINVAL; | 369 | int err = -EINVAL; |
@@ -254,13 +376,13 @@ static int w1_process_command_master(struct w1_master *dev, | |||
254 | case W1_CMD_ALARM_SEARCH: | 376 | case W1_CMD_ALARM_SEARCH: |
255 | case W1_CMD_LIST_SLAVES: | 377 | case W1_CMD_LIST_SLAVES: |
256 | mutex_unlock(&dev->bus_mutex); | 378 | mutex_unlock(&dev->bus_mutex); |
257 | err = w1_get_slaves(dev, req_msg, req_hdr, req_cmd); | 379 | err = w1_get_slaves(dev, req_cmd); |
258 | mutex_lock(&dev->bus_mutex); | 380 | mutex_lock(&dev->bus_mutex); |
259 | break; | 381 | break; |
260 | case W1_CMD_READ: | 382 | case W1_CMD_READ: |
261 | case W1_CMD_WRITE: | 383 | case W1_CMD_WRITE: |
262 | case W1_CMD_TOUCH: | 384 | case W1_CMD_TOUCH: |
263 | err = w1_process_command_io(dev, req_msg, req_hdr, req_cmd); | 385 | err = w1_process_command_io(dev, req_cmd); |
264 | break; | 386 | break; |
265 | case W1_CMD_RESET: | 387 | case W1_CMD_RESET: |
266 | err = w1_reset_bus(dev); | 388 | err = w1_reset_bus(dev); |
@@ -269,8 +391,7 @@ static int w1_process_command_master(struct w1_master *dev, | |||
269 | case W1_CMD_SLAVE_REMOVE: | 391 | case W1_CMD_SLAVE_REMOVE: |
270 | mutex_unlock(&dev->bus_mutex); | 392 | mutex_unlock(&dev->bus_mutex); |
271 | mutex_lock(&dev->mutex); | 393 | mutex_lock(&dev->mutex); |
272 | err = w1_process_command_addremove(dev, req_msg, req_hdr, | 394 | err = w1_process_command_addremove(dev, req_cmd); |
273 | req_cmd); | ||
274 | mutex_unlock(&dev->mutex); | 395 | mutex_unlock(&dev->mutex); |
275 | mutex_lock(&dev->bus_mutex); | 396 | mutex_lock(&dev->bus_mutex); |
276 | break; | 397 | break; |
@@ -282,22 +403,21 @@ static int w1_process_command_master(struct w1_master *dev, | |||
282 | return err; | 403 | return err; |
283 | } | 404 | } |
284 | 405 | ||
285 | static int w1_process_command_slave(struct w1_slave *sl, struct cn_msg *msg, | 406 | static int w1_process_command_slave(struct w1_slave *sl, |
286 | struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) | 407 | struct w1_netlink_cmd *cmd) |
287 | { | 408 | { |
288 | dev_dbg(&sl->master->dev, "%s: %02x.%012llx.%02x: cmd=%02x, len=%u.\n", | 409 | dev_dbg(&sl->master->dev, "%s: %02x.%012llx.%02x: cmd=%02x, len=%u.\n", |
289 | __func__, sl->reg_num.family, (unsigned long long)sl->reg_num.id, | 410 | __func__, sl->reg_num.family, (unsigned long long)sl->reg_num.id, |
290 | sl->reg_num.crc, cmd->cmd, cmd->len); | 411 | sl->reg_num.crc, cmd->cmd, cmd->len); |
291 | 412 | ||
292 | return w1_process_command_io(sl->master, msg, hdr, cmd); | 413 | return w1_process_command_io(sl->master, cmd); |
293 | } | 414 | } |
294 | 415 | ||
295 | static int w1_process_command_root(struct cn_msg *msg, | 416 | static int w1_process_command_root(struct cn_msg *req_cn, u32 portid) |
296 | struct w1_netlink_msg *mcmd, u32 portid) | ||
297 | { | 417 | { |
298 | struct w1_master *m; | 418 | struct w1_master *dev; |
299 | struct cn_msg *cn; | 419 | struct cn_msg *cn; |
300 | struct w1_netlink_msg *w; | 420 | struct w1_netlink_msg *msg; |
301 | u32 *id; | 421 | u32 *id; |
302 | 422 | ||
303 | cn = kmalloc(PAGE_SIZE, GFP_KERNEL); | 423 | cn = kmalloc(PAGE_SIZE, GFP_KERNEL); |
@@ -307,32 +427,30 @@ static int w1_process_command_root(struct cn_msg *msg, | |||
307 | cn->id.idx = CN_W1_IDX; | 427 | cn->id.idx = CN_W1_IDX; |
308 | cn->id.val = CN_W1_VAL; | 428 | cn->id.val = CN_W1_VAL; |
309 | 429 | ||
310 | cn->seq = msg->seq; | 430 | cn->seq = req_cn->seq; |
311 | cn->ack = 1; | 431 | cn->ack = req_cn->seq + 1; |
312 | cn->len = sizeof(struct w1_netlink_msg); | 432 | cn->len = sizeof(struct w1_netlink_msg); |
313 | w = (struct w1_netlink_msg *)(cn + 1); | 433 | msg = (struct w1_netlink_msg *)cn->data; |
314 | 434 | ||
315 | w->type = W1_LIST_MASTERS; | 435 | msg->type = W1_LIST_MASTERS; |
316 | w->status = 0; | 436 | msg->status = 0; |
317 | w->len = 0; | 437 | msg->len = 0; |
318 | id = (u32 *)(w + 1); | 438 | id = (u32 *)msg->data; |
319 | 439 | ||
320 | mutex_lock(&w1_mlock); | 440 | mutex_lock(&w1_mlock); |
321 | list_for_each_entry(m, &w1_masters, w1_master_entry) { | 441 | list_for_each_entry(dev, &w1_masters, w1_master_entry) { |
322 | if (cn->len + sizeof(*id) > PAGE_SIZE - sizeof(struct cn_msg)) { | 442 | if (cn->len + sizeof(*id) > PAGE_SIZE - sizeof(struct cn_msg)) { |
323 | cn_netlink_send(cn, portid, 0, GFP_KERNEL); | 443 | cn_netlink_send(cn, portid, 0, GFP_KERNEL); |
324 | cn->ack++; | ||
325 | cn->len = sizeof(struct w1_netlink_msg); | 444 | cn->len = sizeof(struct w1_netlink_msg); |
326 | w->len = 0; | 445 | msg->len = 0; |
327 | id = (u32 *)(w + 1); | 446 | id = (u32 *)msg->data; |
328 | } | 447 | } |
329 | 448 | ||
330 | *id = m->id; | 449 | *id = dev->id; |
331 | w->len += sizeof(*id); | 450 | msg->len += sizeof(*id); |
332 | cn->len += sizeof(*id); | 451 | cn->len += sizeof(*id); |
333 | id++; | 452 | id++; |
334 | } | 453 | } |
335 | cn->ack = 0; | ||
336 | cn_netlink_send(cn, portid, 0, GFP_KERNEL); | 454 | cn_netlink_send(cn, portid, 0, GFP_KERNEL); |
337 | mutex_unlock(&w1_mlock); | 455 | mutex_unlock(&w1_mlock); |
338 | 456 | ||
@@ -340,100 +458,44 @@ static int w1_process_command_root(struct cn_msg *msg, | |||
340 | return 0; | 458 | return 0; |
341 | } | 459 | } |
342 | 460 | ||
343 | static int w1_netlink_send_error(struct cn_msg *rcmsg, struct w1_netlink_msg *rmsg, | ||
344 | struct w1_netlink_cmd *rcmd, int portid, int error) | ||
345 | { | ||
346 | struct cn_msg *cmsg; | ||
347 | struct w1_netlink_msg *msg; | ||
348 | struct w1_netlink_cmd *cmd; | ||
349 | |||
350 | cmsg = kzalloc(sizeof(*msg) + sizeof(*cmd) + sizeof(*cmsg), GFP_KERNEL); | ||
351 | if (!cmsg) | ||
352 | return -ENOMEM; | ||
353 | |||
354 | msg = (struct w1_netlink_msg *)(cmsg + 1); | ||
355 | cmd = (struct w1_netlink_cmd *)(msg + 1); | ||
356 | |||
357 | memcpy(cmsg, rcmsg, sizeof(*cmsg)); | ||
358 | cmsg->len = sizeof(*msg); | ||
359 | |||
360 | memcpy(msg, rmsg, sizeof(*msg)); | ||
361 | msg->len = 0; | ||
362 | msg->status = (short)-error; | ||
363 | |||
364 | if (rcmd) { | ||
365 | memcpy(cmd, rcmd, sizeof(*cmd)); | ||
366 | cmd->len = 0; | ||
367 | msg->len += sizeof(*cmd); | ||
368 | cmsg->len += sizeof(*cmd); | ||
369 | } | ||
370 | |||
371 | error = cn_netlink_send(cmsg, portid, 0, GFP_KERNEL); | ||
372 | kfree(cmsg); | ||
373 | |||
374 | return error; | ||
375 | } | ||
376 | |||
377 | /* Bundle together a reference count, the full message, and broken out | ||
378 | * commands to be executed on each w1 master kthread in one memory allocation. | ||
379 | */ | ||
380 | struct w1_cb_block { | ||
381 | atomic_t refcnt; | ||
382 | u32 portid; /* Sending process port ID */ | ||
383 | struct cn_msg msg; | ||
384 | /* cn_msg data */ | ||
385 | /* one or more variable length struct w1_cb_node */ | ||
386 | }; | ||
387 | struct w1_cb_node { | ||
388 | struct w1_async_cmd async; | ||
389 | /* pointers within w1_cb_block and msg data */ | ||
390 | struct w1_cb_block *block; | ||
391 | struct w1_netlink_msg *m; | ||
392 | struct w1_slave *sl; | ||
393 | struct w1_master *dev; | ||
394 | }; | ||
395 | |||
396 | static void w1_process_cb(struct w1_master *dev, struct w1_async_cmd *async_cmd) | 461 | static void w1_process_cb(struct w1_master *dev, struct w1_async_cmd *async_cmd) |
397 | { | 462 | { |
398 | struct w1_cb_node *node = container_of(async_cmd, struct w1_cb_node, | 463 | struct w1_cb_node *node = container_of(async_cmd, struct w1_cb_node, |
399 | async); | 464 | async); |
400 | u16 mlen = node->m->len; | 465 | u16 mlen = node->msg->len; |
401 | u8 *cmd_data = node->m->data; | 466 | u16 len; |
402 | int err = 0; | 467 | int err = 0; |
403 | struct w1_slave *sl = node->sl; | 468 | struct w1_slave *sl = node->sl; |
404 | struct w1_netlink_cmd *cmd = NULL; | 469 | struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)node->msg->data; |
405 | 470 | ||
406 | mutex_lock(&dev->bus_mutex); | 471 | mutex_lock(&dev->bus_mutex); |
407 | dev->portid = node->block->portid; | 472 | dev->priv = node->block; |
408 | if (sl && w1_reset_select_slave(sl)) | 473 | if (sl && w1_reset_select_slave(sl)) |
409 | err = -ENODEV; | 474 | err = -ENODEV; |
475 | node->block->cur_msg = node->msg; | ||
410 | 476 | ||
411 | while (mlen && !err) { | 477 | while (mlen && !err) { |
412 | cmd = (struct w1_netlink_cmd *)cmd_data; | ||
413 | |||
414 | if (cmd->len + sizeof(struct w1_netlink_cmd) > mlen) { | 478 | if (cmd->len + sizeof(struct w1_netlink_cmd) > mlen) { |
415 | err = -E2BIG; | 479 | err = -E2BIG; |
416 | break; | 480 | break; |
417 | } | 481 | } |
418 | 482 | ||
419 | if (sl) | 483 | if (sl) |
420 | err = w1_process_command_slave(sl, &node->block->msg, | 484 | err = w1_process_command_slave(sl, cmd); |
421 | node->m, cmd); | ||
422 | else | 485 | else |
423 | err = w1_process_command_master(dev, &node->block->msg, | 486 | err = w1_process_command_master(dev, cmd); |
424 | node->m, cmd); | 487 | w1_netlink_check_send(node->block); |
425 | 488 | ||
426 | w1_netlink_send_error(&node->block->msg, node->m, cmd, | 489 | w1_netlink_queue_status(node->block, node->msg, cmd, err); |
427 | node->block->portid, err); | ||
428 | err = 0; | 490 | err = 0; |
429 | 491 | ||
430 | cmd_data += cmd->len + sizeof(struct w1_netlink_cmd); | 492 | len = sizeof(*cmd) + cmd->len; |
431 | mlen -= cmd->len + sizeof(struct w1_netlink_cmd); | 493 | cmd = (struct w1_netlink_cmd *)((u8 *)cmd + len); |
494 | mlen -= len; | ||
432 | } | 495 | } |
433 | 496 | ||
434 | if (!cmd || err) | 497 | if (!cmd || err) |
435 | w1_netlink_send_error(&node->block->msg, node->m, cmd, | 498 | w1_netlink_queue_status(node->block, node->msg, cmd, err); |
436 | node->block->portid, err); | ||
437 | 499 | ||
438 | /* ref taken in w1_search_slave or w1_search_master_id when building | 500 | /* ref taken in w1_search_slave or w1_search_master_id when building |
439 | * the block | 501 | * the block |
@@ -442,99 +504,186 @@ static void w1_process_cb(struct w1_master *dev, struct w1_async_cmd *async_cmd) | |||
442 | w1_unref_slave(sl); | 504 | w1_unref_slave(sl); |
443 | else | 505 | else |
444 | atomic_dec(&dev->refcnt); | 506 | atomic_dec(&dev->refcnt); |
445 | dev->portid = 0; | 507 | dev->priv = NULL; |
446 | mutex_unlock(&dev->bus_mutex); | 508 | mutex_unlock(&dev->bus_mutex); |
447 | 509 | ||
448 | mutex_lock(&dev->list_mutex); | 510 | mutex_lock(&dev->list_mutex); |
449 | list_del(&async_cmd->async_entry); | 511 | list_del(&async_cmd->async_entry); |
450 | mutex_unlock(&dev->list_mutex); | 512 | mutex_unlock(&dev->list_mutex); |
451 | 513 | ||
452 | if (atomic_sub_return(1, &node->block->refcnt) == 0) | 514 | w1_unref_block(node->block); |
453 | kfree(node->block); | 515 | } |
516 | |||
517 | static void w1_list_count_cmds(struct w1_netlink_msg *msg, int *cmd_count, | ||
518 | u16 *slave_len) | ||
519 | { | ||
520 | struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)msg->data; | ||
521 | u16 mlen = msg->len; | ||
522 | u16 len; | ||
523 | int slave_list = 0; | ||
524 | while (mlen) { | ||
525 | if (cmd->len + sizeof(struct w1_netlink_cmd) > mlen) | ||
526 | break; | ||
527 | |||
528 | switch (cmd->cmd) { | ||
529 | case W1_CMD_SEARCH: | ||
530 | case W1_CMD_ALARM_SEARCH: | ||
531 | case W1_CMD_LIST_SLAVES: | ||
532 | ++slave_list; | ||
533 | } | ||
534 | ++*cmd_count; | ||
535 | len = sizeof(*cmd) + cmd->len; | ||
536 | cmd = (struct w1_netlink_cmd *)((u8 *)cmd + len); | ||
537 | mlen -= len; | ||
538 | } | ||
539 | |||
540 | if (slave_list) { | ||
541 | struct w1_master *dev = w1_search_master_id(msg->id.mst.id); | ||
542 | if (dev) { | ||
543 | /* Bytes, and likely an overstimate, and if it isn't | ||
544 | * the results can still be split between packets. | ||
545 | */ | ||
546 | *slave_len += sizeof(struct w1_reg_num) * slave_list * | ||
547 | (dev->slave_count + dev->max_slave_count); | ||
548 | /* search incremented it */ | ||
549 | atomic_dec(&dev->refcnt); | ||
550 | } | ||
551 | } | ||
454 | } | 552 | } |
455 | 553 | ||
456 | static void w1_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) | 554 | static void w1_cn_callback(struct cn_msg *cn, struct netlink_skb_parms *nsp) |
457 | { | 555 | { |
458 | struct w1_netlink_msg *m = (struct w1_netlink_msg *)(msg + 1); | 556 | struct w1_netlink_msg *msg = (struct w1_netlink_msg *)(cn + 1); |
459 | struct w1_slave *sl; | 557 | struct w1_slave *sl; |
460 | struct w1_master *dev; | 558 | struct w1_master *dev; |
461 | u16 msg_len; | 559 | u16 msg_len; |
560 | u16 slave_len = 0; | ||
462 | int err = 0; | 561 | int err = 0; |
463 | struct w1_cb_block *block = NULL; | 562 | struct w1_cb_block *block = NULL; |
464 | struct w1_cb_node *node = NULL; | 563 | struct w1_cb_node *node = NULL; |
465 | int node_count = 0; | 564 | int node_count = 0; |
565 | int cmd_count = 0; | ||
566 | |||
567 | /* If any unknown flag is set let the application know, that way | ||
568 | * applications can detect the absence of features in kernels that | ||
569 | * don't know about them. http://lwn.net/Articles/587527/ | ||
570 | */ | ||
571 | if (cn->flags & ~(W1_CN_BUNDLE)) { | ||
572 | w1_netlink_send_error(cn, msg, nsp->portid, -EINVAL); | ||
573 | return; | ||
574 | } | ||
466 | 575 | ||
467 | /* Count the number of master or slave commands there are to allocate | 576 | /* Count the number of master or slave commands there are to allocate |
468 | * space for one cb_node each. | 577 | * space for one cb_node each. |
469 | */ | 578 | */ |
470 | msg_len = msg->len; | 579 | msg_len = cn->len; |
471 | while (msg_len && !err) { | 580 | while (msg_len && !err) { |
472 | if (m->len + sizeof(struct w1_netlink_msg) > msg_len) { | 581 | if (msg->len + sizeof(struct w1_netlink_msg) > msg_len) { |
473 | err = -E2BIG; | 582 | err = -E2BIG; |
474 | break; | 583 | break; |
475 | } | 584 | } |
476 | 585 | ||
477 | if (m->type == W1_MASTER_CMD || m->type == W1_SLAVE_CMD) | 586 | /* count messages for nodes and allocate any additional space |
587 | * required for slave lists | ||
588 | */ | ||
589 | if (msg->type == W1_MASTER_CMD || msg->type == W1_SLAVE_CMD) { | ||
478 | ++node_count; | 590 | ++node_count; |
591 | w1_list_count_cmds(msg, &cmd_count, &slave_len); | ||
592 | } | ||
479 | 593 | ||
480 | msg_len -= sizeof(struct w1_netlink_msg) + m->len; | 594 | msg_len -= sizeof(struct w1_netlink_msg) + msg->len; |
481 | m = (struct w1_netlink_msg *)(((u8 *)m) + | 595 | msg = (struct w1_netlink_msg *)(((u8 *)msg) + |
482 | sizeof(struct w1_netlink_msg) + m->len); | 596 | sizeof(struct w1_netlink_msg) + msg->len); |
483 | } | 597 | } |
484 | m = (struct w1_netlink_msg *)(msg + 1); | 598 | msg = (struct w1_netlink_msg *)(cn + 1); |
485 | if (node_count) { | 599 | if (node_count) { |
486 | /* msg->len doesn't include itself */ | 600 | int size; |
487 | long size = sizeof(struct w1_cb_block) + msg->len + | 601 | u16 reply_size = sizeof(*cn) + cn->len + slave_len; |
488 | node_count*sizeof(struct w1_cb_node); | 602 | if (cn->flags & W1_CN_BUNDLE) { |
489 | block = kmalloc(size, GFP_KERNEL); | 603 | /* bundling duplicats some of the messages */ |
604 | reply_size += 2 * cmd_count * (sizeof(struct cn_msg) + | ||
605 | sizeof(struct w1_netlink_msg) + | ||
606 | sizeof(struct w1_netlink_cmd)); | ||
607 | } | ||
608 | reply_size = MIN(CONNECTOR_MAX_MSG_SIZE, reply_size); | ||
609 | |||
610 | /* allocate space for the block, a copy of the original message, | ||
611 | * one node per cmd to point into the original message, | ||
612 | * space for replies which is the original message size plus | ||
613 | * space for any list slave data and status messages | ||
614 | * cn->len doesn't include itself which is part of the block | ||
615 | * */ | ||
616 | size = /* block + original message */ | ||
617 | sizeof(struct w1_cb_block) + sizeof(*cn) + cn->len + | ||
618 | /* space for nodes */ | ||
619 | node_count * sizeof(struct w1_cb_node) + | ||
620 | /* replies */ | ||
621 | sizeof(struct cn_msg) + reply_size; | ||
622 | block = kzalloc(size, GFP_KERNEL); | ||
490 | if (!block) { | 623 | if (!block) { |
491 | w1_netlink_send_error(msg, m, NULL, nsp->portid, | 624 | /* if the system is already out of memory, |
492 | -ENOMEM); | 625 | * (A) will this work, and (B) would it be better |
626 | * to not try? | ||
627 | */ | ||
628 | w1_netlink_send_error(cn, msg, nsp->portid, -ENOMEM); | ||
493 | return; | 629 | return; |
494 | } | 630 | } |
495 | atomic_set(&block->refcnt, 1); | 631 | atomic_set(&block->refcnt, 1); |
496 | block->portid = nsp->portid; | 632 | block->portid = nsp->portid; |
497 | memcpy(&block->msg, msg, sizeof(*msg) + msg->len); | 633 | memcpy(&block->request_cn, cn, sizeof(*cn) + cn->len); |
498 | node = (struct w1_cb_node *)((u8 *)block->msg.data + msg->len); | 634 | node = (struct w1_cb_node *)(block->request_cn.data + cn->len); |
635 | |||
636 | /* Sneeky, when not bundling, reply_size is the allocated space | ||
637 | * required for the reply, cn_msg isn't part of maxlen so | ||
638 | * it should be reply_size - sizeof(struct cn_msg), however | ||
639 | * when checking if there is enough space, w1_reply_make_space | ||
640 | * is called with the full message size including cn_msg, | ||
641 | * because it isn't known at that time if an additional cn_msg | ||
642 | * will need to be allocated. So an extra cn_msg is added | ||
643 | * above in "size". | ||
644 | */ | ||
645 | block->maxlen = reply_size; | ||
646 | block->first_cn = (struct cn_msg *)(node + node_count); | ||
647 | memset(block->first_cn, 0, sizeof(*block->first_cn)); | ||
499 | } | 648 | } |
500 | 649 | ||
501 | msg_len = msg->len; | 650 | msg_len = cn->len; |
502 | while (msg_len && !err) { | 651 | while (msg_len && !err) { |
503 | 652 | ||
504 | dev = NULL; | 653 | dev = NULL; |
505 | sl = NULL; | 654 | sl = NULL; |
506 | 655 | ||
507 | if (m->len + sizeof(struct w1_netlink_msg) > msg_len) { | 656 | if (msg->len + sizeof(struct w1_netlink_msg) > msg_len) { |
508 | err = -E2BIG; | 657 | err = -E2BIG; |
509 | break; | 658 | break; |
510 | } | 659 | } |
511 | 660 | ||
512 | /* execute on this thread, no need to process later */ | 661 | /* execute on this thread, no need to process later */ |
513 | if (m->type == W1_LIST_MASTERS) { | 662 | if (msg->type == W1_LIST_MASTERS) { |
514 | err = w1_process_command_root(msg, m, nsp->portid); | 663 | err = w1_process_command_root(cn, nsp->portid); |
515 | goto out_cont; | 664 | goto out_cont; |
516 | } | 665 | } |
517 | 666 | ||
518 | /* All following message types require additional data, | 667 | /* All following message types require additional data, |
519 | * check here before references are taken. | 668 | * check here before references are taken. |
520 | */ | 669 | */ |
521 | if (!m->len) { | 670 | if (!msg->len) { |
522 | err = -EPROTO; | 671 | err = -EPROTO; |
523 | goto out_cont; | 672 | goto out_cont; |
524 | } | 673 | } |
525 | 674 | ||
526 | /* both search calls take reference counts */ | 675 | /* both search calls take references */ |
527 | if (m->type == W1_MASTER_CMD) { | 676 | if (msg->type == W1_MASTER_CMD) { |
528 | dev = w1_search_master_id(m->id.mst.id); | 677 | dev = w1_search_master_id(msg->id.mst.id); |
529 | } else if (m->type == W1_SLAVE_CMD) { | 678 | } else if (msg->type == W1_SLAVE_CMD) { |
530 | sl = w1_search_slave((struct w1_reg_num *)m->id.id); | 679 | sl = w1_search_slave((struct w1_reg_num *)msg->id.id); |
531 | if (sl) | 680 | if (sl) |
532 | dev = sl->master; | 681 | dev = sl->master; |
533 | } else { | 682 | } else { |
534 | printk(KERN_NOTICE | 683 | printk(KERN_NOTICE |
535 | "%s: msg: %x.%x, wrong type: %u, len: %u.\n", | 684 | "%s: cn: %x.%x, wrong type: %u, len: %u.\n", |
536 | __func__, msg->id.idx, msg->id.val, | 685 | __func__, cn->id.idx, cn->id.val, |
537 | m->type, m->len); | 686 | msg->type, msg->len); |
538 | err = -EPROTO; | 687 | err = -EPROTO; |
539 | goto out_cont; | 688 | goto out_cont; |
540 | } | 689 | } |
@@ -549,8 +698,8 @@ static void w1_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) | |||
549 | atomic_inc(&block->refcnt); | 698 | atomic_inc(&block->refcnt); |
550 | node->async.cb = w1_process_cb; | 699 | node->async.cb = w1_process_cb; |
551 | node->block = block; | 700 | node->block = block; |
552 | node->m = (struct w1_netlink_msg *)((u8 *)&block->msg + | 701 | node->msg = (struct w1_netlink_msg *)((u8 *)&block->request_cn + |
553 | (size_t)((u8 *)m - (u8 *)msg)); | 702 | (size_t)((u8 *)msg - (u8 *)cn)); |
554 | node->sl = sl; | 703 | node->sl = sl; |
555 | node->dev = dev; | 704 | node->dev = dev; |
556 | 705 | ||
@@ -561,11 +710,15 @@ static void w1_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) | |||
561 | ++node; | 710 | ++node; |
562 | 711 | ||
563 | out_cont: | 712 | out_cont: |
713 | /* Can't queue because that modifies block and another | ||
714 | * thread could be processing the messages by now and | ||
715 | * there isn't a lock, send directly. | ||
716 | */ | ||
564 | if (err) | 717 | if (err) |
565 | w1_netlink_send_error(msg, m, NULL, nsp->portid, err); | 718 | w1_netlink_send_error(cn, msg, nsp->portid, err); |
566 | msg_len -= sizeof(struct w1_netlink_msg) + m->len; | 719 | msg_len -= sizeof(struct w1_netlink_msg) + msg->len; |
567 | m = (struct w1_netlink_msg *)(((u8 *)m) + | 720 | msg = (struct w1_netlink_msg *)(((u8 *)msg) + |
568 | sizeof(struct w1_netlink_msg) + m->len); | 721 | sizeof(struct w1_netlink_msg) + msg->len); |
569 | 722 | ||
570 | /* | 723 | /* |
571 | * Let's allow requests for nonexisting devices. | 724 | * Let's allow requests for nonexisting devices. |
@@ -573,8 +726,8 @@ out_cont: | |||
573 | if (err == -ENODEV) | 726 | if (err == -ENODEV) |
574 | err = 0; | 727 | err = 0; |
575 | } | 728 | } |
576 | if (block && atomic_sub_return(1, &block->refcnt) == 0) | 729 | if (block) |
577 | kfree(block); | 730 | w1_unref_block(block); |
578 | } | 731 | } |
579 | 732 | ||
580 | int w1_init_netlink(void) | 733 | int w1_init_netlink(void) |
@@ -591,7 +744,7 @@ void w1_fini_netlink(void) | |||
591 | cn_del_callback(&w1_id); | 744 | cn_del_callback(&w1_id); |
592 | } | 745 | } |
593 | #else | 746 | #else |
594 | void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) | 747 | void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *cn) |
595 | { | 748 | { |
596 | } | 749 | } |
597 | 750 | ||
diff --git a/drivers/w1/w1_netlink.h b/drivers/w1/w1_netlink.h index 1e9504e67650..c99a9ce05e62 100644 --- a/drivers/w1/w1_netlink.h +++ b/drivers/w1/w1_netlink.h | |||
@@ -28,6 +28,17 @@ | |||
28 | #include "w1.h" | 28 | #include "w1.h" |
29 | 29 | ||
30 | /** | 30 | /** |
31 | * enum w1_cn_msg_flags - bitfield flags for struct cn_msg.flags | ||
32 | * | ||
33 | * @W1_CN_BUNDLE: Request bundling replies into fewer messagse. Be prepared | ||
34 | * to handle multiple struct cn_msg, struct w1_netlink_msg, and | ||
35 | * struct w1_netlink_cmd in one packet. | ||
36 | */ | ||
37 | enum w1_cn_msg_flags { | ||
38 | W1_CN_BUNDLE = 1, | ||
39 | }; | ||
40 | |||
41 | /** | ||
31 | * enum w1_netlink_message_types - message type | 42 | * enum w1_netlink_message_types - message type |
32 | * | 43 | * |
33 | * @W1_SLAVE_ADD: notification that a slave device was added | 44 | * @W1_SLAVE_ADD: notification that a slave device was added |
@@ -49,6 +60,19 @@ enum w1_netlink_message_types { | |||
49 | W1_LIST_MASTERS, | 60 | W1_LIST_MASTERS, |
50 | }; | 61 | }; |
51 | 62 | ||
63 | /** | ||
64 | * struct w1_netlink_msg - holds w1 message type, id, and result | ||
65 | * | ||
66 | * @type: one of enum w1_netlink_message_types | ||
67 | * @status: kernel feedback for success 0 or errno failure value | ||
68 | * @len: length of data following w1_netlink_msg | ||
69 | * @id: union holding master bus id (msg.id) and slave device id (id[8]). | ||
70 | * @data: start address of any following data | ||
71 | * | ||
72 | * The base message structure for w1 messages over netlink. | ||
73 | * The netlink connector data sequence is, struct nlmsghdr, struct cn_msg, | ||
74 | * then one or more struct w1_netlink_msg (each with optional data). | ||
75 | */ | ||
52 | struct w1_netlink_msg | 76 | struct w1_netlink_msg |
53 | { | 77 | { |
54 | __u8 type; | 78 | __u8 type; |
@@ -66,6 +90,7 @@ struct w1_netlink_msg | |||
66 | 90 | ||
67 | /** | 91 | /** |
68 | * enum w1_commands - commands available for master or slave operations | 92 | * enum w1_commands - commands available for master or slave operations |
93 | * | ||
69 | * @W1_CMD_READ: read len bytes | 94 | * @W1_CMD_READ: read len bytes |
70 | * @W1_CMD_WRITE: write len bytes | 95 | * @W1_CMD_WRITE: write len bytes |
71 | * @W1_CMD_SEARCH: initiate a standard search, returns only the slave | 96 | * @W1_CMD_SEARCH: initiate a standard search, returns only the slave |
@@ -93,6 +118,17 @@ enum w1_commands { | |||
93 | W1_CMD_MAX | 118 | W1_CMD_MAX |
94 | }; | 119 | }; |
95 | 120 | ||
121 | /** | ||
122 | * struct w1_netlink_cmd - holds the command and data | ||
123 | * | ||
124 | * @cmd: one of enum w1_commands | ||
125 | * @res: reserved | ||
126 | * @len: length of data following w1_netlink_cmd | ||
127 | * @data: start address of any following data | ||
128 | * | ||
129 | * One or more struct w1_netlink_cmd is placed starting at w1_netlink_msg.data | ||
130 | * each with optional data. | ||
131 | */ | ||
96 | struct w1_netlink_cmd | 132 | struct w1_netlink_cmd |
97 | { | 133 | { |
98 | __u8 cmd; | 134 | __u8 cmd; |