aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/xen
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/xen')
-rw-r--r--drivers/xen/events.c101
-rw-r--r--drivers/xen/xenbus/xenbus_probe.c4
-rw-r--r--drivers/xen/xenfs/Makefile3
-rw-r--r--drivers/xen/xenfs/privcmd.c404
-rw-r--r--drivers/xen/xenfs/super.c95
-rw-r--r--drivers/xen/xenfs/xenfs.h3
-rw-r--r--drivers/xen/xenfs/xenstored.c68
7 files changed, 639 insertions, 39 deletions
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index 7d24b0d94ed4..347f17edad77 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -261,7 +261,7 @@ static void init_evtchn_cpu_bindings(void)
261 } 261 }
262#endif 262#endif
263 263
264 memset(cpu_evtchn_mask(0), ~0, sizeof(cpu_evtchn_mask(0))); 264 memset(cpu_evtchn_mask(0), ~0, sizeof(struct cpu_evtchn_s));
265} 265}
266 266
267static inline void clear_evtchn(int port) 267static inline void clear_evtchn(int port)
@@ -377,7 +377,7 @@ int bind_evtchn_to_irq(unsigned int evtchn)
377 irq = find_unbound_irq(); 377 irq = find_unbound_irq();
378 378
379 set_irq_chip_and_handler_name(irq, &xen_dynamic_chip, 379 set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
380 handle_edge_irq, "event"); 380 handle_fasteoi_irq, "event");
381 381
382 evtchn_to_irq[evtchn] = irq; 382 evtchn_to_irq[evtchn] = irq;
383 irq_info[irq] = mk_evtchn_info(evtchn); 383 irq_info[irq] = mk_evtchn_info(evtchn);
@@ -435,6 +435,11 @@ static int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
435 irq = per_cpu(virq_to_irq, cpu)[virq]; 435 irq = per_cpu(virq_to_irq, cpu)[virq];
436 436
437 if (irq == -1) { 437 if (irq == -1) {
438 irq = find_unbound_irq();
439
440 set_irq_chip_and_handler_name(irq, &xen_percpu_chip,
441 handle_percpu_irq, "virq");
442
438 bind_virq.virq = virq; 443 bind_virq.virq = virq;
439 bind_virq.vcpu = cpu; 444 bind_virq.vcpu = cpu;
440 if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, 445 if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
@@ -442,11 +447,6 @@ static int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
442 BUG(); 447 BUG();
443 evtchn = bind_virq.port; 448 evtchn = bind_virq.port;
444 449
445 irq = find_unbound_irq();
446
447 set_irq_chip_and_handler_name(irq, &xen_percpu_chip,
448 handle_percpu_irq, "virq");
449
450 evtchn_to_irq[evtchn] = irq; 450 evtchn_to_irq[evtchn] = irq;
451 irq_info[irq] = mk_virq_info(evtchn, virq); 451 irq_info[irq] = mk_virq_info(evtchn, virq);
452 452
@@ -578,41 +578,75 @@ irqreturn_t xen_debug_interrupt(int irq, void *dev_id)
578{ 578{
579 struct shared_info *sh = HYPERVISOR_shared_info; 579 struct shared_info *sh = HYPERVISOR_shared_info;
580 int cpu = smp_processor_id(); 580 int cpu = smp_processor_id();
581 unsigned long *cpu_evtchn = cpu_evtchn_mask(cpu);
581 int i; 582 int i;
582 unsigned long flags; 583 unsigned long flags;
583 static DEFINE_SPINLOCK(debug_lock); 584 static DEFINE_SPINLOCK(debug_lock);
585 struct vcpu_info *v;
584 586
585 spin_lock_irqsave(&debug_lock, flags); 587 spin_lock_irqsave(&debug_lock, flags);
586 588
587 printk("vcpu %d\n ", cpu); 589 printk("\nvcpu %d\n ", cpu);
588 590
589 for_each_online_cpu(i) { 591 for_each_online_cpu(i) {
590 struct vcpu_info *v = per_cpu(xen_vcpu, i); 592 int pending;
591 printk("%d: masked=%d pending=%d event_sel %08lx\n ", i, 593 v = per_cpu(xen_vcpu, i);
592 (get_irq_regs() && i == cpu) ? xen_irqs_disabled(get_irq_regs()) : v->evtchn_upcall_mask, 594 pending = (get_irq_regs() && i == cpu)
593 v->evtchn_upcall_pending, 595 ? xen_irqs_disabled(get_irq_regs())
594 v->evtchn_pending_sel); 596 : v->evtchn_upcall_mask;
597 printk("%d: masked=%d pending=%d event_sel %0*lx\n ", i,
598 pending, v->evtchn_upcall_pending,
599 (int)(sizeof(v->evtchn_pending_sel)*2),
600 v->evtchn_pending_sel);
601 }
602 v = per_cpu(xen_vcpu, cpu);
603
604 printk("\npending:\n ");
605 for (i = ARRAY_SIZE(sh->evtchn_pending)-1; i >= 0; i--)
606 printk("%0*lx%s", (int)sizeof(sh->evtchn_pending[0])*2,
607 sh->evtchn_pending[i],
608 i % 8 == 0 ? "\n " : " ");
609 printk("\nglobal mask:\n ");
610 for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--)
611 printk("%0*lx%s",
612 (int)(sizeof(sh->evtchn_mask[0])*2),
613 sh->evtchn_mask[i],
614 i % 8 == 0 ? "\n " : " ");
615
616 printk("\nglobally unmasked:\n ");
617 for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--)
618 printk("%0*lx%s", (int)(sizeof(sh->evtchn_mask[0])*2),
619 sh->evtchn_pending[i] & ~sh->evtchn_mask[i],
620 i % 8 == 0 ? "\n " : " ");
621
622 printk("\nlocal cpu%d mask:\n ", cpu);
623 for (i = (NR_EVENT_CHANNELS/BITS_PER_LONG)-1; i >= 0; i--)
624 printk("%0*lx%s", (int)(sizeof(cpu_evtchn[0])*2),
625 cpu_evtchn[i],
626 i % 8 == 0 ? "\n " : " ");
627
628 printk("\nlocally unmasked:\n ");
629 for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--) {
630 unsigned long pending = sh->evtchn_pending[i]
631 & ~sh->evtchn_mask[i]
632 & cpu_evtchn[i];
633 printk("%0*lx%s", (int)(sizeof(sh->evtchn_mask[0])*2),
634 pending, i % 8 == 0 ? "\n " : " ");
595 } 635 }
596 printk("pending:\n ");
597 for(i = ARRAY_SIZE(sh->evtchn_pending)-1; i >= 0; i--)
598 printk("%08lx%s", sh->evtchn_pending[i],
599 i % 8 == 0 ? "\n " : " ");
600 printk("\nmasks:\n ");
601 for(i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--)
602 printk("%08lx%s", sh->evtchn_mask[i],
603 i % 8 == 0 ? "\n " : " ");
604
605 printk("\nunmasked:\n ");
606 for(i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--)
607 printk("%08lx%s", sh->evtchn_pending[i] & ~sh->evtchn_mask[i],
608 i % 8 == 0 ? "\n " : " ");
609 636
610 printk("\npending list:\n"); 637 printk("\npending list:\n");
611 for(i = 0; i < NR_EVENT_CHANNELS; i++) { 638 for (i = 0; i < NR_EVENT_CHANNELS; i++) {
612 if (sync_test_bit(i, sh->evtchn_pending)) { 639 if (sync_test_bit(i, sh->evtchn_pending)) {
613 printk(" %d: event %d -> irq %d\n", 640 int word_idx = i / BITS_PER_LONG;
641 printk(" %d: event %d -> irq %d%s%s%s\n",
614 cpu_from_evtchn(i), i, 642 cpu_from_evtchn(i), i,
615 evtchn_to_irq[i]); 643 evtchn_to_irq[i],
644 sync_test_bit(word_idx, &v->evtchn_pending_sel)
645 ? "" : " l2-clear",
646 !sync_test_bit(i, sh->evtchn_mask)
647 ? "" : " globally-masked",
648 sync_test_bit(i, cpu_evtchn)
649 ? "" : " locally-masked");
616 } 650 }
617 } 651 }
618 652
@@ -663,6 +697,9 @@ static void __xen_evtchn_do_upcall(void)
663 int irq = evtchn_to_irq[port]; 697 int irq = evtchn_to_irq[port];
664 struct irq_desc *desc; 698 struct irq_desc *desc;
665 699
700 mask_evtchn(port);
701 clear_evtchn(port);
702
666 if (irq != -1) { 703 if (irq != -1) {
667 desc = irq_to_desc(irq); 704 desc = irq_to_desc(irq);
668 if (desc) 705 if (desc)
@@ -800,10 +837,10 @@ static void ack_dynirq(unsigned int irq)
800{ 837{
801 int evtchn = evtchn_from_irq(irq); 838 int evtchn = evtchn_from_irq(irq);
802 839
803 move_native_irq(irq); 840 move_masked_irq(irq);
804 841
805 if (VALID_EVTCHN(evtchn)) 842 if (VALID_EVTCHN(evtchn))
806 clear_evtchn(evtchn); 843 unmask_evtchn(evtchn);
807} 844}
808 845
809static int retrigger_dynirq(unsigned int irq) 846static int retrigger_dynirq(unsigned int irq)
@@ -959,7 +996,7 @@ static struct irq_chip xen_dynamic_chip __read_mostly = {
959 .mask = disable_dynirq, 996 .mask = disable_dynirq,
960 .unmask = enable_dynirq, 997 .unmask = enable_dynirq,
961 998
962 .ack = ack_dynirq, 999 .eoi = ack_dynirq,
963 .set_affinity = set_affinity_irq, 1000 .set_affinity = set_affinity_irq,
964 .retrigger = retrigger_dynirq, 1001 .retrigger = retrigger_dynirq,
965}; 1002};
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
index d409495876f1..132939f36020 100644
--- a/drivers/xen/xenbus/xenbus_probe.c
+++ b/drivers/xen/xenbus/xenbus_probe.c
@@ -64,9 +64,11 @@
64 64
65 65
66int xen_store_evtchn; 66int xen_store_evtchn;
67EXPORT_SYMBOL(xen_store_evtchn); 67EXPORT_SYMBOL_GPL(xen_store_evtchn);
68 68
69struct xenstore_domain_interface *xen_store_interface; 69struct xenstore_domain_interface *xen_store_interface;
70EXPORT_SYMBOL_GPL(xen_store_interface);
71
70static unsigned long xen_store_mfn; 72static unsigned long xen_store_mfn;
71 73
72static BLOCKING_NOTIFIER_HEAD(xenstore_chain); 74static BLOCKING_NOTIFIER_HEAD(xenstore_chain);
diff --git a/drivers/xen/xenfs/Makefile b/drivers/xen/xenfs/Makefile
index 25275c3bbdff..4fde9440fe1f 100644
--- a/drivers/xen/xenfs/Makefile
+++ b/drivers/xen/xenfs/Makefile
@@ -1,3 +1,4 @@
1obj-$(CONFIG_XENFS) += xenfs.o 1obj-$(CONFIG_XENFS) += xenfs.o
2 2
3xenfs-objs = super.o xenbus.o \ No newline at end of file 3xenfs-y = super.o xenbus.o privcmd.o
4xenfs-$(CONFIG_XEN_DOM0) += xenstored.o
diff --git a/drivers/xen/xenfs/privcmd.c b/drivers/xen/xenfs/privcmd.c
new file mode 100644
index 000000000000..f80be7f6eb95
--- /dev/null
+++ b/drivers/xen/xenfs/privcmd.c
@@ -0,0 +1,404 @@
1/******************************************************************************
2 * privcmd.c
3 *
4 * Interface to privileged domain-0 commands.
5 *
6 * Copyright (c) 2002-2004, K A Fraser, B Dragovic
7 */
8
9#include <linux/kernel.h>
10#include <linux/sched.h>
11#include <linux/slab.h>
12#include <linux/string.h>
13#include <linux/errno.h>
14#include <linux/mm.h>
15#include <linux/mman.h>
16#include <linux/uaccess.h>
17#include <linux/swap.h>
18#include <linux/smp_lock.h>
19#include <linux/highmem.h>
20#include <linux/pagemap.h>
21#include <linux/seq_file.h>
22
23#include <asm/pgalloc.h>
24#include <asm/pgtable.h>
25#include <asm/tlb.h>
26#include <asm/xen/hypervisor.h>
27#include <asm/xen/hypercall.h>
28
29#include <xen/xen.h>
30#include <xen/privcmd.h>
31#include <xen/interface/xen.h>
32#include <xen/features.h>
33#include <xen/page.h>
34#include <xen/xen-ops.h>
35
36#ifndef HAVE_ARCH_PRIVCMD_MMAP
37static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma);
38#endif
39
40static long privcmd_ioctl_hypercall(void __user *udata)
41{
42 struct privcmd_hypercall hypercall;
43 long ret;
44
45 if (copy_from_user(&hypercall, udata, sizeof(hypercall)))
46 return -EFAULT;
47
48 ret = privcmd_call(hypercall.op,
49 hypercall.arg[0], hypercall.arg[1],
50 hypercall.arg[2], hypercall.arg[3],
51 hypercall.arg[4]);
52
53 return ret;
54}
55
56static void free_page_list(struct list_head *pages)
57{
58 struct page *p, *n;
59
60 list_for_each_entry_safe(p, n, pages, lru)
61 __free_page(p);
62
63 INIT_LIST_HEAD(pages);
64}
65
66/*
67 * Given an array of items in userspace, return a list of pages
68 * containing the data. If copying fails, either because of memory
69 * allocation failure or a problem reading user memory, return an
70 * error code; its up to the caller to dispose of any partial list.
71 */
72static int gather_array(struct list_head *pagelist,
73 unsigned nelem, size_t size,
74 void __user *data)
75{
76 unsigned pageidx;
77 void *pagedata;
78 int ret;
79
80 if (size > PAGE_SIZE)
81 return 0;
82
83 pageidx = PAGE_SIZE;
84 pagedata = NULL; /* quiet, gcc */
85 while (nelem--) {
86 if (pageidx > PAGE_SIZE-size) {
87 struct page *page = alloc_page(GFP_KERNEL);
88
89 ret = -ENOMEM;
90 if (page == NULL)
91 goto fail;
92
93 pagedata = page_address(page);
94
95 list_add_tail(&page->lru, pagelist);
96 pageidx = 0;
97 }
98
99 ret = -EFAULT;
100 if (copy_from_user(pagedata + pageidx, data, size))
101 goto fail;
102
103 data += size;
104 pageidx += size;
105 }
106
107 ret = 0;
108
109fail:
110 return ret;
111}
112
113/*
114 * Call function "fn" on each element of the array fragmented
115 * over a list of pages.
116 */
117static int traverse_pages(unsigned nelem, size_t size,
118 struct list_head *pos,
119 int (*fn)(void *data, void *state),
120 void *state)
121{
122 void *pagedata;
123 unsigned pageidx;
124 int ret = 0;
125
126 BUG_ON(size > PAGE_SIZE);
127
128 pageidx = PAGE_SIZE;
129 pagedata = NULL; /* hush, gcc */
130
131 while (nelem--) {
132 if (pageidx > PAGE_SIZE-size) {
133 struct page *page;
134 pos = pos->next;
135 page = list_entry(pos, struct page, lru);
136 pagedata = page_address(page);
137 pageidx = 0;
138 }
139
140 ret = (*fn)(pagedata + pageidx, state);
141 if (ret)
142 break;
143 pageidx += size;
144 }
145
146 return ret;
147}
148
149struct mmap_mfn_state {
150 unsigned long va;
151 struct vm_area_struct *vma;
152 domid_t domain;
153};
154
155static int mmap_mfn_range(void *data, void *state)
156{
157 struct privcmd_mmap_entry *msg = data;
158 struct mmap_mfn_state *st = state;
159 struct vm_area_struct *vma = st->vma;
160 int rc;
161
162 /* Do not allow range to wrap the address space. */
163 if ((msg->npages > (LONG_MAX >> PAGE_SHIFT)) ||
164 ((unsigned long)(msg->npages << PAGE_SHIFT) >= -st->va))
165 return -EINVAL;
166
167 /* Range chunks must be contiguous in va space. */
168 if ((msg->va != st->va) ||
169 ((msg->va+(msg->npages<<PAGE_SHIFT)) > vma->vm_end))
170 return -EINVAL;
171
172 rc = xen_remap_domain_mfn_range(vma,
173 msg->va & PAGE_MASK,
174 msg->mfn, msg->npages,
175 vma->vm_page_prot,
176 st->domain);
177 if (rc < 0)
178 return rc;
179
180 st->va += msg->npages << PAGE_SHIFT;
181
182 return 0;
183}
184
185static long privcmd_ioctl_mmap(void __user *udata)
186{
187 struct privcmd_mmap mmapcmd;
188 struct mm_struct *mm = current->mm;
189 struct vm_area_struct *vma;
190 int rc;
191 LIST_HEAD(pagelist);
192 struct mmap_mfn_state state;
193
194 if (!xen_initial_domain())
195 return -EPERM;
196
197 if (copy_from_user(&mmapcmd, udata, sizeof(mmapcmd)))
198 return -EFAULT;
199
200 rc = gather_array(&pagelist,
201 mmapcmd.num, sizeof(struct privcmd_mmap_entry),
202 mmapcmd.entry);
203
204 if (rc || list_empty(&pagelist))
205 goto out;
206
207 down_write(&mm->mmap_sem);
208
209 {
210 struct page *page = list_first_entry(&pagelist,
211 struct page, lru);
212 struct privcmd_mmap_entry *msg = page_address(page);
213
214 vma = find_vma(mm, msg->va);
215 rc = -EINVAL;
216
217 if (!vma || (msg->va != vma->vm_start) ||
218 !privcmd_enforce_singleshot_mapping(vma))
219 goto out_up;
220 }
221
222 state.va = vma->vm_start;
223 state.vma = vma;
224 state.domain = mmapcmd.dom;
225
226 rc = traverse_pages(mmapcmd.num, sizeof(struct privcmd_mmap_entry),
227 &pagelist,
228 mmap_mfn_range, &state);
229
230
231out_up:
232 up_write(&mm->mmap_sem);
233
234out:
235 free_page_list(&pagelist);
236
237 return rc;
238}
239
240struct mmap_batch_state {
241 domid_t domain;
242 unsigned long va;
243 struct vm_area_struct *vma;
244 int err;
245
246 xen_pfn_t __user *user;
247};
248
249static int mmap_batch_fn(void *data, void *state)
250{
251 xen_pfn_t *mfnp = data;
252 struct mmap_batch_state *st = state;
253
254 if (xen_remap_domain_mfn_range(st->vma, st->va & PAGE_MASK, *mfnp, 1,
255 st->vma->vm_page_prot, st->domain) < 0) {
256 *mfnp |= 0xf0000000U;
257 st->err++;
258 }
259 st->va += PAGE_SIZE;
260
261 return 0;
262}
263
264static int mmap_return_errors(void *data, void *state)
265{
266 xen_pfn_t *mfnp = data;
267 struct mmap_batch_state *st = state;
268
269 put_user(*mfnp, st->user++);
270
271 return 0;
272}
273
274static struct vm_operations_struct privcmd_vm_ops;
275
276static long privcmd_ioctl_mmap_batch(void __user *udata)
277{
278 int ret;
279 struct privcmd_mmapbatch m;
280 struct mm_struct *mm = current->mm;
281 struct vm_area_struct *vma;
282 unsigned long nr_pages;
283 LIST_HEAD(pagelist);
284 struct mmap_batch_state state;
285
286 if (!xen_initial_domain())
287 return -EPERM;
288
289 if (copy_from_user(&m, udata, sizeof(m)))
290 return -EFAULT;
291
292 nr_pages = m.num;
293 if ((m.num <= 0) || (nr_pages > (LONG_MAX >> PAGE_SHIFT)))
294 return -EINVAL;
295
296 ret = gather_array(&pagelist, m.num, sizeof(xen_pfn_t),
297 m.arr);
298
299 if (ret || list_empty(&pagelist))
300 goto out;
301
302 down_write(&mm->mmap_sem);
303
304 vma = find_vma(mm, m.addr);
305 ret = -EINVAL;
306 if (!vma ||
307 vma->vm_ops != &privcmd_vm_ops ||
308 (m.addr != vma->vm_start) ||
309 ((m.addr + (nr_pages << PAGE_SHIFT)) != vma->vm_end) ||
310 !privcmd_enforce_singleshot_mapping(vma)) {
311 up_write(&mm->mmap_sem);
312 goto out;
313 }
314
315 state.domain = m.dom;
316 state.vma = vma;
317 state.va = m.addr;
318 state.err = 0;
319
320 ret = traverse_pages(m.num, sizeof(xen_pfn_t),
321 &pagelist, mmap_batch_fn, &state);
322
323 up_write(&mm->mmap_sem);
324
325 if (state.err > 0) {
326 ret = 0;
327
328 state.user = m.arr;
329 traverse_pages(m.num, sizeof(xen_pfn_t),
330 &pagelist,
331 mmap_return_errors, &state);
332 }
333
334out:
335 free_page_list(&pagelist);
336
337 return ret;
338}
339
340static long privcmd_ioctl(struct file *file,
341 unsigned int cmd, unsigned long data)
342{
343 int ret = -ENOSYS;
344 void __user *udata = (void __user *) data;
345
346 switch (cmd) {
347 case IOCTL_PRIVCMD_HYPERCALL:
348 ret = privcmd_ioctl_hypercall(udata);
349 break;
350
351 case IOCTL_PRIVCMD_MMAP:
352 ret = privcmd_ioctl_mmap(udata);
353 break;
354
355 case IOCTL_PRIVCMD_MMAPBATCH:
356 ret = privcmd_ioctl_mmap_batch(udata);
357 break;
358
359 default:
360 ret = -EINVAL;
361 break;
362 }
363
364 return ret;
365}
366
367#ifndef HAVE_ARCH_PRIVCMD_MMAP
368static int privcmd_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
369{
370 printk(KERN_DEBUG "privcmd_fault: vma=%p %lx-%lx, pgoff=%lx, uv=%p\n",
371 vma, vma->vm_start, vma->vm_end,
372 vmf->pgoff, vmf->virtual_address);
373
374 return VM_FAULT_SIGBUS;
375}
376
377static struct vm_operations_struct privcmd_vm_ops = {
378 .fault = privcmd_fault
379};
380
381static int privcmd_mmap(struct file *file, struct vm_area_struct *vma)
382{
383 /* Unsupported for auto-translate guests. */
384 if (xen_feature(XENFEAT_auto_translated_physmap))
385 return -ENOSYS;
386
387 /* DONTCOPY is essential for Xen as copy_page_range is broken. */
388 vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY;
389 vma->vm_ops = &privcmd_vm_ops;
390 vma->vm_private_data = NULL;
391
392 return 0;
393}
394
395static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma)
396{
397 return (xchg(&vma->vm_private_data, (void *)1) == NULL);
398}
399#endif
400
401const struct file_operations privcmd_file_ops = {
402 .unlocked_ioctl = privcmd_ioctl,
403 .mmap = privcmd_mmap,
404};
diff --git a/drivers/xen/xenfs/super.c b/drivers/xen/xenfs/super.c
index bd96340063c1..d6662b789b6b 100644
--- a/drivers/xen/xenfs/super.c
+++ b/drivers/xen/xenfs/super.c
@@ -12,6 +12,8 @@
12#include <linux/module.h> 12#include <linux/module.h>
13#include <linux/fs.h> 13#include <linux/fs.h>
14#include <linux/magic.h> 14#include <linux/magic.h>
15#include <linux/mm.h>
16#include <linux/backing-dev.h>
15 17
16#include <xen/xen.h> 18#include <xen/xen.h>
17 19
@@ -22,6 +24,62 @@
22MODULE_DESCRIPTION("Xen filesystem"); 24MODULE_DESCRIPTION("Xen filesystem");
23MODULE_LICENSE("GPL"); 25MODULE_LICENSE("GPL");
24 26
27static int xenfs_set_page_dirty(struct page *page)
28{
29 return !TestSetPageDirty(page);
30}
31
32static const struct address_space_operations xenfs_aops = {
33 .set_page_dirty = xenfs_set_page_dirty,
34};
35
36static struct backing_dev_info xenfs_backing_dev_info = {
37 .ra_pages = 0, /* No readahead */
38 .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK,
39};
40
41static struct inode *xenfs_make_inode(struct super_block *sb, int mode)
42{
43 struct inode *ret = new_inode(sb);
44
45 if (ret) {
46 ret->i_mode = mode;
47 ret->i_mapping->a_ops = &xenfs_aops;
48 ret->i_mapping->backing_dev_info = &xenfs_backing_dev_info;
49 ret->i_uid = ret->i_gid = 0;
50 ret->i_blocks = 0;
51 ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
52 }
53 return ret;
54}
55
56static struct dentry *xenfs_create_file(struct super_block *sb,
57 struct dentry *parent,
58 const char *name,
59 const struct file_operations *fops,
60 void *data,
61 int mode)
62{
63 struct dentry *dentry;
64 struct inode *inode;
65
66 dentry = d_alloc_name(parent, name);
67 if (!dentry)
68 return NULL;
69
70 inode = xenfs_make_inode(sb, S_IFREG | mode);
71 if (!inode) {
72 dput(dentry);
73 return NULL;
74 }
75
76 inode->i_fop = fops;
77 inode->i_private = data;
78
79 d_add(dentry, inode);
80 return dentry;
81}
82
25static ssize_t capabilities_read(struct file *file, char __user *buf, 83static ssize_t capabilities_read(struct file *file, char __user *buf,
26 size_t size, loff_t *off) 84 size_t size, loff_t *off)
27{ 85{
@@ -44,10 +102,23 @@ static int xenfs_fill_super(struct super_block *sb, void *data, int silent)
44 [1] = {}, 102 [1] = {},
45 { "xenbus", &xenbus_file_ops, S_IRUSR|S_IWUSR }, 103 { "xenbus", &xenbus_file_ops, S_IRUSR|S_IWUSR },
46 { "capabilities", &capabilities_file_ops, S_IRUGO }, 104 { "capabilities", &capabilities_file_ops, S_IRUGO },
105 { "privcmd", &privcmd_file_ops, S_IRUSR|S_IWUSR },
47 {""}, 106 {""},
48 }; 107 };
108 int rc;
49 109
50 return simple_fill_super(sb, XENFS_SUPER_MAGIC, xenfs_files); 110 rc = simple_fill_super(sb, XENFS_SUPER_MAGIC, xenfs_files);
111 if (rc < 0)
112 return rc;
113
114 if (xen_initial_domain()) {
115 xenfs_create_file(sb, sb->s_root, "xsd_kva",
116 &xsd_kva_file_ops, NULL, S_IRUSR|S_IWUSR);
117 xenfs_create_file(sb, sb->s_root, "xsd_port",
118 &xsd_port_file_ops, NULL, S_IRUSR|S_IWUSR);
119 }
120
121 return rc;
51} 122}
52 123
53static int xenfs_get_sb(struct file_system_type *fs_type, 124static int xenfs_get_sb(struct file_system_type *fs_type,
@@ -66,11 +137,25 @@ static struct file_system_type xenfs_type = {
66 137
67static int __init xenfs_init(void) 138static int __init xenfs_init(void)
68{ 139{
69 if (xen_domain()) 140 int err;
70 return register_filesystem(&xenfs_type); 141 if (!xen_domain()) {
142 printk(KERN_INFO "xenfs: not registering filesystem on non-xen platform\n");
143 return 0;
144 }
145
146 err = register_filesystem(&xenfs_type);
147 if (err) {
148 printk(KERN_ERR "xenfs: Unable to register filesystem!\n");
149 goto out;
150 }
151
152 err = bdi_init(&xenfs_backing_dev_info);
153 if (err)
154 unregister_filesystem(&xenfs_type);
155
156 out:
71 157
72 printk(KERN_INFO "XENFS: not registering filesystem on non-xen platform\n"); 158 return err;
73 return 0;
74} 159}
75 160
76static void __exit xenfs_exit(void) 161static void __exit xenfs_exit(void)
diff --git a/drivers/xen/xenfs/xenfs.h b/drivers/xen/xenfs/xenfs.h
index 51f08b2d0bf1..b68aa6200003 100644
--- a/drivers/xen/xenfs/xenfs.h
+++ b/drivers/xen/xenfs/xenfs.h
@@ -2,5 +2,8 @@
2#define _XENFS_XENBUS_H 2#define _XENFS_XENBUS_H
3 3
4extern const struct file_operations xenbus_file_ops; 4extern const struct file_operations xenbus_file_ops;
5extern const struct file_operations privcmd_file_ops;
6extern const struct file_operations xsd_kva_file_ops;
7extern const struct file_operations xsd_port_file_ops;
5 8
6#endif /* _XENFS_XENBUS_H */ 9#endif /* _XENFS_XENBUS_H */
diff --git a/drivers/xen/xenfs/xenstored.c b/drivers/xen/xenfs/xenstored.c
new file mode 100644
index 000000000000..fef20dbc6a5c
--- /dev/null
+++ b/drivers/xen/xenfs/xenstored.c
@@ -0,0 +1,68 @@
1#include <linux/slab.h>
2#include <linux/types.h>
3#include <linux/mm.h>
4#include <linux/fs.h>
5
6#include <xen/page.h>
7
8#include "xenfs.h"
9#include "../xenbus/xenbus_comms.h"
10
11static ssize_t xsd_read(struct file *file, char __user *buf,
12 size_t size, loff_t *off)
13{
14 const char *str = (const char *)file->private_data;
15 return simple_read_from_buffer(buf, size, off, str, strlen(str));
16}
17
18static int xsd_release(struct inode *inode, struct file *file)
19{
20 kfree(file->private_data);
21 return 0;
22}
23
24static int xsd_kva_open(struct inode *inode, struct file *file)
25{
26 file->private_data = (void *)kasprintf(GFP_KERNEL, "0x%p",
27 xen_store_interface);
28 if (!file->private_data)
29 return -ENOMEM;
30 return 0;
31}
32
33static int xsd_kva_mmap(struct file *file, struct vm_area_struct *vma)
34{
35 size_t size = vma->vm_end - vma->vm_start;
36
37 if ((size > PAGE_SIZE) || (vma->vm_pgoff != 0))
38 return -EINVAL;
39
40 if (remap_pfn_range(vma, vma->vm_start,
41 virt_to_pfn(xen_store_interface),
42 size, vma->vm_page_prot))
43 return -EAGAIN;
44
45 return 0;
46}
47
48const struct file_operations xsd_kva_file_ops = {
49 .open = xsd_kva_open,
50 .mmap = xsd_kva_mmap,
51 .read = xsd_read,
52 .release = xsd_release,
53};
54
55static int xsd_port_open(struct inode *inode, struct file *file)
56{
57 file->private_data = (void *)kasprintf(GFP_KERNEL, "%d",
58 xen_store_evtchn);
59 if (!file->private_data)
60 return -ENOMEM;
61 return 0;
62}
63
64const struct file_operations xsd_port_file_ops = {
65 .open = xsd_port_open,
66 .read = xsd_read,
67 .release = xsd_release,
68};