| .. | .. |
|---|
| 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 | +} |
|---|