debuggers.hg

view linux-2.6.11-xen-sparse/arch/xen/kernel/gnttab.c @ 4649:ebeac8efe955

bitkeeper revision 1.1350 (42676ee4BkgqwvPiIyB44k55uY8cSA)

Fix blkdev suspend/resume.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Thu Apr 21 09:14:12 2005 +0000 (2005-04-21)
parents 260db0c4de3b
children acc1ae9083e5
line source
1 /******************************************************************************
2 * gnttab.c
3 *
4 * Two sets of functionality:
5 * 1. Granting foreign access to our memory reservation.
6 * 2. Accessing others' memory reservations via grant references.
7 * (i.e., mechanisms for both sender and recipient of grant references)
8 *
9 * Copyright (c) 2005, Christopher Clark
10 * Copyright (c) 2004, K A Fraser
11 */
13 #include <linux/config.h>
14 #include <linux/module.h>
15 #include <linux/sched.h>
16 #include <asm/pgtable.h>
17 #include <asm/fixmap.h>
18 #include <asm/uaccess.h>
19 #include <asm-xen/xen_proc.h>
20 #include <asm-xen/linux-public/privcmd.h>
21 #include <asm-xen/gnttab.h>
23 #ifndef set_fixmap_ma
24 #define set_fixmap_ma set_fixmap
25 #endif
27 #if 1
28 #define ASSERT(_p) \
29 if ( !(_p) ) { printk(KERN_ALERT"Assertion '%s': line %d, file %s\n", \
30 #_p , __LINE__, __FILE__); *(int*)0=0; }
31 #else
32 #define ASSERT(_p) ((void)0)
33 #endif
35 #define WPRINTK(fmt, args...) \
36 printk(KERN_WARNING "xen_grant: " fmt, ##args)
39 EXPORT_SYMBOL(gnttab_grant_foreign_access);
40 EXPORT_SYMBOL(gnttab_end_foreign_access);
41 EXPORT_SYMBOL(gnttab_query_foreign_access);
42 EXPORT_SYMBOL(gnttab_grant_foreign_transfer);
43 EXPORT_SYMBOL(gnttab_end_foreign_transfer);
44 EXPORT_SYMBOL(gnttab_alloc_grant_references);
45 EXPORT_SYMBOL(gnttab_free_grant_references);
46 EXPORT_SYMBOL(gnttab_claim_grant_reference);
47 EXPORT_SYMBOL(gnttab_release_grant_reference);
48 EXPORT_SYMBOL(gnttab_grant_foreign_access_ref);
49 EXPORT_SYMBOL(gnttab_grant_foreign_transfer_ref);
51 static grant_ref_t gnttab_free_list[NR_GRANT_ENTRIES];
52 static grant_ref_t gnttab_free_head;
54 static grant_entry_t *shared;
56 /* /proc/xen/grant */
57 static struct proc_dir_entry *grant_pde;
60 /*
61 * Lock-free grant-entry allocator
62 */
64 static inline int
65 get_free_entry(
66 void)
67 {
68 grant_ref_t fh, nfh = gnttab_free_head;
69 do { if ( unlikely((fh = nfh) == NR_GRANT_ENTRIES) ) return -1; }
70 while ( unlikely((nfh = cmpxchg(&gnttab_free_head, fh,
71 gnttab_free_list[fh])) != fh) );
72 return fh;
73 }
75 static inline void
76 put_free_entry(
77 grant_ref_t ref)
78 {
79 grant_ref_t fh, nfh = gnttab_free_head;
80 do { gnttab_free_list[ref] = fh = nfh; wmb(); }
81 while ( unlikely((nfh = cmpxchg(&gnttab_free_head, fh, ref)) != fh) );
82 }
84 /*
85 * Public grant-issuing interface functions
86 */
88 int
89 gnttab_grant_foreign_access(
90 domid_t domid, unsigned long frame, int readonly)
91 {
92 int ref;
94 if ( unlikely((ref = get_free_entry()) == -1) )
95 return -ENOSPC;
97 shared[ref].frame = frame;
98 shared[ref].domid = domid;
99 wmb();
100 shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
102 return ref;
103 }
105 void
106 gnttab_grant_foreign_access_ref(
107 grant_ref_t ref, domid_t domid, unsigned long frame, int readonly)
108 {
109 shared[ref].frame = frame;
110 shared[ref].domid = domid;
111 wmb();
112 shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
113 }
116 int
117 gnttab_query_foreign_access( grant_ref_t ref )
118 {
119 u16 nflags;
121 nflags = shared[ref].flags;
123 return ( nflags & (GTF_reading|GTF_writing) );
124 }
126 void
127 gnttab_end_foreign_access( grant_ref_t ref, int readonly )
128 {
129 u16 flags, nflags;
131 nflags = shared[ref].flags;
132 do {
133 if ( (flags = nflags) & (GTF_reading|GTF_writing) )
134 printk(KERN_ALERT "WARNING: g.e. still in use!\n");
135 }
136 while ( (nflags = cmpxchg(&shared[ref].flags, flags, 0)) != flags );
138 put_free_entry(ref);
139 }
141 int
142 gnttab_grant_foreign_transfer(
143 domid_t domid, unsigned long pfn )
144 {
145 int ref;
147 if ( unlikely((ref = get_free_entry()) == -1) )
148 return -ENOSPC;
150 shared[ref].frame = pfn;
151 shared[ref].domid = domid;
152 wmb();
153 shared[ref].flags = GTF_accept_transfer;
155 return ref;
156 }
158 void
159 gnttab_grant_foreign_transfer_ref(
160 grant_ref_t ref, domid_t domid, unsigned long pfn )
161 {
162 shared[ref].frame = pfn;
163 shared[ref].domid = domid;
164 wmb();
165 shared[ref].flags = GTF_accept_transfer;
166 }
168 unsigned long
169 gnttab_end_foreign_transfer(
170 grant_ref_t ref)
171 {
172 unsigned long frame = 0;
173 u16 flags;
175 flags = shared[ref].flags;
176 ASSERT(flags == (GTF_accept_transfer | GTF_transfer_committed));
178 /*
179 * If a transfer is committed then wait for the frame address to appear.
180 * Otherwise invalidate the grant entry against future use.
181 */
182 if ( likely(flags != GTF_accept_transfer) ||
183 (cmpxchg(&shared[ref].flags, flags, 0) != GTF_accept_transfer) )
184 while ( unlikely((frame = shared[ref].frame) == 0) )
185 cpu_relax();
187 put_free_entry(ref);
189 return frame;
190 }
192 void
193 gnttab_free_grant_references( u16 count, grant_ref_t head )
194 {
195 /* TODO: O(N)...? */
196 grant_ref_t to_die = 0, next = head;
197 int i;
199 for ( i = 0; i < count; i++ )
200 to_die = next;
201 next = gnttab_free_list[next];
202 put_free_entry( to_die );
203 }
205 int
206 gnttab_alloc_grant_references( u16 count,
207 grant_ref_t *head,
208 grant_ref_t *terminal )
209 {
210 int i;
211 grant_ref_t h = gnttab_free_head;
213 for ( i = 0; i < count; i++ )
214 if ( unlikely(get_free_entry() == -1) )
215 goto not_enough_refs;
217 *head = h;
218 *terminal = gnttab_free_head;
220 return 0;
222 not_enough_refs:
223 gnttab_free_head = h;
224 return -ENOSPC;
225 }
227 int
228 gnttab_claim_grant_reference( grant_ref_t *private_head,
229 grant_ref_t terminal )
230 {
231 grant_ref_t g;
232 if ( unlikely((g = *private_head) == terminal) )
233 return -ENOSPC;
234 *private_head = gnttab_free_list[g];
235 return g;
236 }
238 void
239 gnttab_release_grant_reference( grant_ref_t *private_head,
240 grant_ref_t release )
241 {
242 gnttab_free_list[release] = *private_head;
243 *private_head = release;
244 }
246 static int grant_ioctl(struct inode *inode, struct file *file,
247 unsigned int cmd, unsigned long data)
248 {
249 int ret;
250 privcmd_hypercall_t hypercall;
252 /* XXX Need safety checks here if using for anything other
253 * than debugging */
254 return -ENOSYS;
256 if ( cmd != IOCTL_PRIVCMD_HYPERCALL )
257 return -ENOSYS;
259 if ( copy_from_user(&hypercall, (void *)data, sizeof(hypercall)) )
260 return -EFAULT;
262 if ( hypercall.op != __HYPERVISOR_grant_table_op )
263 return -ENOSYS;
265 /* hypercall-invoking asm taken from privcmd.c */
266 __asm__ __volatile__ (
267 "pushl %%ebx; pushl %%ecx; pushl %%edx; pushl %%esi; pushl %%edi; "
268 "movl 4(%%eax),%%ebx ;"
269 "movl 8(%%eax),%%ecx ;"
270 "movl 12(%%eax),%%edx ;"
271 "movl 16(%%eax),%%esi ;"
272 "movl 20(%%eax),%%edi ;"
273 "movl (%%eax),%%eax ;"
274 TRAP_INSTR "; "
275 "popl %%edi; popl %%esi; popl %%edx; popl %%ecx; popl %%ebx"
276 : "=a" (ret) : "0" (&hypercall) : "memory" );
278 return ret;
279 }
281 static struct file_operations grant_file_ops = {
282 ioctl: grant_ioctl,
283 };
285 static int grant_read(char *page, char **start, off_t off,
286 int count, int *eof, void *data)
287 {
288 int len;
289 unsigned int i;
290 grant_entry_t *gt;
292 gt = (grant_entry_t *)shared;
293 len = 0;
295 for ( i = 0; i < NR_GRANT_ENTRIES; i++ )
296 /* TODO: safety catch here until this can handle >PAGE_SIZE output */
297 if (len > (PAGE_SIZE - 200))
298 {
299 len += sprintf( page + len, "Truncated.\n");
300 break;
301 }
303 if ( gt[i].flags )
304 len += sprintf( page + len,
305 "Grant: ref (0x%x) flags (0x%hx) dom (0x%hx) frame (0x%x)\n",
306 i,
307 gt[i].flags,
308 gt[i].domid,
309 gt[i].frame );
311 *eof = 1;
312 return len;
313 }
315 static int grant_write(struct file *file, const char __user *buffer,
316 unsigned long count, void *data)
317 {
318 /* TODO: implement this */
319 return -ENOSYS;
320 }
323 int gnttab_resume(void)
324 {
325 gnttab_setup_table_t setup;
326 unsigned long frames[NR_GRANT_FRAMES];
327 int i;
329 setup.dom = DOMID_SELF;
330 setup.nr_frames = NR_GRANT_FRAMES;
331 setup.frame_list = frames;
333 BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1) != 0);
334 BUG_ON(setup.status != 0);
336 for ( i = 0; i < NR_GRANT_FRAMES; i++ )
337 set_fixmap_ma(FIX_GNTTAB_END - i, frames[i] << PAGE_SHIFT);
339 return 0;
340 }
342 int gnttab_suspend(void)
343 {
344 int i;
346 for ( i = 0; i < NR_GRANT_FRAMES; i++ )
347 clear_fixmap(FIX_GNTTAB_END - i);
349 return 0;
350 }
352 static int __init gnttab_init(void)
353 {
354 int i;
356 BUG_ON(gnttab_resume());
358 shared = (grant_entry_t *)fix_to_virt(FIX_GNTTAB_END);
360 for ( i = 0; i < NR_GRANT_ENTRIES; i++ )
361 gnttab_free_list[i] = i + 1;
363 /*
364 * /proc/xen/grant : used by libxc to access grant tables
365 */
366 if ( (grant_pde = create_xen_proc_entry("grant", 0600)) == NULL )
367 {
368 WPRINTK("Unable to create grant xen proc entry\n");
369 return -1;
370 }
372 grant_file_ops.read = grant_pde->proc_fops->read;
373 grant_file_ops.write = grant_pde->proc_fops->write;
375 grant_pde->proc_fops = &grant_file_ops;
377 grant_pde->read_proc = &grant_read;
378 grant_pde->write_proc = &grant_write;
380 printk("Grant table initialized\n");
381 return 0;
382 }
384 __initcall(gnttab_init);