ia64/xen-unstable

changeset 9977:e891c49c7bc0

[IA64] linux: privcmd_mmap() and direct_remap_pfn_range()

implemented direct_remap_pfn_range() and ia64-specific privcmd_mmap()
for foreing domain page mapping.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
author awilliam@xenbuild.aw
date Tue May 09 11:44:26 2006 -0600 (2006-05-09)
parents fc75a2c9835e
children 5f0bdd0ef9dc
files linux-2.6-xen-sparse/arch/ia64/xen/hypervisor.c linux-2.6-xen-sparse/include/asm-ia64/hypervisor.h
line diff
     1.1 --- a/linux-2.6-xen-sparse/arch/ia64/xen/hypervisor.c	Tue May 09 11:42:26 2006 -0600
     1.2 +++ b/linux-2.6-xen-sparse/arch/ia64/xen/hypervisor.c	Tue May 09 11:44:26 2006 -0600
     1.3 @@ -290,3 +290,284 @@ EXPORT_SYMBOL(balloon_update_driver_allo
     1.4  
     1.5  struct address_space xen_ia64_foreign_dummy_mapping;
     1.6  
     1.7 +///////////////////////////////////////////////////////////////////////////
     1.8 +// foreign mapping
     1.9 +
    1.10 +struct xen_ia64_privcmd_entry {
    1.11 +	atomic_t	map_count;
    1.12 +	struct page*	page;
    1.13 +	unsigned long	mfn;
    1.14 +};
    1.15 +
    1.16 +static void
    1.17 +xen_ia64_privcmd_init_entry(struct xen_ia64_privcmd_entry* entry)
    1.18 +{
    1.19 +	atomic_set(&entry->map_count, 0);
    1.20 +	entry->page = NULL;
    1.21 +	entry->mfn = INVALID_MFN;
    1.22 +}
    1.23 +
    1.24 +static int
    1.25 +xen_ia64_privcmd_entry_mmap(struct vm_area_struct* vma,
    1.26 +			    unsigned long addr,
    1.27 +			    struct xen_ia64_privcmd_entry* entry,
    1.28 +			    unsigned long mfn,
    1.29 +			    pgprot_t prot,
    1.30 +			    domid_t domid)
    1.31 +{
    1.32 +	int error = 0;
    1.33 +	struct page* page;
    1.34 +	unsigned long gpfn;
    1.35 +
    1.36 +	BUG_ON((addr & ~PAGE_MASK) != 0);
    1.37 +	BUG_ON(mfn == INVALID_MFN);
    1.38 +
    1.39 +	if (entry->page != NULL) {
    1.40 +		error = -EBUSY;
    1.41 +		goto out;
    1.42 +	}
    1.43 +	page = alloc_page(GFP_KERNEL);
    1.44 +	if (page == NULL) {
    1.45 +		error = -ENOMEM;
    1.46 +		goto out;
    1.47 +	}
    1.48 +	gpfn = page_to_pfn(page);
    1.49 +
    1.50 +	error = HYPERVISOR_add_physmap(gpfn, mfn, 0/* prot:XXX */,
    1.51 +				       domid);
    1.52 +	if (error != 0) {
    1.53 +		goto out;
    1.54 +	}
    1.55 +
    1.56 +	prot = vma->vm_page_prot;
    1.57 +	error = remap_pfn_range(vma, addr, gpfn, 1 << PAGE_SHIFT, prot);
    1.58 +	if (error != 0) {
    1.59 +		(void)HYPERVISOR_zap_physmap(gpfn, 0);
    1.60 +		error = HYPERVISOR_populate_physmap(gpfn, 0, 0);
    1.61 +		if (error) {
    1.62 +			BUG();//XXX
    1.63 +		}
    1.64 +		__free_page(page);
    1.65 +	} else {
    1.66 +		atomic_inc(&entry->map_count);
    1.67 +		entry->page = page;
    1.68 +		entry->mfn = mfn;
    1.69 +	}
    1.70 +
    1.71 +out:
    1.72 +	return error;
    1.73 +}
    1.74 +
    1.75 +static void
    1.76 +xen_ia64_privcmd_entry_munmap(struct xen_ia64_privcmd_entry* entry)
    1.77 +{
    1.78 +	struct page* page = entry->page;
    1.79 +	unsigned long gpfn = page_to_pfn(page);
    1.80 +	int error;
    1.81 +
    1.82 +	error = HYPERVISOR_zap_physmap(gpfn, 0);
    1.83 +	if (error) {
    1.84 +		BUG();//XXX
    1.85 +	}
    1.86 +
    1.87 +	error = HYPERVISOR_populate_physmap(gpfn, 0, 0);
    1.88 +	if (error) {
    1.89 +		BUG();//XXX
    1.90 +	}
    1.91 +
    1.92 +	entry->page = NULL;
    1.93 +	entry->mfn = INVALID_MFN;
    1.94 +	__free_page(page);
    1.95 +}
    1.96 +
    1.97 +static int
    1.98 +xen_ia64_privcmd_entry_open(struct xen_ia64_privcmd_entry* entry)
    1.99 +{
   1.100 +	if (entry->page != NULL) {
   1.101 +		atomic_inc(&entry->map_count);
   1.102 +	} else {
   1.103 +		BUG_ON(atomic_read(&entry->map_count) != 0);
   1.104 +	}
   1.105 +}
   1.106 +
   1.107 +static int
   1.108 +xen_ia64_privcmd_entry_close(struct xen_ia64_privcmd_entry* entry)
   1.109 +{
   1.110 +	if (entry->page != NULL && atomic_dec_and_test(&entry->map_count)) {
   1.111 +		xen_ia64_privcmd_entry_munmap(entry);
   1.112 +	}
   1.113 +}
   1.114 +
   1.115 +struct xen_ia64_privcmd_file {
   1.116 +	struct file*			file;
   1.117 +	atomic_t			map_count;
   1.118 +	unsigned long			pgoff; // in PAGE_SIZE
   1.119 +
   1.120 +	unsigned long			num_entries;
   1.121 +	struct xen_ia64_privcmd_entry	entries[0];
   1.122 +};
   1.123 +
   1.124 +struct xen_ia64_privcmd_vma {
   1.125 +	struct xen_ia64_privcmd_file*	file;
   1.126 +	unsigned long			num_entries;
   1.127 +	struct xen_ia64_privcmd_entry*	entries;
   1.128 +};
   1.129 +
   1.130 +static void xen_ia64_privcmd_vma_open(struct vm_area_struct* vma);
   1.131 +static void xen_ia64_privcmd_vma_close(struct vm_area_struct* vma);
   1.132 +
   1.133 +struct vm_operations_struct xen_ia64_privcmd_vm_ops = {
   1.134 +	.open = &xen_ia64_privcmd_vma_open,
   1.135 +	.close = &xen_ia64_privcmd_vma_close,
   1.136 +};
   1.137 +
   1.138 +static void
   1.139 +__xen_ia64_privcmd_vma_open(struct vm_area_struct* vma,
   1.140 +			    struct xen_ia64_privcmd_vma* privcmd_vma)
   1.141 +{
   1.142 +	struct xen_ia64_privcmd_file* privcmd_file =
   1.143 +		(struct xen_ia64_privcmd_file*)vma->vm_file->private_data;
   1.144 +	unsigned long entry_offset = vma->vm_pgoff - privcmd_file->pgoff;
   1.145 +	unsigned long num_entries = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
   1.146 +	unsigned long i;
   1.147 +
   1.148 +	BUG_ON(entry_offset < 0);
   1.149 +	BUG_ON(entry_offset + num_entries > privcmd_file->num_entries);
   1.150 +
   1.151 +	privcmd_vma->file = privcmd_file;
   1.152 +	privcmd_vma->num_entries = num_entries;
   1.153 +	privcmd_vma->entries = &privcmd_file->entries[entry_offset];
   1.154 +	vma->vm_private_data = privcmd_vma;
   1.155 +	for (i = 0; i < privcmd_vma->num_entries; i++) {
   1.156 +		xen_ia64_privcmd_entry_open(&privcmd_vma->entries[i]);
   1.157 +	}
   1.158 +
   1.159 +	vma->vm_private_data = privcmd_vma;
   1.160 +	vma->vm_ops = &xen_ia64_privcmd_vm_ops;
   1.161 +}
   1.162 +
   1.163 +static void
   1.164 +xen_ia64_privcmd_vma_open(struct vm_area_struct* vma)
   1.165 +{
   1.166 +	struct xen_ia64_privcmd_file* privcmd_file =
   1.167 +		(struct xen_ia64_privcmd_file*)vma->vm_file->private_data;
   1.168 +	struct xen_ia64_privcmd_vma* privcmd_vma;
   1.169 +
   1.170 +	atomic_inc(&privcmd_file->map_count);
   1.171 +	// vm_op->open() can't fail.
   1.172 +	privcmd_vma = kmalloc(sizeof(*privcmd_vma), GFP_KERNEL | __GFP_NOFAIL);
   1.173 +
   1.174 +	__xen_ia64_privcmd_vma_open(vma, privcmd_vma);
   1.175 +}
   1.176 +
   1.177 +static void
   1.178 +xen_ia64_privcmd_vma_close(struct vm_area_struct* vma)
   1.179 +{
   1.180 +	struct xen_ia64_privcmd_vma* privcmd_vma =
   1.181 +		(struct xen_ia64_privcmd_vma*)vma->vm_private_data;
   1.182 +	struct xen_ia64_privcmd_file* privcmd_file = privcmd_vma->file;
   1.183 +	unsigned long i;
   1.184 +
   1.185 +	for (i = 0; i < privcmd_vma->num_entries; i++) {
   1.186 +		xen_ia64_privcmd_entry_close(&privcmd_vma->entries[i]);
   1.187 +	}
   1.188 +	vma->vm_private_data = NULL;
   1.189 +	kfree(privcmd_vma);
   1.190 +
   1.191 +	if (atomic_dec_and_test(&privcmd_file->map_count)) {
   1.192 +#if 1
   1.193 +		for (i = 0; i < privcmd_file->num_entries; i++) {
   1.194 +			struct xen_ia64_privcmd_entry* entry =
   1.195 +				&privcmd_vma->entries[i];
   1.196 +			BUG_ON(atomic_read(&entry->map_count) != 0);
   1.197 +			BUG_ON(entry->page != NULL);
   1.198 +		}
   1.199 +#endif
   1.200 +		privcmd_file->file->private_data = NULL;
   1.201 +		kfree(privcmd_file->file->private_data);
   1.202 +	}
   1.203 +}
   1.204 +
   1.205 +int
   1.206 +privcmd_mmap(struct file * file, struct vm_area_struct * vma)
   1.207 +{
   1.208 +	unsigned long num_entries = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
   1.209 +	struct xen_ia64_privcmd_file* privcmd_file;
   1.210 +	struct xen_ia64_privcmd_vma* privcmd_vma;
   1.211 +	unsigned long i;
   1.212 +	BUG_ON(!running_on_xen);
   1.213 +
   1.214 +        /* DONTCOPY is essential for Xen as copy_page_range is broken. */
   1.215 +        vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY;
   1.216 +
   1.217 +	if (file->private_data != NULL) {
   1.218 +		return -EBUSY;
   1.219 +	}
   1.220 +
   1.221 +	privcmd_file = kmalloc(sizeof(*privcmd_file) +
   1.222 +			       sizeof(privcmd_file->entries[0]) * num_entries,
   1.223 +			       GFP_KERNEL);
   1.224 +	if (privcmd_file == NULL) {
   1.225 +		goto out_enomem0;
   1.226 +	}
   1.227 +	privcmd_vma = kmalloc(sizeof(*privcmd_vma), GFP_KERNEL);
   1.228 +	if (privcmd_vma == NULL) {
   1.229 +		goto out_enomem1;
   1.230 +	}
   1.231 +
   1.232 +	atomic_set(&privcmd_file->map_count, 1);
   1.233 +	privcmd_file->num_entries = num_entries;
   1.234 +	for (i = 0; i < privcmd_file->num_entries; i++) {
   1.235 +		xen_ia64_privcmd_init_entry(&privcmd_file->entries[i]);
   1.236 +	}
   1.237 +	file->private_data = privcmd_file;
   1.238 +	privcmd_file->file = file;
   1.239 +	privcmd_file->pgoff = vma->vm_pgoff;
   1.240 +
   1.241 +	__xen_ia64_privcmd_vma_open(vma, privcmd_vma);
   1.242 +	return 0;
   1.243 +
   1.244 +out_enomem1:
   1.245 +	kfree(privcmd_vma);
   1.246 +out_enomem0:
   1.247 +	kfree(privcmd_file);
   1.248 +	return -ENOMEM;
   1.249 +}
   1.250 +
   1.251 +int
   1.252 +direct_remap_pfn_range(struct vm_area_struct *vma,
   1.253 +		       unsigned long address,	// process virtual address
   1.254 +		       unsigned long mfn,	// mfn, mfn + 1, ... mfn + size/PAGE_SIZE
   1.255 +		       unsigned long size,
   1.256 +		       pgprot_t prot,
   1.257 +		       domid_t  domid)		// target domain
   1.258 +{
   1.259 +	struct xen_ia64_privcmd_vma* privcmd_vma =
   1.260 +		(struct xen_ia64_privcmd_vma*)vma->vm_private_data;
   1.261 +	unsigned long i;
   1.262 +	unsigned long offset;
   1.263 +	int error = 0;
   1.264 +	BUG_ON(!running_on_xen);
   1.265 +
   1.266 +#if 0
   1.267 +	if (prot != vm->vm_page_prot) {
   1.268 +		return -EINVAL;
   1.269 +	}
   1.270 +#endif
   1.271 +
   1.272 +	i = (address - vma->vm_start) >> PAGE_SHIFT;
   1.273 +	for (offset = 0; offset < size; offset += PAGE_SIZE) {
   1.274 +		struct xen_ia64_privcmd_entry* entry =
   1.275 +			&privcmd_vma->file->entries[i];
   1.276 +		error = xen_ia64_privcmd_entry_mmap(vma, (address + offset) & PAGE_MASK, entry, mfn, prot, domid);
   1.277 +		if (error != 0) {
   1.278 +			break;
   1.279 +		}
   1.280 +
   1.281 +		i++;
   1.282 +		mfn++;
   1.283 +        }
   1.284 +
   1.285 +	return error;
   1.286 +}
   1.287 +
     2.1 --- a/linux-2.6-xen-sparse/include/asm-ia64/hypervisor.h	Tue May 09 11:42:26 2006 -0600
     2.2 +++ b/linux-2.6-xen-sparse/include/asm-ia64/hypervisor.h	Tue May 09 11:44:26 2006 -0600
     2.3 @@ -118,11 +118,22 @@ HYPERVISOR_poll(
     2.4  }
     2.5  
     2.6  // for drivers/xen/privcmd/privcmd.c
     2.7 -#define direct_remap_pfn_range(a,b,c,d,e,f) remap_pfn_range(a,b,c,d,e)
     2.8  #define machine_to_phys_mapping 0
     2.9  #ifndef CONFIG_XEN_IA64_DOM0_VP
    2.10 +#define direct_remap_pfn_range(a,b,c,d,e,f) remap_pfn_range(a,b,c,d,e)
    2.11  #define	pfn_to_mfn(x)	(x)
    2.12  #define	mfn_to_pfn(x)	(x)
    2.13 +#else
    2.14 +struct vm_area_struct;
    2.15 +int direct_remap_pfn_range(struct vm_area_struct *vma,
    2.16 +			   unsigned long address,
    2.17 +			   unsigned long mfn,
    2.18 +			   unsigned long size,
    2.19 +			   pgprot_t prot,
    2.20 +			   domid_t  domid);
    2.21 +struct file;
    2.22 +int privcmd_mmap(struct file * file, struct vm_area_struct * vma);
    2.23 +#define HAVE_ARCH_PRIVCMD_MMAP
    2.24  #endif
    2.25  
    2.26  // for drivers/xen/balloon/balloon.c