diff options
Diffstat (limited to 'drivers/block/xen-blkback/xenbus.c')
-rw-r--r-- | drivers/block/xen-blkback/xenbus.c | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index 04608a6502d7..fe5c3cd10c34 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c | |||
@@ -98,12 +98,17 @@ static void xen_update_blkif_status(struct xen_blkif *blkif) | |||
98 | err = PTR_ERR(blkif->xenblkd); | 98 | err = PTR_ERR(blkif->xenblkd); |
99 | blkif->xenblkd = NULL; | 99 | blkif->xenblkd = NULL; |
100 | xenbus_dev_error(blkif->be->dev, err, "start xenblkd"); | 100 | xenbus_dev_error(blkif->be->dev, err, "start xenblkd"); |
101 | return; | ||
101 | } | 102 | } |
102 | } | 103 | } |
103 | 104 | ||
104 | static struct xen_blkif *xen_blkif_alloc(domid_t domid) | 105 | static struct xen_blkif *xen_blkif_alloc(domid_t domid) |
105 | { | 106 | { |
106 | struct xen_blkif *blkif; | 107 | struct xen_blkif *blkif; |
108 | struct pending_req *req, *n; | ||
109 | int i, j; | ||
110 | |||
111 | BUILD_BUG_ON(MAX_INDIRECT_PAGES > BLKIF_MAX_INDIRECT_PAGES_PER_REQUEST); | ||
107 | 112 | ||
108 | blkif = kmem_cache_zalloc(xen_blkif_cachep, GFP_KERNEL); | 113 | blkif = kmem_cache_zalloc(xen_blkif_cachep, GFP_KERNEL); |
109 | if (!blkif) | 114 | if (!blkif) |
@@ -118,8 +123,57 @@ static struct xen_blkif *xen_blkif_alloc(domid_t domid) | |||
118 | blkif->st_print = jiffies; | 123 | blkif->st_print = jiffies; |
119 | init_waitqueue_head(&blkif->waiting_to_free); | 124 | init_waitqueue_head(&blkif->waiting_to_free); |
120 | blkif->persistent_gnts.rb_node = NULL; | 125 | blkif->persistent_gnts.rb_node = NULL; |
126 | spin_lock_init(&blkif->free_pages_lock); | ||
127 | INIT_LIST_HEAD(&blkif->free_pages); | ||
128 | blkif->free_pages_num = 0; | ||
129 | atomic_set(&blkif->persistent_gnt_in_use, 0); | ||
130 | |||
131 | INIT_LIST_HEAD(&blkif->pending_free); | ||
132 | |||
133 | for (i = 0; i < XEN_BLKIF_REQS; i++) { | ||
134 | req = kzalloc(sizeof(*req), GFP_KERNEL); | ||
135 | if (!req) | ||
136 | goto fail; | ||
137 | list_add_tail(&req->free_list, | ||
138 | &blkif->pending_free); | ||
139 | for (j = 0; j < MAX_INDIRECT_SEGMENTS; j++) { | ||
140 | req->segments[j] = kzalloc(sizeof(*req->segments[0]), | ||
141 | GFP_KERNEL); | ||
142 | if (!req->segments[j]) | ||
143 | goto fail; | ||
144 | } | ||
145 | for (j = 0; j < MAX_INDIRECT_PAGES; j++) { | ||
146 | req->indirect_pages[j] = kzalloc(sizeof(*req->indirect_pages[0]), | ||
147 | GFP_KERNEL); | ||
148 | if (!req->indirect_pages[j]) | ||
149 | goto fail; | ||
150 | } | ||
151 | } | ||
152 | spin_lock_init(&blkif->pending_free_lock); | ||
153 | init_waitqueue_head(&blkif->pending_free_wq); | ||
154 | init_waitqueue_head(&blkif->shutdown_wq); | ||
121 | 155 | ||
122 | return blkif; | 156 | return blkif; |
157 | |||
158 | fail: | ||
159 | list_for_each_entry_safe(req, n, &blkif->pending_free, free_list) { | ||
160 | list_del(&req->free_list); | ||
161 | for (j = 0; j < MAX_INDIRECT_SEGMENTS; j++) { | ||
162 | if (!req->segments[j]) | ||
163 | break; | ||
164 | kfree(req->segments[j]); | ||
165 | } | ||
166 | for (j = 0; j < MAX_INDIRECT_PAGES; j++) { | ||
167 | if (!req->indirect_pages[j]) | ||
168 | break; | ||
169 | kfree(req->indirect_pages[j]); | ||
170 | } | ||
171 | kfree(req); | ||
172 | } | ||
173 | |||
174 | kmem_cache_free(xen_blkif_cachep, blkif); | ||
175 | |||
176 | return ERR_PTR(-ENOMEM); | ||
123 | } | 177 | } |
124 | 178 | ||
125 | static int xen_blkif_map(struct xen_blkif *blkif, unsigned long shared_page, | 179 | static int xen_blkif_map(struct xen_blkif *blkif, unsigned long shared_page, |
@@ -178,6 +232,7 @@ static void xen_blkif_disconnect(struct xen_blkif *blkif) | |||
178 | { | 232 | { |
179 | if (blkif->xenblkd) { | 233 | if (blkif->xenblkd) { |
180 | kthread_stop(blkif->xenblkd); | 234 | kthread_stop(blkif->xenblkd); |
235 | wake_up(&blkif->shutdown_wq); | ||
181 | blkif->xenblkd = NULL; | 236 | blkif->xenblkd = NULL; |
182 | } | 237 | } |
183 | 238 | ||
@@ -198,8 +253,28 @@ static void xen_blkif_disconnect(struct xen_blkif *blkif) | |||
198 | 253 | ||
199 | static void xen_blkif_free(struct xen_blkif *blkif) | 254 | static void xen_blkif_free(struct xen_blkif *blkif) |
200 | { | 255 | { |
256 | struct pending_req *req, *n; | ||
257 | int i = 0, j; | ||
258 | |||
201 | if (!atomic_dec_and_test(&blkif->refcnt)) | 259 | if (!atomic_dec_and_test(&blkif->refcnt)) |
202 | BUG(); | 260 | BUG(); |
261 | |||
262 | /* Check that there is no request in use */ | ||
263 | list_for_each_entry_safe(req, n, &blkif->pending_free, free_list) { | ||
264 | list_del(&req->free_list); | ||
265 | |||
266 | for (j = 0; j < MAX_INDIRECT_SEGMENTS; j++) | ||
267 | kfree(req->segments[j]); | ||
268 | |||
269 | for (j = 0; j < MAX_INDIRECT_PAGES; j++) | ||
270 | kfree(req->indirect_pages[j]); | ||
271 | |||
272 | kfree(req); | ||
273 | i++; | ||
274 | } | ||
275 | |||
276 | WARN_ON(i != XEN_BLKIF_REQS); | ||
277 | |||
203 | kmem_cache_free(xen_blkif_cachep, blkif); | 278 | kmem_cache_free(xen_blkif_cachep, blkif); |
204 | } | 279 | } |
205 | 280 | ||
@@ -678,6 +753,11 @@ again: | |||
678 | dev->nodename); | 753 | dev->nodename); |
679 | goto abort; | 754 | goto abort; |
680 | } | 755 | } |
756 | err = xenbus_printf(xbt, dev->nodename, "feature-max-indirect-segments", "%u", | ||
757 | MAX_INDIRECT_SEGMENTS); | ||
758 | if (err) | ||
759 | dev_warn(&dev->dev, "writing %s/feature-max-indirect-segments (%d)", | ||
760 | dev->nodename, err); | ||
681 | 761 | ||
682 | err = xenbus_printf(xbt, dev->nodename, "sectors", "%llu", | 762 | err = xenbus_printf(xbt, dev->nodename, "sectors", "%llu", |
683 | (unsigned long long)vbd_sz(&be->blkif->vbd)); | 763 | (unsigned long long)vbd_sz(&be->blkif->vbd)); |
@@ -704,6 +784,11 @@ again: | |||
704 | dev->nodename); | 784 | dev->nodename); |
705 | goto abort; | 785 | goto abort; |
706 | } | 786 | } |
787 | err = xenbus_printf(xbt, dev->nodename, "physical-sector-size", "%u", | ||
788 | bdev_physical_block_size(be->blkif->vbd.bdev)); | ||
789 | if (err) | ||
790 | xenbus_dev_error(dev, err, "writing %s/physical-sector-size", | ||
791 | dev->nodename); | ||
707 | 792 | ||
708 | err = xenbus_transaction_end(xbt, 0); | 793 | err = xenbus_transaction_end(xbt, 0); |
709 | if (err == -EAGAIN) | 794 | if (err == -EAGAIN) |