.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* Xenbus code for blkif backend |
---|
2 | 3 | Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au> |
---|
3 | 4 | Copyright (C) 2005 XenSource Ltd |
---|
4 | 5 | |
---|
5 | | - This program is free software; you can redistribute it and/or modify |
---|
6 | | - it under the terms of the GNU General Public License as published by |
---|
7 | | - the Free Software Foundation; either version 2 of the License, or |
---|
8 | | - (at your option) any later version. |
---|
9 | | - |
---|
10 | | - This program is distributed in the hope that it will be useful, |
---|
11 | | - but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
12 | | - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
13 | | - GNU General Public License for more details. |
---|
14 | 6 | |
---|
15 | 7 | */ |
---|
16 | 8 | |
---|
.. | .. |
---|
152 | 144 | INIT_LIST_HEAD(&ring->pending_free); |
---|
153 | 145 | INIT_LIST_HEAD(&ring->persistent_purge_list); |
---|
154 | 146 | INIT_WORK(&ring->persistent_purge_work, xen_blkbk_unmap_purged_grants); |
---|
155 | | - spin_lock_init(&ring->free_pages_lock); |
---|
156 | | - INIT_LIST_HEAD(&ring->free_pages); |
---|
| 147 | + gnttab_page_cache_init(&ring->free_pages); |
---|
157 | 148 | |
---|
158 | 149 | spin_lock_init(&ring->pending_free_lock); |
---|
159 | 150 | init_waitqueue_head(&ring->pending_free_wq); |
---|
.. | .. |
---|
165 | 156 | |
---|
166 | 157 | return 0; |
---|
167 | 158 | } |
---|
| 159 | + |
---|
| 160 | +/* Enable the persistent grants feature. */ |
---|
| 161 | +static bool feature_persistent = true; |
---|
| 162 | +module_param(feature_persistent, bool, 0644); |
---|
| 163 | +MODULE_PARM_DESC(feature_persistent, "Enables the persistent grants feature"); |
---|
168 | 164 | |
---|
169 | 165 | static struct xen_blkif *xen_blkif_alloc(domid_t domid) |
---|
170 | 166 | { |
---|
.. | .. |
---|
198 | 194 | { |
---|
199 | 195 | int err; |
---|
200 | 196 | struct xen_blkif *blkif = ring->blkif; |
---|
| 197 | + const struct blkif_common_sring *sring_common; |
---|
| 198 | + RING_IDX rsp_prod, req_prod; |
---|
| 199 | + unsigned int size; |
---|
201 | 200 | |
---|
202 | 201 | /* Already connected through? */ |
---|
203 | 202 | if (ring->irq) |
---|
.. | .. |
---|
208 | 207 | if (err < 0) |
---|
209 | 208 | return err; |
---|
210 | 209 | |
---|
| 210 | + sring_common = (struct blkif_common_sring *)ring->blk_ring; |
---|
| 211 | + rsp_prod = READ_ONCE(sring_common->rsp_prod); |
---|
| 212 | + req_prod = READ_ONCE(sring_common->req_prod); |
---|
| 213 | + |
---|
211 | 214 | switch (blkif->blk_protocol) { |
---|
212 | 215 | case BLKIF_PROTOCOL_NATIVE: |
---|
213 | 216 | { |
---|
214 | | - struct blkif_sring *sring; |
---|
215 | | - sring = (struct blkif_sring *)ring->blk_ring; |
---|
216 | | - BACK_RING_INIT(&ring->blk_rings.native, sring, |
---|
217 | | - XEN_PAGE_SIZE * nr_grefs); |
---|
| 217 | + struct blkif_sring *sring_native = |
---|
| 218 | + (struct blkif_sring *)ring->blk_ring; |
---|
| 219 | + |
---|
| 220 | + BACK_RING_ATTACH(&ring->blk_rings.native, sring_native, |
---|
| 221 | + rsp_prod, XEN_PAGE_SIZE * nr_grefs); |
---|
| 222 | + size = __RING_SIZE(sring_native, XEN_PAGE_SIZE * nr_grefs); |
---|
218 | 223 | break; |
---|
219 | 224 | } |
---|
220 | 225 | case BLKIF_PROTOCOL_X86_32: |
---|
221 | 226 | { |
---|
222 | | - struct blkif_x86_32_sring *sring_x86_32; |
---|
223 | | - sring_x86_32 = (struct blkif_x86_32_sring *)ring->blk_ring; |
---|
224 | | - BACK_RING_INIT(&ring->blk_rings.x86_32, sring_x86_32, |
---|
225 | | - XEN_PAGE_SIZE * nr_grefs); |
---|
| 227 | + struct blkif_x86_32_sring *sring_x86_32 = |
---|
| 228 | + (struct blkif_x86_32_sring *)ring->blk_ring; |
---|
| 229 | + |
---|
| 230 | + BACK_RING_ATTACH(&ring->blk_rings.x86_32, sring_x86_32, |
---|
| 231 | + rsp_prod, XEN_PAGE_SIZE * nr_grefs); |
---|
| 232 | + size = __RING_SIZE(sring_x86_32, XEN_PAGE_SIZE * nr_grefs); |
---|
226 | 233 | break; |
---|
227 | 234 | } |
---|
228 | 235 | case BLKIF_PROTOCOL_X86_64: |
---|
229 | 236 | { |
---|
230 | | - struct blkif_x86_64_sring *sring_x86_64; |
---|
231 | | - sring_x86_64 = (struct blkif_x86_64_sring *)ring->blk_ring; |
---|
232 | | - BACK_RING_INIT(&ring->blk_rings.x86_64, sring_x86_64, |
---|
233 | | - XEN_PAGE_SIZE * nr_grefs); |
---|
| 237 | + struct blkif_x86_64_sring *sring_x86_64 = |
---|
| 238 | + (struct blkif_x86_64_sring *)ring->blk_ring; |
---|
| 239 | + |
---|
| 240 | + BACK_RING_ATTACH(&ring->blk_rings.x86_64, sring_x86_64, |
---|
| 241 | + rsp_prod, XEN_PAGE_SIZE * nr_grefs); |
---|
| 242 | + size = __RING_SIZE(sring_x86_64, XEN_PAGE_SIZE * nr_grefs); |
---|
234 | 243 | break; |
---|
235 | 244 | } |
---|
236 | 245 | default: |
---|
237 | 246 | BUG(); |
---|
238 | 247 | } |
---|
239 | 248 | |
---|
| 249 | + err = -EIO; |
---|
| 250 | + if (req_prod - rsp_prod > size) |
---|
| 251 | + goto fail; |
---|
| 252 | + |
---|
240 | 253 | err = bind_interdomain_evtchn_to_irqhandler_lateeoi(blkif->domid, |
---|
241 | 254 | evtchn, xen_blkif_be_int, 0, "blkif-backend", ring); |
---|
242 | | - if (err < 0) { |
---|
243 | | - xenbus_unmap_ring_vfree(blkif->be->dev, ring->blk_ring); |
---|
244 | | - ring->blk_rings.common.sring = NULL; |
---|
245 | | - return err; |
---|
246 | | - } |
---|
| 255 | + if (err < 0) |
---|
| 256 | + goto fail; |
---|
247 | 257 | ring->irq = err; |
---|
248 | 258 | |
---|
249 | 259 | return 0; |
---|
| 260 | + |
---|
| 261 | +fail: |
---|
| 262 | + xenbus_unmap_ring_vfree(blkif->be->dev, ring->blk_ring); |
---|
| 263 | + ring->blk_rings.common.sring = NULL; |
---|
| 264 | + return err; |
---|
250 | 265 | } |
---|
251 | 266 | |
---|
252 | 267 | static int xen_blkif_disconnect(struct xen_blkif *blkif) |
---|
.. | .. |
---|
307 | 322 | BUG_ON(atomic_read(&ring->persistent_gnt_in_use) != 0); |
---|
308 | 323 | BUG_ON(!list_empty(&ring->persistent_purge_list)); |
---|
309 | 324 | BUG_ON(!RB_EMPTY_ROOT(&ring->persistent_gnts)); |
---|
310 | | - BUG_ON(!list_empty(&ring->free_pages)); |
---|
311 | | - BUG_ON(ring->free_pages_num != 0); |
---|
| 325 | + BUG_ON(ring->free_pages.num_pages != 0); |
---|
312 | 326 | BUG_ON(ring->persistent_gnt_c != 0); |
---|
313 | 327 | WARN_ON(i != (XEN_BLKIF_REQS_PER_PAGE * blkif->nr_ring_pages)); |
---|
314 | 328 | ring->active = false; |
---|
.. | .. |
---|
349 | 363 | return -ENOMEM; |
---|
350 | 364 | |
---|
351 | 365 | return 0; |
---|
| 366 | +} |
---|
| 367 | + |
---|
| 368 | +void xen_blkif_interface_fini(void) |
---|
| 369 | +{ |
---|
| 370 | + kmem_cache_destroy(xen_blkif_cachep); |
---|
| 371 | + xen_blkif_cachep = NULL; |
---|
352 | 372 | } |
---|
353 | 373 | |
---|
354 | 374 | /* |
---|
.. | .. |
---|
450 | 470 | device_remove_file(&dev->dev, &dev_attr_physical_device); |
---|
451 | 471 | } |
---|
452 | 472 | |
---|
453 | | - |
---|
454 | 473 | static void xen_vbd_free(struct xen_vbd *vbd) |
---|
455 | 474 | { |
---|
456 | 475 | if (vbd->bdev) |
---|
.. | .. |
---|
507 | 526 | handle, blkif->domid); |
---|
508 | 527 | return 0; |
---|
509 | 528 | } |
---|
| 529 | + |
---|
510 | 530 | static int xen_blkbk_remove(struct xenbus_device *dev) |
---|
511 | 531 | { |
---|
512 | 532 | struct backend_info *be = dev_get_drvdata(&dev->dev); |
---|
.. | .. |
---|
590 | 610 | if (err) |
---|
591 | 611 | dev_warn(&dev->dev, "writing feature-discard (%d)", err); |
---|
592 | 612 | } |
---|
| 613 | + |
---|
593 | 614 | int xen_blkbk_barrier(struct xenbus_transaction xbt, |
---|
594 | 615 | struct backend_info *be, int state) |
---|
595 | 616 | { |
---|
.. | .. |
---|
674 | 695 | xen_blkbk_remove(dev); |
---|
675 | 696 | return err; |
---|
676 | 697 | } |
---|
677 | | - |
---|
678 | 698 | |
---|
679 | 699 | /* |
---|
680 | 700 | * Callback received when the hotplug scripts have placed the physical-device |
---|
.. | .. |
---|
767 | 787 | } |
---|
768 | 788 | } |
---|
769 | 789 | |
---|
770 | | - |
---|
771 | 790 | /* |
---|
772 | 791 | * Callback received when the frontend's state changes. |
---|
773 | 792 | */ |
---|
.. | .. |
---|
828 | 847 | xenbus_switch_state(dev, XenbusStateClosed); |
---|
829 | 848 | if (xenbus_dev_is_online(dev)) |
---|
830 | 849 | break; |
---|
831 | | - /* fall through */ |
---|
| 850 | + fallthrough; |
---|
832 | 851 | /* if not online */ |
---|
833 | 852 | case XenbusStateUnknown: |
---|
834 | 853 | /* implies xen_blkif_disconnect() via xen_blkbk_remove() */ |
---|
.. | .. |
---|
842 | 861 | } |
---|
843 | 862 | } |
---|
844 | 863 | |
---|
| 864 | +/* Once a memory pressure is detected, squeeze free page pools for a while. */ |
---|
| 865 | +static unsigned int buffer_squeeze_duration_ms = 10; |
---|
| 866 | +module_param_named(buffer_squeeze_duration_ms, |
---|
| 867 | + buffer_squeeze_duration_ms, int, 0644); |
---|
| 868 | +MODULE_PARM_DESC(buffer_squeeze_duration_ms, |
---|
| 869 | +"Duration in ms to squeeze pages buffer when a memory pressure is detected"); |
---|
| 870 | + |
---|
| 871 | +/* |
---|
| 872 | + * Callback received when the memory pressure is detected. |
---|
| 873 | + */ |
---|
| 874 | +static void reclaim_memory(struct xenbus_device *dev) |
---|
| 875 | +{ |
---|
| 876 | + struct backend_info *be = dev_get_drvdata(&dev->dev); |
---|
| 877 | + |
---|
| 878 | + if (!be) |
---|
| 879 | + return; |
---|
| 880 | + be->blkif->buffer_squeeze_end = jiffies + |
---|
| 881 | + msecs_to_jiffies(buffer_squeeze_duration_ms); |
---|
| 882 | +} |
---|
845 | 883 | |
---|
846 | 884 | /* ** Connection ** */ |
---|
847 | | - |
---|
848 | 885 | |
---|
849 | 886 | /* |
---|
850 | 887 | * Write the physical details regarding the block device to the store, and |
---|
.. | .. |
---|
873 | 910 | |
---|
874 | 911 | xen_blkbk_barrier(xbt, be, be->blkif->vbd.flush_support); |
---|
875 | 912 | |
---|
876 | | - err = xenbus_printf(xbt, dev->nodename, "feature-persistent", "%u", 1); |
---|
| 913 | + err = xenbus_printf(xbt, dev->nodename, "feature-persistent", "%u", |
---|
| 914 | + be->blkif->vbd.feature_gnt_persistent_parm); |
---|
877 | 915 | if (err) { |
---|
878 | 916 | xenbus_dev_fatal(dev, err, "writing %s/feature-persistent", |
---|
879 | 917 | dev->nodename); |
---|
.. | .. |
---|
937 | 975 | int err, i, j; |
---|
938 | 976 | struct xen_blkif *blkif = ring->blkif; |
---|
939 | 977 | struct xenbus_device *dev = blkif->be->dev; |
---|
940 | | - unsigned int ring_page_order, nr_grefs, evtchn; |
---|
| 978 | + unsigned int nr_grefs, evtchn; |
---|
941 | 979 | |
---|
942 | 980 | err = xenbus_scanf(XBT_NIL, dir, "event-channel", "%u", |
---|
943 | 981 | &evtchn); |
---|
.. | .. |
---|
947 | 985 | return err; |
---|
948 | 986 | } |
---|
949 | 987 | |
---|
950 | | - err = xenbus_scanf(XBT_NIL, dev->otherend, "ring-page-order", "%u", |
---|
951 | | - &ring_page_order); |
---|
952 | | - if (err != 1) { |
---|
953 | | - err = xenbus_scanf(XBT_NIL, dir, "ring-ref", "%u", &ring_ref[0]); |
---|
| 988 | + nr_grefs = blkif->nr_ring_pages; |
---|
| 989 | + |
---|
| 990 | + if (unlikely(!nr_grefs)) { |
---|
| 991 | + WARN_ON(true); |
---|
| 992 | + return -EINVAL; |
---|
| 993 | + } |
---|
| 994 | + |
---|
| 995 | + for (i = 0; i < nr_grefs; i++) { |
---|
| 996 | + char ring_ref_name[RINGREF_NAME_LEN]; |
---|
| 997 | + |
---|
| 998 | + if (blkif->multi_ref) |
---|
| 999 | + snprintf(ring_ref_name, RINGREF_NAME_LEN, "ring-ref%u", i); |
---|
| 1000 | + else { |
---|
| 1001 | + WARN_ON(i != 0); |
---|
| 1002 | + snprintf(ring_ref_name, RINGREF_NAME_LEN, "ring-ref"); |
---|
| 1003 | + } |
---|
| 1004 | + |
---|
| 1005 | + err = xenbus_scanf(XBT_NIL, dir, ring_ref_name, |
---|
| 1006 | + "%u", &ring_ref[i]); |
---|
| 1007 | + |
---|
954 | 1008 | if (err != 1) { |
---|
955 | 1009 | err = -EINVAL; |
---|
956 | | - xenbus_dev_fatal(dev, err, "reading %s/ring-ref", dir); |
---|
| 1010 | + xenbus_dev_fatal(dev, err, "reading %s/%s", |
---|
| 1011 | + dir, ring_ref_name); |
---|
957 | 1012 | return err; |
---|
958 | | - } |
---|
959 | | - nr_grefs = 1; |
---|
960 | | - } else { |
---|
961 | | - unsigned int i; |
---|
962 | | - |
---|
963 | | - if (ring_page_order > xen_blkif_max_ring_order) { |
---|
964 | | - err = -EINVAL; |
---|
965 | | - xenbus_dev_fatal(dev, err, "%s/request %d ring page order exceed max:%d", |
---|
966 | | - dir, ring_page_order, |
---|
967 | | - xen_blkif_max_ring_order); |
---|
968 | | - return err; |
---|
969 | | - } |
---|
970 | | - |
---|
971 | | - nr_grefs = 1 << ring_page_order; |
---|
972 | | - for (i = 0; i < nr_grefs; i++) { |
---|
973 | | - char ring_ref_name[RINGREF_NAME_LEN]; |
---|
974 | | - |
---|
975 | | - snprintf(ring_ref_name, RINGREF_NAME_LEN, "ring-ref%u", i); |
---|
976 | | - err = xenbus_scanf(XBT_NIL, dir, ring_ref_name, |
---|
977 | | - "%u", &ring_ref[i]); |
---|
978 | | - if (err != 1) { |
---|
979 | | - err = -EINVAL; |
---|
980 | | - xenbus_dev_fatal(dev, err, "reading %s/%s", |
---|
981 | | - dir, ring_ref_name); |
---|
982 | | - return err; |
---|
983 | | - } |
---|
984 | 1013 | } |
---|
985 | 1014 | } |
---|
986 | | - blkif->nr_ring_pages = nr_grefs; |
---|
987 | 1015 | |
---|
988 | 1016 | err = -ENOMEM; |
---|
989 | 1017 | for (i = 0; i < nr_grefs * XEN_BLKIF_REQS_PER_PAGE; i++) { |
---|
.. | .. |
---|
1034 | 1062 | static int connect_ring(struct backend_info *be) |
---|
1035 | 1063 | { |
---|
1036 | 1064 | struct xenbus_device *dev = be->dev; |
---|
1037 | | - unsigned int pers_grants; |
---|
| 1065 | + struct xen_blkif *blkif = be->blkif; |
---|
1038 | 1066 | char protocol[64] = ""; |
---|
1039 | 1067 | int err, i; |
---|
1040 | 1068 | char *xspath; |
---|
1041 | 1069 | size_t xspathsize; |
---|
1042 | 1070 | const size_t xenstore_path_ext_size = 11; /* sufficient for "/queue-NNN" */ |
---|
1043 | 1071 | unsigned int requested_num_queues = 0; |
---|
| 1072 | + unsigned int ring_page_order; |
---|
1044 | 1073 | |
---|
1045 | 1074 | pr_debug("%s %s\n", __func__, dev->otherend); |
---|
1046 | 1075 | |
---|
1047 | | - be->blkif->blk_protocol = BLKIF_PROTOCOL_DEFAULT; |
---|
| 1076 | + blkif->blk_protocol = BLKIF_PROTOCOL_DEFAULT; |
---|
1048 | 1077 | err = xenbus_scanf(XBT_NIL, dev->otherend, "protocol", |
---|
1049 | 1078 | "%63s", protocol); |
---|
1050 | 1079 | if (err <= 0) |
---|
1051 | 1080 | strcpy(protocol, "unspecified, assuming default"); |
---|
1052 | 1081 | else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_NATIVE)) |
---|
1053 | | - be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE; |
---|
| 1082 | + blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE; |
---|
1054 | 1083 | else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_32)) |
---|
1055 | | - be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_32; |
---|
| 1084 | + blkif->blk_protocol = BLKIF_PROTOCOL_X86_32; |
---|
1056 | 1085 | else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_64)) |
---|
1057 | | - be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_64; |
---|
| 1086 | + blkif->blk_protocol = BLKIF_PROTOCOL_X86_64; |
---|
1058 | 1087 | else { |
---|
1059 | 1088 | xenbus_dev_fatal(dev, err, "unknown fe protocol %s", protocol); |
---|
1060 | 1089 | return -ENOSYS; |
---|
1061 | 1090 | } |
---|
1062 | | - pers_grants = xenbus_read_unsigned(dev->otherend, "feature-persistent", |
---|
1063 | | - 0); |
---|
1064 | | - be->blkif->vbd.feature_gnt_persistent = pers_grants; |
---|
1065 | | - be->blkif->vbd.overflow_max_grants = 0; |
---|
| 1091 | + |
---|
| 1092 | + blkif->vbd.feature_gnt_persistent_parm = feature_persistent; |
---|
| 1093 | + blkif->vbd.feature_gnt_persistent = |
---|
| 1094 | + blkif->vbd.feature_gnt_persistent_parm && |
---|
| 1095 | + xenbus_read_unsigned(dev->otherend, "feature-persistent", 0); |
---|
| 1096 | + |
---|
| 1097 | + blkif->vbd.overflow_max_grants = 0; |
---|
1066 | 1098 | |
---|
1067 | 1099 | /* |
---|
1068 | 1100 | * Read the number of hardware queues from frontend. |
---|
.. | .. |
---|
1078 | 1110 | requested_num_queues, xenblk_max_queues); |
---|
1079 | 1111 | return -ENOSYS; |
---|
1080 | 1112 | } |
---|
1081 | | - be->blkif->nr_rings = requested_num_queues; |
---|
1082 | | - if (xen_blkif_alloc_rings(be->blkif)) |
---|
| 1113 | + blkif->nr_rings = requested_num_queues; |
---|
| 1114 | + if (xen_blkif_alloc_rings(blkif)) |
---|
1083 | 1115 | return -ENOMEM; |
---|
1084 | 1116 | |
---|
1085 | 1117 | pr_info("%s: using %d queues, protocol %d (%s) %s\n", dev->nodename, |
---|
1086 | | - be->blkif->nr_rings, be->blkif->blk_protocol, protocol, |
---|
1087 | | - pers_grants ? "persistent grants" : ""); |
---|
| 1118 | + blkif->nr_rings, blkif->blk_protocol, protocol, |
---|
| 1119 | + blkif->vbd.feature_gnt_persistent ? "persistent grants" : ""); |
---|
1088 | 1120 | |
---|
1089 | | - if (be->blkif->nr_rings == 1) |
---|
1090 | | - return read_per_ring_refs(&be->blkif->rings[0], dev->otherend); |
---|
| 1121 | + err = xenbus_scanf(XBT_NIL, dev->otherend, "ring-page-order", "%u", |
---|
| 1122 | + &ring_page_order); |
---|
| 1123 | + if (err != 1) { |
---|
| 1124 | + blkif->nr_ring_pages = 1; |
---|
| 1125 | + blkif->multi_ref = false; |
---|
| 1126 | + } else if (ring_page_order <= xen_blkif_max_ring_order) { |
---|
| 1127 | + blkif->nr_ring_pages = 1 << ring_page_order; |
---|
| 1128 | + blkif->multi_ref = true; |
---|
| 1129 | + } else { |
---|
| 1130 | + err = -EINVAL; |
---|
| 1131 | + xenbus_dev_fatal(dev, err, |
---|
| 1132 | + "requested ring page order %d exceed max:%d", |
---|
| 1133 | + ring_page_order, |
---|
| 1134 | + xen_blkif_max_ring_order); |
---|
| 1135 | + return err; |
---|
| 1136 | + } |
---|
| 1137 | + |
---|
| 1138 | + if (blkif->nr_rings == 1) |
---|
| 1139 | + return read_per_ring_refs(&blkif->rings[0], dev->otherend); |
---|
1091 | 1140 | else { |
---|
1092 | 1141 | xspathsize = strlen(dev->otherend) + xenstore_path_ext_size; |
---|
1093 | 1142 | xspath = kmalloc(xspathsize, GFP_KERNEL); |
---|
.. | .. |
---|
1096 | 1145 | return -ENOMEM; |
---|
1097 | 1146 | } |
---|
1098 | 1147 | |
---|
1099 | | - for (i = 0; i < be->blkif->nr_rings; i++) { |
---|
| 1148 | + for (i = 0; i < blkif->nr_rings; i++) { |
---|
1100 | 1149 | memset(xspath, 0, xspathsize); |
---|
1101 | 1150 | snprintf(xspath, xspathsize, "%s/queue-%u", dev->otherend, i); |
---|
1102 | | - err = read_per_ring_refs(&be->blkif->rings[i], xspath); |
---|
| 1151 | + err = read_per_ring_refs(&blkif->rings[i], xspath); |
---|
1103 | 1152 | if (err) { |
---|
1104 | 1153 | kfree(xspath); |
---|
1105 | 1154 | return err; |
---|
.. | .. |
---|
1119 | 1168 | .ids = xen_blkbk_ids, |
---|
1120 | 1169 | .probe = xen_blkbk_probe, |
---|
1121 | 1170 | .remove = xen_blkbk_remove, |
---|
1122 | | - .otherend_changed = frontend_changed |
---|
| 1171 | + .otherend_changed = frontend_changed, |
---|
| 1172 | + .allow_rebind = true, |
---|
| 1173 | + .reclaim_memory = reclaim_memory, |
---|
1123 | 1174 | }; |
---|
1124 | 1175 | |
---|
1125 | 1176 | int xen_blkif_xenbus_init(void) |
---|
1126 | 1177 | { |
---|
1127 | 1178 | return xenbus_register_backend(&xen_blkbk_driver); |
---|
1128 | 1179 | } |
---|
| 1180 | + |
---|
| 1181 | +void xen_blkif_xenbus_fini(void) |
---|
| 1182 | +{ |
---|
| 1183 | + xenbus_unregister_driver(&xen_blkbk_driver); |
---|
| 1184 | +} |
---|