ia64/xen-unstable

view xen/common/grant_table.c @ 13992:eecd0361df4a

Fix grant-table initialisation so that domain destruction does not barf.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Fri Feb 16 12:13:33 2007 +0000 (2007-02-16)
parents 70f05d642a2e
children 09a9b6d6c356
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/shadow.h>
32 #include <xen/mm.h>
33 #include <xen/trace.h>
34 #include <xen/guest_access.h>
35 #include <xen/domain_page.h>
36 #include <acm/acm_hooks.h>
38 unsigned int max_nr_grant_frames = DEFAULT_MAX_NR_GRANT_FRAMES;
39 integer_param("gnttab_max_nr_frames", max_nr_grant_frames);
41 /* The maximum number of grant mappings is defined as a multiplier of the
42 * maximum number of grant table entries. This defines the multiplier used.
43 * Pretty arbitrary. [POLICY]
44 */
45 #define MAX_MAPTRACK_TO_GRANTS_RATIO 8
47 /*
48 * The first two members of a grant entry are updated as a combined pair.
49 * The following union allows that to happen in an endian-neutral fashion.
50 */
51 union grant_combo {
52 uint32_t word;
53 struct {
54 uint16_t flags;
55 domid_t domid;
56 } shorts;
57 };
59 #define PIN_FAIL(_lbl, _rc, _f, _a...) \
60 do { \
61 gdprintk(XENLOG_WARNING, _f, ## _a ); \
62 rc = (_rc); \
63 goto _lbl; \
64 } while ( 0 )
66 #define MAPTRACK_PER_PAGE (PAGE_SIZE / sizeof(struct grant_mapping))
67 #define maptrack_entry(t, e) \
68 ((t)->maptrack[(e)/MAPTRACK_PER_PAGE][(e)%MAPTRACK_PER_PAGE])
70 static inline unsigned int
71 nr_maptrack_frames(struct grant_table *t)
72 {
73 return t->maptrack_limit / MAPTRACK_PER_PAGE;
74 }
76 static unsigned inline int max_nr_maptrack_frames(void)
77 {
78 return (max_nr_grant_frames * MAX_MAPTRACK_TO_GRANTS_RATIO);
79 }
81 static inline unsigned int
82 num_act_frames_from_sha_frames(const unsigned int num)
83 {
84 /* How many frames are needed for the active grant table,
85 * given the size of the shared grant table?
86 *
87 * act_per_page = PAGE_SIZE / sizeof(active_grant_entry_t);
88 * sha_per_page = PAGE_SIZE / sizeof(grant_entry_t);
89 * num_sha_entries = num * sha_per_page;
90 * num_act_frames = (num_sha_entries + (act_per_page-1)) / act_per_page;
91 */
92 return ((num * (PAGE_SIZE / sizeof(grant_entry_t))) +
93 ((PAGE_SIZE / sizeof(struct active_grant_entry))-1))
94 / (PAGE_SIZE / sizeof(struct active_grant_entry));
95 }
97 static inline unsigned int
98 nr_active_grant_frames(struct grant_table *gt)
99 {
100 return num_act_frames_from_sha_frames(nr_grant_frames(gt));
101 }
103 #define SHGNT_PER_PAGE (PAGE_SIZE / sizeof(grant_entry_t))
104 #define shared_entry(t, e) \
105 ((t)->shared[(e)/SHGNT_PER_PAGE][(e)%SHGNT_PER_PAGE])
106 #define ACGNT_PER_PAGE (PAGE_SIZE / sizeof(struct active_grant_entry))
107 #define active_entry(t, e) \
108 ((t)->active[(e)/ACGNT_PER_PAGE][(e)%ACGNT_PER_PAGE])
110 static inline int
111 __get_maptrack_handle(
112 struct grant_table *t)
113 {
114 unsigned int h;
115 if ( unlikely((h = t->maptrack_head) == (t->maptrack_limit - 1)) )
116 return -1;
117 t->maptrack_head = maptrack_entry(t, h).ref;
118 t->map_count++;
119 return h;
120 }
122 static inline void
123 put_maptrack_handle(
124 struct grant_table *t, int handle)
125 {
126 maptrack_entry(t, handle).ref = t->maptrack_head;
127 t->maptrack_head = handle;
128 t->map_count--;
129 }
131 static inline int
132 get_maptrack_handle(
133 struct grant_table *lgt)
134 {
135 int i;
136 grant_handle_t handle;
137 struct grant_mapping *new_mt;
138 unsigned int new_mt_limit, nr_frames;
140 if ( unlikely((handle = __get_maptrack_handle(lgt)) == -1) )
141 {
142 spin_lock(&lgt->lock);
144 if ( unlikely((handle = __get_maptrack_handle(lgt)) == -1) )
145 {
146 nr_frames = nr_maptrack_frames(lgt);
147 if ( nr_frames >= max_nr_maptrack_frames() )
148 {
149 spin_unlock(&lgt->lock);
150 return -1;
151 }
153 new_mt = alloc_xenheap_page();
154 if ( new_mt == NULL )
155 {
156 spin_unlock(&lgt->lock);
157 return -1;
158 }
160 memset(new_mt, 0, PAGE_SIZE);
162 new_mt_limit = lgt->maptrack_limit + MAPTRACK_PER_PAGE;
164 for ( i = lgt->maptrack_limit; i < new_mt_limit; i++ )
165 {
166 new_mt[i % MAPTRACK_PER_PAGE].ref = i+1;
167 new_mt[i % MAPTRACK_PER_PAGE].flags = 0;
168 }
170 lgt->maptrack[nr_frames] = new_mt;
171 lgt->maptrack_limit = new_mt_limit;
173 gdprintk(XENLOG_INFO,
174 "Increased maptrack size to %u frames.\n", nr_frames + 1);
175 handle = __get_maptrack_handle(lgt);
176 }
178 spin_unlock(&lgt->lock);
179 }
180 return handle;
181 }
183 /*
184 * Returns 0 if TLB flush / invalidate required by caller.
185 * va will indicate the address to be invalidated.
186 *
187 * addr is _either_ a host virtual address, or the address of the pte to
188 * update, as indicated by the GNTMAP_contains_pte flag.
189 */
190 static void
191 __gnttab_map_grant_ref(
192 struct gnttab_map_grant_ref *op)
193 {
194 struct domain *ld, *rd;
195 struct vcpu *led;
196 int handle;
197 unsigned long frame = 0;
198 int rc = GNTST_okay;
199 struct active_grant_entry *act;
200 struct grant_mapping *mt;
201 grant_entry_t *sha;
202 union grant_combo scombo, prev_scombo, new_scombo;
204 /*
205 * We bound the number of times we retry CMPXCHG on memory locations that
206 * we share with a guest OS. The reason is that the guest can modify that
207 * location at a higher rate than we can read-modify-CMPXCHG, so the guest
208 * could cause us to livelock. There are a few cases where it is valid for
209 * the guest to race our updates (e.g., to change the GTF_readonly flag),
210 * so we allow a few retries before failing.
211 */
212 int retries = 0;
214 led = current;
215 ld = led->domain;
217 if ( unlikely((op->flags & (GNTMAP_device_map|GNTMAP_host_map)) == 0) )
218 {
219 gdprintk(XENLOG_INFO, "Bad flags in grant map op (%x).\n", op->flags);
220 op->status = GNTST_bad_gntref;
221 return;
222 }
224 if ( acm_pre_grant_map_ref(op->dom) )
225 {
226 op->status = GNTST_permission_denied;
227 return;
228 }
230 if ( unlikely((rd = get_domain_by_id(op->dom)) == NULL) )
231 {
232 if ( rd != NULL )
233 put_domain(rd);
234 gdprintk(XENLOG_INFO, "Could not find domain %d\n", op->dom);
235 op->status = GNTST_bad_domain;
236 return;
237 }
239 if ( unlikely((handle = get_maptrack_handle(ld->grant_table)) == -1) )
240 {
241 put_domain(rd);
242 gdprintk(XENLOG_INFO, "Failed to obtain maptrack handle.\n");
243 op->status = GNTST_no_device_space;
244 return;
245 }
247 spin_lock(&rd->grant_table->lock);
249 /* Bounds check on the grant ref */
250 if ( unlikely(op->ref >= nr_grant_entries(rd->grant_table)))
251 PIN_FAIL(unlock_out, GNTST_bad_gntref, "Bad ref (%d).\n", op->ref);
253 act = &active_entry(rd->grant_table, op->ref);
254 sha = &shared_entry(rd->grant_table, op->ref);
256 /* If already pinned, check the active domid and avoid refcnt overflow. */
257 if ( act->pin &&
258 ((act->domid != ld->domain_id) ||
259 (act->pin & 0x80808080U) != 0) )
260 PIN_FAIL(unlock_out, GNTST_general_error,
261 "Bad domain (%d != %d), or risk of counter overflow %08x\n",
262 act->domid, ld->domain_id, act->pin);
264 if ( !act->pin ||
265 (!(op->flags & GNTMAP_readonly) &&
266 !(act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask))) )
267 {
268 scombo.word = *(u32 *)&sha->flags;
270 /*
271 * This loop attempts to set the access (reading/writing) flags
272 * in the grant table entry. It tries a cmpxchg on the field
273 * up to five times, and then fails under the assumption that
274 * the guest is misbehaving.
275 */
276 for ( ; ; )
277 {
278 /* If not already pinned, check the grant domid and type. */
279 if ( !act->pin &&
280 (((scombo.shorts.flags & GTF_type_mask) !=
281 GTF_permit_access) ||
282 (scombo.shorts.domid != ld->domain_id)) )
283 PIN_FAIL(unlock_out, GNTST_general_error,
284 "Bad flags (%x) or dom (%d). (expected dom %d)\n",
285 scombo.shorts.flags, scombo.shorts.domid,
286 ld->domain_id);
288 new_scombo = scombo;
289 new_scombo.shorts.flags |= GTF_reading;
291 if ( !(op->flags & GNTMAP_readonly) )
292 {
293 new_scombo.shorts.flags |= GTF_writing;
294 if ( unlikely(scombo.shorts.flags & GTF_readonly) )
295 PIN_FAIL(unlock_out, GNTST_general_error,
296 "Attempt to write-pin a r/o grant entry.\n");
297 }
299 prev_scombo.word = cmpxchg((u32 *)&sha->flags,
300 scombo.word, new_scombo.word);
301 if ( likely(prev_scombo.word == scombo.word) )
302 break;
304 if ( retries++ == 4 )
305 PIN_FAIL(unlock_out, GNTST_general_error,
306 "Shared grant entry is unstable.\n");
308 scombo = prev_scombo;
309 }
311 if ( !act->pin )
312 {
313 act->domid = scombo.shorts.domid;
314 act->frame = gmfn_to_mfn(rd, sha->frame);
315 }
316 }
318 if ( op->flags & GNTMAP_device_map )
319 act->pin += (op->flags & GNTMAP_readonly) ?
320 GNTPIN_devr_inc : GNTPIN_devw_inc;
321 if ( op->flags & GNTMAP_host_map )
322 act->pin += (op->flags & GNTMAP_readonly) ?
323 GNTPIN_hstr_inc : GNTPIN_hstw_inc;
325 frame = act->frame;
327 spin_unlock(&rd->grant_table->lock);
329 if ( unlikely(!mfn_valid(frame)) ||
330 unlikely(!((op->flags & GNTMAP_readonly) ?
331 get_page(mfn_to_page(frame), rd) :
332 get_page_and_type(mfn_to_page(frame), rd,
333 PGT_writable_page))) )
334 {
335 if ( !test_bit(_DOMF_dying, &rd->domain_flags) )
336 gdprintk(XENLOG_WARNING, "Could not pin grant frame %lx\n", frame);
337 rc = GNTST_general_error;
338 goto undo_out;
339 }
341 if ( op->flags & GNTMAP_host_map )
342 {
343 rc = create_grant_host_mapping(op->host_addr, frame, op->flags);
344 if ( rc != GNTST_okay )
345 {
346 if ( !(op->flags & GNTMAP_readonly) )
347 put_page_type(mfn_to_page(frame));
348 put_page(mfn_to_page(frame));
349 goto undo_out;
350 }
352 if ( op->flags & GNTMAP_device_map )
353 {
354 (void)get_page(mfn_to_page(frame), rd);
355 if ( !(op->flags & GNTMAP_readonly) )
356 get_page_type(mfn_to_page(frame), PGT_writable_page);
357 }
358 }
360 TRACE_1D(TRC_MEM_PAGE_GRANT_MAP, op->dom);
362 mt = &maptrack_entry(ld->grant_table, handle);
363 mt->domid = op->dom;
364 mt->ref = op->ref;
365 mt->flags = op->flags;
367 op->dev_bus_addr = (u64)frame << PAGE_SHIFT;
368 op->handle = handle;
369 op->status = GNTST_okay;
371 put_domain(rd);
372 return;
374 undo_out:
375 spin_lock(&rd->grant_table->lock);
377 act = &active_entry(rd->grant_table, op->ref);
378 sha = &shared_entry(rd->grant_table, op->ref);
380 if ( op->flags & GNTMAP_device_map )
381 act->pin -= (op->flags & GNTMAP_readonly) ?
382 GNTPIN_devr_inc : GNTPIN_devw_inc;
383 if ( op->flags & GNTMAP_host_map )
384 act->pin -= (op->flags & GNTMAP_readonly) ?
385 GNTPIN_hstr_inc : GNTPIN_hstw_inc;
387 if ( !(op->flags & GNTMAP_readonly) &&
388 !(act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask)) )
389 gnttab_clear_flag(_GTF_writing, &sha->flags);
391 if ( !act->pin )
392 gnttab_clear_flag(_GTF_reading, &sha->flags);
394 unlock_out:
395 spin_unlock(&rd->grant_table->lock);
396 op->status = rc;
397 put_maptrack_handle(ld->grant_table, handle);
398 put_domain(rd);
399 }
401 static long
402 gnttab_map_grant_ref(
403 XEN_GUEST_HANDLE(gnttab_map_grant_ref_t) uop, unsigned int count)
404 {
405 int i;
406 struct gnttab_map_grant_ref op;
408 for ( i = 0; i < count; i++ )
409 {
410 if ( unlikely(__copy_from_guest_offset(&op, uop, i, 1)) )
411 return -EFAULT;
412 __gnttab_map_grant_ref(&op);
413 if ( unlikely(__copy_to_guest_offset(uop, i, &op, 1)) )
414 return -EFAULT;
415 }
417 return 0;
418 }
420 static void
421 __gnttab_unmap_grant_ref(
422 struct gnttab_unmap_grant_ref *op)
423 {
424 domid_t dom;
425 grant_ref_t ref;
426 struct domain *ld, *rd;
427 struct active_grant_entry *act;
428 grant_entry_t *sha;
429 struct grant_mapping *map;
430 u16 flags;
431 s16 rc = 0;
432 unsigned long frame;
434 ld = current->domain;
436 frame = (unsigned long)(op->dev_bus_addr >> PAGE_SHIFT);
438 if ( unlikely(op->handle >= ld->grant_table->maptrack_limit) )
439 {
440 gdprintk(XENLOG_INFO, "Bad handle (%d).\n", op->handle);
441 op->status = GNTST_bad_handle;
442 return;
443 }
445 map = &maptrack_entry(ld->grant_table, op->handle);
447 if ( unlikely(!map->flags) )
448 {
449 gdprintk(XENLOG_INFO, "Zero flags for handle (%d).\n", op->handle);
450 op->status = GNTST_bad_handle;
451 return;
452 }
454 dom = map->domid;
455 ref = map->ref;
456 flags = map->flags;
458 if ( unlikely((rd = get_domain_by_id(dom)) == NULL) )
459 {
460 /* This can happen when a grant is implicitly unmapped. */
461 gdprintk(XENLOG_INFO, "Could not find domain %d\n", dom);
462 domain_crash(ld); /* naughty... */
463 return;
464 }
466 TRACE_1D(TRC_MEM_PAGE_GRANT_UNMAP, dom);
468 spin_lock(&rd->grant_table->lock);
470 act = &active_entry(rd->grant_table, ref);
471 sha = &shared_entry(rd->grant_table, ref);
473 if ( frame == 0 )
474 {
475 frame = act->frame;
476 }
477 else
478 {
479 if ( unlikely(frame != act->frame) )
480 PIN_FAIL(unmap_out, GNTST_general_error,
481 "Bad frame number doesn't match gntref.\n");
482 if ( flags & GNTMAP_device_map )
483 {
484 ASSERT(act->pin & (GNTPIN_devw_mask | GNTPIN_devr_mask));
485 map->flags &= ~GNTMAP_device_map;
486 if ( flags & GNTMAP_readonly )
487 {
488 act->pin -= GNTPIN_devr_inc;
489 put_page(mfn_to_page(frame));
490 }
491 else
492 {
493 act->pin -= GNTPIN_devw_inc;
494 put_page_and_type(mfn_to_page(frame));
495 }
496 }
497 }
499 if ( (op->host_addr != 0) && (flags & GNTMAP_host_map) )
500 {
501 if ( (rc = destroy_grant_host_mapping(op->host_addr,
502 frame, flags)) < 0 )
503 goto unmap_out;
505 ASSERT(act->pin & (GNTPIN_hstw_mask | GNTPIN_hstr_mask));
506 map->flags &= ~GNTMAP_host_map;
507 if ( flags & GNTMAP_readonly )
508 {
509 act->pin -= GNTPIN_hstr_inc;
510 put_page(mfn_to_page(frame));
511 }
512 else
513 {
514 act->pin -= GNTPIN_hstw_inc;
515 put_page_and_type(mfn_to_page(frame));
516 }
517 }
519 if ( (map->flags & (GNTMAP_device_map|GNTMAP_host_map)) == 0 )
520 {
521 map->flags = 0;
522 put_maptrack_handle(ld->grant_table, op->handle);
523 }
525 /* If just unmapped a writable mapping, mark as dirtied */
526 if ( !(flags & GNTMAP_readonly) )
527 gnttab_mark_dirty(rd, frame);
529 if ( ((act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0) &&
530 !(flags & GNTMAP_readonly) )
531 gnttab_clear_flag(_GTF_writing, &sha->flags);
533 if ( act->pin == 0 )
534 gnttab_clear_flag(_GTF_reading, &sha->flags);
536 unmap_out:
537 op->status = rc;
538 spin_unlock(&rd->grant_table->lock);
539 put_domain(rd);
540 }
542 static long
543 gnttab_unmap_grant_ref(
544 XEN_GUEST_HANDLE(gnttab_unmap_grant_ref_t) uop, unsigned int count)
545 {
546 int i;
547 struct gnttab_unmap_grant_ref op;
549 for ( i = 0; i < count; i++ )
550 {
551 if ( unlikely(__copy_from_guest_offset(&op, uop, i, 1)) )
552 goto fault;
553 __gnttab_unmap_grant_ref(&op);
554 if ( unlikely(__copy_to_guest_offset(uop, i, &op, 1)) )
555 goto fault;
556 }
558 flush_tlb_mask(current->domain->domain_dirty_cpumask);
559 return 0;
561 fault:
562 flush_tlb_mask(current->domain->domain_dirty_cpumask);
563 return -EFAULT;
564 }
566 int
567 gnttab_grow_table(struct domain *d, unsigned int req_nr_frames)
568 {
569 /* d's grant table lock must be held by the caller */
571 struct grant_table *gt = d->grant_table;
572 unsigned int i;
574 ASSERT(req_nr_frames <= max_nr_grant_frames);
576 gdprintk(XENLOG_INFO,
577 "Expanding dom (%d) grant table from (%d) to (%d) frames.\n",
578 d->domain_id, nr_grant_frames(gt), req_nr_frames);
580 /* Active */
581 for ( i = nr_active_grant_frames(gt);
582 i < num_act_frames_from_sha_frames(req_nr_frames); i++ )
583 {
584 if ( (gt->active[i] = alloc_xenheap_page()) == NULL )
585 goto active_alloc_failed;
586 memset(gt->active[i], 0, PAGE_SIZE);
587 }
589 /* Shared */
590 for ( i = nr_grant_frames(gt); i < req_nr_frames; i++ )
591 {
592 if ( (gt->shared[i] = alloc_xenheap_page()) == NULL )
593 goto shared_alloc_failed;
594 memset(gt->shared[i], 0, PAGE_SIZE);
595 }
597 /* Share the new shared frames with the recipient domain */
598 for ( i = nr_grant_frames(gt); i < req_nr_frames; i++ )
599 gnttab_create_shared_page(d, gt, i);
601 gt->nr_grant_frames = req_nr_frames;
603 return 1;
605 shared_alloc_failed:
606 for ( i = nr_grant_frames(gt); i < req_nr_frames; i++ )
607 {
608 free_xenheap_page(gt->shared[i]);
609 gt->shared[i] = NULL;
610 }
611 active_alloc_failed:
612 for ( i = nr_active_grant_frames(gt);
613 i < num_act_frames_from_sha_frames(req_nr_frames); i++ )
614 {
615 free_xenheap_page(gt->active[i]);
616 gt->active[i] = NULL;
617 }
618 gdprintk(XENLOG_INFO, "Allocation failure when expanding grant table.\n");
619 return 0;
620 }
622 static long
623 gnttab_setup_table(
624 XEN_GUEST_HANDLE(gnttab_setup_table_t) uop, unsigned int count)
625 {
626 struct gnttab_setup_table op;
627 struct domain *d;
628 int i;
629 unsigned long gmfn;
630 domid_t dom;
632 if ( count != 1 )
633 return -EINVAL;
635 if ( unlikely(copy_from_guest(&op, uop, 1) != 0) )
636 {
637 gdprintk(XENLOG_INFO, "Fault while reading gnttab_setup_table_t.\n");
638 return -EFAULT;
639 }
641 if ( unlikely(op.nr_frames > max_nr_grant_frames) )
642 {
643 gdprintk(XENLOG_INFO, "Xen only supports up to %d grant-table frames"
644 " per domain.\n",
645 max_nr_grant_frames);
646 op.status = GNTST_general_error;
647 goto out;
648 }
650 dom = op.dom;
651 if ( dom == DOMID_SELF )
652 {
653 dom = current->domain->domain_id;
654 }
655 else if ( unlikely(!IS_PRIV(current->domain)) )
656 {
657 op.status = GNTST_permission_denied;
658 goto out;
659 }
661 if ( unlikely((d = get_domain_by_id(dom)) == NULL) )
662 {
663 gdprintk(XENLOG_INFO, "Bad domid %d.\n", dom);
664 op.status = GNTST_bad_domain;
665 goto out;
666 }
668 spin_lock(&d->grant_table->lock);
670 if ( (op.nr_frames > nr_grant_frames(d->grant_table)) &&
671 !gnttab_grow_table(d, op.nr_frames) )
672 {
673 gdprintk(XENLOG_INFO,
674 "Expand grant table to %d failed. Current: %d Max: %d.\n",
675 op.nr_frames,
676 nr_grant_frames(d->grant_table),
677 max_nr_grant_frames);
678 op.status = GNTST_general_error;
679 goto setup_unlock_out;
680 }
682 op.status = GNTST_okay;
683 for ( i = 0; i < op.nr_frames; i++ )
684 {
685 gmfn = gnttab_shared_gmfn(d, d->grant_table, i);
686 (void)copy_to_guest_offset(op.frame_list, i, &gmfn, 1);
687 }
689 setup_unlock_out:
690 spin_unlock(&d->grant_table->lock);
692 put_domain(d);
694 out:
695 if ( unlikely(copy_to_guest(uop, &op, 1)) )
696 return -EFAULT;
698 return 0;
699 }
701 static long
702 gnttab_query_size(
703 XEN_GUEST_HANDLE(gnttab_query_size_t) uop, unsigned int count)
704 {
705 struct gnttab_query_size op;
706 struct domain *d;
707 domid_t dom;
709 if ( count != 1 )
710 return -EINVAL;
712 if ( unlikely(copy_from_guest(&op, uop, 1) != 0) )
713 {
714 gdprintk(XENLOG_INFO, "Fault while reading gnttab_query_size_t.\n");
715 return -EFAULT;
716 }
718 dom = op.dom;
719 if ( dom == DOMID_SELF )
720 {
721 dom = current->domain->domain_id;
722 }
723 else if ( unlikely(!IS_PRIV(current->domain)) )
724 {
725 op.status = GNTST_permission_denied;
726 goto query_out;
727 }
729 if ( unlikely((d = get_domain_by_id(dom)) == NULL) )
730 {
731 gdprintk(XENLOG_INFO, "Bad domid %d.\n", dom);
732 op.status = GNTST_bad_domain;
733 goto query_out;
734 }
736 spin_lock(&d->grant_table->lock);
738 op.nr_frames = nr_grant_frames(d->grant_table);
739 op.max_nr_frames = max_nr_grant_frames;
740 op.status = GNTST_okay;
742 spin_unlock(&d->grant_table->lock);
744 put_domain(d);
746 query_out:
747 if ( unlikely(copy_to_guest(uop, &op, 1)) )
748 return -EFAULT;
750 return 0;
751 }
753 /*
754 * Check that the given grant reference (rd,ref) allows 'ld' to transfer
755 * ownership of a page frame. If so, lock down the grant entry.
756 */
757 static int
758 gnttab_prepare_for_transfer(
759 struct domain *rd, struct domain *ld, grant_ref_t ref)
760 {
761 struct grant_table *rgt;
762 struct grant_entry *sha;
763 union grant_combo scombo, prev_scombo, new_scombo;
764 int retries = 0;
766 if ( unlikely((rgt = rd->grant_table) == NULL) )
767 {
768 gdprintk(XENLOG_INFO, "Dom %d has no grant table.\n", rd->domain_id);
769 return 0;
770 }
772 spin_lock(&rgt->lock);
774 if ( unlikely(ref >= nr_grant_entries(rd->grant_table)) )
775 {
776 gdprintk(XENLOG_INFO,
777 "Bad grant reference (%d) for transfer to domain(%d).\n",
778 ref, rd->domain_id);
779 goto fail;
780 }
782 sha = &shared_entry(rgt, ref);
784 scombo.word = *(u32 *)&sha->flags;
786 for ( ; ; )
787 {
788 if ( unlikely(scombo.shorts.flags != GTF_accept_transfer) ||
789 unlikely(scombo.shorts.domid != ld->domain_id) )
790 {
791 gdprintk(XENLOG_INFO, "Bad flags (%x) or dom (%d). "
792 "(NB. expected dom %d)\n",
793 scombo.shorts.flags, scombo.shorts.domid,
794 ld->domain_id);
795 goto fail;
796 }
798 new_scombo = scombo;
799 new_scombo.shorts.flags |= GTF_transfer_committed;
801 prev_scombo.word = cmpxchg((u32 *)&sha->flags,
802 scombo.word, new_scombo.word);
803 if ( likely(prev_scombo.word == scombo.word) )
804 break;
806 if ( retries++ == 4 )
807 {
808 gdprintk(XENLOG_WARNING, "Shared grant entry is unstable.\n");
809 goto fail;
810 }
812 scombo = prev_scombo;
813 }
815 spin_unlock(&rgt->lock);
816 return 1;
818 fail:
819 spin_unlock(&rgt->lock);
820 return 0;
821 }
823 static long
824 gnttab_transfer(
825 XEN_GUEST_HANDLE(gnttab_transfer_t) uop, unsigned int count)
826 {
827 struct domain *d = current->domain;
828 struct domain *e;
829 struct page_info *page;
830 int i;
831 grant_entry_t *sha;
832 struct gnttab_transfer gop;
833 unsigned long mfn;
835 for ( i = 0; i < count; i++ )
836 {
837 /* Read from caller address space. */
838 if ( unlikely(__copy_from_guest_offset(&gop, uop, i, 1)) )
839 {
840 gdprintk(XENLOG_INFO, "gnttab_transfer: error reading req %d/%d\n",
841 i, count);
842 return -EFAULT;
843 }
845 mfn = gmfn_to_mfn(d, gop.mfn);
847 /* Check the passed page frame for basic validity. */
848 if ( unlikely(!mfn_valid(mfn)) )
849 {
850 gdprintk(XENLOG_INFO, "gnttab_transfer: out-of-range %lx\n",
851 (unsigned long)gop.mfn);
852 gop.status = GNTST_bad_page;
853 goto copyback;
854 }
856 page = mfn_to_page(mfn);
857 if ( unlikely(IS_XEN_HEAP_FRAME(page)) )
858 {
859 gdprintk(XENLOG_INFO, "gnttab_transfer: xen frame %lx\n",
860 (unsigned long)gop.mfn);
861 gop.status = GNTST_bad_page;
862 goto copyback;
863 }
865 if ( steal_page(d, page, 0) < 0 )
866 {
867 gop.status = GNTST_bad_page;
868 goto copyback;
869 }
871 /* Find the target domain. */
872 if ( unlikely((e = get_domain_by_id(gop.domid)) == NULL) )
873 {
874 gdprintk(XENLOG_INFO, "gnttab_transfer: can't find domain %d\n",
875 gop.domid);
876 page->count_info &= ~(PGC_count_mask|PGC_allocated);
877 free_domheap_page(page);
878 gop.status = GNTST_bad_domain;
879 goto copyback;
880 }
882 spin_lock(&e->page_alloc_lock);
884 /*
885 * Check that 'e' will accept the page and has reservation
886 * headroom. Also, a domain mustn't have PGC_allocated
887 * pages when it is dying.
888 */
889 if ( unlikely(test_bit(_DOMF_dying, &e->domain_flags)) ||
890 unlikely(e->tot_pages >= e->max_pages) ||
891 unlikely(!gnttab_prepare_for_transfer(e, d, gop.ref)) )
892 {
893 if ( !test_bit(_DOMF_dying, &e->domain_flags) )
894 gdprintk(XENLOG_INFO, "gnttab_transfer: "
895 "Transferee has no reservation "
896 "headroom (%d,%d) or provided a bad grant ref (%08x) "
897 "or is dying (%lx)\n",
898 e->tot_pages, e->max_pages, gop.ref, e->domain_flags);
899 spin_unlock(&e->page_alloc_lock);
900 put_domain(e);
901 page->count_info &= ~(PGC_count_mask|PGC_allocated);
902 free_domheap_page(page);
903 gop.status = GNTST_general_error;
904 goto copyback;
905 }
907 /* Okay, add the page to 'e'. */
908 if ( unlikely(e->tot_pages++ == 0) )
909 get_knownalive_domain(e);
910 list_add_tail(&page->list, &e->page_list);
911 page_set_owner(page, e);
913 spin_unlock(&e->page_alloc_lock);
915 TRACE_1D(TRC_MEM_PAGE_GRANT_TRANSFER, e->domain_id);
917 /* Tell the guest about its new page frame. */
918 spin_lock(&e->grant_table->lock);
920 sha = &shared_entry(e->grant_table, gop.ref);
921 guest_physmap_add_page(e, sha->frame, mfn);
922 sha->frame = mfn;
923 wmb();
924 sha->flags |= GTF_transfer_completed;
926 spin_unlock(&e->grant_table->lock);
928 put_domain(e);
930 gop.status = GNTST_okay;
932 copyback:
933 if ( unlikely(__copy_to_guest_offset(uop, i, &gop, 1)) )
934 {
935 gdprintk(XENLOG_INFO, "gnttab_transfer: error writing resp "
936 "%d/%d\n", i, count);
937 return -EFAULT;
938 }
939 }
941 return 0;
942 }
944 /* Undo __acquire_grant_for_copy. Again, this has no effect on page
945 type and reference counts. */
946 static void
947 __release_grant_for_copy(
948 struct domain *rd, unsigned long gref, int readonly)
949 {
950 grant_entry_t *sha;
951 struct active_grant_entry *act;
952 unsigned long r_frame;
954 spin_lock(&rd->grant_table->lock);
956 act = &active_entry(rd->grant_table, gref);
957 sha = &shared_entry(rd->grant_table, gref);
958 r_frame = act->frame;
960 if ( readonly )
961 {
962 act->pin -= GNTPIN_hstr_inc;
963 }
964 else
965 {
966 gnttab_mark_dirty(rd, r_frame);
968 act->pin -= GNTPIN_hstw_inc;
969 if ( !(act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) )
970 gnttab_clear_flag(_GTF_writing, &sha->flags);
971 }
973 if ( !act->pin )
974 gnttab_clear_flag(_GTF_reading, &sha->flags);
976 spin_unlock(&rd->grant_table->lock);
977 }
979 /* Grab a frame number from a grant entry and update the flags and pin
980 count as appropriate. Note that this does *not* update the page
981 type or reference counts, and does not check that the mfn is
982 actually valid. */
983 static int
984 __acquire_grant_for_copy(
985 struct domain *rd, unsigned long gref, int readonly,
986 unsigned long *frame)
987 {
988 grant_entry_t *sha;
989 struct active_grant_entry *act;
990 s16 rc = GNTST_okay;
991 int retries = 0;
992 union grant_combo scombo, prev_scombo, new_scombo;
994 spin_lock(&rd->grant_table->lock);
996 if ( unlikely(gref >= nr_grant_entries(rd->grant_table)) )
997 PIN_FAIL(unlock_out, GNTST_bad_gntref,
998 "Bad grant reference %ld\n", gref);
1000 act = &active_entry(rd->grant_table, gref);
1001 sha = &shared_entry(rd->grant_table, gref);
1003 /* If already pinned, check the active domid and avoid refcnt overflow. */
1004 if ( act->pin &&
1005 ((act->domid != current->domain->domain_id) ||
1006 (act->pin & 0x80808080U) != 0) )
1007 PIN_FAIL(unlock_out, GNTST_general_error,
1008 "Bad domain (%d != %d), or risk of counter overflow %08x\n",
1009 act->domid, current->domain->domain_id, act->pin);
1011 if ( !act->pin ||
1012 (!readonly && !(act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask))) )
1014 scombo.word = *(u32 *)&sha->flags;
1016 for ( ; ; )
1018 /* If not already pinned, check the grant domid and type. */
1019 if ( !act->pin &&
1020 (((scombo.shorts.flags & GTF_type_mask) !=
1021 GTF_permit_access) ||
1022 (scombo.shorts.domid != current->domain->domain_id)) )
1023 PIN_FAIL(unlock_out, GNTST_general_error,
1024 "Bad flags (%x) or dom (%d). (expected dom %d)\n",
1025 scombo.shorts.flags, scombo.shorts.domid,
1026 current->domain->domain_id);
1028 new_scombo = scombo;
1029 new_scombo.shorts.flags |= GTF_reading;
1031 if ( !readonly )
1033 new_scombo.shorts.flags |= GTF_writing;
1034 if ( unlikely(scombo.shorts.flags & GTF_readonly) )
1035 PIN_FAIL(unlock_out, GNTST_general_error,
1036 "Attempt to write-pin a r/o grant entry.\n");
1039 prev_scombo.word = cmpxchg((u32 *)&sha->flags,
1040 scombo.word, new_scombo.word);
1041 if ( likely(prev_scombo.word == scombo.word) )
1042 break;
1044 if ( retries++ == 4 )
1045 PIN_FAIL(unlock_out, GNTST_general_error,
1046 "Shared grant entry is unstable.\n");
1048 scombo = prev_scombo;
1051 if ( !act->pin )
1053 act->domid = scombo.shorts.domid;
1054 act->frame = gmfn_to_mfn(rd, sha->frame);
1058 act->pin += readonly ? GNTPIN_hstr_inc : GNTPIN_hstw_inc;
1060 *frame = act->frame;
1062 unlock_out:
1063 spin_unlock(&rd->grant_table->lock);
1064 return rc;
1067 static void
1068 __gnttab_copy(
1069 struct gnttab_copy *op)
1071 struct domain *sd = NULL, *dd = NULL;
1072 unsigned long s_frame, d_frame;
1073 char *sp, *dp;
1074 s16 rc = GNTST_okay;
1075 int have_d_grant = 0, have_s_grant = 0, have_s_ref = 0;
1076 int src_is_gref, dest_is_gref;
1078 if ( ((op->source.offset + op->len) > PAGE_SIZE) ||
1079 ((op->dest.offset + op->len) > PAGE_SIZE) )
1080 PIN_FAIL(error_out, GNTST_bad_copy_arg, "copy beyond page area.\n");
1082 src_is_gref = op->flags & GNTCOPY_source_gref;
1083 dest_is_gref = op->flags & GNTCOPY_dest_gref;
1085 if ( (op->source.domid != DOMID_SELF && !src_is_gref ) ||
1086 (op->dest.domid != DOMID_SELF && !dest_is_gref) )
1087 PIN_FAIL(error_out, GNTST_permission_denied,
1088 "only allow copy-by-mfn for DOMID_SELF.\n");
1090 if ( op->source.domid == DOMID_SELF )
1092 sd = current->domain;
1093 get_knownalive_domain(sd);
1095 else if ( (sd = get_domain_by_id(op->source.domid)) == NULL )
1097 PIN_FAIL(error_out, GNTST_bad_domain,
1098 "couldn't find %d\n", op->source.domid);
1101 if ( op->dest.domid == DOMID_SELF )
1103 dd = current->domain;
1104 get_knownalive_domain(dd);
1106 else if ( (dd = get_domain_by_id(op->dest.domid)) == NULL )
1108 PIN_FAIL(error_out, GNTST_bad_domain,
1109 "couldn't find %d\n", op->dest.domid);
1112 if ( src_is_gref )
1114 rc = __acquire_grant_for_copy(sd, op->source.u.ref, 1, &s_frame);
1115 if ( rc != GNTST_okay )
1116 goto error_out;
1117 have_s_grant = 1;
1119 else
1121 s_frame = gmfn_to_mfn(sd, op->source.u.gmfn);
1123 if ( unlikely(!mfn_valid(s_frame)) )
1124 PIN_FAIL(error_out, GNTST_general_error,
1125 "source frame %lx invalid.\n", s_frame);
1126 if ( !get_page(mfn_to_page(s_frame), sd) )
1128 if ( !test_bit(_DOMF_dying, &sd->domain_flags) )
1129 gdprintk(XENLOG_WARNING, "Could not get src frame %lx\n", s_frame);
1130 rc = GNTST_general_error;
1131 goto error_out;
1133 have_s_ref = 1;
1135 if ( dest_is_gref )
1137 rc = __acquire_grant_for_copy(dd, op->dest.u.ref, 0, &d_frame);
1138 if ( rc != GNTST_okay )
1139 goto error_out;
1140 have_d_grant = 1;
1142 else
1144 d_frame = gmfn_to_mfn(dd, op->dest.u.gmfn);
1146 if ( unlikely(!mfn_valid(d_frame)) )
1147 PIN_FAIL(error_out, GNTST_general_error,
1148 "destination frame %lx invalid.\n", d_frame);
1149 if ( !get_page_and_type(mfn_to_page(d_frame), dd, PGT_writable_page) )
1151 if ( !test_bit(_DOMF_dying, &dd->domain_flags) )
1152 gdprintk(XENLOG_WARNING, "Could not get dst frame %lx\n", d_frame);
1153 rc = GNTST_general_error;
1154 goto error_out;
1157 sp = map_domain_page(s_frame);
1158 dp = map_domain_page(d_frame);
1160 memcpy(dp + op->dest.offset, sp + op->source.offset, op->len);
1162 unmap_domain_page(dp);
1163 unmap_domain_page(sp);
1165 gnttab_mark_dirty(dd, d_frame);
1167 put_page_and_type(mfn_to_page(d_frame));
1168 error_out:
1169 if ( have_s_ref )
1170 put_page(mfn_to_page(s_frame));
1171 if ( have_s_grant )
1172 __release_grant_for_copy(sd, op->source.u.ref, 1);
1173 if ( have_d_grant )
1174 __release_grant_for_copy(dd, op->dest.u.ref, 0);
1175 if ( sd )
1176 put_domain(sd);
1177 if ( dd )
1178 put_domain(dd);
1179 op->status = rc;
1182 static long
1183 gnttab_copy(
1184 XEN_GUEST_HANDLE(gnttab_copy_t) uop, unsigned int count)
1186 int i;
1187 struct gnttab_copy op;
1189 for ( i = 0; i < count; i++ )
1191 if ( unlikely(__copy_from_guest_offset(&op, uop, i, 1)) )
1192 return -EFAULT;
1193 __gnttab_copy(&op);
1194 if ( unlikely(__copy_to_guest_offset(uop, i, &op, 1)) )
1195 return -EFAULT;
1197 return 0;
1200 long
1201 do_grant_table_op(
1202 unsigned int cmd, XEN_GUEST_HANDLE(void) uop, unsigned int count)
1204 long rc;
1205 struct domain *d = current->domain;
1207 if ( count > 512 )
1208 return -EINVAL;
1210 LOCK_BIGLOCK(d);
1212 rc = -EFAULT;
1213 switch ( cmd )
1215 case GNTTABOP_map_grant_ref:
1217 XEN_GUEST_HANDLE(gnttab_map_grant_ref_t) map =
1218 guest_handle_cast(uop, gnttab_map_grant_ref_t);
1219 if ( unlikely(!guest_handle_okay(map, count)) )
1220 goto out;
1221 rc = -EPERM;
1222 if ( unlikely(!grant_operation_permitted(d)) )
1223 goto out;
1224 rc = gnttab_map_grant_ref(map, count);
1225 break;
1227 case GNTTABOP_unmap_grant_ref:
1229 XEN_GUEST_HANDLE(gnttab_unmap_grant_ref_t) unmap =
1230 guest_handle_cast(uop, gnttab_unmap_grant_ref_t);
1231 if ( unlikely(!guest_handle_okay(unmap, count)) )
1232 goto out;
1233 rc = -EPERM;
1234 if ( unlikely(!grant_operation_permitted(d)) )
1235 goto out;
1236 rc = gnttab_unmap_grant_ref(unmap, count);
1237 break;
1239 case GNTTABOP_setup_table:
1241 rc = gnttab_setup_table(
1242 guest_handle_cast(uop, gnttab_setup_table_t), count);
1243 break;
1245 case GNTTABOP_transfer:
1247 XEN_GUEST_HANDLE(gnttab_transfer_t) transfer =
1248 guest_handle_cast(uop, gnttab_transfer_t);
1249 if ( unlikely(!guest_handle_okay(transfer, count)) )
1250 goto out;
1251 rc = -EPERM;
1252 if ( unlikely(!grant_operation_permitted(d)) )
1253 goto out;
1254 rc = gnttab_transfer(transfer, count);
1255 break;
1257 case GNTTABOP_copy:
1259 XEN_GUEST_HANDLE(gnttab_copy_t) copy =
1260 guest_handle_cast(uop, gnttab_copy_t);
1261 if ( unlikely(!guest_handle_okay(copy, count)) )
1262 goto out;
1263 rc = gnttab_copy(copy, count);
1264 break;
1266 case GNTTABOP_query_size:
1268 rc = gnttab_query_size(
1269 guest_handle_cast(uop, gnttab_query_size_t), count);
1270 break;
1272 default:
1273 rc = -ENOSYS;
1274 break;
1277 out:
1278 UNLOCK_BIGLOCK(d);
1280 return rc;
1283 #ifdef CONFIG_COMPAT
1284 #include "compat/grant_table.c"
1285 #endif
1287 static unsigned int max_nr_active_grant_frames(void)
1289 return (((max_nr_grant_frames * (PAGE_SIZE / sizeof(grant_entry_t))) +
1290 ((PAGE_SIZE / sizeof(struct active_grant_entry))-1))
1291 / (PAGE_SIZE / sizeof(struct active_grant_entry)));
1294 int
1295 grant_table_create(
1296 struct domain *d)
1298 struct grant_table *t;
1299 int i;
1301 /* If this sizeof assertion fails, fix the function: shared_index */
1302 ASSERT(sizeof(grant_entry_t) == 8);
1304 if ( (t = xmalloc(struct grant_table)) == NULL )
1305 goto no_mem_0;
1307 /* Simple stuff. */
1308 memset(t, 0, sizeof(*t));
1309 spin_lock_init(&t->lock);
1310 t->nr_grant_frames = INITIAL_NR_GRANT_FRAMES;
1312 /* Active grant table. */
1313 if ( (t->active = xmalloc_array(struct active_grant_entry *,
1314 max_nr_active_grant_frames())) == NULL )
1315 goto no_mem_1;
1316 memset(t->active, 0, max_nr_active_grant_frames() * sizeof(t->active[0]));
1317 for ( i = 0;
1318 i < num_act_frames_from_sha_frames(INITIAL_NR_GRANT_FRAMES); i++ )
1320 if ( (t->active[i] = alloc_xenheap_page()) == NULL )
1321 goto no_mem_2;
1322 memset(t->active[i], 0, PAGE_SIZE);
1325 /* Tracking of mapped foreign frames table */
1326 if ( (t->maptrack = xmalloc_array(struct grant_mapping *,
1327 max_nr_maptrack_frames())) == NULL )
1328 goto no_mem_2;
1329 memset(t->maptrack, 0, max_nr_maptrack_frames() * sizeof(t->maptrack[0]));
1330 if ( (t->maptrack[0] = alloc_xenheap_page()) == NULL )
1331 goto no_mem_3;
1332 memset(t->maptrack[0], 0, PAGE_SIZE);
1333 t->maptrack_limit = PAGE_SIZE / sizeof(struct grant_mapping);
1334 for ( i = 0; i < t->maptrack_limit; i++ )
1335 t->maptrack[0][i].ref = i+1;
1337 /* Shared grant table. */
1338 if ( (t->shared = xmalloc_array(struct grant_entry *,
1339 max_nr_grant_frames)) == NULL )
1340 goto no_mem_3;
1341 memset(t->shared, 0, max_nr_grant_frames * sizeof(t->shared[0]));
1342 for ( i = 0; i < INITIAL_NR_GRANT_FRAMES; i++ )
1344 if ( (t->shared[i] = alloc_xenheap_page()) == NULL )
1345 goto no_mem_4;
1346 memset(t->shared[i], 0, PAGE_SIZE);
1349 for ( i = 0; i < INITIAL_NR_GRANT_FRAMES; i++ )
1350 gnttab_create_shared_page(d, t, i);
1352 /* Okay, install the structure. */
1353 d->grant_table = t;
1354 return 0;
1356 no_mem_4:
1357 for ( i = 0; i < INITIAL_NR_GRANT_FRAMES; i++ )
1358 free_xenheap_page(t->shared[i]);
1359 xfree(t->shared);
1360 no_mem_3:
1361 free_xenheap_page(t->maptrack[0]);
1362 xfree(t->maptrack);
1363 no_mem_2:
1364 for ( i = 0;
1365 i < num_act_frames_from_sha_frames(INITIAL_NR_GRANT_FRAMES); i++ )
1366 free_xenheap_page(t->active[i]);
1367 xfree(t->active);
1368 no_mem_1:
1369 xfree(t);
1370 no_mem_0:
1371 return -ENOMEM;
1374 void
1375 gnttab_release_mappings(
1376 struct domain *d)
1378 struct grant_table *gt = d->grant_table;
1379 struct grant_mapping *map;
1380 grant_ref_t ref;
1381 grant_handle_t handle;
1382 struct domain *rd;
1383 struct active_grant_entry *act;
1384 struct grant_entry *sha;
1386 BUG_ON(!test_bit(_DOMF_dying, &d->domain_flags));
1388 for ( handle = 0; handle < gt->maptrack_limit; handle++ )
1390 map = &maptrack_entry(gt, handle);
1391 if ( !(map->flags & (GNTMAP_device_map|GNTMAP_host_map)) )
1392 continue;
1394 ref = map->ref;
1396 gdprintk(XENLOG_INFO, "Grant release (%hu) ref:(%hu) "
1397 "flags:(%x) dom:(%hu)\n",
1398 handle, ref, map->flags, map->domid);
1400 rd = get_domain_by_id(map->domid);
1401 if ( rd == NULL )
1403 /* Nothing to clear up... */
1404 map->flags = 0;
1405 continue;
1408 spin_lock(&rd->grant_table->lock);
1410 act = &active_entry(rd->grant_table, ref);
1411 sha = &shared_entry(rd->grant_table, ref);
1413 if ( map->flags & GNTMAP_readonly )
1415 if ( map->flags & GNTMAP_device_map )
1417 BUG_ON(!(act->pin & GNTPIN_devr_mask));
1418 act->pin -= GNTPIN_devr_inc;
1419 put_page(mfn_to_page(act->frame));
1422 if ( map->flags & GNTMAP_host_map )
1424 BUG_ON(!(act->pin & GNTPIN_hstr_mask));
1425 act->pin -= GNTPIN_hstr_inc;
1426 /* Done implicitly when page tables are destroyed. */
1427 /* put_page(mfn_to_page(act->frame)); */
1430 else
1432 if ( map->flags & GNTMAP_device_map )
1434 BUG_ON(!(act->pin & GNTPIN_devw_mask));
1435 act->pin -= GNTPIN_devw_inc;
1436 put_page_and_type(mfn_to_page(act->frame));
1439 if ( map->flags & GNTMAP_host_map )
1441 BUG_ON(!(act->pin & GNTPIN_hstw_mask));
1442 act->pin -= GNTPIN_hstw_inc;
1443 /* Done implicitly when page tables are destroyed. */
1444 /* put_page_and_type(mfn_to_page(act->frame)); */
1447 if ( (act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0 )
1448 gnttab_clear_flag(_GTF_writing, &sha->flags);
1451 if ( act->pin == 0 )
1452 gnttab_clear_flag(_GTF_reading, &sha->flags);
1454 spin_unlock(&rd->grant_table->lock);
1456 put_domain(rd);
1458 map->flags = 0;
1463 void
1464 grant_table_destroy(
1465 struct domain *d)
1467 struct grant_table *t = d->grant_table;
1468 int i;
1470 if ( t == NULL )
1471 return;
1473 for ( i = 0; i < nr_grant_frames(t); i++ )
1474 free_xenheap_page(t->shared[i]);
1475 xfree(t->shared);
1477 for ( i = 0; i < nr_maptrack_frames(t); i++ )
1478 free_xenheap_page(t->maptrack[i]);
1479 xfree(t->maptrack);
1481 for ( i = 0; i < nr_active_grant_frames(t); i++ )
1482 free_xenheap_page(t->active[i]);
1483 xfree(t->active);
1485 xfree(t);
1486 d->grant_table = NULL;
1489 /*
1490 * Local variables:
1491 * mode: C
1492 * c-set-style: "BSD"
1493 * c-basic-offset: 4
1494 * tab-width: 4
1495 * indent-tabs-mode: nil
1496 * End:
1497 */