direct-io.hg

view linux-2.6-xen-sparse/arch/xen/kernel/gnttab.c @ 7710:83ec10103067

gnttab_request_free_callback needs to be exported for building modular
blkfront

Signed-off-by: Jeremy Katz <katzj@redhat.com>
author kaf24@firebug.cl.cam.ac.uk
date Wed Nov 09 14:41:37 2005 +0100 (2005-11-09)
parents 1470a9d40072
children 0add9fbe93ab
line source
1 /******************************************************************************
2 * gnttab.c
3 *
4 * Granting foreign access to our memory reservation.
5 *
6 * Copyright (c) 2005, Christopher Clark
7 * Copyright (c) 2004-2005, K A Fraser
8 */
10 #include <linux/config.h>
11 #include <linux/module.h>
12 #include <linux/sched.h>
13 #include <asm/pgtable.h>
14 #include <asm-xen/xen-public/xen.h>
15 #include <asm/fixmap.h>
16 #include <asm/uaccess.h>
17 #include <asm-xen/xen_proc.h>
18 #include <asm-xen/linux-public/privcmd.h>
19 #include <asm-xen/gnttab.h>
20 #include <asm/synch_bitops.h>
22 #if 1
23 #define ASSERT(_p) \
24 if ( !(_p) ) { printk(KERN_ALERT"Assertion '%s': line %d, file %s\n", \
25 #_p , __LINE__, __FILE__); *(int*)0=0; }
26 #else
27 #define ASSERT(_p) ((void)0)
28 #endif
30 #define WPRINTK(fmt, args...) \
31 printk(KERN_WARNING "xen_grant: " fmt, ##args)
34 EXPORT_SYMBOL(gnttab_grant_foreign_access);
35 EXPORT_SYMBOL(gnttab_end_foreign_access_ref);
36 EXPORT_SYMBOL(gnttab_end_foreign_access);
37 EXPORT_SYMBOL(gnttab_query_foreign_access);
38 EXPORT_SYMBOL(gnttab_grant_foreign_transfer);
39 EXPORT_SYMBOL(gnttab_end_foreign_transfer_ref);
40 EXPORT_SYMBOL(gnttab_end_foreign_transfer);
41 EXPORT_SYMBOL(gnttab_alloc_grant_references);
42 EXPORT_SYMBOL(gnttab_free_grant_references);
43 EXPORT_SYMBOL(gnttab_free_grant_reference);
44 EXPORT_SYMBOL(gnttab_claim_grant_reference);
45 EXPORT_SYMBOL(gnttab_release_grant_reference);
46 EXPORT_SYMBOL(gnttab_request_free_callback);
47 EXPORT_SYMBOL(gnttab_grant_foreign_access_ref);
48 EXPORT_SYMBOL(gnttab_grant_foreign_transfer_ref);
50 /* External tools reserve first few grant table entries. */
51 #define NR_RESERVED_ENTRIES 8
53 #define NR_GRANT_ENTRIES (NR_GRANT_FRAMES * PAGE_SIZE / sizeof(grant_entry_t))
54 #define GNTTAB_LIST_END (NR_GRANT_ENTRIES + 1)
56 static grant_ref_t gnttab_list[NR_GRANT_ENTRIES];
57 static int gnttab_free_count;
58 static grant_ref_t gnttab_free_head;
59 static spinlock_t gnttab_list_lock = SPIN_LOCK_UNLOCKED;
61 static grant_entry_t *shared;
63 static struct gnttab_free_callback *gnttab_free_callback_list = NULL;
65 static int
66 get_free_entries(int count)
67 {
68 unsigned long flags;
69 int ref;
70 grant_ref_t head;
71 spin_lock_irqsave(&gnttab_list_lock, flags);
72 if (gnttab_free_count < count) {
73 spin_unlock_irqrestore(&gnttab_list_lock, flags);
74 return -1;
75 }
76 ref = head = gnttab_free_head;
77 gnttab_free_count -= count;
78 while (count-- > 1)
79 head = gnttab_list[head];
80 gnttab_free_head = gnttab_list[head];
81 gnttab_list[head] = GNTTAB_LIST_END;
82 spin_unlock_irqrestore(&gnttab_list_lock, flags);
83 return ref;
84 }
86 #define get_free_entry() get_free_entries(1)
88 static void
89 do_free_callbacks(void)
90 {
91 struct gnttab_free_callback *callback, *next;
93 callback = gnttab_free_callback_list;
94 gnttab_free_callback_list = NULL;
96 while (callback != NULL) {
97 next = callback->next;
98 if (gnttab_free_count >= callback->count) {
99 callback->next = NULL;
100 callback->fn(callback->arg);
101 } else {
102 callback->next = gnttab_free_callback_list;
103 gnttab_free_callback_list = callback;
104 }
105 callback = next;
106 }
107 }
109 static inline void
110 check_free_callbacks(void)
111 {
112 if (unlikely(gnttab_free_callback_list))
113 do_free_callbacks();
114 }
116 static void
117 put_free_entry(grant_ref_t ref)
118 {
119 unsigned long flags;
120 spin_lock_irqsave(&gnttab_list_lock, flags);
121 gnttab_list[ref] = gnttab_free_head;
122 gnttab_free_head = ref;
123 gnttab_free_count++;
124 check_free_callbacks();
125 spin_unlock_irqrestore(&gnttab_list_lock, flags);
126 }
128 /*
129 * Public grant-issuing interface functions
130 */
132 int
133 gnttab_grant_foreign_access(domid_t domid, unsigned long frame, int readonly)
134 {
135 int ref;
137 if (unlikely((ref = get_free_entry()) == -1))
138 return -ENOSPC;
140 shared[ref].frame = frame;
141 shared[ref].domid = domid;
142 wmb();
143 shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
145 return ref;
146 }
148 void
149 gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
150 unsigned long frame, int readonly)
151 {
152 shared[ref].frame = frame;
153 shared[ref].domid = domid;
154 wmb();
155 shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
156 }
159 int
160 gnttab_query_foreign_access(grant_ref_t ref)
161 {
162 u16 nflags;
164 nflags = shared[ref].flags;
166 return (nflags & (GTF_reading|GTF_writing));
167 }
169 int
170 gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
171 {
172 u16 flags, nflags;
174 nflags = shared[ref].flags;
175 do {
176 if ( (flags = nflags) & (GTF_reading|GTF_writing) ) {
177 printk(KERN_ALERT "WARNING: g.e. still in use!\n");
178 return 0;
179 }
180 }
181 while ((nflags = synch_cmpxchg(&shared[ref].flags, flags, 0)) !=
182 flags);
184 return 1;
185 }
187 void
188 gnttab_end_foreign_access(grant_ref_t ref, int readonly, unsigned long page)
189 {
190 if (gnttab_end_foreign_access_ref(ref, readonly)) {
191 put_free_entry(ref);
192 if (page != 0) {
193 free_page(page);
194 }
195 }
196 else {
197 /* XXX This needs to be fixed so that the ref and page are
198 placed on a list to be freed up later. */
199 printk(KERN_WARNING
200 "WARNING: leaking g.e. and page still in use!\n");
201 }
202 }
204 int
205 gnttab_grant_foreign_transfer(domid_t domid)
206 {
207 int ref;
209 if (unlikely((ref = get_free_entry()) == -1))
210 return -ENOSPC;
212 shared[ref].frame = 0;
213 shared[ref].domid = domid;
214 wmb();
215 shared[ref].flags = GTF_accept_transfer;
217 return ref;
218 }
220 void
221 gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid)
222 {
223 shared[ref].frame = 0;
224 shared[ref].domid = domid;
225 wmb();
226 shared[ref].flags = GTF_accept_transfer;
227 }
229 unsigned long
230 gnttab_end_foreign_transfer_ref(grant_ref_t ref)
231 {
232 unsigned long frame = 0;
233 u16 flags;
235 flags = shared[ref].flags;
237 /*
238 * If a transfer is committed then wait for the frame address to
239 * appear. Otherwise invalidate the grant entry against future use.
240 */
241 if (likely(flags != GTF_accept_transfer) ||
242 (synch_cmpxchg(&shared[ref].flags, flags, 0) !=
243 GTF_accept_transfer))
244 while (unlikely((frame = shared[ref].frame) == 0))
245 cpu_relax();
247 return frame;
248 }
250 unsigned long
251 gnttab_end_foreign_transfer(grant_ref_t ref)
252 {
253 unsigned long frame = gnttab_end_foreign_transfer_ref(ref);
254 put_free_entry(ref);
255 return frame;
256 }
258 void
259 gnttab_free_grant_reference(grant_ref_t ref)
260 {
262 put_free_entry(ref);
263 }
265 void
266 gnttab_free_grant_references(grant_ref_t head)
267 {
268 grant_ref_t ref;
269 unsigned long flags;
270 int count = 1;
271 if (head == GNTTAB_LIST_END)
272 return;
273 spin_lock_irqsave(&gnttab_list_lock, flags);
274 ref = head;
275 while (gnttab_list[ref] != GNTTAB_LIST_END) {
276 ref = gnttab_list[ref];
277 count++;
278 }
279 gnttab_list[ref] = gnttab_free_head;
280 gnttab_free_head = head;
281 gnttab_free_count += count;
282 check_free_callbacks();
283 spin_unlock_irqrestore(&gnttab_list_lock, flags);
284 }
286 int
287 gnttab_alloc_grant_references(u16 count, grant_ref_t *head)
288 {
289 int h = get_free_entries(count);
291 if (h == -1)
292 return -ENOSPC;
294 *head = h;
296 return 0;
297 }
299 int
300 gnttab_claim_grant_reference(grant_ref_t *private_head)
301 {
302 grant_ref_t g = *private_head;
303 if (unlikely(g == GNTTAB_LIST_END))
304 return -ENOSPC;
305 *private_head = gnttab_list[g];
306 return g;
307 }
309 void
310 gnttab_release_grant_reference(grant_ref_t *private_head, grant_ref_t release)
311 {
312 gnttab_list[release] = *private_head;
313 *private_head = release;
314 }
316 void
317 gnttab_request_free_callback(struct gnttab_free_callback *callback,
318 void (*fn)(void *), void *arg, u16 count)
319 {
320 unsigned long flags;
321 spin_lock_irqsave(&gnttab_list_lock, flags);
322 if (callback->next)
323 goto out;
324 callback->fn = fn;
325 callback->arg = arg;
326 callback->count = count;
327 callback->next = gnttab_free_callback_list;
328 gnttab_free_callback_list = callback;
329 check_free_callbacks();
330 out:
331 spin_unlock_irqrestore(&gnttab_list_lock, flags);
332 }
334 /*
335 * ProcFS operations
336 */
338 #ifdef CONFIG_PROC_FS
340 static struct proc_dir_entry *grant_pde;
341 static struct file_operations grant_file_ops;
343 static int
344 grant_read(char *page, char **start, off_t off, int count, int *eof,
345 void *data)
346 {
347 int len;
348 unsigned int i;
349 grant_entry_t *gt;
351 gt = (grant_entry_t *)shared;
352 len = 0;
354 for (i = 0; i < NR_GRANT_ENTRIES; i++) {
355 if (len > (PAGE_SIZE - 200)) {
356 len += sprintf( page + len, "Truncated.\n");
357 break;
358 }
359 }
361 if (gt[i].flags) {
362 len += sprintf(page + len,
363 "Grant: ref (0x%x) flags (0x%hx) "
364 "dom (0x%hx) frame (0x%x)\n",
365 i,
366 gt[i].flags,
367 gt[i].domid,
368 gt[i].frame );
369 }
371 *eof = 1;
372 return len;
373 }
375 static int
376 grant_write(struct file *file, const char __user *buffer, unsigned long count,
377 void *data)
378 {
379 /* TODO: implement this */
380 return -ENOSYS;
381 }
383 #endif /* CONFIG_PROC_FS */
385 int
386 gnttab_resume(void)
387 {
388 gnttab_setup_table_t setup;
389 unsigned long frames[NR_GRANT_FRAMES];
390 int i;
392 setup.dom = DOMID_SELF;
393 setup.nr_frames = NR_GRANT_FRAMES;
394 setup.frame_list = frames;
396 BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1));
397 BUG_ON(setup.status != 0);
399 #ifdef __ia64__
400 shared = __va(frames[0] << PAGE_SHIFT);
401 printk("grant table at %p\n", shared);
402 #else
403 for (i = 0; i < NR_GRANT_FRAMES; i++)
404 set_fixmap(FIX_GNTTAB_END - i, frames[i] << PAGE_SHIFT);
405 #endif
407 return 0;
408 }
410 int
411 gnttab_suspend(void)
412 {
413 int i;
415 for (i = 0; i < NR_GRANT_FRAMES; i++)
416 clear_fixmap(FIX_GNTTAB_END - i);
418 return 0;
419 }
421 static int __init
422 gnttab_init(void)
423 {
424 int i;
426 if (xen_init() < 0)
427 return -ENODEV;
429 BUG_ON(gnttab_resume());
431 #ifndef __ia64__
432 shared = (grant_entry_t *)fix_to_virt(FIX_GNTTAB_END);
433 #endif
435 for (i = NR_RESERVED_ENTRIES; i < NR_GRANT_ENTRIES; i++)
436 gnttab_list[i] = i + 1;
437 gnttab_free_count = NR_GRANT_ENTRIES - NR_RESERVED_ENTRIES;
438 gnttab_free_head = NR_RESERVED_ENTRIES;
440 #ifdef CONFIG_PROC_FS
441 /*
442 * /proc/xen/grant : used by libxc to access grant tables
443 */
444 if ((grant_pde = create_xen_proc_entry("grant", 0600)) == NULL) {
445 WPRINTK("Unable to create grant xen proc entry\n");
446 return -1;
447 }
449 grant_file_ops.read = grant_pde->proc_fops->read;
450 grant_file_ops.write = grant_pde->proc_fops->write;
452 grant_pde->proc_fops = &grant_file_ops;
454 grant_pde->read_proc = &grant_read;
455 grant_pde->write_proc = &grant_write;
456 #endif
458 printk("Grant table initialized\n");
459 return 0;
460 }
462 __initcall(gnttab_init);
464 /*
465 * Local variables:
466 * c-file-style: "linux"
467 * indent-tabs-mode: t
468 * c-indent-level: 8
469 * c-basic-offset: 8
470 * tab-width: 8
471 * End:
472 */