Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sunvdc: reconnect ldc after vds service domain restarts

This change enables the sunvdc driver to reconnect and recover if a vds
service domain is disconnected or bounced.

By default, it will wait indefinitely for the service domain to become
available again, but will honor a non-zero vdc-timout md property if one
is set. If a timeout is reached, any in-progress I/O's are completed
with -EIO.

Signed-off-by: Dwight Engen <dwight.engen@oracle.com>
Reviewed-by: Chris Hyser <chris.hyser@oracle.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Dwight Engen and committed by
David S. Miller
76e74bbe 1678c2bd

+183 -22
+183 -22
drivers/block/sunvdc.c
··· 23 23 24 24 #define DRV_MODULE_NAME "sunvdc" 25 25 #define PFX DRV_MODULE_NAME ": " 26 - #define DRV_MODULE_VERSION "1.1" 27 - #define DRV_MODULE_RELDATE "February 13, 2013" 26 + #define DRV_MODULE_VERSION "1.2" 27 + #define DRV_MODULE_RELDATE "November 24, 2014" 28 28 29 29 static char version[] = 30 30 DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; ··· 39 39 #define WAITING_FOR_TX_SPACE 0x02 40 40 #define WAITING_FOR_GEN_CMD 0x04 41 41 #define WAITING_FOR_ANY -1 42 + 43 + static struct workqueue_struct *sunvdc_wq; 42 44 43 45 struct vdc_req_entry { 44 46 struct request *req; ··· 62 60 u64 max_xfer_size; 63 61 u32 vdisk_block_size; 64 62 63 + u64 ldc_timeout; 64 + struct timer_list ldc_reset_timer; 65 + struct work_struct ldc_reset_work; 66 + 65 67 /* The server fills these in for us in the disk attribute 66 68 * ACK packet. 67 69 */ ··· 76 70 77 71 char disk_name[32]; 78 72 }; 73 + 74 + static void vdc_ldc_reset(struct vdc_port *port); 75 + static void vdc_ldc_reset_work(struct work_struct *work); 76 + static void vdc_ldc_reset_timer(unsigned long _arg); 79 77 80 78 static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio) 81 79 { ··· 160 150 .ioctl = vdc_ioctl, 161 151 }; 162 152 153 + static void vdc_blk_queue_start(struct vdc_port *port) 154 + { 155 + struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING]; 156 + 157 + /* restart blk queue when ring is half emptied. also called after 158 + * handshake completes, so check for initial handshake before we've 159 + * allocated a disk. 160 + */ 161 + if (port->disk && blk_queue_stopped(port->disk->queue) && 162 + vdc_tx_dring_avail(dr) * 100 / VDC_TX_RING_SIZE >= 50) { 163 + blk_start_queue(port->disk->queue); 164 + } 165 + 166 + } 167 + 163 168 static void vdc_finish(struct vio_driver_state *vio, int err, int waiting_for) 164 169 { 165 170 if (vio->cmp && ··· 188 163 189 164 static void vdc_handshake_complete(struct vio_driver_state *vio) 190 165 { 166 + struct vdc_port *port = to_vdc_port(vio); 167 + 168 + del_timer(&port->ldc_reset_timer); 191 169 vdc_finish(vio, 0, WAITING_FOR_LINK_UP); 170 + vdc_blk_queue_start(port); 192 171 } 193 172 194 173 static int vdc_handle_unknown(struct vdc_port *port, void *arg) ··· 310 281 311 282 __blk_end_request(req, (desc->status ? -EIO : 0), desc->size); 312 283 313 - /* restart blk queue when ring is half emptied */ 314 - if (blk_queue_stopped(port->disk->queue) && 315 - vdc_tx_dring_avail(dr) * 100 / VDC_TX_RING_SIZE >= 50) 316 - blk_start_queue(port->disk->queue); 284 + vdc_blk_queue_start(port); 317 285 } 318 286 319 287 static int vdc_ack(struct vdc_port *port, void *msgbuf) ··· 343 317 344 318 spin_lock_irqsave(&vio->lock, flags); 345 319 346 - if (unlikely(event == LDC_EVENT_RESET || 347 - event == LDC_EVENT_UP)) { 320 + if (unlikely(event == LDC_EVENT_RESET)) { 348 321 vio_link_state_change(vio, event); 349 - spin_unlock_irqrestore(&vio->lock, flags); 350 - return; 322 + queue_work(sunvdc_wq, &port->ldc_reset_work); 323 + goto out; 324 + } 325 + 326 + if (unlikely(event == LDC_EVENT_UP)) { 327 + vio_link_state_change(vio, event); 328 + goto out; 351 329 } 352 330 353 331 if (unlikely(event != LDC_EVENT_DATA_READY)) { 354 - printk(KERN_WARNING PFX "Unexpected LDC event %d\n", event); 355 - spin_unlock_irqrestore(&vio->lock, flags); 356 - return; 332 + pr_warn(PFX "Unexpected LDC event %d\n", event); 333 + goto out; 357 334 } 358 335 359 336 err = 0; ··· 400 371 } 401 372 if (err < 0) 402 373 vdc_finish(&port->vio, err, WAITING_FOR_ANY); 374 + out: 403 375 spin_unlock_irqrestore(&vio->lock, flags); 404 376 } 405 377 ··· 433 403 delay = 128; 434 404 } while (err == -EAGAIN); 435 405 406 + if (err == -ENOTCONN) 407 + vdc_ldc_reset(port); 436 408 return err; 437 409 } 438 410 ··· 722 690 } 723 691 } 724 692 725 - static int probe_disk(struct vdc_port *port) 693 + static int vdc_port_up(struct vdc_port *port) 726 694 { 727 695 struct vio_completion comp; 728 - struct request_queue *q; 729 - struct gendisk *g; 730 - int err; 731 696 732 697 init_completion(&comp.com); 733 698 comp.err = 0; ··· 732 703 port->vio.cmp = &comp; 733 704 734 705 vio_port_up(&port->vio); 735 - 736 706 wait_for_completion(&comp.com); 737 - if (comp.err) 738 - return comp.err; 707 + return comp.err; 708 + } 709 + 710 + static void vdc_port_down(struct vdc_port *port) 711 + { 712 + ldc_disconnect(port->vio.lp); 713 + ldc_unbind(port->vio.lp); 714 + vdc_free_tx_ring(port); 715 + vio_ldc_free(&port->vio); 716 + } 717 + 718 + static int probe_disk(struct vdc_port *port) 719 + { 720 + struct request_queue *q; 721 + struct gendisk *g; 722 + int err; 723 + 724 + err = vdc_port_up(port); 725 + if (err) 726 + return err; 739 727 740 728 if (vdc_version_supported(port, 1, 1)) { 741 729 /* vdisk_size should be set during the handshake, if it wasn't ··· 865 819 struct mdesc_handle *hp; 866 820 struct vdc_port *port; 867 821 int err; 822 + const u64 *ldc_timeout; 868 823 869 824 print_version(); 870 825 ··· 894 847 snprintf(port->disk_name, sizeof(port->disk_name), 895 848 VDCBLK_NAME "%c", 'a' + ((int)vdev->dev_no % 26)); 896 849 port->vdisk_size = -1; 850 + 851 + /* Actual wall time may be double due to do_generic_file_read() doing 852 + * a readahead I/O first, and once that fails it will try to read a 853 + * single page. 854 + */ 855 + ldc_timeout = mdesc_get_property(hp, vdev->mp, "vdc-timeout", NULL); 856 + port->ldc_timeout = ldc_timeout ? *ldc_timeout : 0; 857 + setup_timer(&port->ldc_reset_timer, vdc_ldc_reset_timer, 858 + (unsigned long)port); 859 + INIT_WORK(&port->ldc_reset_work, vdc_ldc_reset_work); 897 860 898 861 err = vio_driver_init(&port->vio, vdev, VDEV_DISK, 899 862 vdc_versions, ARRAY_SIZE(vdc_versions), ··· 959 902 blk_stop_queue(port->disk->queue); 960 903 spin_unlock_irqrestore(&port->vio.lock, flags); 961 904 905 + flush_work(&port->ldc_reset_work); 906 + del_timer_sync(&port->ldc_reset_timer); 962 907 del_timer_sync(&port->vio.timer); 963 908 964 909 del_gendisk(port->disk); ··· 976 917 kfree(port); 977 918 } 978 919 return 0; 920 + } 921 + 922 + static void vdc_requeue_inflight(struct vdc_port *port) 923 + { 924 + struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING]; 925 + u32 idx; 926 + 927 + for (idx = dr->cons; idx != dr->prod; idx = vio_dring_next(dr, idx)) { 928 + struct vio_disk_desc *desc = vio_dring_entry(dr, idx); 929 + struct vdc_req_entry *rqe = &port->rq_arr[idx]; 930 + struct request *req; 931 + 932 + ldc_unmap(port->vio.lp, desc->cookies, desc->ncookies); 933 + desc->hdr.state = VIO_DESC_FREE; 934 + dr->cons = vio_dring_next(dr, idx); 935 + 936 + req = rqe->req; 937 + if (req == NULL) { 938 + vdc_end_special(port, desc); 939 + continue; 940 + } 941 + 942 + rqe->req = NULL; 943 + blk_requeue_request(port->disk->queue, req); 944 + } 945 + } 946 + 947 + static void vdc_queue_drain(struct vdc_port *port) 948 + { 949 + struct request *req; 950 + 951 + while ((req = blk_fetch_request(port->disk->queue)) != NULL) 952 + __blk_end_request_all(req, -EIO); 953 + } 954 + 955 + static void vdc_ldc_reset_timer(unsigned long _arg) 956 + { 957 + struct vdc_port *port = (struct vdc_port *) _arg; 958 + struct vio_driver_state *vio = &port->vio; 959 + unsigned long flags; 960 + 961 + spin_lock_irqsave(&vio->lock, flags); 962 + if (!(port->vio.hs_state & VIO_HS_COMPLETE)) { 963 + pr_warn(PFX "%s ldc down %llu seconds, draining queue\n", 964 + port->disk_name, port->ldc_timeout); 965 + vdc_queue_drain(port); 966 + vdc_blk_queue_start(port); 967 + } 968 + spin_unlock_irqrestore(&vio->lock, flags); 969 + } 970 + 971 + static void vdc_ldc_reset_work(struct work_struct *work) 972 + { 973 + struct vdc_port *port; 974 + struct vio_driver_state *vio; 975 + unsigned long flags; 976 + 977 + port = container_of(work, struct vdc_port, ldc_reset_work); 978 + vio = &port->vio; 979 + 980 + spin_lock_irqsave(&vio->lock, flags); 981 + vdc_ldc_reset(port); 982 + spin_unlock_irqrestore(&vio->lock, flags); 983 + } 984 + 985 + static void vdc_ldc_reset(struct vdc_port *port) 986 + { 987 + int err; 988 + 989 + assert_spin_locked(&port->vio.lock); 990 + 991 + pr_warn(PFX "%s ldc link reset\n", port->disk_name); 992 + blk_stop_queue(port->disk->queue); 993 + vdc_requeue_inflight(port); 994 + vdc_port_down(port); 995 + 996 + err = vio_ldc_alloc(&port->vio, &vdc_ldc_cfg, port); 997 + if (err) { 998 + pr_err(PFX "%s vio_ldc_alloc:%d\n", port->disk_name, err); 999 + return; 1000 + } 1001 + 1002 + err = vdc_alloc_tx_ring(port); 1003 + if (err) { 1004 + pr_err(PFX "%s vio_alloc_tx_ring:%d\n", port->disk_name, err); 1005 + goto err_free_ldc; 1006 + } 1007 + 1008 + if (port->ldc_timeout) 1009 + mod_timer(&port->ldc_reset_timer, 1010 + round_jiffies(jiffies + HZ * port->ldc_timeout)); 1011 + mod_timer(&port->vio.timer, round_jiffies(jiffies + HZ)); 1012 + return; 1013 + 1014 + err_free_ldc: 1015 + vio_ldc_free(&port->vio); 979 1016 } 980 1017 981 1018 static const struct vio_device_id vdc_port_match[] = { ··· 1093 938 { 1094 939 int err; 1095 940 941 + sunvdc_wq = alloc_workqueue("sunvdc", 0, 0); 942 + if (!sunvdc_wq) 943 + return -ENOMEM; 944 + 1096 945 err = register_blkdev(0, VDCBLK_NAME); 1097 946 if (err < 0) 1098 - goto out_err; 947 + goto out_free_wq; 1099 948 1100 949 vdc_major = err; 1101 950 ··· 1113 954 unregister_blkdev(vdc_major, VDCBLK_NAME); 1114 955 vdc_major = 0; 1115 956 1116 - out_err: 957 + out_free_wq: 958 + destroy_workqueue(sunvdc_wq); 1117 959 return err; 1118 960 } 1119 961 ··· 1122 962 { 1123 963 vio_unregister_driver(&vdc_port_driver); 1124 964 unregister_blkdev(vdc_major, VDCBLK_NAME); 965 + destroy_workqueue(sunvdc_wq); 1125 966 } 1126 967 1127 968 module_init(vdc_init);