diff options
Diffstat (limited to 'net/iucv/af_iucv.c')
| -rw-r--r-- | net/iucv/af_iucv.c | 147 |
1 files changed, 144 insertions, 3 deletions
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index a9b3a6f9ea95..656cbd195825 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c | |||
| @@ -1,11 +1,12 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * linux/net/iucv/af_iucv.c | ||
| 3 | * | ||
| 4 | * IUCV protocol stack for Linux on zSeries | 2 | * IUCV protocol stack for Linux on zSeries |
| 5 | * | 3 | * |
| 6 | * Copyright 2006 IBM Corporation | 4 | * Copyright IBM Corp. 2006, 2009 |
| 7 | * | 5 | * |
| 8 | * Author(s): Jennifer Hunt <jenhunt@us.ibm.com> | 6 | * Author(s): Jennifer Hunt <jenhunt@us.ibm.com> |
| 7 | * Hendrik Brueckner <brueckner@linux.vnet.ibm.com> | ||
| 8 | * PM functions: | ||
| 9 | * Ursula Braun <ursula.braun@de.ibm.com> | ||
| 9 | */ | 10 | */ |
| 10 | 11 | ||
| 11 | #define KMSG_COMPONENT "af_iucv" | 12 | #define KMSG_COMPONENT "af_iucv" |
| @@ -90,6 +91,122 @@ static inline void low_nmcpy(unsigned char *dst, char *src) | |||
| 90 | memcpy(&dst[8], src, 8); | 91 | memcpy(&dst[8], src, 8); |
| 91 | } | 92 | } |
| 92 | 93 | ||
| 94 | static int afiucv_pm_prepare(struct device *dev) | ||
| 95 | { | ||
| 96 | #ifdef CONFIG_PM_DEBUG | ||
| 97 | printk(KERN_WARNING "afiucv_pm_prepare\n"); | ||
| 98 | #endif | ||
| 99 | return 0; | ||
| 100 | } | ||
| 101 | |||
| 102 | static void afiucv_pm_complete(struct device *dev) | ||
| 103 | { | ||
| 104 | #ifdef CONFIG_PM_DEBUG | ||
| 105 | printk(KERN_WARNING "afiucv_pm_complete\n"); | ||
| 106 | #endif | ||
| 107 | return; | ||
| 108 | } | ||
| 109 | |||
| 110 | /** | ||
| 111 | * afiucv_pm_freeze() - Freeze PM callback | ||
| 112 | * @dev: AFIUCV dummy device | ||
| 113 | * | ||
| 114 | * Sever all established IUCV communication pathes | ||
| 115 | */ | ||
| 116 | static int afiucv_pm_freeze(struct device *dev) | ||
| 117 | { | ||
| 118 | struct iucv_sock *iucv; | ||
| 119 | struct sock *sk; | ||
| 120 | struct hlist_node *node; | ||
| 121 | int err = 0; | ||
| 122 | |||
| 123 | #ifdef CONFIG_PM_DEBUG | ||
| 124 | printk(KERN_WARNING "afiucv_pm_freeze\n"); | ||
| 125 | #endif | ||
| 126 | read_lock(&iucv_sk_list.lock); | ||
| 127 | sk_for_each(sk, node, &iucv_sk_list.head) { | ||
| 128 | iucv = iucv_sk(sk); | ||
| 129 | skb_queue_purge(&iucv->send_skb_q); | ||
| 130 | skb_queue_purge(&iucv->backlog_skb_q); | ||
| 131 | switch (sk->sk_state) { | ||
| 132 | case IUCV_SEVERED: | ||
| 133 | case IUCV_DISCONN: | ||
| 134 | case IUCV_CLOSING: | ||
| 135 | case IUCV_CONNECTED: | ||
| 136 | if (iucv->path) { | ||
| 137 | err = iucv_path_sever(iucv->path, NULL); | ||
| 138 | iucv_path_free(iucv->path); | ||
| 139 | iucv->path = NULL; | ||
| 140 | } | ||
| 141 | break; | ||
| 142 | case IUCV_OPEN: | ||
| 143 | case IUCV_BOUND: | ||
| 144 | case IUCV_LISTEN: | ||
| 145 | case IUCV_CLOSED: | ||
| 146 | default: | ||
| 147 | break; | ||
| 148 | } | ||
| 149 | } | ||
| 150 | read_unlock(&iucv_sk_list.lock); | ||
| 151 | return err; | ||
| 152 | } | ||
| 153 | |||
| 154 | /** | ||
| 155 | * afiucv_pm_restore_thaw() - Thaw and restore PM callback | ||
| 156 | * @dev: AFIUCV dummy device | ||
| 157 | * | ||
| 158 | * socket clean up after freeze | ||
| 159 | */ | ||
| 160 | static int afiucv_pm_restore_thaw(struct device *dev) | ||
| 161 | { | ||
| 162 | struct iucv_sock *iucv; | ||
| 163 | struct sock *sk; | ||
| 164 | struct hlist_node *node; | ||
| 165 | |||
| 166 | #ifdef CONFIG_PM_DEBUG | ||
| 167 | printk(KERN_WARNING "afiucv_pm_restore_thaw\n"); | ||
| 168 | #endif | ||
| 169 | read_lock(&iucv_sk_list.lock); | ||
| 170 | sk_for_each(sk, node, &iucv_sk_list.head) { | ||
| 171 | iucv = iucv_sk(sk); | ||
| 172 | switch (sk->sk_state) { | ||
| 173 | case IUCV_CONNECTED: | ||
| 174 | sk->sk_err = EPIPE; | ||
| 175 | sk->sk_state = IUCV_DISCONN; | ||
| 176 | sk->sk_state_change(sk); | ||
| 177 | break; | ||
| 178 | case IUCV_DISCONN: | ||
| 179 | case IUCV_SEVERED: | ||
| 180 | case IUCV_CLOSING: | ||
| 181 | case IUCV_LISTEN: | ||
| 182 | case IUCV_BOUND: | ||
| 183 | case IUCV_OPEN: | ||
| 184 | default: | ||
| 185 | break; | ||
| 186 | } | ||
| 187 | } | ||
| 188 | read_unlock(&iucv_sk_list.lock); | ||
| 189 | return 0; | ||
| 190 | } | ||
| 191 | |||
| 192 | static struct dev_pm_ops afiucv_pm_ops = { | ||
| 193 | .prepare = afiucv_pm_prepare, | ||
| 194 | .complete = afiucv_pm_complete, | ||
| 195 | .freeze = afiucv_pm_freeze, | ||
| 196 | .thaw = afiucv_pm_restore_thaw, | ||
| 197 | .restore = afiucv_pm_restore_thaw, | ||
| 198 | }; | ||
| 199 | |||
| 200 | static struct device_driver af_iucv_driver = { | ||
| 201 | .owner = THIS_MODULE, | ||
| 202 | .name = "afiucv", | ||
| 203 | .bus = &iucv_bus, | ||
| 204 | .pm = &afiucv_pm_ops, | ||
| 205 | }; | ||
| 206 | |||
| 207 | /* dummy device used as trigger for PM functions */ | ||
| 208 | static struct device *af_iucv_dev; | ||
| 209 | |||
| 93 | /** | 210 | /** |
| 94 | * iucv_msg_length() - Returns the length of an iucv message. | 211 | * iucv_msg_length() - Returns the length of an iucv message. |
| 95 | * @msg: Pointer to struct iucv_message, MUST NOT be NULL | 212 | * @msg: Pointer to struct iucv_message, MUST NOT be NULL |
| @@ -1556,8 +1673,30 @@ static int __init afiucv_init(void) | |||
| 1556 | err = sock_register(&iucv_sock_family_ops); | 1673 | err = sock_register(&iucv_sock_family_ops); |
| 1557 | if (err) | 1674 | if (err) |
| 1558 | goto out_proto; | 1675 | goto out_proto; |
| 1676 | /* establish dummy device */ | ||
| 1677 | err = driver_register(&af_iucv_driver); | ||
| 1678 | if (err) | ||
| 1679 | goto out_sock; | ||
| 1680 | af_iucv_dev = kzalloc(sizeof(struct device), GFP_KERNEL); | ||
| 1681 | if (!af_iucv_dev) { | ||
| 1682 | err = -ENOMEM; | ||
| 1683 | goto out_driver; | ||
| 1684 | } | ||
| 1685 | dev_set_name(af_iucv_dev, "af_iucv"); | ||
| 1686 | af_iucv_dev->bus = &iucv_bus; | ||
| 1687 | af_iucv_dev->parent = iucv_root; | ||
| 1688 | af_iucv_dev->release = (void (*)(struct device *))kfree; | ||
| 1689 | af_iucv_dev->driver = &af_iucv_driver; | ||
| 1690 | err = device_register(af_iucv_dev); | ||
| 1691 | if (err) | ||
| 1692 | goto out_driver; | ||
| 1693 | |||
| 1559 | return 0; | 1694 | return 0; |
| 1560 | 1695 | ||
| 1696 | out_driver: | ||
| 1697 | driver_unregister(&af_iucv_driver); | ||
| 1698 | out_sock: | ||
| 1699 | sock_unregister(PF_IUCV); | ||
| 1561 | out_proto: | 1700 | out_proto: |
| 1562 | proto_unregister(&iucv_proto); | 1701 | proto_unregister(&iucv_proto); |
| 1563 | out_iucv: | 1702 | out_iucv: |
| @@ -1568,6 +1707,8 @@ out: | |||
| 1568 | 1707 | ||
| 1569 | static void __exit afiucv_exit(void) | 1708 | static void __exit afiucv_exit(void) |
| 1570 | { | 1709 | { |
| 1710 | device_unregister(af_iucv_dev); | ||
| 1711 | driver_unregister(&af_iucv_driver); | ||
| 1571 | sock_unregister(PF_IUCV); | 1712 | sock_unregister(PF_IUCV); |
| 1572 | proto_unregister(&iucv_proto); | 1713 | proto_unregister(&iucv_proto); |
| 1573 | iucv_unregister(&af_iucv_handler, 0); | 1714 | iucv_unregister(&af_iucv_handler, 0); |
