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>
This commit is contained in:
parent
c69748d1c9
commit
6fcd61f7bf
1 changed files with 74 additions and 45 deletions
|
@ -42,6 +42,8 @@ static struct proto iucv_proto = {
|
||||||
.obj_size = sizeof(struct iucv_sock),
|
.obj_size = sizeof(struct iucv_sock),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct iucv_interface *pr_iucv;
|
||||||
|
|
||||||
/* special AF_IUCV IPRM messages */
|
/* special AF_IUCV IPRM messages */
|
||||||
static const u8 iprm_shutdown[8] =
|
static const u8 iprm_shutdown[8] =
|
||||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
|
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
|
||||||
|
@ -165,7 +167,7 @@ static int afiucv_pm_freeze(struct device *dev)
|
||||||
case IUCV_CLOSING:
|
case IUCV_CLOSING:
|
||||||
case IUCV_CONNECTED:
|
case IUCV_CONNECTED:
|
||||||
if (iucv->path) {
|
if (iucv->path) {
|
||||||
err = iucv_path_sever(iucv->path, NULL);
|
err = pr_iucv->path_sever(iucv->path, NULL);
|
||||||
iucv_path_free(iucv->path);
|
iucv_path_free(iucv->path);
|
||||||
iucv->path = NULL;
|
iucv->path = NULL;
|
||||||
}
|
}
|
||||||
|
@ -229,7 +231,7 @@ static const struct dev_pm_ops afiucv_pm_ops = {
|
||||||
static struct device_driver af_iucv_driver = {
|
static struct device_driver af_iucv_driver = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.name = "afiucv",
|
.name = "afiucv",
|
||||||
.bus = &iucv_bus,
|
.bus = NULL,
|
||||||
.pm = &afiucv_pm_ops,
|
.pm = &afiucv_pm_ops,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -412,7 +414,7 @@ static void iucv_sock_close(struct sock *sk)
|
||||||
low_nmcpy(user_data, iucv->src_name);
|
low_nmcpy(user_data, iucv->src_name);
|
||||||
high_nmcpy(user_data, iucv->dst_name);
|
high_nmcpy(user_data, iucv->dst_name);
|
||||||
ASCEBC(user_data, sizeof(user_data));
|
ASCEBC(user_data, sizeof(user_data));
|
||||||
iucv_path_sever(iucv->path, user_data);
|
pr_iucv->path_sever(iucv->path, user_data);
|
||||||
iucv_path_free(iucv->path);
|
iucv_path_free(iucv->path);
|
||||||
iucv->path = NULL;
|
iucv->path = NULL;
|
||||||
}
|
}
|
||||||
|
@ -704,8 +706,9 @@ static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr,
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
err = iucv_path_connect(iucv->path, &af_iucv_handler,
|
err = pr_iucv->path_connect(iucv->path, &af_iucv_handler,
|
||||||
sa->siucv_user_id, NULL, user_data, sk);
|
sa->siucv_user_id, NULL, user_data,
|
||||||
|
sk);
|
||||||
if (err) {
|
if (err) {
|
||||||
iucv_path_free(iucv->path);
|
iucv_path_free(iucv->path);
|
||||||
iucv->path = NULL;
|
iucv->path = NULL;
|
||||||
|
@ -738,7 +741,7 @@ static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
iucv_path_sever(iucv->path, NULL);
|
pr_iucv->path_sever(iucv->path, NULL);
|
||||||
iucv_path_free(iucv->path);
|
iucv_path_free(iucv->path);
|
||||||
iucv->path = NULL;
|
iucv->path = NULL;
|
||||||
}
|
}
|
||||||
|
@ -871,7 +874,7 @@ static int iucv_send_iprm(struct iucv_path *path, struct iucv_message *msg,
|
||||||
|
|
||||||
memcpy(prmdata, (void *) skb->data, skb->len);
|
memcpy(prmdata, (void *) skb->data, skb->len);
|
||||||
prmdata[7] = 0xff - (u8) skb->len;
|
prmdata[7] = 0xff - (u8) skb->len;
|
||||||
return iucv_message_send(path, msg, IUCV_IPRMDATA, 0,
|
return pr_iucv->message_send(path, msg, IUCV_IPRMDATA, 0,
|
||||||
(void *) prmdata, 8);
|
(void *) prmdata, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -999,13 +1002,13 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
|
||||||
/* this error should never happen since the
|
/* this error should never happen since the
|
||||||
* IUCV_IPRMDATA path flag is set... sever path */
|
* IUCV_IPRMDATA path flag is set... sever path */
|
||||||
if (err == 0x15) {
|
if (err == 0x15) {
|
||||||
iucv_path_sever(iucv->path, NULL);
|
pr_iucv->path_sever(iucv->path, NULL);
|
||||||
skb_unlink(skb, &iucv->send_skb_q);
|
skb_unlink(skb, &iucv->send_skb_q);
|
||||||
err = -EPIPE;
|
err = -EPIPE;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
err = iucv_message_send(iucv->path, &txmsg, 0, 0,
|
err = pr_iucv->message_send(iucv->path, &txmsg, 0, 0,
|
||||||
(void *) skb->data, skb->len);
|
(void *) skb->data, skb->len);
|
||||||
if (err) {
|
if (err) {
|
||||||
if (err == 3) {
|
if (err == 3) {
|
||||||
|
@ -1095,8 +1098,9 @@ static void iucv_process_message(struct sock *sk, struct sk_buff *skb,
|
||||||
skb->len = 0;
|
skb->len = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rc = iucv_message_receive(path, msg, msg->flags & IUCV_IPRMDATA,
|
rc = pr_iucv->message_receive(path, msg,
|
||||||
skb->data, len, NULL);
|
msg->flags & IUCV_IPRMDATA,
|
||||||
|
skb->data, len, NULL);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
return;
|
return;
|
||||||
|
@ -1110,7 +1114,7 @@ static void iucv_process_message(struct sock *sk, struct sk_buff *skb,
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
skb = NULL;
|
skb = NULL;
|
||||||
if (rc) {
|
if (rc) {
|
||||||
iucv_path_sever(path, NULL);
|
pr_iucv->path_sever(path, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
skb = skb_dequeue(&iucv_sk(sk)->backlog_skb_q);
|
skb = skb_dequeue(&iucv_sk(sk)->backlog_skb_q);
|
||||||
|
@ -1327,8 +1331,8 @@ static int iucv_sock_shutdown(struct socket *sock, int how)
|
||||||
if (how == SEND_SHUTDOWN || how == SHUTDOWN_MASK) {
|
if (how == SEND_SHUTDOWN || how == SHUTDOWN_MASK) {
|
||||||
txmsg.class = 0;
|
txmsg.class = 0;
|
||||||
txmsg.tag = 0;
|
txmsg.tag = 0;
|
||||||
err = iucv_message_send(iucv->path, &txmsg, IUCV_IPRMDATA, 0,
|
err = pr_iucv->message_send(iucv->path, &txmsg, IUCV_IPRMDATA,
|
||||||
(void *) iprm_shutdown, 8);
|
0, (void *) iprm_shutdown, 8);
|
||||||
if (err) {
|
if (err) {
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case 1:
|
case 1:
|
||||||
|
@ -1345,7 +1349,7 @@ static int iucv_sock_shutdown(struct socket *sock, int how)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (how == RCV_SHUTDOWN || how == SHUTDOWN_MASK) {
|
if (how == RCV_SHUTDOWN || how == SHUTDOWN_MASK) {
|
||||||
err = iucv_path_quiesce(iucv_sk(sk)->path, NULL);
|
err = pr_iucv->path_quiesce(iucv->path, NULL);
|
||||||
if (err)
|
if (err)
|
||||||
err = -ENOTCONN;
|
err = -ENOTCONN;
|
||||||
|
|
||||||
|
@ -1372,7 +1376,7 @@ static int iucv_sock_release(struct socket *sock)
|
||||||
|
|
||||||
/* Unregister with IUCV base support */
|
/* Unregister with IUCV base support */
|
||||||
if (iucv_sk(sk)->path) {
|
if (iucv_sk(sk)->path) {
|
||||||
iucv_path_sever(iucv_sk(sk)->path, NULL);
|
pr_iucv->path_sever(iucv_sk(sk)->path, NULL);
|
||||||
iucv_path_free(iucv_sk(sk)->path);
|
iucv_path_free(iucv_sk(sk)->path);
|
||||||
iucv_sk(sk)->path = NULL;
|
iucv_sk(sk)->path = NULL;
|
||||||
}
|
}
|
||||||
|
@ -1514,14 +1518,14 @@ static int iucv_callback_connreq(struct iucv_path *path,
|
||||||
high_nmcpy(user_data, iucv->dst_name);
|
high_nmcpy(user_data, iucv->dst_name);
|
||||||
ASCEBC(user_data, sizeof(user_data));
|
ASCEBC(user_data, sizeof(user_data));
|
||||||
if (sk->sk_state != IUCV_LISTEN) {
|
if (sk->sk_state != IUCV_LISTEN) {
|
||||||
err = iucv_path_sever(path, user_data);
|
err = pr_iucv->path_sever(path, user_data);
|
||||||
iucv_path_free(path);
|
iucv_path_free(path);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for backlog size */
|
/* Check for backlog size */
|
||||||
if (sk_acceptq_is_full(sk)) {
|
if (sk_acceptq_is_full(sk)) {
|
||||||
err = iucv_path_sever(path, user_data);
|
err = pr_iucv->path_sever(path, user_data);
|
||||||
iucv_path_free(path);
|
iucv_path_free(path);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
@ -1529,7 +1533,7 @@ static int iucv_callback_connreq(struct iucv_path *path,
|
||||||
/* Create the new socket */
|
/* Create the new socket */
|
||||||
nsk = iucv_sock_alloc(NULL, sk->sk_type, GFP_ATOMIC);
|
nsk = iucv_sock_alloc(NULL, sk->sk_type, GFP_ATOMIC);
|
||||||
if (!nsk) {
|
if (!nsk) {
|
||||||
err = iucv_path_sever(path, user_data);
|
err = pr_iucv->path_sever(path, user_data);
|
||||||
iucv_path_free(path);
|
iucv_path_free(path);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
@ -1553,9 +1557,9 @@ static int iucv_callback_connreq(struct iucv_path *path,
|
||||||
/* set message limit for path based on msglimit of accepting socket */
|
/* set message limit for path based on msglimit of accepting socket */
|
||||||
niucv->msglimit = iucv->msglimit;
|
niucv->msglimit = iucv->msglimit;
|
||||||
path->msglim = iucv->msglimit;
|
path->msglim = iucv->msglimit;
|
||||||
err = iucv_path_accept(path, &af_iucv_handler, nuser_data, nsk);
|
err = pr_iucv->path_accept(path, &af_iucv_handler, nuser_data, nsk);
|
||||||
if (err) {
|
if (err) {
|
||||||
err = iucv_path_sever(path, user_data);
|
err = pr_iucv->path_sever(path, user_data);
|
||||||
iucv_path_free(path);
|
iucv_path_free(path);
|
||||||
iucv_sock_kill(nsk);
|
iucv_sock_kill(nsk);
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -1589,7 +1593,7 @@ static void iucv_callback_rx(struct iucv_path *path, struct iucv_message *msg)
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
if (sk->sk_shutdown & RCV_SHUTDOWN) {
|
if (sk->sk_shutdown & RCV_SHUTDOWN) {
|
||||||
iucv_message_reject(path, msg);
|
pr_iucv->message_reject(path, msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1718,6 +1722,41 @@ static const struct net_proto_family iucv_sock_family_ops = {
|
||||||
.create = iucv_sock_create,
|
.create = iucv_sock_create,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int __init afiucv_iucv_init(void)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = pr_iucv->iucv_register(&af_iucv_handler, 0);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
/* establish dummy device */
|
||||||
|
af_iucv_driver.bus = pr_iucv->bus;
|
||||||
|
err = driver_register(&af_iucv_driver);
|
||||||
|
if (err)
|
||||||
|
goto out_iucv;
|
||||||
|
af_iucv_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
|
||||||
|
if (!af_iucv_dev) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto out_driver;
|
||||||
|
}
|
||||||
|
dev_set_name(af_iucv_dev, "af_iucv");
|
||||||
|
af_iucv_dev->bus = pr_iucv->bus;
|
||||||
|
af_iucv_dev->parent = pr_iucv->root;
|
||||||
|
af_iucv_dev->release = (void (*)(struct device *))kfree;
|
||||||
|
af_iucv_dev->driver = &af_iucv_driver;
|
||||||
|
err = device_register(af_iucv_dev);
|
||||||
|
if (err)
|
||||||
|
goto out_driver;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out_driver:
|
||||||
|
driver_unregister(&af_iucv_driver);
|
||||||
|
out_iucv:
|
||||||
|
pr_iucv->iucv_unregister(&af_iucv_handler, 0);
|
||||||
|
out:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static int __init afiucv_init(void)
|
static int __init afiucv_init(void)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
@ -1735,44 +1774,33 @@ static int __init afiucv_init(void)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = iucv_register(&af_iucv_handler, 0);
|
pr_iucv = try_then_request_module(symbol_get(iucv_if), "iucv");
|
||||||
if (err)
|
if (!pr_iucv) {
|
||||||
|
printk(KERN_WARNING "iucv_if lookup failed\n");
|
||||||
|
err = -EPROTONOSUPPORT;
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
err = proto_register(&iucv_proto, 0);
|
err = proto_register(&iucv_proto, 0);
|
||||||
if (err)
|
if (err)
|
||||||
goto out_iucv;
|
goto out;
|
||||||
err = sock_register(&iucv_sock_family_ops);
|
err = sock_register(&iucv_sock_family_ops);
|
||||||
if (err)
|
if (err)
|
||||||
goto out_proto;
|
goto out_proto;
|
||||||
/* establish dummy device */
|
|
||||||
err = driver_register(&af_iucv_driver);
|
err = afiucv_iucv_init();
|
||||||
if (err)
|
if (err)
|
||||||
goto out_sock;
|
goto out_sock;
|
||||||
af_iucv_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
|
|
||||||
if (!af_iucv_dev) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto out_driver;
|
|
||||||
}
|
|
||||||
dev_set_name(af_iucv_dev, "af_iucv");
|
|
||||||
af_iucv_dev->bus = &iucv_bus;
|
|
||||||
af_iucv_dev->parent = iucv_root;
|
|
||||||
af_iucv_dev->release = (void (*)(struct device *))kfree;
|
|
||||||
af_iucv_dev->driver = &af_iucv_driver;
|
|
||||||
err = device_register(af_iucv_dev);
|
|
||||||
if (err)
|
|
||||||
goto out_driver;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_driver:
|
|
||||||
driver_unregister(&af_iucv_driver);
|
|
||||||
out_sock:
|
out_sock:
|
||||||
sock_unregister(PF_IUCV);
|
sock_unregister(PF_IUCV);
|
||||||
out_proto:
|
out_proto:
|
||||||
proto_unregister(&iucv_proto);
|
proto_unregister(&iucv_proto);
|
||||||
out_iucv:
|
|
||||||
iucv_unregister(&af_iucv_handler, 0);
|
|
||||||
out:
|
out:
|
||||||
|
if (pr_iucv)
|
||||||
|
symbol_put(iucv_if);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1780,9 +1808,10 @@ static void __exit afiucv_exit(void)
|
||||||
{
|
{
|
||||||
device_unregister(af_iucv_dev);
|
device_unregister(af_iucv_dev);
|
||||||
driver_unregister(&af_iucv_driver);
|
driver_unregister(&af_iucv_driver);
|
||||||
|
pr_iucv->iucv_unregister(&af_iucv_handler, 0);
|
||||||
|
symbol_put(iucv_if);
|
||||||
sock_unregister(PF_IUCV);
|
sock_unregister(PF_IUCV);
|
||||||
proto_unregister(&iucv_proto);
|
proto_unregister(&iucv_proto);
|
||||||
iucv_unregister(&af_iucv_handler, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(afiucv_init);
|
module_init(afiucv_init);
|
||||||
|
|
Loading…
Add table
Reference in a new issue