# HG changeset patch # User yamahata@xxxxxxxxxxxxx # Date 1185762640 -32400 # Node ID fb5043d15cae94f0686f5ad009d67ff97d0a1c3c # Parent 4492a0285bae734ee18f6acbb6b3f9c80f153be7 remove xencomm page size limit. Currently xencomm has page size limit so that a domain with many memory (e.g. 100GB+) can't be created. This patch allows that the address array of struct xencomm_desc to cross page boundary so that the size of struct xencomm_desc can exceed page size. Note that struct xencomm_desc itself can't page boundary. PATCHNAME: remove_xencomm_page_size_limit_xen_side Signed-off-by: Isaku Yamahata diff -r 4492a0285bae -r fb5043d15cae xen/arch/ia64/xen/xencomm.c --- a/xen/arch/ia64/xen/xencomm.c Fri Jul 27 08:15:16 2007 -0600 +++ b/xen/arch/ia64/xen/xencomm.c Mon Jul 30 11:30:40 2007 +0900 @@ -34,6 +34,15 @@ static int xencomm_debug = 1; /* extreme #else #define xencomm_debug 0 #endif + +static int +xencomm_desc_cross_page_boundary(unsigned long paddr) +{ + unsigned long offset = paddr & ~PAGE_MASK; + if (offset > PAGE_SIZE - sizeof(struct xencomm_desc)) + return 1; + return 0; +} static int xencomm_copy_chunk_from( @@ -85,15 +94,18 @@ xencomm_copy_from_guest( unsigned int n, unsigned int skip) { + unsigned long from_ulong = (unsigned long)from; struct xencomm_desc *desc; unsigned long desc_addr; + struct xencomm_desc *desc_paddr; + unsigned long *address; unsigned int from_pos = 0; unsigned int to_pos = 0; unsigned int i = 0; if (xencomm_debug) printk("xencomm_copy_from_guest: from=%lx+%u n=%u\n", - (unsigned long)from, skip, n); + from_ulong, skip, n); if (XENCOMM_IS_INLINE(from)) { unsigned long src_paddr = XENCOMM_INLINE_ADDR(from); @@ -121,8 +133,11 @@ xencomm_copy_from_guest( return 0; } + /* check if struct desc doesn't cross page boundry */ + if (xencomm_desc_cross_page_boundary(from_ulong)) + return -EINVAL; /* first we need to access the descriptor */ - desc_addr = xencomm_paddr_to_maddr((unsigned long)from); + desc_addr = xencomm_paddr_to_maddr(from_ulong); if (desc_addr == 0) return -EFAULT; @@ -132,18 +147,26 @@ xencomm_copy_from_guest( __func__, desc, desc->magic); return -EFAULT; } + desc_paddr = (struct xencomm_desc *)from; + address = &desc->address[i]; /* iterate through the descriptor, copying up to a page at a time */ while ((to_pos < n) && (i < desc->nr_addrs)) { - unsigned long src_paddr = desc->address[i]; + unsigned long src_paddr; unsigned int pgoffset; unsigned int chunksz; unsigned int chunk_skip; - if (src_paddr == XENCOMM_INVALID) { - i++; - continue; - } + /* When crossing page boundary, machine address must be calculated. */ + if (((unsigned long)address & ~PAGE_MASK) == 0) { + address = (unsigned long*)xencomm_paddr_to_maddr( + (unsigned long)&desc_paddr->address[i]); + if (address == NULL) + return -EFAULT; + } + src_paddr = *address; + if (src_paddr == XENCOMM_INVALID) + goto skip_to_next; pgoffset = src_paddr % PAGE_SIZE; chunksz = PAGE_SIZE - pgoffset; @@ -170,7 +193,9 @@ xencomm_copy_from_guest( to_pos += bytes; } + skip_to_next: i++; + address++; } return n - to_pos; @@ -226,15 +251,18 @@ xencomm_copy_to_guest( unsigned int n, unsigned int skip) { + unsigned long to_ulong = (unsigned long)to; struct xencomm_desc *desc; unsigned long desc_addr; + struct xencomm_desc *desc_paddr; + unsigned long *address; unsigned int from_pos = 0; unsigned int to_pos = 0; unsigned int i = 0; if (xencomm_debug) printk ("xencomm_copy_to_guest: to=%lx+%u n=%u\n", - (unsigned long)to, skip, n); + to_ulong, skip, n); if (XENCOMM_IS_INLINE(to)) { unsigned long dest_paddr = XENCOMM_INLINE_ADDR(to); @@ -263,8 +291,11 @@ xencomm_copy_to_guest( return 0; } + /* check if struct desc doesn't cross page boundry */ + if (xencomm_desc_cross_page_boundary(to_ulong)) + return -EINVAL; /* first we need to access the descriptor */ - desc_addr = xencomm_paddr_to_maddr((unsigned long)to); + desc_addr = xencomm_paddr_to_maddr(to_ulong); if (desc_addr == 0) return -EFAULT; @@ -273,18 +304,26 @@ xencomm_copy_to_guest( printk("%s error: %p magic was 0x%x\n", __func__, desc, desc->magic); return -EFAULT; } + desc_paddr = (struct xencomm_desc*)to; + address = &desc->address[i]; /* iterate through the descriptor, copying up to a page at a time */ while ((from_pos < n) && (i < desc->nr_addrs)) { - unsigned long dest_paddr = desc->address[i]; + unsigned long dest_paddr; unsigned int pgoffset; unsigned int chunksz; unsigned int chunk_skip; - if (dest_paddr == XENCOMM_INVALID) { - i++; - continue; - } + /* When crossing page boundary, machine address must be calculated. */ + if (((unsigned long)address & ~PAGE_MASK) == 0) { + address = (unsigned long*)xencomm_paddr_to_maddr( + (unsigned long)&desc_paddr->address[i]); + if (address == NULL) + return -EFAULT; + } + dest_paddr = *address; + if (dest_paddr == XENCOMM_INVALID) + goto skip_to_next; pgoffset = dest_paddr % PAGE_SIZE; chunksz = PAGE_SIZE - pgoffset; @@ -308,7 +347,9 @@ xencomm_copy_to_guest( to_pos += bytes; } + skip_to_next: i++; + address++; } return n - from_pos; } @@ -320,15 +361,21 @@ xencomm_add_offset( void *handle, unsigned int bytes) { + unsigned long handle_ulong = (unsigned long)handle; struct xencomm_desc *desc; unsigned long desc_addr; + struct xencomm_desc *desc_paddr; + unsigned long *address; int i = 0; if (XENCOMM_IS_INLINE(handle)) return (void *)((unsigned long)handle + bytes); + /* check if struct desc doesn't cross page boundry */ + if (xencomm_desc_cross_page_boundary(handle_ulong)) + return NULL; /* first we need to access the descriptor */ - desc_addr = xencomm_paddr_to_maddr((unsigned long)handle); + desc_addr = xencomm_paddr_to_maddr(handle_ulong); if (desc_addr == 0) return NULL; @@ -337,18 +384,26 @@ xencomm_add_offset( printk("%s error: %p magic was 0x%x\n", __func__, desc, desc->magic); return NULL; } + desc_paddr = (struct xencomm_desc*)handle; + address = &desc->address[i]; /* iterate through the descriptor incrementing addresses */ while ((bytes > 0) && (i < desc->nr_addrs)) { - unsigned long dest_paddr = desc->address[i]; + unsigned long dest_paddr; unsigned int pgoffset; unsigned int chunksz; unsigned int chunk_skip; - if (dest_paddr == XENCOMM_INVALID) { - i++; - continue; - } + /* When crossing page boundary, machine address must be calculated. */ + if (((unsigned long)address & ~PAGE_MASK) == 0) { + address = (unsigned long*)xencomm_paddr_to_maddr( + (unsigned long)&desc_paddr->address[i]); + if (address == NULL) + return NULL; + } + dest_paddr = *address; + if (dest_paddr == XENCOMM_INVALID) + goto skip_to_next; pgoffset = dest_paddr % PAGE_SIZE; chunksz = PAGE_SIZE - pgoffset; @@ -356,13 +411,15 @@ xencomm_add_offset( chunk_skip = min(chunksz, bytes); if (chunk_skip == chunksz) { /* exhausted this page */ - desc->address[i] = XENCOMM_INVALID; + *address = XENCOMM_INVALID; } else { - desc->address[i] += chunk_skip; + *address += chunk_skip; } bytes -= chunk_skip; - - i++; + + skip_to_next: + i++; + address++; } return handle; }