diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-16 15:01:03 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-16 15:01:03 -0400 |
commit | 497a5df7bf6ffd136ae21c49d1a01292930d7ca2 (patch) | |
tree | 774215d43cdc9fbd8660086d1801400163dcbd52 /drivers/xen | |
parent | 714d8e7e27197dd39b2550e762a6a6fcf397a471 (diff) | |
parent | 0b97b03d88b40bfbd7ff0e069186a137d9786d43 (diff) |
Merge tag 'stable/for-linus-4.1-rc0-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip
Pull xen features and fixes from David Vrabel:
- use a single source list of hypercalls, generating other tables etc.
at build time.
- add a "Xen PV" APIC driver to support >255 VCPUs in PV guests.
- significant performance improve to guest save/restore/migration.
- scsiback/front save/restore support.
- infrastructure for multi-page xenbus rings.
- misc fixes.
* tag 'stable/for-linus-4.1-rc0-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip:
xen/pci: Try harder to get PXM information for Xen
xenbus_client: Extend interface to support multi-page ring
xen-pciback: also support disabling of bus-mastering and memory-write-invalidate
xen: support suspend/resume in pvscsi frontend
xen: scsiback: add LUN of restored domain
xen-scsiback: define a pr_fmt macro with xen-pvscsi
xen/mce: fix up xen_late_init_mcelog() error handling
xen/privcmd: improve performance of MMAPBATCH_V2
xen: unify foreign GFN map/unmap for auto-xlated physmap guests
x86/xen/apic: WARN with details.
x86/xen: Provide a "Xen PV" APIC driver to support >255 VCPUs
xen/pciback: Don't print scary messages when unsupported by hypervisor.
xen: use generated hypercall symbols in arch/x86/xen/xen-head.S
xen: use generated hypervisor symbols in arch/x86/xen/trace.c
xen: synchronize include/xen/interface/xen.h with xen
xen: build infrastructure for generating hypercall depending symbols
xen: balloon: Use static attribute groups for sysfs entries
xen: pcpu: Use static attribute groups for sysfs entry
Diffstat (limited to 'drivers/xen')
-rw-r--r-- | drivers/xen/Kconfig | 6 | ||||
-rw-r--r-- | drivers/xen/Makefile | 1 | ||||
-rw-r--r-- | drivers/xen/mcelog.c | 25 | ||||
-rw-r--r-- | drivers/xen/pci.c | 15 | ||||
-rw-r--r-- | drivers/xen/pcpu.c | 44 | ||||
-rw-r--r-- | drivers/xen/privcmd.c | 117 | ||||
-rw-r--r-- | drivers/xen/xen-balloon.c | 45 | ||||
-rw-r--r-- | drivers/xen/xen-pciback/conf_space_header.c | 15 | ||||
-rw-r--r-- | drivers/xen/xen-pciback/pci_stub.c | 4 | ||||
-rw-r--r-- | drivers/xen/xen-pciback/xenbus.c | 2 | ||||
-rw-r--r-- | drivers/xen/xen-scsiback.c | 96 | ||||
-rw-r--r-- | drivers/xen/xenbus/xenbus_client.c | 387 | ||||
-rw-r--r-- | drivers/xen/xlate_mmu.c | 143 |
13 files changed, 665 insertions, 235 deletions
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index 94d96809e686..a270004c9605 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig | |||
@@ -270,4 +270,10 @@ config XEN_EFI | |||
270 | def_bool y | 270 | def_bool y |
271 | depends on X86_64 && EFI | 271 | depends on X86_64 && EFI |
272 | 272 | ||
273 | config XEN_AUTO_XLATE | ||
274 | def_bool y | ||
275 | depends on ARM || ARM64 || XEN_PVHVM | ||
276 | help | ||
277 | Support for auto-translated physmap guests. | ||
278 | |||
273 | endmenu | 279 | endmenu |
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index 2ccd3592d41f..40edd1cbb60d 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile | |||
@@ -37,6 +37,7 @@ obj-$(CONFIG_XEN_ACPI_HOTPLUG_CPU) += xen-acpi-cpuhotplug.o | |||
37 | obj-$(CONFIG_XEN_ACPI_PROCESSOR) += xen-acpi-processor.o | 37 | obj-$(CONFIG_XEN_ACPI_PROCESSOR) += xen-acpi-processor.o |
38 | obj-$(CONFIG_XEN_EFI) += efi.o | 38 | obj-$(CONFIG_XEN_EFI) += efi.o |
39 | obj-$(CONFIG_XEN_SCSI_BACKEND) += xen-scsiback.o | 39 | obj-$(CONFIG_XEN_SCSI_BACKEND) += xen-scsiback.o |
40 | obj-$(CONFIG_XEN_AUTO_XLATE) += xlate_mmu.o | ||
40 | xen-evtchn-y := evtchn.o | 41 | xen-evtchn-y := evtchn.o |
41 | xen-gntdev-y := gntdev.o | 42 | xen-gntdev-y := gntdev.o |
42 | xen-gntalloc-y := gntalloc.o | 43 | xen-gntalloc-y := gntalloc.o |
diff --git a/drivers/xen/mcelog.c b/drivers/xen/mcelog.c index 6ab6a79c38a5..a493c7315e94 100644 --- a/drivers/xen/mcelog.c +++ b/drivers/xen/mcelog.c | |||
@@ -393,14 +393,25 @@ static int bind_virq_for_mce(void) | |||
393 | 393 | ||
394 | static int __init xen_late_init_mcelog(void) | 394 | static int __init xen_late_init_mcelog(void) |
395 | { | 395 | { |
396 | int ret; | ||
397 | |||
396 | /* Only DOM0 is responsible for MCE logging */ | 398 | /* Only DOM0 is responsible for MCE logging */ |
397 | if (xen_initial_domain()) { | 399 | if (!xen_initial_domain()) |
398 | /* register character device /dev/mcelog for xen mcelog */ | 400 | return -ENODEV; |
399 | if (misc_register(&xen_mce_chrdev_device)) | 401 | |
400 | return -ENODEV; | 402 | /* register character device /dev/mcelog for xen mcelog */ |
401 | return bind_virq_for_mce(); | 403 | ret = misc_register(&xen_mce_chrdev_device); |
402 | } | 404 | if (ret) |
405 | return ret; | ||
406 | |||
407 | ret = bind_virq_for_mce(); | ||
408 | if (ret) | ||
409 | goto deregister; | ||
403 | 410 | ||
404 | return -ENODEV; | 411 | return 0; |
412 | |||
413 | deregister: | ||
414 | misc_deregister(&xen_mce_chrdev_device); | ||
415 | return ret; | ||
405 | } | 416 | } |
406 | device_initcall(xen_late_init_mcelog); | 417 | device_initcall(xen_late_init_mcelog); |
diff --git a/drivers/xen/pci.c b/drivers/xen/pci.c index 95ee4302ffb8..7494dbeb4409 100644 --- a/drivers/xen/pci.c +++ b/drivers/xen/pci.c | |||
@@ -19,6 +19,7 @@ | |||
19 | 19 | ||
20 | #include <linux/pci.h> | 20 | #include <linux/pci.h> |
21 | #include <linux/acpi.h> | 21 | #include <linux/acpi.h> |
22 | #include <linux/pci-acpi.h> | ||
22 | #include <xen/xen.h> | 23 | #include <xen/xen.h> |
23 | #include <xen/interface/physdev.h> | 24 | #include <xen/interface/physdev.h> |
24 | #include <xen/interface/xen.h> | 25 | #include <xen/interface/xen.h> |
@@ -67,12 +68,22 @@ static int xen_add_device(struct device *dev) | |||
67 | 68 | ||
68 | #ifdef CONFIG_ACPI | 69 | #ifdef CONFIG_ACPI |
69 | handle = ACPI_HANDLE(&pci_dev->dev); | 70 | handle = ACPI_HANDLE(&pci_dev->dev); |
70 | if (!handle && pci_dev->bus->bridge) | ||
71 | handle = ACPI_HANDLE(pci_dev->bus->bridge); | ||
72 | #ifdef CONFIG_PCI_IOV | 71 | #ifdef CONFIG_PCI_IOV |
73 | if (!handle && pci_dev->is_virtfn) | 72 | if (!handle && pci_dev->is_virtfn) |
74 | handle = ACPI_HANDLE(physfn->bus->bridge); | 73 | handle = ACPI_HANDLE(physfn->bus->bridge); |
75 | #endif | 74 | #endif |
75 | if (!handle) { | ||
76 | /* | ||
77 | * This device was not listed in the ACPI name space at | ||
78 | * all. Try to get acpi handle of parent pci bus. | ||
79 | */ | ||
80 | struct pci_bus *pbus; | ||
81 | for (pbus = pci_dev->bus; pbus; pbus = pbus->parent) { | ||
82 | handle = acpi_pci_get_bridge_handle(pbus); | ||
83 | if (handle) | ||
84 | break; | ||
85 | } | ||
86 | } | ||
76 | if (handle) { | 87 | if (handle) { |
77 | acpi_status status; | 88 | acpi_status status; |
78 | 89 | ||
diff --git a/drivers/xen/pcpu.c b/drivers/xen/pcpu.c index 0aac403d53fd..49e88f2ce7a1 100644 --- a/drivers/xen/pcpu.c +++ b/drivers/xen/pcpu.c | |||
@@ -132,6 +132,33 @@ static ssize_t __ref store_online(struct device *dev, | |||
132 | } | 132 | } |
133 | static DEVICE_ATTR(online, S_IRUGO | S_IWUSR, show_online, store_online); | 133 | static DEVICE_ATTR(online, S_IRUGO | S_IWUSR, show_online, store_online); |
134 | 134 | ||
135 | static struct attribute *pcpu_dev_attrs[] = { | ||
136 | &dev_attr_online.attr, | ||
137 | NULL | ||
138 | }; | ||
139 | |||
140 | static umode_t pcpu_dev_is_visible(struct kobject *kobj, | ||
141 | struct attribute *attr, int idx) | ||
142 | { | ||
143 | struct device *dev = kobj_to_dev(kobj); | ||
144 | /* | ||
145 | * Xen never offline cpu0 due to several restrictions | ||
146 | * and assumptions. This basically doesn't add a sys control | ||
147 | * to user, one cannot attempt to offline BSP. | ||
148 | */ | ||
149 | return dev->id ? attr->mode : 0; | ||
150 | } | ||
151 | |||
152 | static const struct attribute_group pcpu_dev_group = { | ||
153 | .attrs = pcpu_dev_attrs, | ||
154 | .is_visible = pcpu_dev_is_visible, | ||
155 | }; | ||
156 | |||
157 | static const struct attribute_group *pcpu_dev_groups[] = { | ||
158 | &pcpu_dev_group, | ||
159 | NULL | ||
160 | }; | ||
161 | |||
135 | static bool xen_pcpu_online(uint32_t flags) | 162 | static bool xen_pcpu_online(uint32_t flags) |
136 | { | 163 | { |
137 | return !!(flags & XEN_PCPU_FLAGS_ONLINE); | 164 | return !!(flags & XEN_PCPU_FLAGS_ONLINE); |
@@ -181,9 +208,6 @@ static void unregister_and_remove_pcpu(struct pcpu *pcpu) | |||
181 | return; | 208 | return; |
182 | 209 | ||
183 | dev = &pcpu->dev; | 210 | dev = &pcpu->dev; |
184 | if (dev->id) | ||
185 | device_remove_file(dev, &dev_attr_online); | ||
186 | |||
187 | /* pcpu remove would be implicitly done */ | 211 | /* pcpu remove would be implicitly done */ |
188 | device_unregister(dev); | 212 | device_unregister(dev); |
189 | } | 213 | } |
@@ -200,6 +224,7 @@ static int register_pcpu(struct pcpu *pcpu) | |||
200 | dev->bus = &xen_pcpu_subsys; | 224 | dev->bus = &xen_pcpu_subsys; |
201 | dev->id = pcpu->cpu_id; | 225 | dev->id = pcpu->cpu_id; |
202 | dev->release = pcpu_release; | 226 | dev->release = pcpu_release; |
227 | dev->groups = pcpu_dev_groups; | ||
203 | 228 | ||
204 | err = device_register(dev); | 229 | err = device_register(dev); |
205 | if (err) { | 230 | if (err) { |
@@ -207,19 +232,6 @@ static int register_pcpu(struct pcpu *pcpu) | |||
207 | return err; | 232 | return err; |
208 | } | 233 | } |
209 | 234 | ||
210 | /* | ||
211 | * Xen never offline cpu0 due to several restrictions | ||
212 | * and assumptions. This basically doesn't add a sys control | ||
213 | * to user, one cannot attempt to offline BSP. | ||
214 | */ | ||
215 | if (dev->id) { | ||
216 | err = device_create_file(dev, &dev_attr_online); | ||
217 | if (err) { | ||
218 | device_unregister(dev); | ||
219 | return err; | ||
220 | } | ||
221 | } | ||
222 | |||
223 | return 0; | 235 | return 0; |
224 | } | 236 | } |
225 | 237 | ||
diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c index 59ac71c4a043..5a296161d843 100644 --- a/drivers/xen/privcmd.c +++ b/drivers/xen/privcmd.c | |||
@@ -159,6 +159,40 @@ static int traverse_pages(unsigned nelem, size_t size, | |||
159 | return ret; | 159 | return ret; |
160 | } | 160 | } |
161 | 161 | ||
162 | /* | ||
163 | * Similar to traverse_pages, but use each page as a "block" of | ||
164 | * data to be processed as one unit. | ||
165 | */ | ||
166 | static int traverse_pages_block(unsigned nelem, size_t size, | ||
167 | struct list_head *pos, | ||
168 | int (*fn)(void *data, int nr, void *state), | ||
169 | void *state) | ||
170 | { | ||
171 | void *pagedata; | ||
172 | unsigned pageidx; | ||
173 | int ret = 0; | ||
174 | |||
175 | BUG_ON(size > PAGE_SIZE); | ||
176 | |||
177 | pageidx = PAGE_SIZE; | ||
178 | |||
179 | while (nelem) { | ||
180 | int nr = (PAGE_SIZE/size); | ||
181 | struct page *page; | ||
182 | if (nr > nelem) | ||
183 | nr = nelem; | ||
184 | pos = pos->next; | ||
185 | page = list_entry(pos, struct page, lru); | ||
186 | pagedata = page_address(page); | ||
187 | ret = (*fn)(pagedata, nr, state); | ||
188 | if (ret) | ||
189 | break; | ||
190 | nelem -= nr; | ||
191 | } | ||
192 | |||
193 | return ret; | ||
194 | } | ||
195 | |||
162 | struct mmap_mfn_state { | 196 | struct mmap_mfn_state { |
163 | unsigned long va; | 197 | unsigned long va; |
164 | struct vm_area_struct *vma; | 198 | struct vm_area_struct *vma; |
@@ -274,39 +308,25 @@ struct mmap_batch_state { | |||
274 | /* auto translated dom0 note: if domU being created is PV, then mfn is | 308 | /* auto translated dom0 note: if domU being created is PV, then mfn is |
275 | * mfn(addr on bus). If it's auto xlated, then mfn is pfn (input to HAP). | 309 | * mfn(addr on bus). If it's auto xlated, then mfn is pfn (input to HAP). |
276 | */ | 310 | */ |
277 | static int mmap_batch_fn(void *data, void *state) | 311 | static int mmap_batch_fn(void *data, int nr, void *state) |
278 | { | 312 | { |
279 | xen_pfn_t *mfnp = data; | 313 | xen_pfn_t *mfnp = data; |
280 | struct mmap_batch_state *st = state; | 314 | struct mmap_batch_state *st = state; |
281 | struct vm_area_struct *vma = st->vma; | 315 | struct vm_area_struct *vma = st->vma; |
282 | struct page **pages = vma->vm_private_data; | 316 | struct page **pages = vma->vm_private_data; |
283 | struct page *cur_page = NULL; | 317 | struct page **cur_pages = NULL; |
284 | int ret; | 318 | int ret; |
285 | 319 | ||
286 | if (xen_feature(XENFEAT_auto_translated_physmap)) | 320 | if (xen_feature(XENFEAT_auto_translated_physmap)) |
287 | cur_page = pages[st->index++]; | 321 | cur_pages = &pages[st->index]; |
288 | 322 | ||
289 | ret = xen_remap_domain_mfn_range(st->vma, st->va & PAGE_MASK, *mfnp, 1, | 323 | BUG_ON(nr < 0); |
290 | st->vma->vm_page_prot, st->domain, | 324 | ret = xen_remap_domain_mfn_array(st->vma, st->va & PAGE_MASK, mfnp, nr, |
291 | &cur_page); | 325 | (int *)mfnp, st->vma->vm_page_prot, |
326 | st->domain, cur_pages); | ||
292 | 327 | ||
293 | /* Store error code for second pass. */ | 328 | /* Adjust the global_error? */ |
294 | if (st->version == 1) { | 329 | if (ret != nr) { |
295 | if (ret < 0) { | ||
296 | /* | ||
297 | * V1 encodes the error codes in the 32bit top nibble of the | ||
298 | * mfn (with its known limitations vis-a-vis 64 bit callers). | ||
299 | */ | ||
300 | *mfnp |= (ret == -ENOENT) ? | ||
301 | PRIVCMD_MMAPBATCH_PAGED_ERROR : | ||
302 | PRIVCMD_MMAPBATCH_MFN_ERROR; | ||
303 | } | ||
304 | } else { /* st->version == 2 */ | ||
305 | *((int *) mfnp) = ret; | ||
306 | } | ||
307 | |||
308 | /* And see if it affects the global_error. */ | ||
309 | if (ret < 0) { | ||
310 | if (ret == -ENOENT) | 330 | if (ret == -ENOENT) |
311 | st->global_error = -ENOENT; | 331 | st->global_error = -ENOENT; |
312 | else { | 332 | else { |
@@ -315,23 +335,35 @@ static int mmap_batch_fn(void *data, void *state) | |||
315 | st->global_error = 1; | 335 | st->global_error = 1; |
316 | } | 336 | } |
317 | } | 337 | } |
318 | st->va += PAGE_SIZE; | 338 | st->va += PAGE_SIZE * nr; |
339 | st->index += nr; | ||
319 | 340 | ||
320 | return 0; | 341 | return 0; |
321 | } | 342 | } |
322 | 343 | ||
323 | static int mmap_return_errors(void *data, void *state) | 344 | static int mmap_return_error(int err, struct mmap_batch_state *st) |
324 | { | 345 | { |
325 | struct mmap_batch_state *st = state; | 346 | int ret; |
326 | 347 | ||
327 | if (st->version == 1) { | 348 | if (st->version == 1) { |
328 | xen_pfn_t mfnp = *((xen_pfn_t *) data); | 349 | if (err) { |
329 | if (mfnp & PRIVCMD_MMAPBATCH_MFN_ERROR) | 350 | xen_pfn_t mfn; |
330 | return __put_user(mfnp, st->user_mfn++); | 351 | |
331 | else | 352 | ret = get_user(mfn, st->user_mfn); |
353 | if (ret < 0) | ||
354 | return ret; | ||
355 | /* | ||
356 | * V1 encodes the error codes in the 32bit top | ||
357 | * nibble of the mfn (with its known | ||
358 | * limitations vis-a-vis 64 bit callers). | ||
359 | */ | ||
360 | mfn |= (err == -ENOENT) ? | ||
361 | PRIVCMD_MMAPBATCH_PAGED_ERROR : | ||
362 | PRIVCMD_MMAPBATCH_MFN_ERROR; | ||
363 | return __put_user(mfn, st->user_mfn++); | ||
364 | } else | ||
332 | st->user_mfn++; | 365 | st->user_mfn++; |
333 | } else { /* st->version == 2 */ | 366 | } else { /* st->version == 2 */ |
334 | int err = *((int *) data); | ||
335 | if (err) | 367 | if (err) |
336 | return __put_user(err, st->user_err++); | 368 | return __put_user(err, st->user_err++); |
337 | else | 369 | else |
@@ -341,6 +373,21 @@ static int mmap_return_errors(void *data, void *state) | |||
341 | return 0; | 373 | return 0; |
342 | } | 374 | } |
343 | 375 | ||
376 | static int mmap_return_errors(void *data, int nr, void *state) | ||
377 | { | ||
378 | struct mmap_batch_state *st = state; | ||
379 | int *errs = data; | ||
380 | int i; | ||
381 | int ret; | ||
382 | |||
383 | for (i = 0; i < nr; i++) { | ||
384 | ret = mmap_return_error(errs[i], st); | ||
385 | if (ret < 0) | ||
386 | return ret; | ||
387 | } | ||
388 | return 0; | ||
389 | } | ||
390 | |||
344 | /* Allocate pfns that are then mapped with gmfns from foreign domid. Update | 391 | /* Allocate pfns that are then mapped with gmfns from foreign domid. Update |
345 | * the vma with the page info to use later. | 392 | * the vma with the page info to use later. |
346 | * Returns: 0 if success, otherwise -errno | 393 | * Returns: 0 if success, otherwise -errno |
@@ -472,8 +519,8 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version) | |||
472 | state.version = version; | 519 | state.version = version; |
473 | 520 | ||
474 | /* mmap_batch_fn guarantees ret == 0 */ | 521 | /* mmap_batch_fn guarantees ret == 0 */ |
475 | BUG_ON(traverse_pages(m.num, sizeof(xen_pfn_t), | 522 | BUG_ON(traverse_pages_block(m.num, sizeof(xen_pfn_t), |
476 | &pagelist, mmap_batch_fn, &state)); | 523 | &pagelist, mmap_batch_fn, &state)); |
477 | 524 | ||
478 | up_write(&mm->mmap_sem); | 525 | up_write(&mm->mmap_sem); |
479 | 526 | ||
@@ -481,8 +528,8 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version) | |||
481 | /* Write back errors in second pass. */ | 528 | /* Write back errors in second pass. */ |
482 | state.user_mfn = (xen_pfn_t *)m.arr; | 529 | state.user_mfn = (xen_pfn_t *)m.arr; |
483 | state.user_err = m.err; | 530 | state.user_err = m.err; |
484 | ret = traverse_pages(m.num, sizeof(xen_pfn_t), | 531 | ret = traverse_pages_block(m.num, sizeof(xen_pfn_t), |
485 | &pagelist, mmap_return_errors, &state); | 532 | &pagelist, mmap_return_errors, &state); |
486 | } else | 533 | } else |
487 | ret = 0; | 534 | ret = 0; |
488 | 535 | ||
diff --git a/drivers/xen/xen-balloon.c b/drivers/xen/xen-balloon.c index e555845d61fa..39e7ef8d3957 100644 --- a/drivers/xen/xen-balloon.c +++ b/drivers/xen/xen-balloon.c | |||
@@ -193,13 +193,18 @@ static DEVICE_ATTR(target, S_IRUGO | S_IWUSR, | |||
193 | show_target, store_target); | 193 | show_target, store_target); |
194 | 194 | ||
195 | 195 | ||
196 | static struct device_attribute *balloon_attrs[] = { | 196 | static struct attribute *balloon_attrs[] = { |
197 | &dev_attr_target_kb, | 197 | &dev_attr_target_kb.attr, |
198 | &dev_attr_target, | 198 | &dev_attr_target.attr, |
199 | &dev_attr_schedule_delay.attr, | 199 | &dev_attr_schedule_delay.attr.attr, |
200 | &dev_attr_max_schedule_delay.attr, | 200 | &dev_attr_max_schedule_delay.attr.attr, |
201 | &dev_attr_retry_count.attr, | 201 | &dev_attr_retry_count.attr.attr, |
202 | &dev_attr_max_retry_count.attr | 202 | &dev_attr_max_retry_count.attr.attr, |
203 | NULL | ||
204 | }; | ||
205 | |||
206 | static const struct attribute_group balloon_group = { | ||
207 | .attrs = balloon_attrs | ||
203 | }; | 208 | }; |
204 | 209 | ||
205 | static struct attribute *balloon_info_attrs[] = { | 210 | static struct attribute *balloon_info_attrs[] = { |
@@ -214,6 +219,12 @@ static const struct attribute_group balloon_info_group = { | |||
214 | .attrs = balloon_info_attrs | 219 | .attrs = balloon_info_attrs |
215 | }; | 220 | }; |
216 | 221 | ||
222 | static const struct attribute_group *balloon_groups[] = { | ||
223 | &balloon_group, | ||
224 | &balloon_info_group, | ||
225 | NULL | ||
226 | }; | ||
227 | |||
217 | static struct bus_type balloon_subsys = { | 228 | static struct bus_type balloon_subsys = { |
218 | .name = BALLOON_CLASS_NAME, | 229 | .name = BALLOON_CLASS_NAME, |
219 | .dev_name = BALLOON_CLASS_NAME, | 230 | .dev_name = BALLOON_CLASS_NAME, |
@@ -221,7 +232,7 @@ static struct bus_type balloon_subsys = { | |||
221 | 232 | ||
222 | static int register_balloon(struct device *dev) | 233 | static int register_balloon(struct device *dev) |
223 | { | 234 | { |
224 | int i, error; | 235 | int error; |
225 | 236 | ||
226 | error = subsys_system_register(&balloon_subsys, NULL); | 237 | error = subsys_system_register(&balloon_subsys, NULL); |
227 | if (error) | 238 | if (error) |
@@ -229,6 +240,7 @@ static int register_balloon(struct device *dev) | |||
229 | 240 | ||
230 | dev->id = 0; | 241 | dev->id = 0; |
231 | dev->bus = &balloon_subsys; | 242 | dev->bus = &balloon_subsys; |
243 | dev->groups = balloon_groups; | ||
232 | 244 | ||
233 | error = device_register(dev); | 245 | error = device_register(dev); |
234 | if (error) { | 246 | if (error) { |
@@ -236,24 +248,7 @@ static int register_balloon(struct device *dev) | |||
236 | return error; | 248 | return error; |
237 | } | 249 | } |
238 | 250 | ||
239 | for (i = 0; i < ARRAY_SIZE(balloon_attrs); i++) { | ||
240 | error = device_create_file(dev, balloon_attrs[i]); | ||
241 | if (error) | ||
242 | goto fail; | ||
243 | } | ||
244 | |||
245 | error = sysfs_create_group(&dev->kobj, &balloon_info_group); | ||
246 | if (error) | ||
247 | goto fail; | ||
248 | |||
249 | return 0; | 251 | return 0; |
250 | |||
251 | fail: | ||
252 | while (--i >= 0) | ||
253 | device_remove_file(dev, balloon_attrs[i]); | ||
254 | device_unregister(dev); | ||
255 | bus_unregister(&balloon_subsys); | ||
256 | return error; | ||
257 | } | 252 | } |
258 | 253 | ||
259 | MODULE_LICENSE("GPL"); | 254 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/xen/xen-pciback/conf_space_header.c b/drivers/xen/xen-pciback/conf_space_header.c index 2d7369391472..c2260a0456c9 100644 --- a/drivers/xen/xen-pciback/conf_space_header.c +++ b/drivers/xen/xen-pciback/conf_space_header.c | |||
@@ -88,9 +88,15 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data) | |||
88 | printk(KERN_DEBUG DRV_NAME ": %s: set bus master\n", | 88 | printk(KERN_DEBUG DRV_NAME ": %s: set bus master\n", |
89 | pci_name(dev)); | 89 | pci_name(dev)); |
90 | pci_set_master(dev); | 90 | pci_set_master(dev); |
91 | } else if (dev->is_busmaster && !is_master_cmd(value)) { | ||
92 | if (unlikely(verbose_request)) | ||
93 | printk(KERN_DEBUG DRV_NAME ": %s: clear bus master\n", | ||
94 | pci_name(dev)); | ||
95 | pci_clear_master(dev); | ||
91 | } | 96 | } |
92 | 97 | ||
93 | if (value & PCI_COMMAND_INVALIDATE) { | 98 | if (!(cmd->val & PCI_COMMAND_INVALIDATE) && |
99 | (value & PCI_COMMAND_INVALIDATE)) { | ||
94 | if (unlikely(verbose_request)) | 100 | if (unlikely(verbose_request)) |
95 | printk(KERN_DEBUG | 101 | printk(KERN_DEBUG |
96 | DRV_NAME ": %s: enable memory-write-invalidate\n", | 102 | DRV_NAME ": %s: enable memory-write-invalidate\n", |
@@ -101,6 +107,13 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data) | |||
101 | pci_name(dev), err); | 107 | pci_name(dev), err); |
102 | value &= ~PCI_COMMAND_INVALIDATE; | 108 | value &= ~PCI_COMMAND_INVALIDATE; |
103 | } | 109 | } |
110 | } else if ((cmd->val & PCI_COMMAND_INVALIDATE) && | ||
111 | !(value & PCI_COMMAND_INVALIDATE)) { | ||
112 | if (unlikely(verbose_request)) | ||
113 | printk(KERN_DEBUG | ||
114 | DRV_NAME ": %s: disable memory-write-invalidate\n", | ||
115 | pci_name(dev)); | ||
116 | pci_clear_mwi(dev); | ||
104 | } | 117 | } |
105 | 118 | ||
106 | cmd->val = value; | 119 | cmd->val = value; |
diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c index cc3cbb4435f8..258b7c325649 100644 --- a/drivers/xen/xen-pciback/pci_stub.c +++ b/drivers/xen/xen-pciback/pci_stub.c | |||
@@ -118,7 +118,7 @@ static void pcistub_device_release(struct kref *kref) | |||
118 | int err = HYPERVISOR_physdev_op(PHYSDEVOP_release_msix, | 118 | int err = HYPERVISOR_physdev_op(PHYSDEVOP_release_msix, |
119 | &ppdev); | 119 | &ppdev); |
120 | 120 | ||
121 | if (err) | 121 | if (err && err != -ENOSYS) |
122 | dev_warn(&dev->dev, "MSI-X release failed (%d)\n", | 122 | dev_warn(&dev->dev, "MSI-X release failed (%d)\n", |
123 | err); | 123 | err); |
124 | } | 124 | } |
@@ -402,7 +402,7 @@ static int pcistub_init_device(struct pci_dev *dev) | |||
402 | }; | 402 | }; |
403 | 403 | ||
404 | err = HYPERVISOR_physdev_op(PHYSDEVOP_prepare_msix, &ppdev); | 404 | err = HYPERVISOR_physdev_op(PHYSDEVOP_prepare_msix, &ppdev); |
405 | if (err) | 405 | if (err && err != -ENOSYS) |
406 | dev_err(&dev->dev, "MSI-X preparation failed (%d)\n", | 406 | dev_err(&dev->dev, "MSI-X preparation failed (%d)\n", |
407 | err); | 407 | err); |
408 | } | 408 | } |
diff --git a/drivers/xen/xen-pciback/xenbus.c b/drivers/xen/xen-pciback/xenbus.c index fe17c80ff4b7..98bc345f296e 100644 --- a/drivers/xen/xen-pciback/xenbus.c +++ b/drivers/xen/xen-pciback/xenbus.c | |||
@@ -113,7 +113,7 @@ static int xen_pcibk_do_attach(struct xen_pcibk_device *pdev, int gnt_ref, | |||
113 | "Attaching to frontend resources - gnt_ref=%d evtchn=%d\n", | 113 | "Attaching to frontend resources - gnt_ref=%d evtchn=%d\n", |
114 | gnt_ref, remote_evtchn); | 114 | gnt_ref, remote_evtchn); |
115 | 115 | ||
116 | err = xenbus_map_ring_valloc(pdev->xdev, gnt_ref, &vaddr); | 116 | err = xenbus_map_ring_valloc(pdev->xdev, &gnt_ref, 1, &vaddr); |
117 | if (err < 0) { | 117 | if (err < 0) { |
118 | xenbus_dev_fatal(pdev->xdev, err, | 118 | xenbus_dev_fatal(pdev->xdev, err, |
119 | "Error mapping other domain page in ours."); | 119 | "Error mapping other domain page in ours."); |
diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c index 42bd55a6c237..07ef38325223 100644 --- a/drivers/xen/xen-scsiback.c +++ b/drivers/xen/xen-scsiback.c | |||
@@ -31,6 +31,8 @@ | |||
31 | * IN THE SOFTWARE. | 31 | * IN THE SOFTWARE. |
32 | */ | 32 | */ |
33 | 33 | ||
34 | #define pr_fmt(fmt) "xen-pvscsi: " fmt | ||
35 | |||
34 | #include <stdarg.h> | 36 | #include <stdarg.h> |
35 | 37 | ||
36 | #include <linux/module.h> | 38 | #include <linux/module.h> |
@@ -69,9 +71,6 @@ | |||
69 | #include <xen/interface/grant_table.h> | 71 | #include <xen/interface/grant_table.h> |
70 | #include <xen/interface/io/vscsiif.h> | 72 | #include <xen/interface/io/vscsiif.h> |
71 | 73 | ||
72 | #define DPRINTK(_f, _a...) \ | ||
73 | pr_debug("(file=%s, line=%d) " _f, __FILE__ , __LINE__ , ## _a) | ||
74 | |||
75 | #define VSCSI_VERSION "v0.1" | 74 | #define VSCSI_VERSION "v0.1" |
76 | #define VSCSI_NAMELEN 32 | 75 | #define VSCSI_NAMELEN 32 |
77 | 76 | ||
@@ -271,7 +270,7 @@ static void scsiback_print_status(char *sense_buffer, int errors, | |||
271 | { | 270 | { |
272 | struct scsiback_tpg *tpg = pending_req->v2p->tpg; | 271 | struct scsiback_tpg *tpg = pending_req->v2p->tpg; |
273 | 272 | ||
274 | pr_err("xen-pvscsi[%s:%d] cmnd[0]=%02x -> st=%02x msg=%02x host=%02x drv=%02x\n", | 273 | pr_err("[%s:%d] cmnd[0]=%02x -> st=%02x msg=%02x host=%02x drv=%02x\n", |
275 | tpg->tport->tport_name, pending_req->v2p->lun, | 274 | tpg->tport->tport_name, pending_req->v2p->lun, |
276 | pending_req->cmnd[0], status_byte(errors), msg_byte(errors), | 275 | pending_req->cmnd[0], status_byte(errors), msg_byte(errors), |
277 | host_byte(errors), driver_byte(errors)); | 276 | host_byte(errors), driver_byte(errors)); |
@@ -427,7 +426,7 @@ static int scsiback_gnttab_data_map_batch(struct gnttab_map_grant_ref *map, | |||
427 | BUG_ON(err); | 426 | BUG_ON(err); |
428 | for (i = 0; i < cnt; i++) { | 427 | for (i = 0; i < cnt; i++) { |
429 | if (unlikely(map[i].status != GNTST_okay)) { | 428 | if (unlikely(map[i].status != GNTST_okay)) { |
430 | pr_err("xen-pvscsi: invalid buffer -- could not remap it\n"); | 429 | pr_err("invalid buffer -- could not remap it\n"); |
431 | map[i].handle = SCSIBACK_INVALID_HANDLE; | 430 | map[i].handle = SCSIBACK_INVALID_HANDLE; |
432 | err = -ENOMEM; | 431 | err = -ENOMEM; |
433 | } else { | 432 | } else { |
@@ -449,7 +448,7 @@ static int scsiback_gnttab_data_map_list(struct vscsibk_pend *pending_req, | |||
449 | for (i = 0; i < cnt; i++) { | 448 | for (i = 0; i < cnt; i++) { |
450 | if (get_free_page(pg + mapcount)) { | 449 | if (get_free_page(pg + mapcount)) { |
451 | put_free_pages(pg, mapcount); | 450 | put_free_pages(pg, mapcount); |
452 | pr_err("xen-pvscsi: no grant page\n"); | 451 | pr_err("no grant page\n"); |
453 | return -ENOMEM; | 452 | return -ENOMEM; |
454 | } | 453 | } |
455 | gnttab_set_map_op(&map[mapcount], vaddr_page(pg[mapcount]), | 454 | gnttab_set_map_op(&map[mapcount], vaddr_page(pg[mapcount]), |
@@ -492,7 +491,7 @@ static int scsiback_gnttab_data_map(struct vscsiif_request *ring_req, | |||
492 | return 0; | 491 | return 0; |
493 | 492 | ||
494 | if (nr_segments > VSCSIIF_SG_TABLESIZE) { | 493 | if (nr_segments > VSCSIIF_SG_TABLESIZE) { |
495 | DPRINTK("xen-pvscsi: invalid parameter nr_seg = %d\n", | 494 | pr_debug("invalid parameter nr_seg = %d\n", |
496 | ring_req->nr_segments); | 495 | ring_req->nr_segments); |
497 | return -EINVAL; | 496 | return -EINVAL; |
498 | } | 497 | } |
@@ -516,13 +515,12 @@ static int scsiback_gnttab_data_map(struct vscsiif_request *ring_req, | |||
516 | nr_segments += n_segs; | 515 | nr_segments += n_segs; |
517 | } | 516 | } |
518 | if (nr_segments > SG_ALL) { | 517 | if (nr_segments > SG_ALL) { |
519 | DPRINTK("xen-pvscsi: invalid nr_seg = %d\n", | 518 | pr_debug("invalid nr_seg = %d\n", nr_segments); |
520 | nr_segments); | ||
521 | return -EINVAL; | 519 | return -EINVAL; |
522 | } | 520 | } |
523 | } | 521 | } |
524 | 522 | ||
525 | /* free of (sgl) in fast_flush_area()*/ | 523 | /* free of (sgl) in fast_flush_area() */ |
526 | pending_req->sgl = kmalloc_array(nr_segments, | 524 | pending_req->sgl = kmalloc_array(nr_segments, |
527 | sizeof(struct scatterlist), GFP_KERNEL); | 525 | sizeof(struct scatterlist), GFP_KERNEL); |
528 | if (!pending_req->sgl) | 526 | if (!pending_req->sgl) |
@@ -679,7 +677,8 @@ static int prepare_pending_reqs(struct vscsibk_info *info, | |||
679 | v2p = scsiback_do_translation(info, &vir); | 677 | v2p = scsiback_do_translation(info, &vir); |
680 | if (!v2p) { | 678 | if (!v2p) { |
681 | pending_req->v2p = NULL; | 679 | pending_req->v2p = NULL; |
682 | DPRINTK("xen-pvscsi: doesn't exist.\n"); | 680 | pr_debug("the v2p of (chn:%d, tgt:%d, lun:%d) doesn't exist.\n", |
681 | vir.chn, vir.tgt, vir.lun); | ||
683 | return -ENODEV; | 682 | return -ENODEV; |
684 | } | 683 | } |
685 | pending_req->v2p = v2p; | 684 | pending_req->v2p = v2p; |
@@ -690,14 +689,14 @@ static int prepare_pending_reqs(struct vscsibk_info *info, | |||
690 | (pending_req->sc_data_direction != DMA_TO_DEVICE) && | 689 | (pending_req->sc_data_direction != DMA_TO_DEVICE) && |
691 | (pending_req->sc_data_direction != DMA_FROM_DEVICE) && | 690 | (pending_req->sc_data_direction != DMA_FROM_DEVICE) && |
692 | (pending_req->sc_data_direction != DMA_NONE)) { | 691 | (pending_req->sc_data_direction != DMA_NONE)) { |
693 | DPRINTK("xen-pvscsi: invalid parameter data_dir = %d\n", | 692 | pr_debug("invalid parameter data_dir = %d\n", |
694 | pending_req->sc_data_direction); | 693 | pending_req->sc_data_direction); |
695 | return -EINVAL; | 694 | return -EINVAL; |
696 | } | 695 | } |
697 | 696 | ||
698 | pending_req->cmd_len = ring_req->cmd_len; | 697 | pending_req->cmd_len = ring_req->cmd_len; |
699 | if (pending_req->cmd_len > VSCSIIF_MAX_COMMAND_SIZE) { | 698 | if (pending_req->cmd_len > VSCSIIF_MAX_COMMAND_SIZE) { |
700 | DPRINTK("xen-pvscsi: invalid parameter cmd_len = %d\n", | 699 | pr_debug("invalid parameter cmd_len = %d\n", |
701 | pending_req->cmd_len); | 700 | pending_req->cmd_len); |
702 | return -EINVAL; | 701 | return -EINVAL; |
703 | } | 702 | } |
@@ -721,7 +720,7 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info) | |||
721 | 720 | ||
722 | if (RING_REQUEST_PROD_OVERFLOW(ring, rp)) { | 721 | if (RING_REQUEST_PROD_OVERFLOW(ring, rp)) { |
723 | rc = ring->rsp_prod_pvt; | 722 | rc = ring->rsp_prod_pvt; |
724 | pr_warn("xen-pvscsi: Dom%d provided bogus ring requests (%#x - %#x = %u). Halting ring processing\n", | 723 | pr_warn("Dom%d provided bogus ring requests (%#x - %#x = %u). Halting ring processing\n", |
725 | info->domid, rp, rc, rp - rc); | 724 | info->domid, rp, rc, rp - rc); |
726 | info->ring_error = 1; | 725 | info->ring_error = 1; |
727 | return 0; | 726 | return 0; |
@@ -772,7 +771,7 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info) | |||
772 | scsiback_device_action(pending_req, TMR_LUN_RESET, 0); | 771 | scsiback_device_action(pending_req, TMR_LUN_RESET, 0); |
773 | break; | 772 | break; |
774 | default: | 773 | default: |
775 | pr_err_ratelimited("xen-pvscsi: invalid request\n"); | 774 | pr_err_ratelimited("invalid request\n"); |
776 | scsiback_do_resp_with_sense(NULL, DRIVER_ERROR << 24, | 775 | scsiback_do_resp_with_sense(NULL, DRIVER_ERROR << 24, |
777 | 0, pending_req); | 776 | 0, pending_req); |
778 | kmem_cache_free(scsiback_cachep, pending_req); | 777 | kmem_cache_free(scsiback_cachep, pending_req); |
@@ -810,7 +809,7 @@ static int scsiback_init_sring(struct vscsibk_info *info, grant_ref_t ring_ref, | |||
810 | if (info->irq) | 809 | if (info->irq) |
811 | return -1; | 810 | return -1; |
812 | 811 | ||
813 | err = xenbus_map_ring_valloc(info->dev, ring_ref, &area); | 812 | err = xenbus_map_ring_valloc(info->dev, &ring_ref, 1, &area); |
814 | if (err) | 813 | if (err) |
815 | return err; | 814 | return err; |
816 | 815 | ||
@@ -874,14 +873,13 @@ static int scsiback_add_translation_entry(struct vscsibk_info *info, | |||
874 | 873 | ||
875 | lunp = strrchr(phy, ':'); | 874 | lunp = strrchr(phy, ':'); |
876 | if (!lunp) { | 875 | if (!lunp) { |
877 | pr_err("xen-pvscsi: illegal format of physical device %s\n", | 876 | pr_err("illegal format of physical device %s\n", phy); |
878 | phy); | ||
879 | return -EINVAL; | 877 | return -EINVAL; |
880 | } | 878 | } |
881 | *lunp = 0; | 879 | *lunp = 0; |
882 | lunp++; | 880 | lunp++; |
883 | if (kstrtouint(lunp, 10, &lun) || lun >= TRANSPORT_MAX_LUNS_PER_TPG) { | 881 | if (kstrtouint(lunp, 10, &lun) || lun >= TRANSPORT_MAX_LUNS_PER_TPG) { |
884 | pr_err("xen-pvscsi: lun number not valid: %s\n", lunp); | 882 | pr_err("lun number not valid: %s\n", lunp); |
885 | return -EINVAL; | 883 | return -EINVAL; |
886 | } | 884 | } |
887 | 885 | ||
@@ -909,7 +907,7 @@ static int scsiback_add_translation_entry(struct vscsibk_info *info, | |||
909 | mutex_unlock(&scsiback_mutex); | 907 | mutex_unlock(&scsiback_mutex); |
910 | 908 | ||
911 | if (!tpg) { | 909 | if (!tpg) { |
912 | pr_err("xen-pvscsi: %s:%d %s\n", phy, lun, error); | 910 | pr_err("%s:%d %s\n", phy, lun, error); |
913 | return -ENODEV; | 911 | return -ENODEV; |
914 | } | 912 | } |
915 | 913 | ||
@@ -926,7 +924,7 @@ static int scsiback_add_translation_entry(struct vscsibk_info *info, | |||
926 | if ((entry->v.chn == v->chn) && | 924 | if ((entry->v.chn == v->chn) && |
927 | (entry->v.tgt == v->tgt) && | 925 | (entry->v.tgt == v->tgt) && |
928 | (entry->v.lun == v->lun)) { | 926 | (entry->v.lun == v->lun)) { |
929 | pr_warn("xen-pvscsi: Virtual ID is already used. Assignment was not performed.\n"); | 927 | pr_warn("Virtual ID is already used. Assignment was not performed.\n"); |
930 | err = -EEXIST; | 928 | err = -EEXIST; |
931 | goto out; | 929 | goto out; |
932 | } | 930 | } |
@@ -992,15 +990,15 @@ found: | |||
992 | } | 990 | } |
993 | 991 | ||
994 | static void scsiback_do_add_lun(struct vscsibk_info *info, const char *state, | 992 | static void scsiback_do_add_lun(struct vscsibk_info *info, const char *state, |
995 | char *phy, struct ids_tuple *vir) | 993 | char *phy, struct ids_tuple *vir, int try) |
996 | { | 994 | { |
997 | if (!scsiback_add_translation_entry(info, phy, vir)) { | 995 | if (!scsiback_add_translation_entry(info, phy, vir)) { |
998 | if (xenbus_printf(XBT_NIL, info->dev->nodename, state, | 996 | if (xenbus_printf(XBT_NIL, info->dev->nodename, state, |
999 | "%d", XenbusStateInitialised)) { | 997 | "%d", XenbusStateInitialised)) { |
1000 | pr_err("xen-pvscsi: xenbus_printf error %s\n", state); | 998 | pr_err("xenbus_printf error %s\n", state); |
1001 | scsiback_del_translation_entry(info, vir); | 999 | scsiback_del_translation_entry(info, vir); |
1002 | } | 1000 | } |
1003 | } else { | 1001 | } else if (!try) { |
1004 | xenbus_printf(XBT_NIL, info->dev->nodename, state, | 1002 | xenbus_printf(XBT_NIL, info->dev->nodename, state, |
1005 | "%d", XenbusStateClosed); | 1003 | "%d", XenbusStateClosed); |
1006 | } | 1004 | } |
@@ -1012,7 +1010,7 @@ static void scsiback_do_del_lun(struct vscsibk_info *info, const char *state, | |||
1012 | if (!scsiback_del_translation_entry(info, vir)) { | 1010 | if (!scsiback_del_translation_entry(info, vir)) { |
1013 | if (xenbus_printf(XBT_NIL, info->dev->nodename, state, | 1011 | if (xenbus_printf(XBT_NIL, info->dev->nodename, state, |
1014 | "%d", XenbusStateClosed)) | 1012 | "%d", XenbusStateClosed)) |
1015 | pr_err("xen-pvscsi: xenbus_printf error %s\n", state); | 1013 | pr_err("xenbus_printf error %s\n", state); |
1016 | } | 1014 | } |
1017 | } | 1015 | } |
1018 | 1016 | ||
@@ -1060,10 +1058,19 @@ static void scsiback_do_1lun_hotplug(struct vscsibk_info *info, int op, | |||
1060 | 1058 | ||
1061 | switch (op) { | 1059 | switch (op) { |
1062 | case VSCSIBACK_OP_ADD_OR_DEL_LUN: | 1060 | case VSCSIBACK_OP_ADD_OR_DEL_LUN: |
1063 | if (device_state == XenbusStateInitialising) | 1061 | switch (device_state) { |
1064 | scsiback_do_add_lun(info, state, phy, &vir); | 1062 | case XenbusStateInitialising: |
1065 | if (device_state == XenbusStateClosing) | 1063 | scsiback_do_add_lun(info, state, phy, &vir, 0); |
1064 | break; | ||
1065 | case XenbusStateConnected: | ||
1066 | scsiback_do_add_lun(info, state, phy, &vir, 1); | ||
1067 | break; | ||
1068 | case XenbusStateClosing: | ||
1066 | scsiback_do_del_lun(info, state, &vir); | 1069 | scsiback_do_del_lun(info, state, &vir); |
1070 | break; | ||
1071 | default: | ||
1072 | break; | ||
1073 | } | ||
1067 | break; | 1074 | break; |
1068 | 1075 | ||
1069 | case VSCSIBACK_OP_UPDATEDEV_STATE: | 1076 | case VSCSIBACK_OP_UPDATEDEV_STATE: |
@@ -1071,15 +1078,14 @@ static void scsiback_do_1lun_hotplug(struct vscsibk_info *info, int op, | |||
1071 | /* modify vscsi-devs/dev-x/state */ | 1078 | /* modify vscsi-devs/dev-x/state */ |
1072 | if (xenbus_printf(XBT_NIL, dev->nodename, state, | 1079 | if (xenbus_printf(XBT_NIL, dev->nodename, state, |
1073 | "%d", XenbusStateConnected)) { | 1080 | "%d", XenbusStateConnected)) { |
1074 | pr_err("xen-pvscsi: xenbus_printf error %s\n", | 1081 | pr_err("xenbus_printf error %s\n", str); |
1075 | str); | ||
1076 | scsiback_del_translation_entry(info, &vir); | 1082 | scsiback_del_translation_entry(info, &vir); |
1077 | xenbus_printf(XBT_NIL, dev->nodename, state, | 1083 | xenbus_printf(XBT_NIL, dev->nodename, state, |
1078 | "%d", XenbusStateClosed); | 1084 | "%d", XenbusStateClosed); |
1079 | } | 1085 | } |
1080 | } | 1086 | } |
1081 | break; | 1087 | break; |
1082 | /*When it is necessary, processing is added here.*/ | 1088 | /* When it is necessary, processing is added here. */ |
1083 | default: | 1089 | default: |
1084 | break; | 1090 | break; |
1085 | } | 1091 | } |
@@ -1196,7 +1202,7 @@ static int scsiback_probe(struct xenbus_device *dev, | |||
1196 | struct vscsibk_info *info = kzalloc(sizeof(struct vscsibk_info), | 1202 | struct vscsibk_info *info = kzalloc(sizeof(struct vscsibk_info), |
1197 | GFP_KERNEL); | 1203 | GFP_KERNEL); |
1198 | 1204 | ||
1199 | DPRINTK("%p %d\n", dev, dev->otherend_id); | 1205 | pr_debug("%s %p %d\n", __func__, dev, dev->otherend_id); |
1200 | 1206 | ||
1201 | if (!info) { | 1207 | if (!info) { |
1202 | xenbus_dev_fatal(dev, -ENOMEM, "allocating backend structure"); | 1208 | xenbus_dev_fatal(dev, -ENOMEM, "allocating backend structure"); |
@@ -1227,7 +1233,7 @@ static int scsiback_probe(struct xenbus_device *dev, | |||
1227 | return 0; | 1233 | return 0; |
1228 | 1234 | ||
1229 | fail: | 1235 | fail: |
1230 | pr_warn("xen-pvscsi: %s failed\n", __func__); | 1236 | pr_warn("%s failed\n", __func__); |
1231 | scsiback_remove(dev); | 1237 | scsiback_remove(dev); |
1232 | 1238 | ||
1233 | return err; | 1239 | return err; |
@@ -1432,7 +1438,7 @@ check_len: | |||
1432 | } | 1438 | } |
1433 | snprintf(&tport->tport_name[0], VSCSI_NAMELEN, "%s", &name[off]); | 1439 | snprintf(&tport->tport_name[0], VSCSI_NAMELEN, "%s", &name[off]); |
1434 | 1440 | ||
1435 | pr_debug("xen-pvscsi: Allocated emulated Target %s Address: %s\n", | 1441 | pr_debug("Allocated emulated Target %s Address: %s\n", |
1436 | scsiback_dump_proto_id(tport), name); | 1442 | scsiback_dump_proto_id(tport), name); |
1437 | 1443 | ||
1438 | return &tport->tport_wwn; | 1444 | return &tport->tport_wwn; |
@@ -1443,7 +1449,7 @@ static void scsiback_drop_tport(struct se_wwn *wwn) | |||
1443 | struct scsiback_tport *tport = container_of(wwn, | 1449 | struct scsiback_tport *tport = container_of(wwn, |
1444 | struct scsiback_tport, tport_wwn); | 1450 | struct scsiback_tport, tport_wwn); |
1445 | 1451 | ||
1446 | pr_debug("xen-pvscsi: Deallocating emulated Target %s Address: %s\n", | 1452 | pr_debug("Deallocating emulated Target %s Address: %s\n", |
1447 | scsiback_dump_proto_id(tport), tport->tport_name); | 1453 | scsiback_dump_proto_id(tport), tport->tport_name); |
1448 | 1454 | ||
1449 | kfree(tport); | 1455 | kfree(tport); |
@@ -1470,8 +1476,8 @@ static u32 scsiback_tpg_get_inst_index(struct se_portal_group *se_tpg) | |||
1470 | static int scsiback_check_stop_free(struct se_cmd *se_cmd) | 1476 | static int scsiback_check_stop_free(struct se_cmd *se_cmd) |
1471 | { | 1477 | { |
1472 | /* | 1478 | /* |
1473 | * Do not release struct se_cmd's containing a valid TMR | 1479 | * Do not release struct se_cmd's containing a valid TMR pointer. |
1474 | * pointer. These will be released directly in scsiback_device_action() | 1480 | * These will be released directly in scsiback_device_action() |
1475 | * with transport_generic_free_cmd(). | 1481 | * with transport_generic_free_cmd(). |
1476 | */ | 1482 | */ |
1477 | if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) | 1483 | if (se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB) |
@@ -1637,7 +1643,7 @@ static int scsiback_make_nexus(struct scsiback_tpg *tpg, | |||
1637 | return -ENOMEM; | 1643 | return -ENOMEM; |
1638 | } | 1644 | } |
1639 | /* | 1645 | /* |
1640 | * Initialize the struct se_session pointer | 1646 | * Initialize the struct se_session pointer |
1641 | */ | 1647 | */ |
1642 | tv_nexus->tvn_se_sess = transport_init_session(TARGET_PROT_NORMAL); | 1648 | tv_nexus->tvn_se_sess = transport_init_session(TARGET_PROT_NORMAL); |
1643 | if (IS_ERR(tv_nexus->tvn_se_sess)) { | 1649 | if (IS_ERR(tv_nexus->tvn_se_sess)) { |
@@ -1705,7 +1711,7 @@ static int scsiback_drop_nexus(struct scsiback_tpg *tpg) | |||
1705 | return -EBUSY; | 1711 | return -EBUSY; |
1706 | } | 1712 | } |
1707 | 1713 | ||
1708 | pr_debug("xen-pvscsi: Removing I_T Nexus to emulated %s Initiator Port: %s\n", | 1714 | pr_debug("Removing I_T Nexus to emulated %s Initiator Port: %s\n", |
1709 | scsiback_dump_proto_id(tpg->tport), | 1715 | scsiback_dump_proto_id(tpg->tport), |
1710 | tv_nexus->tvn_se_sess->se_node_acl->initiatorname); | 1716 | tv_nexus->tvn_se_sess->se_node_acl->initiatorname); |
1711 | 1717 | ||
@@ -1751,7 +1757,7 @@ static ssize_t scsiback_tpg_store_nexus(struct se_portal_group *se_tpg, | |||
1751 | unsigned char i_port[VSCSI_NAMELEN], *ptr, *port_ptr; | 1757 | unsigned char i_port[VSCSI_NAMELEN], *ptr, *port_ptr; |
1752 | int ret; | 1758 | int ret; |
1753 | /* | 1759 | /* |
1754 | * Shutdown the active I_T nexus if 'NULL' is passed.. | 1760 | * Shutdown the active I_T nexus if 'NULL' is passed. |
1755 | */ | 1761 | */ |
1756 | if (!strncmp(page, "NULL", 4)) { | 1762 | if (!strncmp(page, "NULL", 4)) { |
1757 | ret = scsiback_drop_nexus(tpg); | 1763 | ret = scsiback_drop_nexus(tpg); |
@@ -1922,7 +1928,7 @@ static void scsiback_drop_tpg(struct se_portal_group *se_tpg) | |||
1922 | */ | 1928 | */ |
1923 | scsiback_drop_nexus(tpg); | 1929 | scsiback_drop_nexus(tpg); |
1924 | /* | 1930 | /* |
1925 | * Deregister the se_tpg from TCM.. | 1931 | * Deregister the se_tpg from TCM. |
1926 | */ | 1932 | */ |
1927 | core_tpg_deregister(se_tpg); | 1933 | core_tpg_deregister(se_tpg); |
1928 | kfree(tpg); | 1934 | kfree(tpg); |
@@ -1992,7 +1998,7 @@ static int scsiback_register_configfs(void) | |||
1992 | struct target_fabric_configfs *fabric; | 1998 | struct target_fabric_configfs *fabric; |
1993 | int ret; | 1999 | int ret; |
1994 | 2000 | ||
1995 | pr_debug("xen-pvscsi: fabric module %s on %s/%s on "UTS_RELEASE"\n", | 2001 | pr_debug("fabric module %s on %s/%s on "UTS_RELEASE"\n", |
1996 | VSCSI_VERSION, utsname()->sysname, utsname()->machine); | 2002 | VSCSI_VERSION, utsname()->sysname, utsname()->machine); |
1997 | /* | 2003 | /* |
1998 | * Register the top level struct config_item_type with TCM core | 2004 | * Register the top level struct config_item_type with TCM core |
@@ -2029,7 +2035,7 @@ static int scsiback_register_configfs(void) | |||
2029 | * Setup our local pointer to *fabric | 2035 | * Setup our local pointer to *fabric |
2030 | */ | 2036 | */ |
2031 | scsiback_fabric_configfs = fabric; | 2037 | scsiback_fabric_configfs = fabric; |
2032 | pr_debug("xen-pvscsi: Set fabric -> scsiback_fabric_configfs\n"); | 2038 | pr_debug("Set fabric -> scsiback_fabric_configfs\n"); |
2033 | return 0; | 2039 | return 0; |
2034 | }; | 2040 | }; |
2035 | 2041 | ||
@@ -2040,7 +2046,7 @@ static void scsiback_deregister_configfs(void) | |||
2040 | 2046 | ||
2041 | target_fabric_configfs_deregister(scsiback_fabric_configfs); | 2047 | target_fabric_configfs_deregister(scsiback_fabric_configfs); |
2042 | scsiback_fabric_configfs = NULL; | 2048 | scsiback_fabric_configfs = NULL; |
2043 | pr_debug("xen-pvscsi: Cleared scsiback_fabric_configfs\n"); | 2049 | pr_debug("Cleared scsiback_fabric_configfs\n"); |
2044 | }; | 2050 | }; |
2045 | 2051 | ||
2046 | static const struct xenbus_device_id scsiback_ids[] = { | 2052 | static const struct xenbus_device_id scsiback_ids[] = { |
@@ -2091,7 +2097,7 @@ out_unregister_xenbus: | |||
2091 | xenbus_unregister_driver(&scsiback_driver); | 2097 | xenbus_unregister_driver(&scsiback_driver); |
2092 | out_cache_destroy: | 2098 | out_cache_destroy: |
2093 | kmem_cache_destroy(scsiback_cachep); | 2099 | kmem_cache_destroy(scsiback_cachep); |
2094 | pr_err("xen-pvscsi: %s: error %d\n", __func__, ret); | 2100 | pr_err("%s: error %d\n", __func__, ret); |
2095 | return ret; | 2101 | return ret; |
2096 | } | 2102 | } |
2097 | 2103 | ||
diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c index ca744102b666..96b2011d25f3 100644 --- a/drivers/xen/xenbus/xenbus_client.c +++ b/drivers/xen/xenbus/xenbus_client.c | |||
@@ -52,17 +52,25 @@ | |||
52 | struct xenbus_map_node { | 52 | struct xenbus_map_node { |
53 | struct list_head next; | 53 | struct list_head next; |
54 | union { | 54 | union { |
55 | struct vm_struct *area; /* PV */ | 55 | struct { |
56 | struct page *page; /* HVM */ | 56 | struct vm_struct *area; |
57 | } pv; | ||
58 | struct { | ||
59 | struct page *pages[XENBUS_MAX_RING_PAGES]; | ||
60 | void *addr; | ||
61 | } hvm; | ||
57 | }; | 62 | }; |
58 | grant_handle_t handle; | 63 | grant_handle_t handles[XENBUS_MAX_RING_PAGES]; |
64 | unsigned int nr_handles; | ||
59 | }; | 65 | }; |
60 | 66 | ||
61 | static DEFINE_SPINLOCK(xenbus_valloc_lock); | 67 | static DEFINE_SPINLOCK(xenbus_valloc_lock); |
62 | static LIST_HEAD(xenbus_valloc_pages); | 68 | static LIST_HEAD(xenbus_valloc_pages); |
63 | 69 | ||
64 | struct xenbus_ring_ops { | 70 | struct xenbus_ring_ops { |
65 | int (*map)(struct xenbus_device *dev, int gnt, void **vaddr); | 71 | int (*map)(struct xenbus_device *dev, |
72 | grant_ref_t *gnt_refs, unsigned int nr_grefs, | ||
73 | void **vaddr); | ||
66 | int (*unmap)(struct xenbus_device *dev, void *vaddr); | 74 | int (*unmap)(struct xenbus_device *dev, void *vaddr); |
67 | }; | 75 | }; |
68 | 76 | ||
@@ -355,17 +363,39 @@ static void xenbus_switch_fatal(struct xenbus_device *dev, int depth, int err, | |||
355 | /** | 363 | /** |
356 | * xenbus_grant_ring | 364 | * xenbus_grant_ring |
357 | * @dev: xenbus device | 365 | * @dev: xenbus device |
358 | * @ring_mfn: mfn of ring to grant | 366 | * @vaddr: starting virtual address of the ring |
359 | 367 | * @nr_pages: number of pages to be granted | |
360 | * Grant access to the given @ring_mfn to the peer of the given device. Return | 368 | * @grefs: grant reference array to be filled in |
361 | * a grant reference on success, or -errno on error. On error, the device will | 369 | * |
362 | * switch to XenbusStateClosing, and the error will be saved in the store. | 370 | * Grant access to the given @vaddr to the peer of the given device. |
371 | * Then fill in @grefs with grant references. Return 0 on success, or | ||
372 | * -errno on error. On error, the device will switch to | ||
373 | * XenbusStateClosing, and the error will be saved in the store. | ||
363 | */ | 374 | */ |
364 | int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn) | 375 | int xenbus_grant_ring(struct xenbus_device *dev, void *vaddr, |
376 | unsigned int nr_pages, grant_ref_t *grefs) | ||
365 | { | 377 | { |
366 | int err = gnttab_grant_foreign_access(dev->otherend_id, ring_mfn, 0); | 378 | int err; |
367 | if (err < 0) | 379 | int i, j; |
368 | xenbus_dev_fatal(dev, err, "granting access to ring page"); | 380 | |
381 | for (i = 0; i < nr_pages; i++) { | ||
382 | unsigned long addr = (unsigned long)vaddr + | ||
383 | (PAGE_SIZE * i); | ||
384 | err = gnttab_grant_foreign_access(dev->otherend_id, | ||
385 | virt_to_mfn(addr), 0); | ||
386 | if (err < 0) { | ||
387 | xenbus_dev_fatal(dev, err, | ||
388 | "granting access to ring page"); | ||
389 | goto fail; | ||
390 | } | ||
391 | grefs[i] = err; | ||
392 | } | ||
393 | |||
394 | return 0; | ||
395 | |||
396 | fail: | ||
397 | for (j = 0; j < i; j++) | ||
398 | gnttab_end_foreign_access_ref(grefs[j], 0); | ||
369 | return err; | 399 | return err; |
370 | } | 400 | } |
371 | EXPORT_SYMBOL_GPL(xenbus_grant_ring); | 401 | EXPORT_SYMBOL_GPL(xenbus_grant_ring); |
@@ -419,62 +449,130 @@ EXPORT_SYMBOL_GPL(xenbus_free_evtchn); | |||
419 | /** | 449 | /** |
420 | * xenbus_map_ring_valloc | 450 | * xenbus_map_ring_valloc |
421 | * @dev: xenbus device | 451 | * @dev: xenbus device |
422 | * @gnt_ref: grant reference | 452 | * @gnt_refs: grant reference array |
453 | * @nr_grefs: number of grant references | ||
423 | * @vaddr: pointer to address to be filled out by mapping | 454 | * @vaddr: pointer to address to be filled out by mapping |
424 | * | 455 | * |
425 | * Based on Rusty Russell's skeleton driver's map_page. | 456 | * Map @nr_grefs pages of memory into this domain from another |
426 | * Map a page of memory into this domain from another domain's grant table. | 457 | * domain's grant table. xenbus_map_ring_valloc allocates @nr_grefs |
427 | * xenbus_map_ring_valloc allocates a page of virtual address space, maps the | 458 | * pages of virtual address space, maps the pages to that address, and |
428 | * page to that address, and sets *vaddr to that address. | 459 | * sets *vaddr to that address. Returns 0 on success, and GNTST_* |
429 | * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h) | 460 | * (see xen/include/interface/grant_table.h) or -ENOMEM / -EINVAL on |
430 | * or -ENOMEM on error. If an error is returned, device will switch to | 461 | * error. If an error is returned, device will switch to |
431 | * XenbusStateClosing and the error message will be saved in XenStore. | 462 | * XenbusStateClosing and the error message will be saved in XenStore. |
432 | */ | 463 | */ |
433 | int xenbus_map_ring_valloc(struct xenbus_device *dev, int gnt_ref, void **vaddr) | 464 | int xenbus_map_ring_valloc(struct xenbus_device *dev, grant_ref_t *gnt_refs, |
465 | unsigned int nr_grefs, void **vaddr) | ||
434 | { | 466 | { |
435 | return ring_ops->map(dev, gnt_ref, vaddr); | 467 | return ring_ops->map(dev, gnt_refs, nr_grefs, vaddr); |
436 | } | 468 | } |
437 | EXPORT_SYMBOL_GPL(xenbus_map_ring_valloc); | 469 | EXPORT_SYMBOL_GPL(xenbus_map_ring_valloc); |
438 | 470 | ||
471 | /* N.B. sizeof(phys_addr_t) doesn't always equal to sizeof(unsigned | ||
472 | * long), e.g. 32-on-64. Caller is responsible for preparing the | ||
473 | * right array to feed into this function */ | ||
474 | static int __xenbus_map_ring(struct xenbus_device *dev, | ||
475 | grant_ref_t *gnt_refs, | ||
476 | unsigned int nr_grefs, | ||
477 | grant_handle_t *handles, | ||
478 | phys_addr_t *addrs, | ||
479 | unsigned int flags, | ||
480 | bool *leaked) | ||
481 | { | ||
482 | struct gnttab_map_grant_ref map[XENBUS_MAX_RING_PAGES]; | ||
483 | struct gnttab_unmap_grant_ref unmap[XENBUS_MAX_RING_PAGES]; | ||
484 | int i, j; | ||
485 | int err = GNTST_okay; | ||
486 | |||
487 | if (nr_grefs > XENBUS_MAX_RING_PAGES) | ||
488 | return -EINVAL; | ||
489 | |||
490 | for (i = 0; i < nr_grefs; i++) { | ||
491 | memset(&map[i], 0, sizeof(map[i])); | ||
492 | gnttab_set_map_op(&map[i], addrs[i], flags, gnt_refs[i], | ||
493 | dev->otherend_id); | ||
494 | handles[i] = INVALID_GRANT_HANDLE; | ||
495 | } | ||
496 | |||
497 | gnttab_batch_map(map, i); | ||
498 | |||
499 | for (i = 0; i < nr_grefs; i++) { | ||
500 | if (map[i].status != GNTST_okay) { | ||
501 | err = map[i].status; | ||
502 | xenbus_dev_fatal(dev, map[i].status, | ||
503 | "mapping in shared page %d from domain %d", | ||
504 | gnt_refs[i], dev->otherend_id); | ||
505 | goto fail; | ||
506 | } else | ||
507 | handles[i] = map[i].handle; | ||
508 | } | ||
509 | |||
510 | return GNTST_okay; | ||
511 | |||
512 | fail: | ||
513 | for (i = j = 0; i < nr_grefs; i++) { | ||
514 | if (handles[i] != INVALID_GRANT_HANDLE) { | ||
515 | memset(&unmap[j], 0, sizeof(unmap[j])); | ||
516 | gnttab_set_unmap_op(&unmap[j], (phys_addr_t)addrs[i], | ||
517 | GNTMAP_host_map, handles[i]); | ||
518 | j++; | ||
519 | } | ||
520 | } | ||
521 | |||
522 | if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap, j)) | ||
523 | BUG(); | ||
524 | |||
525 | *leaked = false; | ||
526 | for (i = 0; i < j; i++) { | ||
527 | if (unmap[i].status != GNTST_okay) { | ||
528 | *leaked = true; | ||
529 | break; | ||
530 | } | ||
531 | } | ||
532 | |||
533 | return err; | ||
534 | } | ||
535 | |||
439 | static int xenbus_map_ring_valloc_pv(struct xenbus_device *dev, | 536 | static int xenbus_map_ring_valloc_pv(struct xenbus_device *dev, |
440 | int gnt_ref, void **vaddr) | 537 | grant_ref_t *gnt_refs, |
538 | unsigned int nr_grefs, | ||
539 | void **vaddr) | ||
441 | { | 540 | { |
442 | struct gnttab_map_grant_ref op = { | ||
443 | .flags = GNTMAP_host_map | GNTMAP_contains_pte, | ||
444 | .ref = gnt_ref, | ||
445 | .dom = dev->otherend_id, | ||
446 | }; | ||
447 | struct xenbus_map_node *node; | 541 | struct xenbus_map_node *node; |
448 | struct vm_struct *area; | 542 | struct vm_struct *area; |
449 | pte_t *pte; | 543 | pte_t *ptes[XENBUS_MAX_RING_PAGES]; |
544 | phys_addr_t phys_addrs[XENBUS_MAX_RING_PAGES]; | ||
545 | int err = GNTST_okay; | ||
546 | int i; | ||
547 | bool leaked; | ||
450 | 548 | ||
451 | *vaddr = NULL; | 549 | *vaddr = NULL; |
452 | 550 | ||
551 | if (nr_grefs > XENBUS_MAX_RING_PAGES) | ||
552 | return -EINVAL; | ||
553 | |||
453 | node = kzalloc(sizeof(*node), GFP_KERNEL); | 554 | node = kzalloc(sizeof(*node), GFP_KERNEL); |
454 | if (!node) | 555 | if (!node) |
455 | return -ENOMEM; | 556 | return -ENOMEM; |
456 | 557 | ||
457 | area = alloc_vm_area(PAGE_SIZE, &pte); | 558 | area = alloc_vm_area(PAGE_SIZE * nr_grefs, ptes); |
458 | if (!area) { | 559 | if (!area) { |
459 | kfree(node); | 560 | kfree(node); |
460 | return -ENOMEM; | 561 | return -ENOMEM; |
461 | } | 562 | } |
462 | 563 | ||
463 | op.host_addr = arbitrary_virt_to_machine(pte).maddr; | 564 | for (i = 0; i < nr_grefs; i++) |
565 | phys_addrs[i] = arbitrary_virt_to_machine(ptes[i]).maddr; | ||
464 | 566 | ||
465 | gnttab_batch_map(&op, 1); | 567 | err = __xenbus_map_ring(dev, gnt_refs, nr_grefs, node->handles, |
466 | 568 | phys_addrs, | |
467 | if (op.status != GNTST_okay) { | 569 | GNTMAP_host_map | GNTMAP_contains_pte, |
468 | free_vm_area(area); | 570 | &leaked); |
469 | kfree(node); | 571 | if (err) |
470 | xenbus_dev_fatal(dev, op.status, | 572 | goto failed; |
471 | "mapping in shared page %d from domain %d", | ||
472 | gnt_ref, dev->otherend_id); | ||
473 | return op.status; | ||
474 | } | ||
475 | 573 | ||
476 | node->handle = op.handle; | 574 | node->nr_handles = nr_grefs; |
477 | node->area = area; | 575 | node->pv.area = area; |
478 | 576 | ||
479 | spin_lock(&xenbus_valloc_lock); | 577 | spin_lock(&xenbus_valloc_lock); |
480 | list_add(&node->next, &xenbus_valloc_pages); | 578 | list_add(&node->next, &xenbus_valloc_pages); |
@@ -482,14 +580,33 @@ static int xenbus_map_ring_valloc_pv(struct xenbus_device *dev, | |||
482 | 580 | ||
483 | *vaddr = area->addr; | 581 | *vaddr = area->addr; |
484 | return 0; | 582 | return 0; |
583 | |||
584 | failed: | ||
585 | if (!leaked) | ||
586 | free_vm_area(area); | ||
587 | else | ||
588 | pr_alert("leaking VM area %p size %u page(s)", area, nr_grefs); | ||
589 | |||
590 | kfree(node); | ||
591 | return err; | ||
485 | } | 592 | } |
486 | 593 | ||
487 | static int xenbus_map_ring_valloc_hvm(struct xenbus_device *dev, | 594 | static int xenbus_map_ring_valloc_hvm(struct xenbus_device *dev, |
488 | int gnt_ref, void **vaddr) | 595 | grant_ref_t *gnt_ref, |
596 | unsigned int nr_grefs, | ||
597 | void **vaddr) | ||
489 | { | 598 | { |
490 | struct xenbus_map_node *node; | 599 | struct xenbus_map_node *node; |
600 | int i; | ||
491 | int err; | 601 | int err; |
492 | void *addr; | 602 | void *addr; |
603 | bool leaked = false; | ||
604 | /* Why do we need two arrays? See comment of __xenbus_map_ring */ | ||
605 | phys_addr_t phys_addrs[XENBUS_MAX_RING_PAGES]; | ||
606 | unsigned long addrs[XENBUS_MAX_RING_PAGES]; | ||
607 | |||
608 | if (nr_grefs > XENBUS_MAX_RING_PAGES) | ||
609 | return -EINVAL; | ||
493 | 610 | ||
494 | *vaddr = NULL; | 611 | *vaddr = NULL; |
495 | 612 | ||
@@ -497,15 +614,32 @@ static int xenbus_map_ring_valloc_hvm(struct xenbus_device *dev, | |||
497 | if (!node) | 614 | if (!node) |
498 | return -ENOMEM; | 615 | return -ENOMEM; |
499 | 616 | ||
500 | err = alloc_xenballooned_pages(1, &node->page, false /* lowmem */); | 617 | err = alloc_xenballooned_pages(nr_grefs, node->hvm.pages, |
618 | false /* lowmem */); | ||
501 | if (err) | 619 | if (err) |
502 | goto out_err; | 620 | goto out_err; |
503 | 621 | ||
504 | addr = pfn_to_kaddr(page_to_pfn(node->page)); | 622 | for (i = 0; i < nr_grefs; i++) { |
623 | unsigned long pfn = page_to_pfn(node->hvm.pages[i]); | ||
624 | phys_addrs[i] = (unsigned long)pfn_to_kaddr(pfn); | ||
625 | addrs[i] = (unsigned long)pfn_to_kaddr(pfn); | ||
626 | } | ||
627 | |||
628 | err = __xenbus_map_ring(dev, gnt_ref, nr_grefs, node->handles, | ||
629 | phys_addrs, GNTMAP_host_map, &leaked); | ||
630 | node->nr_handles = nr_grefs; | ||
505 | 631 | ||
506 | err = xenbus_map_ring(dev, gnt_ref, &node->handle, addr); | ||
507 | if (err) | 632 | if (err) |
508 | goto out_err_free_ballooned_pages; | 633 | goto out_free_ballooned_pages; |
634 | |||
635 | addr = vmap(node->hvm.pages, nr_grefs, VM_MAP | VM_IOREMAP, | ||
636 | PAGE_KERNEL); | ||
637 | if (!addr) { | ||
638 | err = -ENOMEM; | ||
639 | goto out_xenbus_unmap_ring; | ||
640 | } | ||
641 | |||
642 | node->hvm.addr = addr; | ||
509 | 643 | ||
510 | spin_lock(&xenbus_valloc_lock); | 644 | spin_lock(&xenbus_valloc_lock); |
511 | list_add(&node->next, &xenbus_valloc_pages); | 645 | list_add(&node->next, &xenbus_valloc_pages); |
@@ -514,8 +648,16 @@ static int xenbus_map_ring_valloc_hvm(struct xenbus_device *dev, | |||
514 | *vaddr = addr; | 648 | *vaddr = addr; |
515 | return 0; | 649 | return 0; |
516 | 650 | ||
517 | out_err_free_ballooned_pages: | 651 | out_xenbus_unmap_ring: |
518 | free_xenballooned_pages(1, &node->page); | 652 | if (!leaked) |
653 | xenbus_unmap_ring(dev, node->handles, node->nr_handles, | ||
654 | addrs); | ||
655 | else | ||
656 | pr_alert("leaking %p size %u page(s)", | ||
657 | addr, nr_grefs); | ||
658 | out_free_ballooned_pages: | ||
659 | if (!leaked) | ||
660 | free_xenballooned_pages(nr_grefs, node->hvm.pages); | ||
519 | out_err: | 661 | out_err: |
520 | kfree(node); | 662 | kfree(node); |
521 | return err; | 663 | return err; |
@@ -525,35 +667,37 @@ static int xenbus_map_ring_valloc_hvm(struct xenbus_device *dev, | |||
525 | /** | 667 | /** |
526 | * xenbus_map_ring | 668 | * xenbus_map_ring |
527 | * @dev: xenbus device | 669 | * @dev: xenbus device |
528 | * @gnt_ref: grant reference | 670 | * @gnt_refs: grant reference array |
529 | * @handle: pointer to grant handle to be filled | 671 | * @nr_grefs: number of grant reference |
530 | * @vaddr: address to be mapped to | 672 | * @handles: pointer to grant handle to be filled |
673 | * @vaddrs: addresses to be mapped to | ||
674 | * @leaked: fail to clean up a failed map, caller should not free vaddr | ||
531 | * | 675 | * |
532 | * Map a page of memory into this domain from another domain's grant table. | 676 | * Map pages of memory into this domain from another domain's grant table. |
533 | * xenbus_map_ring does not allocate the virtual address space (you must do | 677 | * xenbus_map_ring does not allocate the virtual address space (you must do |
534 | * this yourself!). It only maps in the page to the specified address. | 678 | * this yourself!). It only maps in the pages to the specified address. |
535 | * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h) | 679 | * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h) |
536 | * or -ENOMEM on error. If an error is returned, device will switch to | 680 | * or -ENOMEM / -EINVAL on error. If an error is returned, device will switch to |
537 | * XenbusStateClosing and the error message will be saved in XenStore. | 681 | * XenbusStateClosing and the first error message will be saved in XenStore. |
682 | * Further more if we fail to map the ring, caller should check @leaked. | ||
683 | * If @leaked is not zero it means xenbus_map_ring fails to clean up, caller | ||
684 | * should not free the address space of @vaddr. | ||
538 | */ | 685 | */ |
539 | int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref, | 686 | int xenbus_map_ring(struct xenbus_device *dev, grant_ref_t *gnt_refs, |
540 | grant_handle_t *handle, void *vaddr) | 687 | unsigned int nr_grefs, grant_handle_t *handles, |
688 | unsigned long *vaddrs, bool *leaked) | ||
541 | { | 689 | { |
542 | struct gnttab_map_grant_ref op; | 690 | phys_addr_t phys_addrs[XENBUS_MAX_RING_PAGES]; |
543 | 691 | int i; | |
544 | gnttab_set_map_op(&op, (unsigned long)vaddr, GNTMAP_host_map, gnt_ref, | ||
545 | dev->otherend_id); | ||
546 | 692 | ||
547 | gnttab_batch_map(&op, 1); | 693 | if (nr_grefs > XENBUS_MAX_RING_PAGES) |
694 | return -EINVAL; | ||
548 | 695 | ||
549 | if (op.status != GNTST_okay) { | 696 | for (i = 0; i < nr_grefs; i++) |
550 | xenbus_dev_fatal(dev, op.status, | 697 | phys_addrs[i] = (unsigned long)vaddrs[i]; |
551 | "mapping in shared page %d from domain %d", | ||
552 | gnt_ref, dev->otherend_id); | ||
553 | } else | ||
554 | *handle = op.handle; | ||
555 | 698 | ||
556 | return op.status; | 699 | return __xenbus_map_ring(dev, gnt_refs, nr_grefs, handles, |
700 | phys_addrs, GNTMAP_host_map, leaked); | ||
557 | } | 701 | } |
558 | EXPORT_SYMBOL_GPL(xenbus_map_ring); | 702 | EXPORT_SYMBOL_GPL(xenbus_map_ring); |
559 | 703 | ||
@@ -579,14 +723,15 @@ EXPORT_SYMBOL_GPL(xenbus_unmap_ring_vfree); | |||
579 | static int xenbus_unmap_ring_vfree_pv(struct xenbus_device *dev, void *vaddr) | 723 | static int xenbus_unmap_ring_vfree_pv(struct xenbus_device *dev, void *vaddr) |
580 | { | 724 | { |
581 | struct xenbus_map_node *node; | 725 | struct xenbus_map_node *node; |
582 | struct gnttab_unmap_grant_ref op = { | 726 | struct gnttab_unmap_grant_ref unmap[XENBUS_MAX_RING_PAGES]; |
583 | .host_addr = (unsigned long)vaddr, | ||
584 | }; | ||
585 | unsigned int level; | 727 | unsigned int level; |
728 | int i; | ||
729 | bool leaked = false; | ||
730 | int err; | ||
586 | 731 | ||
587 | spin_lock(&xenbus_valloc_lock); | 732 | spin_lock(&xenbus_valloc_lock); |
588 | list_for_each_entry(node, &xenbus_valloc_pages, next) { | 733 | list_for_each_entry(node, &xenbus_valloc_pages, next) { |
589 | if (node->area->addr == vaddr) { | 734 | if (node->pv.area->addr == vaddr) { |
590 | list_del(&node->next); | 735 | list_del(&node->next); |
591 | goto found; | 736 | goto found; |
592 | } | 737 | } |
@@ -601,22 +746,41 @@ static int xenbus_unmap_ring_vfree_pv(struct xenbus_device *dev, void *vaddr) | |||
601 | return GNTST_bad_virt_addr; | 746 | return GNTST_bad_virt_addr; |
602 | } | 747 | } |
603 | 748 | ||
604 | op.handle = node->handle; | 749 | for (i = 0; i < node->nr_handles; i++) { |
605 | op.host_addr = arbitrary_virt_to_machine( | 750 | unsigned long addr; |
606 | lookup_address((unsigned long)vaddr, &level)).maddr; | 751 | |
752 | memset(&unmap[i], 0, sizeof(unmap[i])); | ||
753 | addr = (unsigned long)vaddr + (PAGE_SIZE * i); | ||
754 | unmap[i].host_addr = arbitrary_virt_to_machine( | ||
755 | lookup_address(addr, &level)).maddr; | ||
756 | unmap[i].dev_bus_addr = 0; | ||
757 | unmap[i].handle = node->handles[i]; | ||
758 | } | ||
607 | 759 | ||
608 | if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1)) | 760 | if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap, i)) |
609 | BUG(); | 761 | BUG(); |
610 | 762 | ||
611 | if (op.status == GNTST_okay) | 763 | err = GNTST_okay; |
612 | free_vm_area(node->area); | 764 | leaked = false; |
765 | for (i = 0; i < node->nr_handles; i++) { | ||
766 | if (unmap[i].status != GNTST_okay) { | ||
767 | leaked = true; | ||
768 | xenbus_dev_error(dev, unmap[i].status, | ||
769 | "unmapping page at handle %d error %d", | ||
770 | node->handles[i], unmap[i].status); | ||
771 | err = unmap[i].status; | ||
772 | break; | ||
773 | } | ||
774 | } | ||
775 | |||
776 | if (!leaked) | ||
777 | free_vm_area(node->pv.area); | ||
613 | else | 778 | else |
614 | xenbus_dev_error(dev, op.status, | 779 | pr_alert("leaking VM area %p size %u page(s)", |
615 | "unmapping page at handle %d error %d", | 780 | node->pv.area, node->nr_handles); |
616 | node->handle, op.status); | ||
617 | 781 | ||
618 | kfree(node); | 782 | kfree(node); |
619 | return op.status; | 783 | return err; |
620 | } | 784 | } |
621 | 785 | ||
622 | static int xenbus_unmap_ring_vfree_hvm(struct xenbus_device *dev, void *vaddr) | 786 | static int xenbus_unmap_ring_vfree_hvm(struct xenbus_device *dev, void *vaddr) |
@@ -624,10 +788,12 @@ static int xenbus_unmap_ring_vfree_hvm(struct xenbus_device *dev, void *vaddr) | |||
624 | int rv; | 788 | int rv; |
625 | struct xenbus_map_node *node; | 789 | struct xenbus_map_node *node; |
626 | void *addr; | 790 | void *addr; |
791 | unsigned long addrs[XENBUS_MAX_RING_PAGES]; | ||
792 | int i; | ||
627 | 793 | ||
628 | spin_lock(&xenbus_valloc_lock); | 794 | spin_lock(&xenbus_valloc_lock); |
629 | list_for_each_entry(node, &xenbus_valloc_pages, next) { | 795 | list_for_each_entry(node, &xenbus_valloc_pages, next) { |
630 | addr = pfn_to_kaddr(page_to_pfn(node->page)); | 796 | addr = node->hvm.addr; |
631 | if (addr == vaddr) { | 797 | if (addr == vaddr) { |
632 | list_del(&node->next); | 798 | list_del(&node->next); |
633 | goto found; | 799 | goto found; |
@@ -643,12 +809,16 @@ static int xenbus_unmap_ring_vfree_hvm(struct xenbus_device *dev, void *vaddr) | |||
643 | return GNTST_bad_virt_addr; | 809 | return GNTST_bad_virt_addr; |
644 | } | 810 | } |
645 | 811 | ||
646 | rv = xenbus_unmap_ring(dev, node->handle, addr); | 812 | for (i = 0; i < node->nr_handles; i++) |
813 | addrs[i] = (unsigned long)pfn_to_kaddr(page_to_pfn(node->hvm.pages[i])); | ||
647 | 814 | ||
815 | rv = xenbus_unmap_ring(dev, node->handles, node->nr_handles, | ||
816 | addrs); | ||
648 | if (!rv) | 817 | if (!rv) |
649 | free_xenballooned_pages(1, &node->page); | 818 | vunmap(vaddr); |
650 | else | 819 | else |
651 | WARN(1, "Leaking %p\n", vaddr); | 820 | WARN(1, "Leaking %p, size %u page(s)\n", vaddr, |
821 | node->nr_handles); | ||
652 | 822 | ||
653 | kfree(node); | 823 | kfree(node); |
654 | return rv; | 824 | return rv; |
@@ -657,29 +827,44 @@ static int xenbus_unmap_ring_vfree_hvm(struct xenbus_device *dev, void *vaddr) | |||
657 | /** | 827 | /** |
658 | * xenbus_unmap_ring | 828 | * xenbus_unmap_ring |
659 | * @dev: xenbus device | 829 | * @dev: xenbus device |
660 | * @handle: grant handle | 830 | * @handles: grant handle array |
661 | * @vaddr: addr to unmap | 831 | * @nr_handles: number of handles in the array |
832 | * @vaddrs: addresses to unmap | ||
662 | * | 833 | * |
663 | * Unmap a page of memory in this domain that was imported from another domain. | 834 | * Unmap memory in this domain that was imported from another domain. |
664 | * Returns 0 on success and returns GNTST_* on error | 835 | * Returns 0 on success and returns GNTST_* on error |
665 | * (see xen/include/interface/grant_table.h). | 836 | * (see xen/include/interface/grant_table.h). |
666 | */ | 837 | */ |
667 | int xenbus_unmap_ring(struct xenbus_device *dev, | 838 | int xenbus_unmap_ring(struct xenbus_device *dev, |
668 | grant_handle_t handle, void *vaddr) | 839 | grant_handle_t *handles, unsigned int nr_handles, |
840 | unsigned long *vaddrs) | ||
669 | { | 841 | { |
670 | struct gnttab_unmap_grant_ref op; | 842 | struct gnttab_unmap_grant_ref unmap[XENBUS_MAX_RING_PAGES]; |
843 | int i; | ||
844 | int err; | ||
671 | 845 | ||
672 | gnttab_set_unmap_op(&op, (unsigned long)vaddr, GNTMAP_host_map, handle); | 846 | if (nr_handles > XENBUS_MAX_RING_PAGES) |
847 | return -EINVAL; | ||
673 | 848 | ||
674 | if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1)) | 849 | for (i = 0; i < nr_handles; i++) |
850 | gnttab_set_unmap_op(&unmap[i], vaddrs[i], | ||
851 | GNTMAP_host_map, handles[i]); | ||
852 | |||
853 | if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap, i)) | ||
675 | BUG(); | 854 | BUG(); |
676 | 855 | ||
677 | if (op.status != GNTST_okay) | 856 | err = GNTST_okay; |
678 | xenbus_dev_error(dev, op.status, | 857 | for (i = 0; i < nr_handles; i++) { |
679 | "unmapping page at handle %d error %d", | 858 | if (unmap[i].status != GNTST_okay) { |
680 | handle, op.status); | 859 | xenbus_dev_error(dev, unmap[i].status, |
860 | "unmapping page at handle %d error %d", | ||
861 | handles[i], unmap[i].status); | ||
862 | err = unmap[i].status; | ||
863 | break; | ||
864 | } | ||
865 | } | ||
681 | 866 | ||
682 | return op.status; | 867 | return err; |
683 | } | 868 | } |
684 | EXPORT_SYMBOL_GPL(xenbus_unmap_ring); | 869 | EXPORT_SYMBOL_GPL(xenbus_unmap_ring); |
685 | 870 | ||
diff --git a/drivers/xen/xlate_mmu.c b/drivers/xen/xlate_mmu.c new file mode 100644 index 000000000000..58a5389aec89 --- /dev/null +++ b/drivers/xen/xlate_mmu.c | |||
@@ -0,0 +1,143 @@ | |||
1 | /* | ||
2 | * MMU operations common to all auto-translated physmap guests. | ||
3 | * | ||
4 | * Copyright (C) 2015 Citrix Systems R&D Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version 2 | ||
8 | * as published by the Free Software Foundation; or, when distributed | ||
9 | * separately from the Linux kernel or incorporated into other | ||
10 | * software packages, subject to the following license: | ||
11 | * | ||
12 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
13 | * of this source file (the "Software"), to deal in the Software without | ||
14 | * restriction, including without limitation the rights to use, copy, modify, | ||
15 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, | ||
16 | * and to permit persons to whom the Software is furnished to do so, subject to | ||
17 | * the following conditions: | ||
18 | * | ||
19 | * The above copyright notice and this permission notice shall be included in | ||
20 | * all copies or substantial portions of the Software. | ||
21 | * | ||
22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
25 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
26 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
27 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
28 | * IN THE SOFTWARE. | ||
29 | */ | ||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/mm.h> | ||
32 | |||
33 | #include <asm/xen/hypercall.h> | ||
34 | #include <asm/xen/hypervisor.h> | ||
35 | |||
36 | #include <xen/xen.h> | ||
37 | #include <xen/page.h> | ||
38 | #include <xen/interface/xen.h> | ||
39 | #include <xen/interface/memory.h> | ||
40 | |||
41 | /* map fgmfn of domid to lpfn in the current domain */ | ||
42 | static int map_foreign_page(unsigned long lpfn, unsigned long fgmfn, | ||
43 | unsigned int domid) | ||
44 | { | ||
45 | int rc; | ||
46 | struct xen_add_to_physmap_range xatp = { | ||
47 | .domid = DOMID_SELF, | ||
48 | .foreign_domid = domid, | ||
49 | .size = 1, | ||
50 | .space = XENMAPSPACE_gmfn_foreign, | ||
51 | }; | ||
52 | xen_ulong_t idx = fgmfn; | ||
53 | xen_pfn_t gpfn = lpfn; | ||
54 | int err = 0; | ||
55 | |||
56 | set_xen_guest_handle(xatp.idxs, &idx); | ||
57 | set_xen_guest_handle(xatp.gpfns, &gpfn); | ||
58 | set_xen_guest_handle(xatp.errs, &err); | ||
59 | |||
60 | rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap_range, &xatp); | ||
61 | return rc < 0 ? rc : err; | ||
62 | } | ||
63 | |||
64 | struct remap_data { | ||
65 | xen_pfn_t *fgmfn; /* foreign domain's gmfn */ | ||
66 | pgprot_t prot; | ||
67 | domid_t domid; | ||
68 | struct vm_area_struct *vma; | ||
69 | int index; | ||
70 | struct page **pages; | ||
71 | struct xen_remap_mfn_info *info; | ||
72 | int *err_ptr; | ||
73 | int mapped; | ||
74 | }; | ||
75 | |||
76 | static int remap_pte_fn(pte_t *ptep, pgtable_t token, unsigned long addr, | ||
77 | void *data) | ||
78 | { | ||
79 | struct remap_data *info = data; | ||
80 | struct page *page = info->pages[info->index++]; | ||
81 | unsigned long pfn = page_to_pfn(page); | ||
82 | pte_t pte = pte_mkspecial(pfn_pte(pfn, info->prot)); | ||
83 | int rc; | ||
84 | |||
85 | rc = map_foreign_page(pfn, *info->fgmfn, info->domid); | ||
86 | *info->err_ptr++ = rc; | ||
87 | if (!rc) { | ||
88 | set_pte_at(info->vma->vm_mm, addr, ptep, pte); | ||
89 | info->mapped++; | ||
90 | } | ||
91 | info->fgmfn++; | ||
92 | |||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | int xen_xlate_remap_gfn_array(struct vm_area_struct *vma, | ||
97 | unsigned long addr, | ||
98 | xen_pfn_t *mfn, int nr, | ||
99 | int *err_ptr, pgprot_t prot, | ||
100 | unsigned domid, | ||
101 | struct page **pages) | ||
102 | { | ||
103 | int err; | ||
104 | struct remap_data data; | ||
105 | unsigned long range = nr << PAGE_SHIFT; | ||
106 | |||
107 | /* Kept here for the purpose of making sure code doesn't break | ||
108 | x86 PVOPS */ | ||
109 | BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_IO)) == (VM_PFNMAP | VM_IO))); | ||
110 | |||
111 | data.fgmfn = mfn; | ||
112 | data.prot = prot; | ||
113 | data.domid = domid; | ||
114 | data.vma = vma; | ||
115 | data.pages = pages; | ||
116 | data.index = 0; | ||
117 | data.err_ptr = err_ptr; | ||
118 | data.mapped = 0; | ||
119 | |||
120 | err = apply_to_page_range(vma->vm_mm, addr, range, | ||
121 | remap_pte_fn, &data); | ||
122 | return err < 0 ? err : data.mapped; | ||
123 | } | ||
124 | EXPORT_SYMBOL_GPL(xen_xlate_remap_gfn_array); | ||
125 | |||
126 | int xen_xlate_unmap_gfn_range(struct vm_area_struct *vma, | ||
127 | int nr, struct page **pages) | ||
128 | { | ||
129 | int i; | ||
130 | |||
131 | for (i = 0; i < nr; i++) { | ||
132 | struct xen_remove_from_physmap xrp; | ||
133 | unsigned long pfn; | ||
134 | |||
135 | pfn = page_to_pfn(pages[i]); | ||
136 | |||
137 | xrp.domid = DOMID_SELF; | ||
138 | xrp.gpfn = pfn; | ||
139 | (void)HYPERVISOR_memory_op(XENMEM_remove_from_physmap, &xrp); | ||
140 | } | ||
141 | return 0; | ||
142 | } | ||
143 | EXPORT_SYMBOL_GPL(xen_xlate_unmap_gfn_range); | ||