ia64/xen-unstable

view xen/common/grant_table.c @ 15647:cc48264ed647

Merge
author Tim Deegan <Tim.Deegan@xensource.com>
date Tue Jul 24 14:53:06 2007 +0100 (2007-07-24)
parents 3c28bc13a3f8
children 96f64f4c42f0
line source
1 /******************************************************************************
2 * common/grant_table.c
3 *
4 * Mechanism for granting foreign access to page frames, and receiving
5 * page-ownership transfers.
6 *
7 * Copyright (c) 2005-2006 Christopher Clark
8 * Copyright (c) 2004 K A Fraser
9 * Copyright (c) 2005 Andrew Warfield
10 * Modifications by Geoffrey Lefebvre are (c) Intel Research Cambridge
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
27 #include <xen/config.h>
28 #include <xen/iocap.h>
29 #include <xen/lib.h>
30 #include <xen/sched.h>
31 #include <xen/mm.h>
32 #include <xen/trace.h>
33 #include <xen/guest_access.h>
34 #include <xen/domain_page.h>
35 #include <acm/acm_hooks.h>
37 #ifndef max_nr_grant_frames
38 unsigned int max_nr_grant_frames = DEFAULT_MAX_NR_GRANT_FRAMES;
39 integer_param("gnttab_max_nr_frames", max_nr_grant_frames);
40 #endif
42 /* The maximum number of grant mappings is defined as a multiplier of the
43 * maximum number of grant table entries. This defines the multiplier used.
44 * Pretty arbitrary. [POLICY]
45 */
46 #define MAX_MAPTRACK_TO_GRANTS_RATIO 8
48 /*
49 * The first two members of a grant entry are updated as a combined pair.
50 * The following union allows that to happen in an endian-neutral fashion.
51 */
52 union grant_combo {
53 uint32_t word;
54 struct {
55 uint16_t flags;
56 domid_t domid;
57 } shorts;
58 };
60 /* Used to share code between unmap_grant_ref and unmap_and_replace. */
61 struct gnttab_unmap_common {
62 uint64_t host_addr;
63 uint64_t dev_bus_addr;
64 uint64_t new_addr;
65 grant_handle_t handle;
67 int16_t status;
68 };
70 #define PIN_FAIL(_lbl, _rc, _f, _a...) \
71 do { \
72 gdprintk(XENLOG_WARNING, _f, ## _a ); \
73 rc = (_rc); \
74 goto _lbl; \
75 } while ( 0 )
77 #define MAPTRACK_PER_PAGE (PAGE_SIZE / sizeof(struct grant_mapping))
78 #define maptrack_entry(t, e) \
79 ((t)->maptrack[(e)/MAPTRACK_PER_PAGE][(e)%MAPTRACK_PER_PAGE])
81 static inline unsigned int
82 nr_maptrack_frames(struct grant_table *t)
83 {
84 return t->maptrack_limit / MAPTRACK_PER_PAGE;
85 }
87 static unsigned inline int max_nr_maptrack_frames(void)
88 {
89 return (max_nr_grant_frames * MAX_MAPTRACK_TO_GRANTS_RATIO);
90 }
93 #define SHGNT_PER_PAGE (PAGE_SIZE / sizeof(grant_entry_t))
94 #define shared_entry(t, e) \
95 ((t)->shared[(e)/SHGNT_PER_PAGE][(e)%SHGNT_PER_PAGE])
96 #define ACGNT_PER_PAGE (PAGE_SIZE / sizeof(struct active_grant_entry))
97 #define active_entry(t, e) \
98 ((t)->active[(e)/ACGNT_PER_PAGE][(e)%ACGNT_PER_PAGE])
100 static inline int
101 __get_maptrack_handle(
102 struct grant_table *t)
103 {
104 unsigned int h;
105 if ( unlikely((h = t->maptrack_head) == (t->maptrack_limit - 1)) )
106 return -1;
107 t->maptrack_head = maptrack_entry(t, h).ref;
108 t->map_count++;
109 return h;
110 }
112 static inline void
113 put_maptrack_handle(
114 struct grant_table *t, int handle)
115 {
116 maptrack_entry(t, handle).ref = t->maptrack_head;
117 t->maptrack_head = handle;
118 t->map_count--;
119 }
121 static inline int
122 get_maptrack_handle(
123 struct grant_table *lgt)
124 {
125 int i;
126 grant_handle_t handle;
127 struct grant_mapping *new_mt;
128 unsigned int new_mt_limit, nr_frames;
130 if ( unlikely((handle = __get_maptrack_handle(lgt)) == -1) )
131 {
132 spin_lock(&lgt->lock);
134 if ( unlikely((handle = __get_maptrack_handle(lgt)) == -1) )
135 {
136 nr_frames = nr_maptrack_frames(lgt);
137 if ( nr_frames >= max_nr_maptrack_frames() )
138 {
139 spin_unlock(&lgt->lock);
140 return -1;
141 }
143 new_mt = alloc_xenheap_page();
144 if ( new_mt == NULL )
145 {
146 spin_unlock(&lgt->lock);
147 return -1;
148 }
150 clear_page(new_mt);
152 new_mt_limit = lgt->maptrack_limit + MAPTRACK_PER_PAGE;
154 for ( i = lgt->maptrack_limit; i < new_mt_limit; i++ )
155 {
156 new_mt[i % MAPTRACK_PER_PAGE].ref = i+1;
157 new_mt[i % MAPTRACK_PER_PAGE].flags = 0;
158 }
160 lgt->maptrack[nr_frames] = new_mt;
161 lgt->maptrack_limit = new_mt_limit;
163 gdprintk(XENLOG_INFO,
164 "Increased maptrack size to %u frames.\n", nr_frames + 1);
165 handle = __get_maptrack_handle(lgt);
166 }
168 spin_unlock(&lgt->lock);
169 }
170 return handle;
171 }
173 /*
174 * Returns 0 if TLB flush / invalidate required by caller.
175 * va will indicate the address to be invalidated.
176 *
177 * addr is _either_ a host virtual address, or the address of the pte to
178 * update, as indicated by the GNTMAP_contains_pte flag.
179 */
180 static void
181 __gnttab_map_grant_ref(
182 struct gnttab_map_grant_ref *op)
183 {
184 struct domain *ld, *rd;
185 struct vcpu *led;
186 int handle;
187 unsigned long frame = 0;
188 int rc = GNTST_okay;
189 struct active_grant_entry *act;
190 struct grant_mapping *mt;
191 grant_entry_t *sha;
192 union grant_combo scombo, prev_scombo, new_scombo;
194 /*
195 * We bound the number of times we retry CMPXCHG on memory locations that
196 * we share with a guest OS. The reason is that the guest can modify that
197 * location at a higher rate than we can read-modify-CMPXCHG, so the guest
198 * could cause us to livelock. There are a few cases where it is valid for
199 * the guest to race our updates (e.g., to change the GTF_readonly flag),
200 * so we allow a few retries before failing.
201 */
202 int retries = 0;
204 led = current;
205 ld = led->domain;
207 if ( unlikely((op->flags & (GNTMAP_device_map|GNTMAP_host_map)) == 0) )
208 {
209 gdprintk(XENLOG_INFO, "Bad flags in grant map op (%x).\n", op->flags);
210 op->status = GNTST_bad_gntref;
211 return;
212 }
214 if ( acm_pre_grant_map_ref(op->dom) )
215 {
216 op->status = GNTST_permission_denied;
217 return;
218 }
220 if ( unlikely((rd = rcu_lock_domain_by_id(op->dom)) == NULL) )
221 {
222 gdprintk(XENLOG_INFO, "Could not find domain %d\n", op->dom);
223 op->status = GNTST_bad_domain;
224 return;
225 }
227 if ( unlikely((handle = get_maptrack_handle(ld->grant_table)) == -1) )
228 {
229 rcu_unlock_domain(rd);
230 gdprintk(XENLOG_INFO, "Failed to obtain maptrack handle.\n");
231 op->status = GNTST_no_device_space;
232 return;
233 }
235 spin_lock(&rd->grant_table->lock);
237 /* Bounds check on the grant ref */
238 if ( unlikely(op->ref >= nr_grant_entries(rd->grant_table)))
239 PIN_FAIL(unlock_out, GNTST_bad_gntref, "Bad ref (%d).\n", op->ref);
241 act = &active_entry(rd->grant_table, op->ref);
242 sha = &shared_entry(rd->grant_table, op->ref);
244 /* If already pinned, check the active domid and avoid refcnt overflow. */
245 if ( act->pin &&
246 ((act->domid != ld->domain_id) ||
247 (act->pin & 0x80808080U) != 0) )
248 PIN_FAIL(unlock_out, GNTST_general_error,
249 "Bad domain (%d != %d), or risk of counter overflow %08x\n",
250 act->domid, ld->domain_id, act->pin);
252 if ( !act->pin ||
253 (!(op->flags & GNTMAP_readonly) &&
254 !(act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask))) )
255 {
256 scombo.word = *(u32 *)&sha->flags;
258 /*
259 * This loop attempts to set the access (reading/writing) flags
260 * in the grant table entry. It tries a cmpxchg on the field
261 * up to five times, and then fails under the assumption that
262 * the guest is misbehaving.
263 */
264 for ( ; ; )
265 {
266 /* If not already pinned, check the grant domid and type. */
267 if ( !act->pin &&
268 (((scombo.shorts.flags & GTF_type_mask) !=
269 GTF_permit_access) ||
270 (scombo.shorts.domid != ld->domain_id)) )
271 PIN_FAIL(unlock_out, GNTST_general_error,
272 "Bad flags (%x) or dom (%d). (expected dom %d)\n",
273 scombo.shorts.flags, scombo.shorts.domid,
274 ld->domain_id);
276 new_scombo = scombo;
277 new_scombo.shorts.flags |= GTF_reading;
279 if ( !(op->flags & GNTMAP_readonly) )
280 {
281 new_scombo.shorts.flags |= GTF_writing;
282 if ( unlikely(scombo.shorts.flags & GTF_readonly) )
283 PIN_FAIL(unlock_out, GNTST_general_error,
284 "Attempt to write-pin a r/o grant entry.\n");
285 }
287 prev_scombo.word = cmpxchg((u32 *)&sha->flags,
288 scombo.word, new_scombo.word);
289 if ( likely(prev_scombo.word == scombo.word) )
290 break;
292 if ( retries++ == 4 )
293 PIN_FAIL(unlock_out, GNTST_general_error,
294 "Shared grant entry is unstable.\n");
296 scombo = prev_scombo;
297 }
299 if ( !act->pin )
300 {
301 act->domid = scombo.shorts.domid;
302 act->frame = gmfn_to_mfn(rd, sha->frame);
303 }
304 }
306 if ( op->flags & GNTMAP_device_map )
307 act->pin += (op->flags & GNTMAP_readonly) ?
308 GNTPIN_devr_inc : GNTPIN_devw_inc;
309 if ( op->flags & GNTMAP_host_map )
310 act->pin += (op->flags & GNTMAP_readonly) ?
311 GNTPIN_hstr_inc : GNTPIN_hstw_inc;
313 frame = act->frame;
315 spin_unlock(&rd->grant_table->lock);
317 if ( unlikely(!mfn_valid(frame)) ||
318 unlikely(!((op->flags & GNTMAP_readonly) ?
319 get_page(mfn_to_page(frame), rd) :
320 get_page_and_type(mfn_to_page(frame), rd,
321 PGT_writable_page))) )
322 {
323 if ( !rd->is_dying )
324 gdprintk(XENLOG_WARNING, "Could not pin grant frame %lx\n", frame);
325 rc = GNTST_general_error;
326 goto undo_out;
327 }
329 if ( op->flags & GNTMAP_host_map )
330 {
331 rc = create_grant_host_mapping(op->host_addr, frame, op->flags);
332 if ( rc != GNTST_okay )
333 {
334 if ( !(op->flags & GNTMAP_readonly) )
335 put_page_type(mfn_to_page(frame));
336 put_page(mfn_to_page(frame));
337 goto undo_out;
338 }
340 if ( op->flags & GNTMAP_device_map )
341 {
342 (void)get_page(mfn_to_page(frame), rd);
343 if ( !(op->flags & GNTMAP_readonly) )
344 get_page_type(mfn_to_page(frame), PGT_writable_page);
345 }
346 }
348 TRACE_1D(TRC_MEM_PAGE_GRANT_MAP, op->dom);
350 mt = &maptrack_entry(ld->grant_table, handle);
351 mt->domid = op->dom;
352 mt->ref = op->ref;
353 mt->flags = op->flags;
355 op->dev_bus_addr = (u64)frame << PAGE_SHIFT;
356 op->handle = handle;
357 op->status = GNTST_okay;
359 rcu_unlock_domain(rd);
360 return;
362 undo_out:
363 spin_lock(&rd->grant_table->lock);
365 act = &active_entry(rd->grant_table, op->ref);
366 sha = &shared_entry(rd->grant_table, op->ref);
368 if ( op->flags & GNTMAP_device_map )
369 act->pin -= (op->flags & GNTMAP_readonly) ?
370 GNTPIN_devr_inc : GNTPIN_devw_inc;
371 if ( op->flags & GNTMAP_host_map )
372 act->pin -= (op->flags & GNTMAP_readonly) ?
373 GNTPIN_hstr_inc : GNTPIN_hstw_inc;
375 if ( !(op->flags & GNTMAP_readonly) &&
376 !(act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask)) )
377 gnttab_clear_flag(_GTF_writing, &sha->flags);
379 if ( !act->pin )
380 gnttab_clear_flag(_GTF_reading, &sha->flags);
382 unlock_out:
383 spin_unlock(&rd->grant_table->lock);
384 op->status = rc;
385 put_maptrack_handle(ld->grant_table, handle);
386 rcu_unlock_domain(rd);
387 }
389 static long
390 gnttab_map_grant_ref(
391 XEN_GUEST_HANDLE(gnttab_map_grant_ref_t) uop, unsigned int count)
392 {
393 int i;
394 struct gnttab_map_grant_ref op;
396 for ( i = 0; i < count; i++ )
397 {
398 if ( unlikely(__copy_from_guest_offset(&op, uop, i, 1)) )
399 return -EFAULT;
400 __gnttab_map_grant_ref(&op);
401 if ( unlikely(__copy_to_guest_offset(uop, i, &op, 1)) )
402 return -EFAULT;
403 }
405 return 0;
406 }
408 static void
409 __gnttab_unmap_common(
410 struct gnttab_unmap_common *op)
411 {
412 domid_t dom;
413 grant_ref_t ref;
414 struct domain *ld, *rd;
415 struct active_grant_entry *act;
416 grant_entry_t *sha;
417 struct grant_mapping *map;
418 u16 flags;
419 s16 rc = 0;
420 unsigned long frame;
422 ld = current->domain;
424 frame = (unsigned long)(op->dev_bus_addr >> PAGE_SHIFT);
426 if ( unlikely(op->handle >= ld->grant_table->maptrack_limit) )
427 {
428 gdprintk(XENLOG_INFO, "Bad handle (%d).\n", op->handle);
429 op->status = GNTST_bad_handle;
430 return;
431 }
433 map = &maptrack_entry(ld->grant_table, op->handle);
435 if ( unlikely(!map->flags) )
436 {
437 gdprintk(XENLOG_INFO, "Zero flags for handle (%d).\n", op->handle);
438 op->status = GNTST_bad_handle;
439 return;
440 }
442 dom = map->domid;
443 ref = map->ref;
444 flags = map->flags;
446 if ( unlikely((rd = rcu_lock_domain_by_id(dom)) == NULL) )
447 {
448 /* This can happen when a grant is implicitly unmapped. */
449 gdprintk(XENLOG_INFO, "Could not find domain %d\n", dom);
450 domain_crash(ld); /* naughty... */
451 return;
452 }
454 TRACE_1D(TRC_MEM_PAGE_GRANT_UNMAP, dom);
456 spin_lock(&rd->grant_table->lock);
458 act = &active_entry(rd->grant_table, ref);
459 sha = &shared_entry(rd->grant_table, ref);
461 if ( frame == 0 )
462 {
463 frame = act->frame;
464 }
465 else
466 {
467 if ( unlikely(frame != act->frame) )
468 PIN_FAIL(unmap_out, GNTST_general_error,
469 "Bad frame number doesn't match gntref.\n");
470 if ( flags & GNTMAP_device_map )
471 {
472 ASSERT(act->pin & (GNTPIN_devw_mask | GNTPIN_devr_mask));
473 map->flags &= ~GNTMAP_device_map;
474 if ( flags & GNTMAP_readonly )
475 {
476 act->pin -= GNTPIN_devr_inc;
477 put_page(mfn_to_page(frame));
478 }
479 else
480 {
481 act->pin -= GNTPIN_devw_inc;
482 put_page_and_type(mfn_to_page(frame));
483 }
484 }
485 }
487 if ( (op->host_addr != 0) && (flags & GNTMAP_host_map) )
488 {
489 if ( (rc = replace_grant_host_mapping(op->host_addr,
490 frame, op->new_addr, flags)) < 0 )
491 goto unmap_out;
493 ASSERT(act->pin & (GNTPIN_hstw_mask | GNTPIN_hstr_mask));
494 map->flags &= ~GNTMAP_host_map;
495 if ( flags & GNTMAP_readonly )
496 {
497 act->pin -= GNTPIN_hstr_inc;
498 put_page(mfn_to_page(frame));
499 }
500 else
501 {
502 act->pin -= GNTPIN_hstw_inc;
503 put_page_and_type(mfn_to_page(frame));
504 }
505 }
507 if ( (map->flags & (GNTMAP_device_map|GNTMAP_host_map)) == 0 )
508 {
509 map->flags = 0;
510 put_maptrack_handle(ld->grant_table, op->handle);
511 }
513 /* If just unmapped a writable mapping, mark as dirtied */
514 if ( !(flags & GNTMAP_readonly) )
515 gnttab_mark_dirty(rd, frame);
517 if ( ((act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0) &&
518 !(flags & GNTMAP_readonly) )
519 gnttab_clear_flag(_GTF_writing, &sha->flags);
521 if ( act->pin == 0 )
522 gnttab_clear_flag(_GTF_reading, &sha->flags);
524 unmap_out:
525 op->status = rc;
526 spin_unlock(&rd->grant_table->lock);
527 rcu_unlock_domain(rd);
528 }
530 static void
531 __gnttab_unmap_grant_ref(
532 struct gnttab_unmap_grant_ref *op)
533 {
534 struct gnttab_unmap_common common = {
535 .host_addr = op->host_addr,
536 .dev_bus_addr = op->dev_bus_addr,
537 .handle = op->handle,
538 };
540 __gnttab_unmap_common(&common);
541 op->status = common.status;
542 }
544 static long
545 gnttab_unmap_grant_ref(
546 XEN_GUEST_HANDLE(gnttab_unmap_grant_ref_t) uop, unsigned int count)
547 {
548 int i;
549 struct gnttab_unmap_grant_ref op;
551 for ( i = 0; i < count; i++ )
552 {
553 if ( unlikely(__copy_from_guest_offset(&op, uop, i, 1)) )
554 goto fault;
555 __gnttab_unmap_grant_ref(&op);
556 if ( unlikely(__copy_to_guest_offset(uop, i, &op, 1)) )
557 goto fault;
558 }
560 flush_tlb_mask(current->domain->domain_dirty_cpumask);
561 return 0;
563 fault:
564 flush_tlb_mask(current->domain->domain_dirty_cpumask);
565 return -EFAULT;
566 }
568 static void
569 __gnttab_unmap_and_replace(
570 struct gnttab_unmap_and_replace *op)
571 {
572 struct gnttab_unmap_common common = {
573 .host_addr = op->host_addr,
574 .new_addr = op->new_addr,
575 .handle = op->handle,
576 };
578 __gnttab_unmap_common(&common);
579 op->status = common.status;
580 }
582 static long
583 gnttab_unmap_and_replace(
584 XEN_GUEST_HANDLE(gnttab_unmap_and_replace_t) uop, unsigned int count)
585 {
586 int i;
587 struct gnttab_unmap_and_replace op;
589 for ( i = 0; i < count; i++ )
590 {
591 if ( unlikely(__copy_from_guest_offset(&op, uop, i, 1)) )
592 goto fault;
593 __gnttab_unmap_and_replace(&op);
594 if ( unlikely(__copy_to_guest_offset(uop, i, &op, 1)) )
595 goto fault;
596 }
598 flush_tlb_mask(current->domain->domain_dirty_cpumask);
599 return 0;
601 fault:
602 flush_tlb_mask(current->domain->domain_dirty_cpumask);
603 return -EFAULT;
604 }
606 int
607 gnttab_grow_table(struct domain *d, unsigned int req_nr_frames)
608 {
609 /* d's grant table lock must be held by the caller */
611 struct grant_table *gt = d->grant_table;
612 unsigned int i;
614 ASSERT(req_nr_frames <= max_nr_grant_frames);
616 gdprintk(XENLOG_INFO,
617 "Expanding dom (%d) grant table from (%d) to (%d) frames.\n",
618 d->domain_id, nr_grant_frames(gt), req_nr_frames);
620 /* Active */
621 for ( i = nr_active_grant_frames(gt);
622 i < num_act_frames_from_sha_frames(req_nr_frames); i++ )
623 {
624 if ( (gt->active[i] = alloc_xenheap_page()) == NULL )
625 goto active_alloc_failed;
626 clear_page(gt->active[i]);
627 }
629 /* Shared */
630 for ( i = nr_grant_frames(gt); i < req_nr_frames; i++ )
631 {
632 if ( (gt->shared[i] = alloc_xenheap_page()) == NULL )
633 goto shared_alloc_failed;
634 clear_page(gt->shared[i]);
635 }
637 /* Share the new shared frames with the recipient domain */
638 for ( i = nr_grant_frames(gt); i < req_nr_frames; i++ )
639 gnttab_create_shared_page(d, gt, i);
641 gt->nr_grant_frames = req_nr_frames;
643 return 1;
645 shared_alloc_failed:
646 for ( i = nr_grant_frames(gt); i < req_nr_frames; i++ )
647 {
648 free_xenheap_page(gt->shared[i]);
649 gt->shared[i] = NULL;
650 }
651 active_alloc_failed:
652 for ( i = nr_active_grant_frames(gt);
653 i < num_act_frames_from_sha_frames(req_nr_frames); i++ )
654 {
655 free_xenheap_page(gt->active[i]);
656 gt->active[i] = NULL;
657 }
658 gdprintk(XENLOG_INFO, "Allocation failure when expanding grant table.\n");
659 return 0;
660 }
662 static long
663 gnttab_setup_table(
664 XEN_GUEST_HANDLE(gnttab_setup_table_t) uop, unsigned int count)
665 {
666 struct gnttab_setup_table op;
667 struct domain *d;
668 int i;
669 unsigned long gmfn;
670 domid_t dom;
672 if ( count != 1 )
673 return -EINVAL;
675 if ( unlikely(copy_from_guest(&op, uop, 1) != 0) )
676 {
677 gdprintk(XENLOG_INFO, "Fault while reading gnttab_setup_table_t.\n");
678 return -EFAULT;
679 }
681 if ( unlikely(op.nr_frames > max_nr_grant_frames) )
682 {
683 gdprintk(XENLOG_INFO, "Xen only supports up to %d grant-table frames"
684 " per domain.\n",
685 max_nr_grant_frames);
686 op.status = GNTST_general_error;
687 goto out;
688 }
690 dom = op.dom;
691 if ( dom == DOMID_SELF )
692 {
693 dom = current->domain->domain_id;
694 }
695 else if ( unlikely(!IS_PRIV(current->domain)) )
696 {
697 op.status = GNTST_permission_denied;
698 goto out;
699 }
701 if ( unlikely((d = rcu_lock_domain_by_id(dom)) == NULL) )
702 {
703 gdprintk(XENLOG_INFO, "Bad domid %d.\n", dom);
704 op.status = GNTST_bad_domain;
705 goto out;
706 }
708 spin_lock(&d->grant_table->lock);
710 if ( (op.nr_frames > nr_grant_frames(d->grant_table)) &&
711 !gnttab_grow_table(d, op.nr_frames) )
712 {
713 gdprintk(XENLOG_INFO,
714 "Expand grant table to %d failed. Current: %d Max: %d.\n",
715 op.nr_frames,
716 nr_grant_frames(d->grant_table),
717 max_nr_grant_frames);
718 op.status = GNTST_general_error;
719 goto setup_unlock_out;
720 }
722 op.status = GNTST_okay;
723 for ( i = 0; i < op.nr_frames; i++ )
724 {
725 gmfn = gnttab_shared_gmfn(d, d->grant_table, i);
726 (void)copy_to_guest_offset(op.frame_list, i, &gmfn, 1);
727 }
729 setup_unlock_out:
730 spin_unlock(&d->grant_table->lock);
732 rcu_unlock_domain(d);
734 out:
735 if ( unlikely(copy_to_guest(uop, &op, 1)) )
736 return -EFAULT;
738 return 0;
739 }
741 static long
742 gnttab_query_size(
743 XEN_GUEST_HANDLE(gnttab_query_size_t) uop, unsigned int count)
744 {
745 struct gnttab_query_size op;
746 struct domain *d;
747 domid_t dom;
749 if ( count != 1 )
750 return -EINVAL;
752 if ( unlikely(copy_from_guest(&op, uop, 1) != 0) )
753 {
754 gdprintk(XENLOG_INFO, "Fault while reading gnttab_query_size_t.\n");
755 return -EFAULT;
756 }
758 dom = op.dom;
759 if ( dom == DOMID_SELF )
760 {
761 dom = current->domain->domain_id;
762 }
763 else if ( unlikely(!IS_PRIV(current->domain)) )
764 {
765 op.status = GNTST_permission_denied;
766 goto query_out;
767 }
769 if ( unlikely((d = rcu_lock_domain_by_id(dom)) == NULL) )
770 {
771 gdprintk(XENLOG_INFO, "Bad domid %d.\n", dom);
772 op.status = GNTST_bad_domain;
773 goto query_out;
774 }
776 spin_lock(&d->grant_table->lock);
778 op.nr_frames = nr_grant_frames(d->grant_table);
779 op.max_nr_frames = max_nr_grant_frames;
780 op.status = GNTST_okay;
782 spin_unlock(&d->grant_table->lock);
784 rcu_unlock_domain(d);
786 query_out:
787 if ( unlikely(copy_to_guest(uop, &op, 1)) )
788 return -EFAULT;
790 return 0;
791 }
793 /*
794 * Check that the given grant reference (rd,ref) allows 'ld' to transfer
795 * ownership of a page frame. If so, lock down the grant entry.
796 */
797 static int
798 gnttab_prepare_for_transfer(
799 struct domain *rd, struct domain *ld, grant_ref_t ref)
800 {
801 struct grant_table *rgt;
802 struct grant_entry *sha;
803 union grant_combo scombo, prev_scombo, new_scombo;
804 int retries = 0;
806 if ( unlikely((rgt = rd->grant_table) == NULL) )
807 {
808 gdprintk(XENLOG_INFO, "Dom %d has no grant table.\n", rd->domain_id);
809 return 0;
810 }
812 spin_lock(&rgt->lock);
814 if ( unlikely(ref >= nr_grant_entries(rd->grant_table)) )
815 {
816 gdprintk(XENLOG_INFO,
817 "Bad grant reference (%d) for transfer to domain(%d).\n",
818 ref, rd->domain_id);
819 goto fail;
820 }
822 sha = &shared_entry(rgt, ref);
824 scombo.word = *(u32 *)&sha->flags;
826 for ( ; ; )
827 {
828 if ( unlikely(scombo.shorts.flags != GTF_accept_transfer) ||
829 unlikely(scombo.shorts.domid != ld->domain_id) )
830 {
831 gdprintk(XENLOG_INFO, "Bad flags (%x) or dom (%d). "
832 "(NB. expected dom %d)\n",
833 scombo.shorts.flags, scombo.shorts.domid,
834 ld->domain_id);
835 goto fail;
836 }
838 new_scombo = scombo;
839 new_scombo.shorts.flags |= GTF_transfer_committed;
841 prev_scombo.word = cmpxchg((u32 *)&sha->flags,
842 scombo.word, new_scombo.word);
843 if ( likely(prev_scombo.word == scombo.word) )
844 break;
846 if ( retries++ == 4 )
847 {
848 gdprintk(XENLOG_WARNING, "Shared grant entry is unstable.\n");
849 goto fail;
850 }
852 scombo = prev_scombo;
853 }
855 spin_unlock(&rgt->lock);
856 return 1;
858 fail:
859 spin_unlock(&rgt->lock);
860 return 0;
861 }
863 static long
864 gnttab_transfer(
865 XEN_GUEST_HANDLE(gnttab_transfer_t) uop, unsigned int count)
866 {
867 struct domain *d = current->domain;
868 struct domain *e;
869 struct page_info *page;
870 int i;
871 grant_entry_t *sha;
872 struct gnttab_transfer gop;
873 unsigned long mfn;
875 for ( i = 0; i < count; i++ )
876 {
877 /* Read from caller address space. */
878 if ( unlikely(__copy_from_guest_offset(&gop, uop, i, 1)) )
879 {
880 gdprintk(XENLOG_INFO, "gnttab_transfer: error reading req %d/%d\n",
881 i, count);
882 return -EFAULT;
883 }
885 mfn = gmfn_to_mfn(d, gop.mfn);
887 /* Check the passed page frame for basic validity. */
888 if ( unlikely(!mfn_valid(mfn)) )
889 {
890 gdprintk(XENLOG_INFO, "gnttab_transfer: out-of-range %lx\n",
891 (unsigned long)gop.mfn);
892 gop.status = GNTST_bad_page;
893 goto copyback;
894 }
896 page = mfn_to_page(mfn);
897 if ( unlikely(is_xen_heap_frame(page)) )
898 {
899 gdprintk(XENLOG_INFO, "gnttab_transfer: xen frame %lx\n",
900 (unsigned long)gop.mfn);
901 gop.status = GNTST_bad_page;
902 goto copyback;
903 }
905 if ( steal_page(d, page, 0) < 0 )
906 {
907 gop.status = GNTST_bad_page;
908 goto copyback;
909 }
911 /* Find the target domain. */
912 if ( unlikely((e = rcu_lock_domain_by_id(gop.domid)) == NULL) )
913 {
914 gdprintk(XENLOG_INFO, "gnttab_transfer: can't find domain %d\n",
915 gop.domid);
916 page->count_info &= ~(PGC_count_mask|PGC_allocated);
917 free_domheap_page(page);
918 gop.status = GNTST_bad_domain;
919 goto copyback;
920 }
922 spin_lock(&e->page_alloc_lock);
924 /*
925 * Check that 'e' will accept the page and has reservation
926 * headroom. Also, a domain mustn't have PGC_allocated
927 * pages when it is dying.
928 */
929 if ( unlikely(e->is_dying) ||
930 unlikely(e->tot_pages >= e->max_pages) ||
931 unlikely(!gnttab_prepare_for_transfer(e, d, gop.ref)) )
932 {
933 if ( !e->is_dying )
934 gdprintk(XENLOG_INFO, "gnttab_transfer: "
935 "Transferee has no reservation "
936 "headroom (%d,%d) or provided a bad grant ref (%08x) "
937 "or is dying (%d)\n",
938 e->tot_pages, e->max_pages, gop.ref, e->is_dying);
939 spin_unlock(&e->page_alloc_lock);
940 rcu_unlock_domain(e);
941 page->count_info &= ~(PGC_count_mask|PGC_allocated);
942 free_domheap_page(page);
943 gop.status = GNTST_general_error;
944 goto copyback;
945 }
947 /* Okay, add the page to 'e'. */
948 if ( unlikely(e->tot_pages++ == 0) )
949 get_knownalive_domain(e);
950 list_add_tail(&page->list, &e->page_list);
951 page_set_owner(page, e);
953 spin_unlock(&e->page_alloc_lock);
955 TRACE_1D(TRC_MEM_PAGE_GRANT_TRANSFER, e->domain_id);
957 /* Tell the guest about its new page frame. */
958 spin_lock(&e->grant_table->lock);
960 sha = &shared_entry(e->grant_table, gop.ref);
961 guest_physmap_add_page(e, sha->frame, mfn);
962 sha->frame = mfn;
963 wmb();
964 sha->flags |= GTF_transfer_completed;
966 spin_unlock(&e->grant_table->lock);
968 rcu_unlock_domain(e);
970 gop.status = GNTST_okay;
972 copyback:
973 if ( unlikely(__copy_to_guest_offset(uop, i, &gop, 1)) )
974 {
975 gdprintk(XENLOG_INFO, "gnttab_transfer: error writing resp "
976 "%d/%d\n", i, count);
977 return -EFAULT;
978 }
979 }
981 return 0;
982 }
984 /* Undo __acquire_grant_for_copy. Again, this has no effect on page
985 type and reference counts. */
986 static void
987 __release_grant_for_copy(
988 struct domain *rd, unsigned long gref, int readonly)
989 {
990 grant_entry_t *sha;
991 struct active_grant_entry *act;
992 unsigned long r_frame;
994 spin_lock(&rd->grant_table->lock);
996 act = &active_entry(rd->grant_table, gref);
997 sha = &shared_entry(rd->grant_table, gref);
998 r_frame = act->frame;
1000 if ( readonly )
1002 act->pin -= GNTPIN_hstr_inc;
1004 else
1006 gnttab_mark_dirty(rd, r_frame);
1008 act->pin -= GNTPIN_hstw_inc;
1009 if ( !(act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) )
1010 gnttab_clear_flag(_GTF_writing, &sha->flags);
1013 if ( !act->pin )
1014 gnttab_clear_flag(_GTF_reading, &sha->flags);
1016 spin_unlock(&rd->grant_table->lock);
1019 /* Grab a frame number from a grant entry and update the flags and pin
1020 count as appropriate. Note that this does *not* update the page
1021 type or reference counts, and does not check that the mfn is
1022 actually valid. */
1023 static int
1024 __acquire_grant_for_copy(
1025 struct domain *rd, unsigned long gref, int readonly,
1026 unsigned long *frame)
1028 grant_entry_t *sha;
1029 struct active_grant_entry *act;
1030 s16 rc = GNTST_okay;
1031 int retries = 0;
1032 union grant_combo scombo, prev_scombo, new_scombo;
1034 spin_lock(&rd->grant_table->lock);
1036 if ( unlikely(gref >= nr_grant_entries(rd->grant_table)) )
1037 PIN_FAIL(unlock_out, GNTST_bad_gntref,
1038 "Bad grant reference %ld\n", gref);
1040 act = &active_entry(rd->grant_table, gref);
1041 sha = &shared_entry(rd->grant_table, gref);
1043 /* If already pinned, check the active domid and avoid refcnt overflow. */
1044 if ( act->pin &&
1045 ((act->domid != current->domain->domain_id) ||
1046 (act->pin & 0x80808080U) != 0) )
1047 PIN_FAIL(unlock_out, GNTST_general_error,
1048 "Bad domain (%d != %d), or risk of counter overflow %08x\n",
1049 act->domid, current->domain->domain_id, act->pin);
1051 if ( !act->pin ||
1052 (!readonly && !(act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask))) )
1054 scombo.word = *(u32 *)&sha->flags;
1056 for ( ; ; )
1058 /* If not already pinned, check the grant domid and type. */
1059 if ( !act->pin &&
1060 (((scombo.shorts.flags & GTF_type_mask) !=
1061 GTF_permit_access) ||
1062 (scombo.shorts.domid != current->domain->domain_id)) )
1063 PIN_FAIL(unlock_out, GNTST_general_error,
1064 "Bad flags (%x) or dom (%d). (expected dom %d)\n",
1065 scombo.shorts.flags, scombo.shorts.domid,
1066 current->domain->domain_id);
1068 new_scombo = scombo;
1069 new_scombo.shorts.flags |= GTF_reading;
1071 if ( !readonly )
1073 new_scombo.shorts.flags |= GTF_writing;
1074 if ( unlikely(scombo.shorts.flags & GTF_readonly) )
1075 PIN_FAIL(unlock_out, GNTST_general_error,
1076 "Attempt to write-pin a r/o grant entry.\n");
1079 prev_scombo.word = cmpxchg((u32 *)&sha->flags,
1080 scombo.word, new_scombo.word);
1081 if ( likely(prev_scombo.word == scombo.word) )
1082 break;
1084 if ( retries++ == 4 )
1085 PIN_FAIL(unlock_out, GNTST_general_error,
1086 "Shared grant entry is unstable.\n");
1088 scombo = prev_scombo;
1091 if ( !act->pin )
1093 act->domid = scombo.shorts.domid;
1094 act->frame = gmfn_to_mfn(rd, sha->frame);
1098 act->pin += readonly ? GNTPIN_hstr_inc : GNTPIN_hstw_inc;
1100 *frame = act->frame;
1102 unlock_out:
1103 spin_unlock(&rd->grant_table->lock);
1104 return rc;
1107 static void
1108 __gnttab_copy(
1109 struct gnttab_copy *op)
1111 struct domain *sd = NULL, *dd = NULL;
1112 unsigned long s_frame, d_frame;
1113 char *sp, *dp;
1114 s16 rc = GNTST_okay;
1115 int have_d_grant = 0, have_s_grant = 0, have_s_ref = 0;
1116 int src_is_gref, dest_is_gref;
1118 if ( ((op->source.offset + op->len) > PAGE_SIZE) ||
1119 ((op->dest.offset + op->len) > PAGE_SIZE) )
1120 PIN_FAIL(error_out, GNTST_bad_copy_arg, "copy beyond page area.\n");
1122 src_is_gref = op->flags & GNTCOPY_source_gref;
1123 dest_is_gref = op->flags & GNTCOPY_dest_gref;
1125 if ( (op->source.domid != DOMID_SELF && !src_is_gref ) ||
1126 (op->dest.domid != DOMID_SELF && !dest_is_gref) )
1127 PIN_FAIL(error_out, GNTST_permission_denied,
1128 "only allow copy-by-mfn for DOMID_SELF.\n");
1130 if ( op->source.domid == DOMID_SELF )
1131 sd = rcu_lock_current_domain();
1132 else if ( (sd = rcu_lock_domain_by_id(op->source.domid)) == NULL )
1133 PIN_FAIL(error_out, GNTST_bad_domain,
1134 "couldn't find %d\n", op->source.domid);
1136 if ( op->dest.domid == DOMID_SELF )
1137 dd = rcu_lock_current_domain();
1138 else if ( (dd = rcu_lock_domain_by_id(op->dest.domid)) == NULL )
1139 PIN_FAIL(error_out, GNTST_bad_domain,
1140 "couldn't find %d\n", op->dest.domid);
1142 if ( src_is_gref )
1144 rc = __acquire_grant_for_copy(sd, op->source.u.ref, 1, &s_frame);
1145 if ( rc != GNTST_okay )
1146 goto error_out;
1147 have_s_grant = 1;
1149 else
1151 s_frame = gmfn_to_mfn(sd, op->source.u.gmfn);
1153 if ( unlikely(!mfn_valid(s_frame)) )
1154 PIN_FAIL(error_out, GNTST_general_error,
1155 "source frame %lx invalid.\n", s_frame);
1156 if ( !get_page(mfn_to_page(s_frame), sd) )
1158 if ( !sd->is_dying )
1159 gdprintk(XENLOG_WARNING, "Could not get src frame %lx\n", s_frame);
1160 rc = GNTST_general_error;
1161 goto error_out;
1163 have_s_ref = 1;
1165 if ( dest_is_gref )
1167 rc = __acquire_grant_for_copy(dd, op->dest.u.ref, 0, &d_frame);
1168 if ( rc != GNTST_okay )
1169 goto error_out;
1170 have_d_grant = 1;
1172 else
1174 d_frame = gmfn_to_mfn(dd, op->dest.u.gmfn);
1176 if ( unlikely(!mfn_valid(d_frame)) )
1177 PIN_FAIL(error_out, GNTST_general_error,
1178 "destination frame %lx invalid.\n", d_frame);
1179 if ( !get_page_and_type(mfn_to_page(d_frame), dd, PGT_writable_page) )
1181 if ( !dd->is_dying )
1182 gdprintk(XENLOG_WARNING, "Could not get dst frame %lx\n", d_frame);
1183 rc = GNTST_general_error;
1184 goto error_out;
1187 sp = map_domain_page(s_frame);
1188 dp = map_domain_page(d_frame);
1190 memcpy(dp + op->dest.offset, sp + op->source.offset, op->len);
1192 unmap_domain_page(dp);
1193 unmap_domain_page(sp);
1195 gnttab_mark_dirty(dd, d_frame);
1197 put_page_and_type(mfn_to_page(d_frame));
1198 error_out:
1199 if ( have_s_ref )
1200 put_page(mfn_to_page(s_frame));
1201 if ( have_s_grant )
1202 __release_grant_for_copy(sd, op->source.u.ref, 1);
1203 if ( have_d_grant )
1204 __release_grant_for_copy(dd, op->dest.u.ref, 0);
1205 if ( sd )
1206 rcu_unlock_domain(sd);
1207 if ( dd )
1208 rcu_unlock_domain(dd);
1209 op->status = rc;
1212 static long
1213 gnttab_copy(
1214 XEN_GUEST_HANDLE(gnttab_copy_t) uop, unsigned int count)
1216 int i;
1217 struct gnttab_copy op;
1219 for ( i = 0; i < count; i++ )
1221 if ( unlikely(__copy_from_guest_offset(&op, uop, i, 1)) )
1222 return -EFAULT;
1223 __gnttab_copy(&op);
1224 if ( unlikely(__copy_to_guest_offset(uop, i, &op, 1)) )
1225 return -EFAULT;
1227 return 0;
1230 long
1231 do_grant_table_op(
1232 unsigned int cmd, XEN_GUEST_HANDLE(void) uop, unsigned int count)
1234 long rc;
1235 struct domain *d = current->domain;
1237 if ( count > 512 )
1238 return -EINVAL;
1240 LOCK_BIGLOCK(d);
1242 rc = -EFAULT;
1243 switch ( cmd )
1245 case GNTTABOP_map_grant_ref:
1247 XEN_GUEST_HANDLE(gnttab_map_grant_ref_t) map =
1248 guest_handle_cast(uop, gnttab_map_grant_ref_t);
1249 if ( unlikely(!guest_handle_okay(map, count)) )
1250 goto out;
1251 rc = -EPERM;
1252 if ( unlikely(!grant_operation_permitted(d)) )
1253 goto out;
1254 rc = gnttab_map_grant_ref(map, count);
1255 break;
1257 case GNTTABOP_unmap_grant_ref:
1259 XEN_GUEST_HANDLE(gnttab_unmap_grant_ref_t) unmap =
1260 guest_handle_cast(uop, gnttab_unmap_grant_ref_t);
1261 if ( unlikely(!guest_handle_okay(unmap, count)) )
1262 goto out;
1263 rc = -EPERM;
1264 if ( unlikely(!grant_operation_permitted(d)) )
1265 goto out;
1266 rc = gnttab_unmap_grant_ref(unmap, count);
1267 break;
1269 case GNTTABOP_unmap_and_replace:
1271 XEN_GUEST_HANDLE(gnttab_unmap_and_replace_t) unmap =
1272 guest_handle_cast(uop, gnttab_unmap_and_replace_t);
1273 if ( unlikely(!guest_handle_okay(unmap, count)) )
1274 goto out;
1275 rc = -EPERM;
1276 if ( unlikely(!grant_operation_permitted(d)) )
1277 goto out;
1278 rc = -ENOSYS;
1279 if ( unlikely(!replace_grant_supported()) )
1280 goto out;
1281 rc = gnttab_unmap_and_replace(unmap, count);
1282 break;
1284 case GNTTABOP_setup_table:
1286 rc = gnttab_setup_table(
1287 guest_handle_cast(uop, gnttab_setup_table_t), count);
1288 break;
1290 case GNTTABOP_transfer:
1292 XEN_GUEST_HANDLE(gnttab_transfer_t) transfer =
1293 guest_handle_cast(uop, gnttab_transfer_t);
1294 if ( unlikely(!guest_handle_okay(transfer, count)) )
1295 goto out;
1296 rc = -EPERM;
1297 if ( unlikely(!grant_operation_permitted(d)) )
1298 goto out;
1299 rc = gnttab_transfer(transfer, count);
1300 break;
1302 case GNTTABOP_copy:
1304 XEN_GUEST_HANDLE(gnttab_copy_t) copy =
1305 guest_handle_cast(uop, gnttab_copy_t);
1306 if ( unlikely(!guest_handle_okay(copy, count)) )
1307 goto out;
1308 rc = gnttab_copy(copy, count);
1309 break;
1311 case GNTTABOP_query_size:
1313 rc = gnttab_query_size(
1314 guest_handle_cast(uop, gnttab_query_size_t), count);
1315 break;
1317 default:
1318 rc = -ENOSYS;
1319 break;
1322 out:
1323 UNLOCK_BIGLOCK(d);
1325 return rc;
1328 #ifdef CONFIG_COMPAT
1329 #include "compat/grant_table.c"
1330 #endif
1332 static unsigned int max_nr_active_grant_frames(void)
1334 return (((max_nr_grant_frames * (PAGE_SIZE / sizeof(grant_entry_t))) +
1335 ((PAGE_SIZE / sizeof(struct active_grant_entry))-1))
1336 / (PAGE_SIZE / sizeof(struct active_grant_entry)));
1339 int
1340 grant_table_create(
1341 struct domain *d)
1343 struct grant_table *t;
1344 int i;
1346 /* If this sizeof assertion fails, fix the function: shared_index */
1347 ASSERT(sizeof(grant_entry_t) == 8);
1349 if ( (t = xmalloc(struct grant_table)) == NULL )
1350 goto no_mem_0;
1352 /* Simple stuff. */
1353 memset(t, 0, sizeof(*t));
1354 spin_lock_init(&t->lock);
1355 t->nr_grant_frames = INITIAL_NR_GRANT_FRAMES;
1357 /* Active grant table. */
1358 if ( (t->active = xmalloc_array(struct active_grant_entry *,
1359 max_nr_active_grant_frames())) == NULL )
1360 goto no_mem_1;
1361 memset(t->active, 0, max_nr_active_grant_frames() * sizeof(t->active[0]));
1362 for ( i = 0;
1363 i < num_act_frames_from_sha_frames(INITIAL_NR_GRANT_FRAMES); i++ )
1365 if ( (t->active[i] = alloc_xenheap_page()) == NULL )
1366 goto no_mem_2;
1367 clear_page(t->active[i]);
1370 /* Tracking of mapped foreign frames table */
1371 if ( (t->maptrack = xmalloc_array(struct grant_mapping *,
1372 max_nr_maptrack_frames())) == NULL )
1373 goto no_mem_2;
1374 memset(t->maptrack, 0, max_nr_maptrack_frames() * sizeof(t->maptrack[0]));
1375 if ( (t->maptrack[0] = alloc_xenheap_page()) == NULL )
1376 goto no_mem_3;
1377 clear_page(t->maptrack[0]);
1378 t->maptrack_limit = PAGE_SIZE / sizeof(struct grant_mapping);
1379 for ( i = 0; i < t->maptrack_limit; i++ )
1380 t->maptrack[0][i].ref = i+1;
1382 /* Shared grant table. */
1383 if ( (t->shared = xmalloc_array(struct grant_entry *,
1384 max_nr_grant_frames)) == NULL )
1385 goto no_mem_3;
1386 memset(t->shared, 0, max_nr_grant_frames * sizeof(t->shared[0]));
1387 for ( i = 0; i < INITIAL_NR_GRANT_FRAMES; i++ )
1389 if ( (t->shared[i] = alloc_xenheap_page()) == NULL )
1390 goto no_mem_4;
1391 clear_page(t->shared[i]);
1394 for ( i = 0; i < INITIAL_NR_GRANT_FRAMES; i++ )
1395 gnttab_create_shared_page(d, t, i);
1397 /* Okay, install the structure. */
1398 d->grant_table = t;
1399 return 0;
1401 no_mem_4:
1402 for ( i = 0; i < INITIAL_NR_GRANT_FRAMES; i++ )
1403 free_xenheap_page(t->shared[i]);
1404 xfree(t->shared);
1405 no_mem_3:
1406 free_xenheap_page(t->maptrack[0]);
1407 xfree(t->maptrack);
1408 no_mem_2:
1409 for ( i = 0;
1410 i < num_act_frames_from_sha_frames(INITIAL_NR_GRANT_FRAMES); i++ )
1411 free_xenheap_page(t->active[i]);
1412 xfree(t->active);
1413 no_mem_1:
1414 xfree(t);
1415 no_mem_0:
1416 return -ENOMEM;
1419 void
1420 gnttab_release_mappings(
1421 struct domain *d)
1423 struct grant_table *gt = d->grant_table;
1424 struct grant_mapping *map;
1425 grant_ref_t ref;
1426 grant_handle_t handle;
1427 struct domain *rd;
1428 struct active_grant_entry *act;
1429 struct grant_entry *sha;
1431 BUG_ON(!d->is_dying);
1433 for ( handle = 0; handle < gt->maptrack_limit; handle++ )
1435 map = &maptrack_entry(gt, handle);
1436 if ( !(map->flags & (GNTMAP_device_map|GNTMAP_host_map)) )
1437 continue;
1439 ref = map->ref;
1441 gdprintk(XENLOG_INFO, "Grant release (%hu) ref:(%hu) "
1442 "flags:(%x) dom:(%hu)\n",
1443 handle, ref, map->flags, map->domid);
1445 rd = rcu_lock_domain_by_id(map->domid);
1446 if ( rd == NULL )
1448 /* Nothing to clear up... */
1449 map->flags = 0;
1450 continue;
1453 spin_lock(&rd->grant_table->lock);
1455 act = &active_entry(rd->grant_table, ref);
1456 sha = &shared_entry(rd->grant_table, ref);
1458 if ( map->flags & GNTMAP_readonly )
1460 if ( map->flags & GNTMAP_device_map )
1462 BUG_ON(!(act->pin & GNTPIN_devr_mask));
1463 act->pin -= GNTPIN_devr_inc;
1464 put_page(mfn_to_page(act->frame));
1467 if ( map->flags & GNTMAP_host_map )
1469 BUG_ON(!(act->pin & GNTPIN_hstr_mask));
1470 act->pin -= GNTPIN_hstr_inc;
1471 gnttab_release_put_page(mfn_to_page(act->frame));
1474 else
1476 if ( map->flags & GNTMAP_device_map )
1478 BUG_ON(!(act->pin & GNTPIN_devw_mask));
1479 act->pin -= GNTPIN_devw_inc;
1480 put_page_and_type(mfn_to_page(act->frame));
1483 if ( map->flags & GNTMAP_host_map )
1485 BUG_ON(!(act->pin & GNTPIN_hstw_mask));
1486 act->pin -= GNTPIN_hstw_inc;
1487 gnttab_release_put_page_and_type(mfn_to_page(act->frame));
1490 if ( (act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0 )
1491 gnttab_clear_flag(_GTF_writing, &sha->flags);
1494 if ( act->pin == 0 )
1495 gnttab_clear_flag(_GTF_reading, &sha->flags);
1497 spin_unlock(&rd->grant_table->lock);
1499 rcu_unlock_domain(rd);
1501 map->flags = 0;
1506 void
1507 grant_table_destroy(
1508 struct domain *d)
1510 struct grant_table *t = d->grant_table;
1511 int i;
1513 if ( t == NULL )
1514 return;
1516 for ( i = 0; i < nr_grant_frames(t); i++ )
1517 free_xenheap_page(t->shared[i]);
1518 xfree(t->shared);
1520 for ( i = 0; i < nr_maptrack_frames(t); i++ )
1521 free_xenheap_page(t->maptrack[i]);
1522 xfree(t->maptrack);
1524 for ( i = 0; i < nr_active_grant_frames(t); i++ )
1525 free_xenheap_page(t->active[i]);
1526 xfree(t->active);
1528 xfree(t);
1529 d->grant_table = NULL;
1532 /*
1533 * Local variables:
1534 * mode: C
1535 * c-set-style: "BSD"
1536 * c-basic-offset: 4
1537 * tab-width: 4
1538 * indent-tabs-mode: nil
1539 * End:
1540 */