aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/scsi_netlink.c
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2012-09-07 08:39:21 -0400
committerDavid S. Miller <davem@davemloft.net>2012-09-13 16:26:39 -0400
commit8289bab1daf9768c20114051a99c1bd5f48d4420 (patch)
tree8e989dd8f391c49faa1bb63fc5164a44482911ea /drivers/scsi/scsi_netlink.c
parentf05ba7fccf0c5f0422378adaffcb119d08b9f304 (diff)
scsi_netlink: Remove dead and buggy code
The scsi netlink code confuses the netlink port id with a process id, going so far as to read NETLINK_CREDS(skb)->pid instead of the correct NETLINK_CB(skb).pid. Fortunately it does not matter because nothing registers to respond to scsi netlink requests. The only interesting use of the scsi_netlink interface is fc_host_post_vendor_event which sends a netlink multicast message. Since nothing registers to handle scsi netlink messages kill all of the registration logic, while retaining the same error handling behavior preserving the userspace visible behavior and removing all of the confused code that thought a netlink port id was a process id. This was tested with a kernel allyesconfig build which had no problems. Cc: James Bottomley <James.Bottomley@parallels.com> Cc: James Smart <James.Smart@Emulex.Com> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/scsi/scsi_netlink.c')
-rw-r--r--drivers/scsi/scsi_netlink.c555
1 files changed, 15 insertions, 540 deletions
diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c
index 3252bc9625ee..65123a21b97e 100644
--- a/drivers/scsi/scsi_netlink.c
+++ b/drivers/scsi/scsi_netlink.c
@@ -33,40 +33,6 @@
33struct sock *scsi_nl_sock = NULL; 33struct sock *scsi_nl_sock = NULL;
34EXPORT_SYMBOL_GPL(scsi_nl_sock); 34EXPORT_SYMBOL_GPL(scsi_nl_sock);
35 35
36static DEFINE_SPINLOCK(scsi_nl_lock);
37static struct list_head scsi_nl_drivers;
38
39static u32 scsi_nl_state;
40#define STATE_EHANDLER_BSY 0x00000001
41
42struct scsi_nl_transport {
43 int (*msg_handler)(struct sk_buff *);
44 void (*event_handler)(struct notifier_block *, unsigned long, void *);
45 unsigned int refcnt;
46 int flags;
47};
48
49/* flags values (bit flags) */
50#define HANDLER_DELETING 0x1
51
52static struct scsi_nl_transport transports[SCSI_NL_MAX_TRANSPORTS] =
53 { {NULL, }, };
54
55
56struct scsi_nl_drvr {
57 struct list_head next;
58 int (*dmsg_handler)(struct Scsi_Host *shost, void *payload,
59 u32 len, u32 pid);
60 void (*devt_handler)(struct notifier_block *nb,
61 unsigned long event, void *notify_ptr);
62 struct scsi_host_template *hostt;
63 u64 vendor_id;
64 unsigned int refcnt;
65 int flags;
66};
67
68
69
70/** 36/**
71 * scsi_nl_rcv_msg - Receive message handler. 37 * scsi_nl_rcv_msg - Receive message handler.
72 * @skb: socket receive buffer 38 * @skb: socket receive buffer
@@ -81,7 +47,6 @@ scsi_nl_rcv_msg(struct sk_buff *skb)
81{ 47{
82 struct nlmsghdr *nlh; 48 struct nlmsghdr *nlh;
83 struct scsi_nl_hdr *hdr; 49 struct scsi_nl_hdr *hdr;
84 unsigned long flags;
85 u32 rlen; 50 u32 rlen;
86 int err, tport; 51 int err, tport;
87 52
@@ -126,22 +91,24 @@ scsi_nl_rcv_msg(struct sk_buff *skb)
126 /* 91 /*
127 * Deliver message to the appropriate transport 92 * Deliver message to the appropriate transport
128 */ 93 */
129 spin_lock_irqsave(&scsi_nl_lock, flags);
130
131 tport = hdr->transport; 94 tport = hdr->transport;
132 if ((tport < SCSI_NL_MAX_TRANSPORTS) && 95 if (tport == SCSI_NL_TRANSPORT) {
133 !(transports[tport].flags & HANDLER_DELETING) && 96 switch (hdr->msgtype) {
134 (transports[tport].msg_handler)) { 97 case SCSI_NL_SHOST_VENDOR:
135 transports[tport].refcnt++; 98 /* Locate the driver that corresponds to the message */
136 spin_unlock_irqrestore(&scsi_nl_lock, flags); 99 err = -ESRCH;
137 err = transports[tport].msg_handler(skb); 100 break;
138 spin_lock_irqsave(&scsi_nl_lock, flags); 101 default:
139 transports[tport].refcnt--; 102 err = -EBADR;
140 } else 103 break;
104 }
105 if (err)
106 printk(KERN_WARNING "%s: Msgtype %d failed - err %d\n",
107 __func__, hdr->msgtype, err);
108 }
109 else
141 err = -ENOENT; 110 err = -ENOENT;
142 111
143 spin_unlock_irqrestore(&scsi_nl_lock, flags);
144
145next_msg: 112next_msg:
146 if ((err) || (nlh->nlmsg_flags & NLM_F_ACK)) 113 if ((err) || (nlh->nlmsg_flags & NLM_F_ACK))
147 netlink_ack(skb, nlh, err); 114 netlink_ack(skb, nlh, err);
@@ -150,333 +117,6 @@ next_msg:
150 } 117 }
151} 118}
152 119
153
154/**
155 * scsi_nl_rcv_event - Event handler for a netlink socket.
156 * @this: event notifier block
157 * @event: event type
158 * @ptr: event payload
159 *
160 **/
161static int
162scsi_nl_rcv_event(struct notifier_block *this, unsigned long event, void *ptr)
163{
164 struct netlink_notify *n = ptr;
165 struct scsi_nl_drvr *driver;
166 unsigned long flags;
167 int tport;
168
169 if (n->protocol != NETLINK_SCSITRANSPORT)
170 return NOTIFY_DONE;
171
172 spin_lock_irqsave(&scsi_nl_lock, flags);
173 scsi_nl_state |= STATE_EHANDLER_BSY;
174
175 /*
176 * Pass event on to any transports that may be listening
177 */
178 for (tport = 0; tport < SCSI_NL_MAX_TRANSPORTS; tport++) {
179 if (!(transports[tport].flags & HANDLER_DELETING) &&
180 (transports[tport].event_handler)) {
181 spin_unlock_irqrestore(&scsi_nl_lock, flags);
182 transports[tport].event_handler(this, event, ptr);
183 spin_lock_irqsave(&scsi_nl_lock, flags);
184 }
185 }
186
187 /*
188 * Pass event on to any drivers that may be listening
189 */
190 list_for_each_entry(driver, &scsi_nl_drivers, next) {
191 if (!(driver->flags & HANDLER_DELETING) &&
192 (driver->devt_handler)) {
193 spin_unlock_irqrestore(&scsi_nl_lock, flags);
194 driver->devt_handler(this, event, ptr);
195 spin_lock_irqsave(&scsi_nl_lock, flags);
196 }
197 }
198
199 scsi_nl_state &= ~STATE_EHANDLER_BSY;
200 spin_unlock_irqrestore(&scsi_nl_lock, flags);
201
202 return NOTIFY_DONE;
203}
204
205static struct notifier_block scsi_netlink_notifier = {
206 .notifier_call = scsi_nl_rcv_event,
207};
208
209
210/*
211 * GENERIC SCSI transport receive and event handlers
212 */
213
214/**
215 * scsi_generic_msg_handler - receive message handler for GENERIC transport messages
216 * @skb: socket receive buffer
217 **/
218static int
219scsi_generic_msg_handler(struct sk_buff *skb)
220{
221 struct nlmsghdr *nlh = nlmsg_hdr(skb);
222 struct scsi_nl_hdr *snlh = NLMSG_DATA(nlh);
223 struct scsi_nl_drvr *driver;
224 struct Scsi_Host *shost;
225 unsigned long flags;
226 int err = 0, match, pid;
227
228 pid = NETLINK_CREDS(skb)->pid;
229
230 switch (snlh->msgtype) {
231 case SCSI_NL_SHOST_VENDOR:
232 {
233 struct scsi_nl_host_vendor_msg *msg = NLMSG_DATA(nlh);
234
235 /* Locate the driver that corresponds to the message */
236 spin_lock_irqsave(&scsi_nl_lock, flags);
237 match = 0;
238 list_for_each_entry(driver, &scsi_nl_drivers, next) {
239 if (driver->vendor_id == msg->vendor_id) {
240 match = 1;
241 break;
242 }
243 }
244
245 if ((!match) || (!driver->dmsg_handler)) {
246 spin_unlock_irqrestore(&scsi_nl_lock, flags);
247 err = -ESRCH;
248 goto rcv_exit;
249 }
250
251 if (driver->flags & HANDLER_DELETING) {
252 spin_unlock_irqrestore(&scsi_nl_lock, flags);
253 err = -ESHUTDOWN;
254 goto rcv_exit;
255 }
256
257 driver->refcnt++;
258 spin_unlock_irqrestore(&scsi_nl_lock, flags);
259
260
261 /* if successful, scsi_host_lookup takes a shost reference */
262 shost = scsi_host_lookup(msg->host_no);
263 if (!shost) {
264 err = -ENODEV;
265 goto driver_exit;
266 }
267
268 /* is this host owned by the vendor ? */
269 if (shost->hostt != driver->hostt) {
270 err = -EINVAL;
271 goto vendormsg_put;
272 }
273
274 /* pass message on to the driver */
275 err = driver->dmsg_handler(shost, (void *)&msg[1],
276 msg->vmsg_datalen, pid);
277
278vendormsg_put:
279 /* release reference by scsi_host_lookup */
280 scsi_host_put(shost);
281
282driver_exit:
283 /* release our own reference on the registration object */
284 spin_lock_irqsave(&scsi_nl_lock, flags);
285 driver->refcnt--;
286 spin_unlock_irqrestore(&scsi_nl_lock, flags);
287 break;
288 }
289
290 default:
291 err = -EBADR;
292 break;
293 }
294
295rcv_exit:
296 if (err)
297 printk(KERN_WARNING "%s: Msgtype %d failed - err %d\n",
298 __func__, snlh->msgtype, err);
299 return err;
300}
301
302
303/**
304 * scsi_nl_add_transport -
305 * Registers message and event handlers for a transport. Enables
306 * receipt of netlink messages and events to a transport.
307 *
308 * @tport: transport registering handlers
309 * @msg_handler: receive message handler callback
310 * @event_handler: receive event handler callback
311 **/
312int
313scsi_nl_add_transport(u8 tport,
314 int (*msg_handler)(struct sk_buff *),
315 void (*event_handler)(struct notifier_block *, unsigned long, void *))
316{
317 unsigned long flags;
318 int err = 0;
319
320 if (tport >= SCSI_NL_MAX_TRANSPORTS)
321 return -EINVAL;
322
323 spin_lock_irqsave(&scsi_nl_lock, flags);
324
325 if (scsi_nl_state & STATE_EHANDLER_BSY) {
326 spin_unlock_irqrestore(&scsi_nl_lock, flags);
327 msleep(1);
328 spin_lock_irqsave(&scsi_nl_lock, flags);
329 }
330
331 if (transports[tport].msg_handler || transports[tport].event_handler) {
332 err = -EALREADY;
333 goto register_out;
334 }
335
336 transports[tport].msg_handler = msg_handler;
337 transports[tport].event_handler = event_handler;
338 transports[tport].flags = 0;
339 transports[tport].refcnt = 0;
340
341register_out:
342 spin_unlock_irqrestore(&scsi_nl_lock, flags);
343
344 return err;
345}
346EXPORT_SYMBOL_GPL(scsi_nl_add_transport);
347
348
349/**
350 * scsi_nl_remove_transport -
351 * Disable transport receiption of messages and events
352 *
353 * @tport: transport deregistering handlers
354 *
355 **/
356void
357scsi_nl_remove_transport(u8 tport)
358{
359 unsigned long flags;
360
361 spin_lock_irqsave(&scsi_nl_lock, flags);
362 if (scsi_nl_state & STATE_EHANDLER_BSY) {
363 spin_unlock_irqrestore(&scsi_nl_lock, flags);
364 msleep(1);
365 spin_lock_irqsave(&scsi_nl_lock, flags);
366 }
367
368 if (tport < SCSI_NL_MAX_TRANSPORTS) {
369 transports[tport].flags |= HANDLER_DELETING;
370
371 while (transports[tport].refcnt != 0) {
372 spin_unlock_irqrestore(&scsi_nl_lock, flags);
373 schedule_timeout_uninterruptible(HZ/4);
374 spin_lock_irqsave(&scsi_nl_lock, flags);
375 }
376 transports[tport].msg_handler = NULL;
377 transports[tport].event_handler = NULL;
378 transports[tport].flags = 0;
379 }
380
381 spin_unlock_irqrestore(&scsi_nl_lock, flags);
382
383 return;
384}
385EXPORT_SYMBOL_GPL(scsi_nl_remove_transport);
386
387
388/**
389 * scsi_nl_add_driver -
390 * A driver is registering its interfaces for SCSI netlink messages
391 *
392 * @vendor_id: A unique identification value for the driver.
393 * @hostt: address of the driver's host template. Used
394 * to verify an shost is bound to the driver
395 * @nlmsg_handler: receive message handler callback
396 * @nlevt_handler: receive event handler callback
397 *
398 * Returns:
399 * 0 on Success
400 * error result otherwise
401 **/
402int
403scsi_nl_add_driver(u64 vendor_id, struct scsi_host_template *hostt,
404 int (*nlmsg_handler)(struct Scsi_Host *shost, void *payload,
405 u32 len, u32 pid),
406 void (*nlevt_handler)(struct notifier_block *nb,
407 unsigned long event, void *notify_ptr))
408{
409 struct scsi_nl_drvr *driver;
410 unsigned long flags;
411
412 driver = kzalloc(sizeof(*driver), GFP_KERNEL);
413 if (unlikely(!driver)) {
414 printk(KERN_ERR "%s: allocation failure\n", __func__);
415 return -ENOMEM;
416 }
417
418 driver->dmsg_handler = nlmsg_handler;
419 driver->devt_handler = nlevt_handler;
420 driver->hostt = hostt;
421 driver->vendor_id = vendor_id;
422
423 spin_lock_irqsave(&scsi_nl_lock, flags);
424 if (scsi_nl_state & STATE_EHANDLER_BSY) {
425 spin_unlock_irqrestore(&scsi_nl_lock, flags);
426 msleep(1);
427 spin_lock_irqsave(&scsi_nl_lock, flags);
428 }
429 list_add_tail(&driver->next, &scsi_nl_drivers);
430 spin_unlock_irqrestore(&scsi_nl_lock, flags);
431
432 return 0;
433}
434EXPORT_SYMBOL_GPL(scsi_nl_add_driver);
435
436
437/**
438 * scsi_nl_remove_driver -
439 * An driver is unregistering with the SCSI netlink messages
440 *
441 * @vendor_id: The unique identification value for the driver.
442 **/
443void
444scsi_nl_remove_driver(u64 vendor_id)
445{
446 struct scsi_nl_drvr *driver;
447 unsigned long flags;
448
449 spin_lock_irqsave(&scsi_nl_lock, flags);
450 if (scsi_nl_state & STATE_EHANDLER_BSY) {
451 spin_unlock_irqrestore(&scsi_nl_lock, flags);
452 msleep(1);
453 spin_lock_irqsave(&scsi_nl_lock, flags);
454 }
455
456 list_for_each_entry(driver, &scsi_nl_drivers, next) {
457 if (driver->vendor_id == vendor_id) {
458 driver->flags |= HANDLER_DELETING;
459 while (driver->refcnt != 0) {
460 spin_unlock_irqrestore(&scsi_nl_lock, flags);
461 schedule_timeout_uninterruptible(HZ/4);
462 spin_lock_irqsave(&scsi_nl_lock, flags);
463 }
464 list_del(&driver->next);
465 kfree(driver);
466 spin_unlock_irqrestore(&scsi_nl_lock, flags);
467 return;
468 }
469 }
470
471 spin_unlock_irqrestore(&scsi_nl_lock, flags);
472
473 printk(KERN_ERR "%s: removal of driver failed - vendor_id 0x%llx\n",
474 __func__, (unsigned long long)vendor_id);
475 return;
476}
477EXPORT_SYMBOL_GPL(scsi_nl_remove_driver);
478
479
480/** 120/**
481 * scsi_netlink_init - Called by SCSI subsystem to initialize 121 * scsi_netlink_init - Called by SCSI subsystem to initialize
482 * the SCSI transport netlink interface 122 * the SCSI transport netlink interface
@@ -485,36 +125,19 @@ EXPORT_SYMBOL_GPL(scsi_nl_remove_driver);
485void 125void
486scsi_netlink_init(void) 126scsi_netlink_init(void)
487{ 127{
488 int error;
489 struct netlink_kernel_cfg cfg = { 128 struct netlink_kernel_cfg cfg = {
490 .input = scsi_nl_rcv_msg, 129 .input = scsi_nl_rcv_msg,
491 .groups = SCSI_NL_GRP_CNT, 130 .groups = SCSI_NL_GRP_CNT,
492 }; 131 };
493 132
494 INIT_LIST_HEAD(&scsi_nl_drivers);
495
496 error = netlink_register_notifier(&scsi_netlink_notifier);
497 if (error) {
498 printk(KERN_ERR "%s: register of event handler failed - %d\n",
499 __func__, error);
500 return;
501 }
502
503 scsi_nl_sock = netlink_kernel_create(&init_net, NETLINK_SCSITRANSPORT, 133 scsi_nl_sock = netlink_kernel_create(&init_net, NETLINK_SCSITRANSPORT,
504 &cfg); 134 &cfg);
505 if (!scsi_nl_sock) { 135 if (!scsi_nl_sock) {
506 printk(KERN_ERR "%s: register of receive handler failed\n", 136 printk(KERN_ERR "%s: register of receive handler failed\n",
507 __func__); 137 __func__);
508 netlink_unregister_notifier(&scsi_netlink_notifier);
509 return; 138 return;
510 } 139 }
511 140
512 /* Register the entry points for the generic SCSI transport */
513 error = scsi_nl_add_transport(SCSI_NL_TRANSPORT,
514 scsi_generic_msg_handler, NULL);
515 if (error)
516 printk(KERN_ERR "%s: register of GENERIC transport handler"
517 " failed - %d\n", __func__, error);
518 return; 141 return;
519} 142}
520 143
@@ -526,158 +149,10 @@ scsi_netlink_init(void)
526void 149void
527scsi_netlink_exit(void) 150scsi_netlink_exit(void)
528{ 151{
529 scsi_nl_remove_transport(SCSI_NL_TRANSPORT);
530
531 if (scsi_nl_sock) { 152 if (scsi_nl_sock) {
532 netlink_kernel_release(scsi_nl_sock); 153 netlink_kernel_release(scsi_nl_sock);
533 netlink_unregister_notifier(&scsi_netlink_notifier);
534 } 154 }
535 155
536 return; 156 return;
537} 157}
538 158
539
540/*
541 * Exported Interfaces
542 */
543
544/**
545 * scsi_nl_send_transport_msg -
546 * Generic function to send a single message from a SCSI transport to
547 * a single process
548 *
549 * @pid: receiving pid
550 * @hdr: message payload
551 *
552 **/
553void
554scsi_nl_send_transport_msg(u32 pid, struct scsi_nl_hdr *hdr)
555{
556 struct sk_buff *skb;
557 struct nlmsghdr *nlh;
558 const char *fn;
559 char *datab;
560 u32 len, skblen;
561 int err;
562
563 if (!scsi_nl_sock) {
564 err = -ENOENT;
565 fn = "netlink socket";
566 goto msg_fail;
567 }
568
569 len = NLMSG_SPACE(hdr->msglen);
570 skblen = NLMSG_SPACE(len);
571
572 skb = alloc_skb(skblen, GFP_KERNEL);
573 if (!skb) {
574 err = -ENOBUFS;
575 fn = "alloc_skb";
576 goto msg_fail;
577 }
578
579 nlh = nlmsg_put(skb, pid, 0, SCSI_TRANSPORT_MSG, len - sizeof(*nlh), 0);
580 if (!nlh) {
581 err = -ENOBUFS;
582 fn = "nlmsg_put";
583 goto msg_fail_skb;
584 }
585 datab = NLMSG_DATA(nlh);
586 memcpy(datab, hdr, hdr->msglen);
587
588 err = nlmsg_unicast(scsi_nl_sock, skb, pid);
589 if (err < 0) {
590 fn = "nlmsg_unicast";
591 /* nlmsg_unicast already kfree_skb'd */
592 goto msg_fail;
593 }
594
595 return;
596
597msg_fail_skb:
598 kfree_skb(skb);
599msg_fail:
600 printk(KERN_WARNING
601 "%s: Dropped Message : pid %d Transport %d, msgtype x%x, "
602 "msglen %d: %s : err %d\n",
603 __func__, pid, hdr->transport, hdr->msgtype, hdr->msglen,
604 fn, err);
605 return;
606}
607EXPORT_SYMBOL_GPL(scsi_nl_send_transport_msg);
608
609
610/**
611 * scsi_nl_send_vendor_msg - called to send a shost vendor unique message
612 * to a specific process id.
613 *
614 * @pid: process id of the receiver
615 * @host_no: host # sending the message
616 * @vendor_id: unique identifier for the driver's vendor
617 * @data_len: amount, in bytes, of vendor unique payload data
618 * @data_buf: pointer to vendor unique data buffer
619 *
620 * Returns:
621 * 0 on successful return
622 * otherwise, failing error code
623 *
624 * Notes:
625 * This routine assumes no locks are held on entry.
626 */
627int
628scsi_nl_send_vendor_msg(u32 pid, unsigned short host_no, u64 vendor_id,
629 char *data_buf, u32 data_len)
630{
631 struct sk_buff *skb;
632 struct nlmsghdr *nlh;
633 struct scsi_nl_host_vendor_msg *msg;
634 u32 len, skblen;
635 int err;
636
637 if (!scsi_nl_sock) {
638 err = -ENOENT;
639 goto send_vendor_fail;
640 }
641
642 len = SCSI_NL_MSGALIGN(sizeof(*msg) + data_len);
643 skblen = NLMSG_SPACE(len);
644
645 skb = alloc_skb(skblen, GFP_KERNEL);
646 if (!skb) {
647 err = -ENOBUFS;
648 goto send_vendor_fail;
649 }
650
651 nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG,
652 skblen - sizeof(*nlh), 0);
653 if (!nlh) {
654 err = -ENOBUFS;
655 goto send_vendor_fail_skb;
656 }
657 msg = NLMSG_DATA(nlh);
658
659 INIT_SCSI_NL_HDR(&msg->snlh, SCSI_NL_TRANSPORT,
660 SCSI_NL_SHOST_VENDOR, len);
661 msg->vendor_id = vendor_id;
662 msg->host_no = host_no;
663 msg->vmsg_datalen = data_len; /* bytes */
664 memcpy(&msg[1], data_buf, data_len);
665
666 err = nlmsg_unicast(scsi_nl_sock, skb, pid);
667 if (err)
668 /* nlmsg_multicast already kfree_skb'd */
669 goto send_vendor_fail;
670
671 return 0;
672
673send_vendor_fail_skb:
674 kfree_skb(skb);
675send_vendor_fail:
676 printk(KERN_WARNING
677 "%s: Dropped SCSI Msg : host %d vendor_unique - err %d\n",
678 __func__, host_no, err);
679 return err;
680}
681EXPORT_SYMBOL(scsi_nl_send_vendor_msg);
682
683