[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] blktap: Small changes to blktap + add a hook to clear ptes on implicit release of VMAs.



# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Date 1179998045 -3600
# Node ID 46095d5a59a9d268c247b2b1bf747024759b1f8e
# Parent  17f6163ae930c007d13abc1e3dbc06a624fb5a21
blktap: Small changes to blktap + add a hook to clear ptes on implicit release 
of VMAs.

 * free memory on release
 * invalidate p2m entry when unmapping grants
 * check for alloc failure of idx_map
 * add DONTCOPY vma flag
 * hook for clearing ptes when a vma is freed by the kernel

From: Geoffrey Lefebvre <geoffrey@xxxxxxxxx>
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
 linux-2.6-xen-sparse/drivers/xen/blktap/blktap.c |  117 ++++++++++++++++++++++-
 1 files changed, 115 insertions(+), 2 deletions(-)

diff -r 17f6163ae930 -r 46095d5a59a9 
linux-2.6-xen-sparse/drivers/xen/blktap/blktap.c
--- a/linux-2.6-xen-sparse/drivers/xen/blktap/blktap.c  Thu May 24 09:54:03 
2007 +0100
+++ b/linux-2.6-xen-sparse/drivers/xen/blktap/blktap.c  Thu May 24 10:14:05 
2007 +0100
@@ -269,6 +269,16 @@ static inline int GET_NEXT_REQ(unsigned 
        return INVALID_REQ;
 }
 
+static inline int OFFSET_TO_USR_IDX(int offset)
+{
+       return offset / BLKIF_MAX_SEGMENTS_PER_REQUEST;
+}
+
+static inline int OFFSET_TO_SEG(int offset)
+{
+       return offset % BLKIF_MAX_SEGMENTS_PER_REQUEST;
+}
+
 
 #define BLKTAP_INVALID_HANDLE(_g) \
     (((_g->kernel) == INVALID_GRANT_HANDLE) &&  \
@@ -295,8 +305,90 @@ static struct page *blktap_nopage(struct
        return NOPAGE_SIGBUS;
 }
 
+static pte_t blktap_clear_pte(struct vm_area_struct *vma,
+                             unsigned long uvaddr,
+                             pte_t *ptep, int is_fullmm)
+{
+       pte_t copy = *ptep;
+       tap_blkif_t *info;
+       int offset, seg, usr_idx, pending_idx, mmap_idx;
+       unsigned long uvstart = vma->vm_start + (RING_PAGES << PAGE_SHIFT);
+       unsigned long kvaddr;
+       struct page **map;
+       struct page *pg;
+       struct grant_handle_pair *khandle;
+       struct gnttab_unmap_grant_ref unmap[2];
+       int count = 0;
+       static int print_warning = 1;
+
+       /* Print a warning message once, if the hook gets called. */
+       if (print_warning) {
+               WPRINTK("Clear pte hook called!\n");
+               print_warning = 0;
+       }
+
+       /*
+        * If the address is before the start of the grant mapped region or
+        * if vm_file is NULL (meaning mmap failed and we have nothing to do)
+        */
+       if (uvaddr < uvstart || vma->vm_file == NULL)
+               return copy;
+
+       info = vma->vm_file->private_data;
+       map = vma->vm_private_data;
+
+       /* TODO Should these be changed to if statements? */
+       BUG_ON(!info);
+       BUG_ON(!info->idx_map);
+       BUG_ON(!map);
+
+       offset = (int) ((uvaddr - uvstart) >> PAGE_SHIFT);
+       usr_idx = OFFSET_TO_USR_IDX(offset);
+       seg = OFFSET_TO_SEG(offset);
+
+       pending_idx = MASK_PEND_IDX(ID_TO_IDX(info->idx_map[usr_idx]));
+       mmap_idx = ID_TO_MIDX(info->idx_map[usr_idx]);
+
+       kvaddr = idx_to_kaddr(mmap_idx, pending_idx, seg);
+       pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT);
+       ClearPageReserved(pg);
+       map[offset] = NULL;
+
+       khandle = &pending_handle(mmap_idx, pending_idx, seg);
+
+       if (khandle->kernel != INVALID_GRANT_HANDLE) {
+               gnttab_set_unmap_op(&unmap[count], kvaddr, 
+                                   GNTMAP_host_map, khandle->kernel);
+               count++;
+
+               set_phys_to_machine(__pa(kvaddr) >> PAGE_SHIFT, 
+                                   INVALID_P2M_ENTRY);
+       }
+
+       if (khandle->user != INVALID_GRANT_HANDLE) {
+               BUG_ON(xen_feature(XENFEAT_auto_translated_physmap));
+
+               gnttab_set_unmap_op(&unmap[count], virt_to_machine(ptep), 
+                                   GNTMAP_host_map 
+                                   | GNTMAP_application_map 
+                                   | GNTMAP_contains_pte,
+                                   khandle->user);
+               count++;
+       }
+
+       if (count) {
+               BLKTAP_INVALIDATE_HANDLE(khandle);
+               if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref,
+                                             unmap, count))
+                       BUG();
+       }
+
+       return copy;
+}
+
 struct vm_operations_struct blktap_vm_ops = {
        nopage:   blktap_nopage,
+       zap_pte:  blktap_clear_pte,
 };
 
 /******************************************************************
@@ -477,6 +569,9 @@ static int blktap_open(struct inode *ino
        info->idx_map = kmalloc(sizeof(unsigned long) * MAX_PENDING_REQS, 
                                GFP_KERNEL);
        
+       if (info->idx_map == NULL)
+               goto fail_nomem;
+
        if (idx > 0) {
                init_waitqueue_head(&info->wait);
                for (i = 0; i < MAX_PENDING_REQS; i++) 
@@ -510,16 +605,25 @@ static int blktap_release(struct inode *
                zap_page_range(
                        info->vma, info->vma->vm_start, 
                        info->vma->vm_end - info->vma->vm_start, NULL);
+
+               kfree(info->vma->vm_private_data);
+
                info->vma = NULL;
        }
-       
+
+       if (info->idx_map) {
+               kfree(info->idx_map);
+               info->idx_map = NULL;
+       }
+
        if ( (info->status != CLEANSHUTDOWN) && (info->blkif != NULL) ) {
                if (info->blkif->xenblkd != NULL) {
                        kthread_stop(info->blkif->xenblkd);
                        info->blkif->xenblkd = NULL;
                }
                info->status = CLEANSHUTDOWN;
-       }       
+       }
+
        return 0;
 }
 
@@ -590,6 +694,11 @@ static int blktap_mmap(struct file *filp
     
        vma->vm_private_data = map;
        vma->vm_flags |= VM_FOREIGN;
+       vma->vm_flags |= VM_DONTCOPY;
+
+#ifdef CONFIG_X86
+       vma->vm_mm->context.has_foreign_mappings = 1;
+#endif
 
        info->vma = vma;
        info->ring_ok = 1;
@@ -885,6 +994,10 @@ static void fast_flush_area(pending_req_
                                            idx_to_kaddr(mmap_idx, k_idx, i),
                                            GNTMAP_host_map, khandle->kernel);
                        invcount++;
+
+                       set_phys_to_machine(
+                               __pa(idx_to_kaddr(mmap_idx, k_idx, i))
+                               >> PAGE_SHIFT, INVALID_P2M_ENTRY);
                }
 
                if (khandle->user != INVALID_GRANT_HANDLE) {

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.