diff options
| author | Frank Blaschka <frank.blaschka@de.ibm.com> | 2011-08-07 21:33:51 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2011-08-13 04:10:16 -0400 |
| commit | 6fcd61f7bf5d56a83cbf26c14915138d1a64ca4e (patch) | |
| tree | 5efef0bc1c28fb5e9707bcab7bad9b9cd405ef3d /net/iucv | |
| parent | c69748d1c9b5c2db8daae7a1eb55c46932e4376a (diff) | |
af_iucv: use loadable iucv interface
For future af_iucv extensions the module should be able to run in LPAR
mode too. For this we use the new dynamic loading iucv interface.
Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/iucv')
| -rw-r--r-- | net/iucv/af_iucv.c | 119 |
1 files changed, 74 insertions, 45 deletions
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index e2013e434d03..2270e25a0298 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c | |||
| @@ -42,6 +42,8 @@ static struct proto iucv_proto = { | |||
| 42 | .obj_size = sizeof(struct iucv_sock), | 42 | .obj_size = sizeof(struct iucv_sock), |
| 43 | }; | 43 | }; |
| 44 | 44 | ||
| 45 | static struct iucv_interface *pr_iucv; | ||
| 46 | |||
| 45 | /* special AF_IUCV IPRM messages */ | 47 | /* special AF_IUCV IPRM messages */ |
| 46 | static const u8 iprm_shutdown[8] = | 48 | static const u8 iprm_shutdown[8] = |
| 47 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; | 49 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; |
| @@ -165,7 +167,7 @@ static int afiucv_pm_freeze(struct device *dev) | |||
| 165 | case IUCV_CLOSING: | 167 | case IUCV_CLOSING: |
| 166 | case IUCV_CONNECTED: | 168 | case IUCV_CONNECTED: |
| 167 | if (iucv->path) { | 169 | if (iucv->path) { |
| 168 | err = iucv_path_sever(iucv->path, NULL); | 170 | err = pr_iucv->path_sever(iucv->path, NULL); |
| 169 | iucv_path_free(iucv->path); | 171 | iucv_path_free(iucv->path); |
| 170 | iucv->path = NULL; | 172 | iucv->path = NULL; |
| 171 | } | 173 | } |
| @@ -229,7 +231,7 @@ static const struct dev_pm_ops afiucv_pm_ops = { | |||
| 229 | static struct device_driver af_iucv_driver = { | 231 | static struct device_driver af_iucv_driver = { |
| 230 | .owner = THIS_MODULE, | 232 | .owner = THIS_MODULE, |
| 231 | .name = "afiucv", | 233 | .name = "afiucv", |
| 232 | .bus = &iucv_bus, | 234 | .bus = NULL, |
| 233 | .pm = &afiucv_pm_ops, | 235 | .pm = &afiucv_pm_ops, |
| 234 | }; | 236 | }; |
| 235 | 237 | ||
| @@ -412,7 +414,7 @@ static void iucv_sock_close(struct sock *sk) | |||
| 412 | low_nmcpy(user_data, iucv->src_name); | 414 | low_nmcpy(user_data, iucv->src_name); |
| 413 | high_nmcpy(user_data, iucv->dst_name); | 415 | high_nmcpy(user_data, iucv->dst_name); |
| 414 | ASCEBC(user_data, sizeof(user_data)); | 416 | ASCEBC(user_data, sizeof(user_data)); |
| 415 | iucv_path_sever(iucv->path, user_data); | 417 | pr_iucv->path_sever(iucv->path, user_data); |
| 416 | iucv_path_free(iucv->path); | 418 | iucv_path_free(iucv->path); |
| 417 | iucv->path = NULL; | 419 | iucv->path = NULL; |
| 418 | } | 420 | } |
| @@ -704,8 +706,9 @@ static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr, | |||
| 704 | err = -ENOMEM; | 706 | err = -ENOMEM; |
| 705 | goto done; | 707 | goto done; |
| 706 | } | 708 | } |
| 707 | err = iucv_path_connect(iucv->path, &af_iucv_handler, | 709 | err = pr_iucv->path_connect(iucv->path, &af_iucv_handler, |
| 708 | sa->siucv_user_id, NULL, user_data, sk); | 710 | sa->siucv_user_id, NULL, user_data, |
| 711 | sk); | ||
| 709 | if (err) { | 712 | if (err) { |
| 710 | iucv_path_free(iucv->path); | 713 | iucv_path_free(iucv->path); |
| 711 | iucv->path = NULL; | 714 | iucv->path = NULL; |
| @@ -738,7 +741,7 @@ static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr, | |||
| 738 | } | 741 | } |
| 739 | 742 | ||
| 740 | if (err) { | 743 | if (err) { |
| 741 | iucv_path_sever(iucv->path, NULL); | 744 | pr_iucv->path_sever(iucv->path, NULL); |
| 742 | iucv_path_free(iucv->path); | 745 | iucv_path_free(iucv->path); |
| 743 | iucv->path = NULL; | 746 | iucv->path = NULL; |
| 744 | } | 747 | } |
| @@ -871,7 +874,7 @@ static int iucv_send_iprm(struct iucv_path *path, struct iucv_message *msg, | |||
| 871 | 874 | ||
| 872 | memcpy(prmdata, (void *) skb->data, skb->len); | 875 | memcpy(prmdata, (void *) skb->data, skb->len); |
| 873 | prmdata[7] = 0xff - (u8) skb->len; | 876 | prmdata[7] = 0xff - (u8) skb->len; |
| 874 | return iucv_message_send(path, msg, IUCV_IPRMDATA, 0, | 877 | return pr_iucv->message_send(path, msg, IUCV_IPRMDATA, 0, |
| 875 | (void *) prmdata, 8); | 878 | (void *) prmdata, 8); |
| 876 | } | 879 | } |
| 877 | 880 | ||
| @@ -999,13 +1002,13 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
| 999 | /* this error should never happen since the | 1002 | /* this error should never happen since the |
| 1000 | * IUCV_IPRMDATA path flag is set... sever path */ | 1003 | * IUCV_IPRMDATA path flag is set... sever path */ |
| 1001 | if (err == 0x15) { | 1004 | if (err == 0x15) { |
| 1002 | iucv_path_sever(iucv->path, NULL); | 1005 | pr_iucv->path_sever(iucv->path, NULL); |
| 1003 | skb_unlink(skb, &iucv->send_skb_q); | 1006 | skb_unlink(skb, &iucv->send_skb_q); |
| 1004 | err = -EPIPE; | 1007 | err = -EPIPE; |
| 1005 | goto fail; | 1008 | goto fail; |
| 1006 | } | 1009 | } |
| 1007 | } else | 1010 | } else |
| 1008 | err = iucv_message_send(iucv->path, &txmsg, 0, 0, | 1011 | err = pr_iucv->message_send(iucv->path, &txmsg, 0, 0, |
| 1009 | (void *) skb->data, skb->len); | 1012 | (void *) skb->data, skb->len); |
| 1010 | if (err) { | 1013 | if (err) { |
| 1011 | if (err == 3) { | 1014 | if (err == 3) { |
| @@ -1095,8 +1098,9 @@ static void iucv_process_message(struct sock *sk, struct sk_buff *skb, | |||
| 1095 | skb->len = 0; | 1098 | skb->len = 0; |
| 1096 | } | 1099 | } |
| 1097 | } else { | 1100 | } else { |
| 1098 | rc = iucv_message_receive(path, msg, msg->flags & IUCV_IPRMDATA, | 1101 | rc = pr_iucv->message_receive(path, msg, |
| 1099 | skb->data, len, NULL); | 1102 | msg->flags & IUCV_IPRMDATA, |
| 1103 | skb->data, len, NULL); | ||
| 1100 | if (rc) { | 1104 | if (rc) { |
| 1101 | kfree_skb(skb); | 1105 | kfree_skb(skb); |
| 1102 | return; | 1106 | return; |
| @@ -1110,7 +1114,7 @@ static void iucv_process_message(struct sock *sk, struct sk_buff *skb, | |||
| 1110 | kfree_skb(skb); | 1114 | kfree_skb(skb); |
| 1111 | skb = NULL; | 1115 | skb = NULL; |
| 1112 | if (rc) { | 1116 | if (rc) { |
| 1113 | iucv_path_sever(path, NULL); | 1117 | pr_iucv->path_sever(path, NULL); |
| 1114 | return; | 1118 | return; |
| 1115 | } | 1119 | } |
| 1116 | skb = skb_dequeue(&iucv_sk(sk)->backlog_skb_q); | 1120 | skb = skb_dequeue(&iucv_sk(sk)->backlog_skb_q); |
| @@ -1327,8 +1331,8 @@ static int iucv_sock_shutdown(struct socket *sock, int how) | |||
| 1327 | if (how == SEND_SHUTDOWN || how == SHUTDOWN_MASK) { | 1331 | if (how == SEND_SHUTDOWN || how == SHUTDOWN_MASK) { |
| 1328 | txmsg.class = 0; | 1332 | txmsg.class = 0; |
| 1329 | txmsg.tag = 0; | 1333 | txmsg.tag = 0; |
| 1330 | err = iucv_message_send(iucv->path, &txmsg, IUCV_IPRMDATA, 0, | 1334 | err = pr_iucv->message_send(iucv->path, &txmsg, IUCV_IPRMDATA, |
| 1331 | (void *) iprm_shutdown, 8); | 1335 | 0, (void *) iprm_shutdown, 8); |
| 1332 | if (err) { | 1336 | if (err) { |
| 1333 | switch (err) { | 1337 | switch (err) { |
| 1334 | case 1: | 1338 | case 1: |
| @@ -1345,7 +1349,7 @@ static int iucv_sock_shutdown(struct socket *sock, int how) | |||
| 1345 | } | 1349 | } |
| 1346 | 1350 | ||
| 1347 | if (how == RCV_SHUTDOWN || how == SHUTDOWN_MASK) { | 1351 | if (how == RCV_SHUTDOWN || how == SHUTDOWN_MASK) { |
| 1348 | err = iucv_path_quiesce(iucv_sk(sk)->path, NULL); | 1352 | err = pr_iucv->path_quiesce(iucv->path, NULL); |
| 1349 | if (err) | 1353 | if (err) |
| 1350 | err = -ENOTCONN; | 1354 | err = -ENOTCONN; |
| 1351 | 1355 | ||
| @@ -1372,7 +1376,7 @@ static int iucv_sock_release(struct socket *sock) | |||
| 1372 | 1376 | ||
| 1373 | /* Unregister with IUCV base support */ | 1377 | /* Unregister with IUCV base support */ |
| 1374 | if (iucv_sk(sk)->path) { | 1378 | if (iucv_sk(sk)->path) { |
| 1375 | iucv_path_sever(iucv_sk(sk)->path, NULL); | 1379 | pr_iucv->path_sever(iucv_sk(sk)->path, NULL); |
| 1376 | iucv_path_free(iucv_sk(sk)->path); | 1380 | iucv_path_free(iucv_sk(sk)->path); |
| 1377 | iucv_sk(sk)->path = NULL; | 1381 | iucv_sk(sk)->path = NULL; |
| 1378 | } | 1382 | } |
| @@ -1514,14 +1518,14 @@ static int iucv_callback_connreq(struct iucv_path *path, | |||
| 1514 | high_nmcpy(user_data, iucv->dst_name); | 1518 | high_nmcpy(user_data, iucv->dst_name); |
| 1515 | ASCEBC(user_data, sizeof(user_data)); | 1519 | ASCEBC(user_data, sizeof(user_data)); |
| 1516 | if (sk->sk_state != IUCV_LISTEN) { | 1520 | if (sk->sk_state != IUCV_LISTEN) { |
| 1517 | err = iucv_path_sever(path, user_data); | 1521 | err = pr_iucv->path_sever(path, user_data); |
| 1518 | iucv_path_free(path); | 1522 | iucv_path_free(path); |
| 1519 | goto fail; | 1523 | goto fail; |
| 1520 | } | 1524 | } |
| 1521 | 1525 | ||
| 1522 | /* Check for backlog size */ | 1526 | /* Check for backlog size */ |
| 1523 | if (sk_acceptq_is_full(sk)) { | 1527 | if (sk_acceptq_is_full(sk)) { |
| 1524 | err = iucv_path_sever(path, user_data); | 1528 | err = pr_iucv->path_sever(path, user_data); |
| 1525 | iucv_path_free(path); | 1529 | iucv_path_free(path); |
| 1526 | goto fail; | 1530 | goto fail; |
| 1527 | } | 1531 | } |
| @@ -1529,7 +1533,7 @@ static int iucv_callback_connreq(struct iucv_path *path, | |||
| 1529 | /* Create the new socket */ | 1533 | /* Create the new socket */ |
| 1530 | nsk = iucv_sock_alloc(NULL, sk->sk_type, GFP_ATOMIC); | 1534 | nsk = iucv_sock_alloc(NULL, sk->sk_type, GFP_ATOMIC); |
| 1531 | if (!nsk) { | 1535 | if (!nsk) { |
| 1532 | err = iucv_path_sever(path, user_data); | 1536 | err = pr_iucv->path_sever(path, user_data); |
| 1533 | iucv_path_free(path); | 1537 | iucv_path_free(path); |
| 1534 | goto fail; | 1538 | goto fail; |
| 1535 | } | 1539 | } |
| @@ -1553,9 +1557,9 @@ static int iucv_callback_connreq(struct iucv_path *path, | |||
| 1553 | /* set message limit for path based on msglimit of accepting socket */ | 1557 | /* set message limit for path based on msglimit of accepting socket */ |
| 1554 | niucv->msglimit = iucv->msglimit; | 1558 | niucv->msglimit = iucv->msglimit; |
| 1555 | path->msglim = iucv->msglimit; | 1559 | path->msglim = iucv->msglimit; |
| 1556 | err = iucv_path_accept(path, &af_iucv_handler, nuser_data, nsk); | 1560 | err = pr_iucv->path_accept(path, &af_iucv_handler, nuser_data, nsk); |
| 1557 | if (err) { | 1561 | if (err) { |
| 1558 | err = iucv_path_sever(path, user_data); | 1562 | err = pr_iucv->path_sever(path, user_data); |
| 1559 | iucv_path_free(path); | 1563 | iucv_path_free(path); |
| 1560 | iucv_sock_kill(nsk); | 1564 | iucv_sock_kill(nsk); |
| 1561 | goto fail; | 1565 | goto fail; |
| @@ -1589,7 +1593,7 @@ static void iucv_callback_rx(struct iucv_path *path, struct iucv_message *msg) | |||
| 1589 | int len; | 1593 | int len; |
| 1590 | 1594 | ||
| 1591 | if (sk->sk_shutdown & RCV_SHUTDOWN) { | 1595 | if (sk->sk_shutdown & RCV_SHUTDOWN) { |
| 1592 | iucv_message_reject(path, msg); | 1596 | pr_iucv->message_reject(path, msg); |
| 1593 | return; | 1597 | return; |
| 1594 | } | 1598 | } |
| 1595 | 1599 | ||
| @@ -1718,6 +1722,41 @@ static const struct net_proto_family iucv_sock_family_ops = { | |||
| 1718 | .create = iucv_sock_create, | 1722 | .create = iucv_sock_create, |
| 1719 | }; | 1723 | }; |
| 1720 | 1724 | ||
| 1725 | static int __init afiucv_iucv_init(void) | ||
| 1726 | { | ||
| 1727 | int err; | ||
| 1728 | |||
| 1729 | err = pr_iucv->iucv_register(&af_iucv_handler, 0); | ||
| 1730 | if (err) | ||
| 1731 | goto out; | ||
| 1732 | /* establish dummy device */ | ||
| 1733 | af_iucv_driver.bus = pr_iucv->bus; | ||
| 1734 | err = driver_register(&af_iucv_driver); | ||
| 1735 | if (err) | ||
| 1736 | goto out_iucv; | ||
| 1737 | af_iucv_dev = kzalloc(sizeof(struct device), GFP_KERNEL); | ||
| 1738 | if (!af_iucv_dev) { | ||
| 1739 | err = -ENOMEM; | ||
| 1740 | goto out_driver; | ||
| 1741 | } | ||
| 1742 | dev_set_name(af_iucv_dev, "af_iucv"); | ||
| 1743 | af_iucv_dev->bus = pr_iucv->bus; | ||
| 1744 | af_iucv_dev->parent = pr_iucv->root; | ||
| 1745 | af_iucv_dev->release = (void (*)(struct device *))kfree; | ||
| 1746 | af_iucv_dev->driver = &af_iucv_driver; | ||
| 1747 | err = device_register(af_iucv_dev); | ||
| 1748 | if (err) | ||
| 1749 | goto out_driver; | ||
| 1750 | return 0; | ||
| 1751 | |||
| 1752 | out_driver: | ||
| 1753 | driver_unregister(&af_iucv_driver); | ||
| 1754 | out_iucv: | ||
| 1755 | pr_iucv->iucv_unregister(&af_iucv_handler, 0); | ||
| 1756 | out: | ||
| 1757 | return err; | ||
| 1758 | } | ||
| 1759 | |||
| 1721 | static int __init afiucv_init(void) | 1760 | static int __init afiucv_init(void) |
| 1722 | { | 1761 | { |
| 1723 | int err; | 1762 | int err; |
| @@ -1735,44 +1774,33 @@ static int __init afiucv_init(void) | |||
| 1735 | goto out; | 1774 | goto out; |
| 1736 | } | 1775 | } |
| 1737 | 1776 | ||
| 1738 | err = iucv_register(&af_iucv_handler, 0); | 1777 | pr_iucv = try_then_request_module(symbol_get(iucv_if), "iucv"); |
| 1739 | if (err) | 1778 | if (!pr_iucv) { |
| 1779 | printk(KERN_WARNING "iucv_if lookup failed\n"); | ||
| 1780 | err = -EPROTONOSUPPORT; | ||
| 1740 | goto out; | 1781 | goto out; |
| 1782 | } | ||
| 1783 | |||
| 1741 | err = proto_register(&iucv_proto, 0); | 1784 | err = proto_register(&iucv_proto, 0); |
| 1742 | if (err) | 1785 | if (err) |
| 1743 | goto out_iucv; | 1786 | goto out; |
| 1744 | err = sock_register(&iucv_sock_family_ops); | 1787 | err = sock_register(&iucv_sock_family_ops); |
| 1745 | if (err) | 1788 | if (err) |
| 1746 | goto out_proto; | 1789 | goto out_proto; |
| 1747 | /* establish dummy device */ | 1790 | |
| 1748 | err = driver_register(&af_iucv_driver); | 1791 | err = afiucv_iucv_init(); |
| 1749 | if (err) | 1792 | if (err) |
| 1750 | goto out_sock; | 1793 | goto out_sock; |
| 1751 | af_iucv_dev = kzalloc(sizeof(struct device), GFP_KERNEL); | ||
| 1752 | if (!af_iucv_dev) { | ||
| 1753 | err = -ENOMEM; | ||
| 1754 | goto out_driver; | ||
| 1755 | } | ||
| 1756 | dev_set_name(af_iucv_dev, "af_iucv"); | ||
| 1757 | af_iucv_dev->bus = &iucv_bus; | ||
| 1758 | af_iucv_dev->parent = iucv_root; | ||
| 1759 | af_iucv_dev->release = (void (*)(struct device *))kfree; | ||
| 1760 | af_iucv_dev->driver = &af_iucv_driver; | ||
| 1761 | err = device_register(af_iucv_dev); | ||
| 1762 | if (err) | ||
| 1763 | goto out_driver; | ||
| 1764 | 1794 | ||
| 1765 | return 0; | 1795 | return 0; |
| 1766 | 1796 | ||
| 1767 | out_driver: | ||
| 1768 | driver_unregister(&af_iucv_driver); | ||
| 1769 | out_sock: | 1797 | out_sock: |
| 1770 | sock_unregister(PF_IUCV); | 1798 | sock_unregister(PF_IUCV); |
| 1771 | out_proto: | 1799 | out_proto: |
| 1772 | proto_unregister(&iucv_proto); | 1800 | proto_unregister(&iucv_proto); |
| 1773 | out_iucv: | ||
| 1774 | iucv_unregister(&af_iucv_handler, 0); | ||
| 1775 | out: | 1801 | out: |
| 1802 | if (pr_iucv) | ||
| 1803 | symbol_put(iucv_if); | ||
| 1776 | return err; | 1804 | return err; |
| 1777 | } | 1805 | } |
| 1778 | 1806 | ||
| @@ -1780,9 +1808,10 @@ static void __exit afiucv_exit(void) | |||
| 1780 | { | 1808 | { |
| 1781 | device_unregister(af_iucv_dev); | 1809 | device_unregister(af_iucv_dev); |
| 1782 | driver_unregister(&af_iucv_driver); | 1810 | driver_unregister(&af_iucv_driver); |
| 1811 | pr_iucv->iucv_unregister(&af_iucv_handler, 0); | ||
| 1812 | symbol_put(iucv_if); | ||
| 1783 | sock_unregister(PF_IUCV); | 1813 | sock_unregister(PF_IUCV); |
| 1784 | proto_unregister(&iucv_proto); | 1814 | proto_unregister(&iucv_proto); |
| 1785 | iucv_unregister(&af_iucv_handler, 0); | ||
| 1786 | } | 1815 | } |
| 1787 | 1816 | ||
| 1788 | module_init(afiucv_init); | 1817 | module_init(afiucv_init); |
