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/evtchn.c1
-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.c96
-rw-r--r--drivers/xen/xenfs/xenbus.c1
-rw-r--r--drivers/xen/xenfs/xenfs.h3
-rw-r--r--drivers/xen/xenfs/xenstored.c68
9 files changed, 642 insertions, 39 deletions
diff --git a/drivers/xen/events.c b/drivers/xen/events.c
index 93e98ffe71ae..97612f548a8e 100644
--- a/drivers/xen/events.c
+++ b/drivers/xen/events.c
@@ -296,7 +296,7 @@ static void init_evtchn_cpu_bindings(void)
296 } 296 }
297#endif 297#endif
298 298
299 memset(cpu_evtchn_mask(0), ~0, sizeof(cpu_evtchn_mask(0))); 299 memset(cpu_evtchn_mask(0), ~0, sizeof(struct cpu_evtchn_s));
300} 300}
301 301
302static inline void clear_evtchn(int port) 302static inline void clear_evtchn(int port)
@@ -791,7 +791,7 @@ int bind_evtchn_to_irq(unsigned int evtchn)
791 irq = find_unbound_irq(); 791 irq = find_unbound_irq();
792 792
793 set_irq_chip_and_handler_name(irq, &xen_dynamic_chip, 793 set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
794 handle_edge_irq, "event"); 794 handle_fasteoi_irq, "event");
795 795
796 evtchn_to_irq[evtchn] = irq; 796 evtchn_to_irq[evtchn] = irq;
797 irq_info[irq] = mk_evtchn_info(evtchn); 797 irq_info[irq] = mk_evtchn_info(evtchn);
@@ -849,6 +849,11 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
849 irq = per_cpu(virq_to_irq, cpu)[virq]; 849 irq = per_cpu(virq_to_irq, cpu)[virq];
850 850
851 if (irq == -1) { 851 if (irq == -1) {
852 irq = find_unbound_irq();
853
854 set_irq_chip_and_handler_name(irq, &xen_percpu_chip,
855 handle_percpu_irq, "virq");
856
852 bind_virq.virq = virq; 857 bind_virq.virq = virq;
853 bind_virq.vcpu = cpu; 858 bind_virq.vcpu = cpu;
854 if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, 859 if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
@@ -856,11 +861,6 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
856 BUG(); 861 BUG();
857 evtchn = bind_virq.port; 862 evtchn = bind_virq.port;
858 863
859 irq = find_unbound_irq();
860
861 set_irq_chip_and_handler_name(irq, &xen_percpu_chip,
862 handle_percpu_irq, "virq");
863
864 evtchn_to_irq[evtchn] = irq; 864 evtchn_to_irq[evtchn] = irq;
865 irq_info[irq] = mk_virq_info(evtchn, virq); 865 irq_info[irq] = mk_virq_info(evtchn, virq);
866 866
@@ -992,41 +992,75 @@ irqreturn_t xen_debug_interrupt(int irq, void *dev_id)
992{ 992{
993 struct shared_info *sh = HYPERVISOR_shared_info; 993 struct shared_info *sh = HYPERVISOR_shared_info;
994 int cpu = smp_processor_id(); 994 int cpu = smp_processor_id();
995 unsigned long *cpu_evtchn = cpu_evtchn_mask(cpu);
995 int i; 996 int i;
996 unsigned long flags; 997 unsigned long flags;
997 static DEFINE_SPINLOCK(debug_lock); 998 static DEFINE_SPINLOCK(debug_lock);
999 struct vcpu_info *v;
998 1000
999 spin_lock_irqsave(&debug_lock, flags); 1001 spin_lock_irqsave(&debug_lock, flags);
1000 1002
1001 printk("vcpu %d\n ", cpu); 1003 printk("\nvcpu %d\n ", cpu);
1002 1004
1003 for_each_online_cpu(i) { 1005 for_each_online_cpu(i) {
1004 struct vcpu_info *v = per_cpu(xen_vcpu, i); 1006 int pending;
1005 printk("%d: masked=%d pending=%d event_sel %08lx\n ", i, 1007 v = per_cpu(xen_vcpu, i);
1006 (get_irq_regs() && i == cpu) ? xen_irqs_disabled(get_irq_regs()) : v->evtchn_upcall_mask, 1008 pending = (get_irq_regs() && i == cpu)
1007 v->evtchn_upcall_pending, 1009 ? xen_irqs_disabled(get_irq_regs())
1008 v->evtchn_pending_sel); 1010 : v->evtchn_upcall_mask;
1011 printk("%d: masked=%d pending=%d event_sel %0*lx\n ", i,
1012 pending, v->evtchn_upcall_pending,
1013 (int)(sizeof(v->evtchn_pending_sel)*2),
1014 v->evtchn_pending_sel);
1015 }
1016 v = per_cpu(xen_vcpu, cpu);
1017
1018 printk("\npending:\n ");
1019 for (i = ARRAY_SIZE(sh->evtchn_pending)-1; i >= 0; i--)
1020 printk("%0*lx%s", (int)sizeof(sh->evtchn_pending[0])*2,
1021 sh->evtchn_pending[i],
1022 i % 8 == 0 ? "\n " : " ");
1023 printk("\nglobal mask:\n ");
1024 for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--)
1025 printk("%0*lx%s",
1026 (int)(sizeof(sh->evtchn_mask[0])*2),
1027 sh->evtchn_mask[i],
1028 i % 8 == 0 ? "\n " : " ");
1029
1030 printk("\nglobally unmasked:\n ");
1031 for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--)
1032 printk("%0*lx%s", (int)(sizeof(sh->evtchn_mask[0])*2),
1033 sh->evtchn_pending[i] & ~sh->evtchn_mask[i],
1034 i % 8 == 0 ? "\n " : " ");
1035
1036 printk("\nlocal cpu%d mask:\n ", cpu);
1037 for (i = (NR_EVENT_CHANNELS/BITS_PER_LONG)-1; i >= 0; i--)
1038 printk("%0*lx%s", (int)(sizeof(cpu_evtchn[0])*2),
1039 cpu_evtchn[i],
1040 i % 8 == 0 ? "\n " : " ");
1041
1042 printk("\nlocally unmasked:\n ");
1043 for (i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--) {
1044 unsigned long pending = sh->evtchn_pending[i]
1045 & ~sh->evtchn_mask[i]
1046 & cpu_evtchn[i];
1047 printk("%0*lx%s", (int)(sizeof(sh->evtchn_mask[0])*2),
1048 pending, i % 8 == 0 ? "\n " : " ");
1009 } 1049 }
1010 printk("pending:\n ");
1011 for(i = ARRAY_SIZE(sh->evtchn_pending)-1; i >= 0; i--)
1012 printk("%08lx%s", sh->evtchn_pending[i],
1013 i % 8 == 0 ? "\n " : " ");
1014 printk("\nmasks:\n ");
1015 for(i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--)
1016 printk("%08lx%s", sh->evtchn_mask[i],
1017 i % 8 == 0 ? "\n " : " ");
1018
1019 printk("\nunmasked:\n ");
1020 for(i = ARRAY_SIZE(sh->evtchn_mask)-1; i >= 0; i--)
1021 printk("%08lx%s", sh->evtchn_pending[i] & ~sh->evtchn_mask[i],
1022 i % 8 == 0 ? "\n " : " ");
1023 1050
1024 printk("\npending list:\n"); 1051 printk("\npending list:\n");
1025 for(i = 0; i < NR_EVENT_CHANNELS; i++) { 1052 for (i = 0; i < NR_EVENT_CHANNELS; i++) {
1026 if (sync_test_bit(i, sh->evtchn_pending)) { 1053 if (sync_test_bit(i, sh->evtchn_pending)) {
1027 printk(" %d: event %d -> irq %d\n", 1054 int word_idx = i / BITS_PER_LONG;
1055 printk(" %d: event %d -> irq %d%s%s%s\n",
1028 cpu_from_evtchn(i), i, 1056 cpu_from_evtchn(i), i,
1029 evtchn_to_irq[i]); 1057 evtchn_to_irq[i],
1058 sync_test_bit(word_idx, &v->evtchn_pending_sel)
1059 ? "" : " l2-clear",
1060 !sync_test_bit(i, sh->evtchn_mask)
1061 ? "" : " globally-masked",
1062 sync_test_bit(i, cpu_evtchn)
1063 ? "" : " locally-masked");
1030 } 1064 }
1031 } 1065 }
1032 1066
@@ -1077,6 +1111,9 @@ static void __xen_evtchn_do_upcall(void)
1077 int irq = evtchn_to_irq[port]; 1111 int irq = evtchn_to_irq[port];
1078 struct irq_desc *desc; 1112 struct irq_desc *desc;
1079 1113
1114 mask_evtchn(port);
1115 clear_evtchn(port);
1116
1080 if (irq != -1) { 1117 if (irq != -1) {
1081 desc = irq_to_desc(irq); 1118 desc = irq_to_desc(irq);
1082 if (desc) 1119 if (desc)
@@ -1214,10 +1251,10 @@ static void ack_dynirq(unsigned int irq)
1214{ 1251{
1215 int evtchn = evtchn_from_irq(irq); 1252 int evtchn = evtchn_from_irq(irq);
1216 1253
1217 move_native_irq(irq); 1254 move_masked_irq(irq);
1218 1255
1219 if (VALID_EVTCHN(evtchn)) 1256 if (VALID_EVTCHN(evtchn))
1220 clear_evtchn(evtchn); 1257 unmask_evtchn(evtchn);
1221} 1258}
1222 1259
1223static int retrigger_dynirq(unsigned int irq) 1260static int retrigger_dynirq(unsigned int irq)
@@ -1380,7 +1417,7 @@ static struct irq_chip xen_dynamic_chip __read_mostly = {
1380 .mask = disable_dynirq, 1417 .mask = disable_dynirq,
1381 .unmask = enable_dynirq, 1418 .unmask = enable_dynirq,
1382 1419
1383 .ack = ack_dynirq, 1420 .eoi = ack_dynirq,
1384 .set_affinity = set_affinity_irq, 1421 .set_affinity = set_affinity_irq,
1385 .retrigger = retrigger_dynirq, 1422 .retrigger = retrigger_dynirq,
1386}; 1423};
diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c
index 66e185cfe92f..fec6ba3c08a8 100644
--- a/drivers/xen/evtchn.c
+++ b/drivers/xen/evtchn.c
@@ -467,6 +467,7 @@ static const struct file_operations evtchn_fops = {
467 .fasync = evtchn_fasync, 467 .fasync = evtchn_fasync,
468 .open = evtchn_open, 468 .open = evtchn_open,
469 .release = evtchn_release, 469 .release = evtchn_release,
470 .llseek = noop_llseek,
470}; 471};
471 472
472static struct miscdevice evtchn_miscdev = { 473static struct miscdevice evtchn_miscdev = {
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
index d242610597c0..deb9c4ba3a93 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 78bfab0700ba..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{
@@ -35,6 +93,7 @@ static ssize_t capabilities_read(struct file *file, char __user *buf,
35 93
36static const struct file_operations capabilities_file_ops = { 94static const struct file_operations capabilities_file_ops = {
37 .read = capabilities_read, 95 .read = capabilities_read,
96 .llseek = default_llseek,
38}; 97};
39 98
40static int xenfs_fill_super(struct super_block *sb, void *data, int silent) 99static int xenfs_fill_super(struct super_block *sb, void *data, int silent)
@@ -43,10 +102,23 @@ static int xenfs_fill_super(struct super_block *sb, void *data, int silent)
43 [1] = {}, 102 [1] = {},
44 { "xenbus", &xenbus_file_ops, S_IRUSR|S_IWUSR }, 103 { "xenbus", &xenbus_file_ops, S_IRUSR|S_IWUSR },
45 { "capabilities", &capabilities_file_ops, S_IRUGO }, 104 { "capabilities", &capabilities_file_ops, S_IRUGO },
105 { "privcmd", &privcmd_file_ops, S_IRUSR|S_IWUSR },
46 {""}, 106 {""},
47 }; 107 };
108 int rc;
48 109
49 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;
50} 122}
51 123
52static int xenfs_get_sb(struct file_system_type *fs_type, 124static int xenfs_get_sb(struct file_system_type *fs_type,
@@ -65,11 +137,25 @@ static struct file_system_type xenfs_type = {
65 137
66static int __init xenfs_init(void) 138static int __init xenfs_init(void)
67{ 139{
68 if (xen_domain()) 140 int err;
69 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:
70 157
71 printk(KERN_INFO "XENFS: not registering filesystem on non-xen platform\n"); 158 return err;
72 return 0;
73} 159}
74 160
75static void __exit xenfs_exit(void) 161static void __exit xenfs_exit(void)
diff --git a/drivers/xen/xenfs/xenbus.c b/drivers/xen/xenfs/xenbus.c
index 3b39c3752e21..1c1236087f78 100644
--- a/drivers/xen/xenfs/xenbus.c
+++ b/drivers/xen/xenfs/xenbus.c
@@ -594,4 +594,5 @@ const struct file_operations xenbus_file_ops = {
594 .open = xenbus_file_open, 594 .open = xenbus_file_open,
595 .release = xenbus_file_release, 595 .release = xenbus_file_release,
596 .poll = xenbus_file_poll, 596 .poll = xenbus_file_poll,
597 .llseek = no_llseek,
597}; 598};
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};