diff options
Diffstat (limited to 'drivers/block/xen-blkback/xenbus.c')
-rw-r--r-- | drivers/block/xen-blkback/xenbus.c | 74 |
1 files changed, 57 insertions, 17 deletions
diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index afab208c54e3..4a4749c78942 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c | |||
@@ -105,7 +105,8 @@ static void xen_update_blkif_status(struct xen_blkif *blkif) | |||
105 | static struct xen_blkif *xen_blkif_alloc(domid_t domid) | 105 | static struct xen_blkif *xen_blkif_alloc(domid_t domid) |
106 | { | 106 | { |
107 | struct xen_blkif *blkif; | 107 | struct xen_blkif *blkif; |
108 | int i; | 108 | struct pending_req *req, *n; |
109 | int i, j; | ||
109 | 110 | ||
110 | BUILD_BUG_ON(MAX_INDIRECT_PAGES > BLKIF_MAX_INDIRECT_PAGES_PER_REQUEST); | 111 | BUILD_BUG_ON(MAX_INDIRECT_PAGES > BLKIF_MAX_INDIRECT_PAGES_PER_REQUEST); |
111 | 112 | ||
@@ -127,22 +128,51 @@ static struct xen_blkif *xen_blkif_alloc(domid_t domid) | |||
127 | blkif->free_pages_num = 0; | 128 | blkif->free_pages_num = 0; |
128 | atomic_set(&blkif->persistent_gnt_in_use, 0); | 129 | atomic_set(&blkif->persistent_gnt_in_use, 0); |
129 | 130 | ||
130 | blkif->pending_reqs = kcalloc(XEN_BLKIF_REQS, | ||
131 | sizeof(blkif->pending_reqs[0]), | ||
132 | GFP_KERNEL); | ||
133 | if (!blkif->pending_reqs) { | ||
134 | kmem_cache_free(xen_blkif_cachep, blkif); | ||
135 | return ERR_PTR(-ENOMEM); | ||
136 | } | ||
137 | INIT_LIST_HEAD(&blkif->pending_free); | 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 | } | ||
138 | spin_lock_init(&blkif->pending_free_lock); | 152 | spin_lock_init(&blkif->pending_free_lock); |
139 | init_waitqueue_head(&blkif->pending_free_wq); | 153 | init_waitqueue_head(&blkif->pending_free_wq); |
140 | 154 | ||
141 | for (i = 0; i < XEN_BLKIF_REQS; i++) | ||
142 | list_add_tail(&blkif->pending_reqs[i].free_list, | ||
143 | &blkif->pending_free); | ||
144 | |||
145 | return blkif; | 155 | return blkif; |
156 | |||
157 | fail: | ||
158 | list_for_each_entry_safe(req, n, &blkif->pending_free, free_list) { | ||
159 | list_del(&req->free_list); | ||
160 | for (j = 0; j < MAX_INDIRECT_SEGMENTS; j++) { | ||
161 | if (!req->segments[j]) | ||
162 | break; | ||
163 | kfree(req->segments[j]); | ||
164 | } | ||
165 | for (j = 0; j < MAX_INDIRECT_PAGES; j++) { | ||
166 | if (!req->indirect_pages[j]) | ||
167 | break; | ||
168 | kfree(req->indirect_pages[j]); | ||
169 | } | ||
170 | kfree(req); | ||
171 | } | ||
172 | |||
173 | kmem_cache_free(xen_blkif_cachep, blkif); | ||
174 | |||
175 | return ERR_PTR(-ENOMEM); | ||
146 | } | 176 | } |
147 | 177 | ||
148 | static int xen_blkif_map(struct xen_blkif *blkif, unsigned long shared_page, | 178 | static int xen_blkif_map(struct xen_blkif *blkif, unsigned long shared_page, |
@@ -221,18 +251,28 @@ static void xen_blkif_disconnect(struct xen_blkif *blkif) | |||
221 | 251 | ||
222 | static void xen_blkif_free(struct xen_blkif *blkif) | 252 | static void xen_blkif_free(struct xen_blkif *blkif) |
223 | { | 253 | { |
224 | struct pending_req *req; | 254 | struct pending_req *req, *n; |
225 | int i = 0; | 255 | int i = 0, j; |
226 | 256 | ||
227 | if (!atomic_dec_and_test(&blkif->refcnt)) | 257 | if (!atomic_dec_and_test(&blkif->refcnt)) |
228 | BUG(); | 258 | BUG(); |
229 | 259 | ||
230 | /* Check that there is no request in use */ | 260 | /* Check that there is no request in use */ |
231 | list_for_each_entry(req, &blkif->pending_free, free_list) | 261 | list_for_each_entry_safe(req, n, &blkif->pending_free, free_list) { |
262 | list_del(&req->free_list); | ||
263 | |||
264 | for (j = 0; j < MAX_INDIRECT_SEGMENTS; j++) | ||
265 | kfree(req->segments[j]); | ||
266 | |||
267 | for (j = 0; j < MAX_INDIRECT_PAGES; j++) | ||
268 | kfree(req->indirect_pages[j]); | ||
269 | |||
270 | kfree(req); | ||
232 | i++; | 271 | i++; |
233 | BUG_ON(i != XEN_BLKIF_REQS); | 272 | } |
273 | |||
274 | WARN_ON(i != XEN_BLKIF_REQS); | ||
234 | 275 | ||
235 | kfree(blkif->pending_reqs); | ||
236 | kmem_cache_free(xen_blkif_cachep, blkif); | 276 | kmem_cache_free(xen_blkif_cachep, blkif); |
237 | } | 277 | } |
238 | 278 | ||