Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 12 May 2012 20:42:57 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r235372 - head/sys/vm
Message-ID:  <201205122042.q4CKgvWJ051542@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Sat May 12 20:42:56 2012
New Revision: 235372
URL: http://svn.freebsd.org/changeset/base/235372

Log:
  Add a facility to register a range of physical addresses to be used
  for allocation of fictitious pages, for which PHYS_TO_VM_PAGE()
  returns proper fictitious vm_page_t. The range should be de-registered
  after consumer stopped using it.
  
  De-inline the PHYS_TO_VM_PAGE() since it now carries code to iterate
  over registered ranges.
  
  A hash container might be developed instead of range registration
  interface, and fake pages could be put automatically into the hash,
  were PHYS_TO_VM_PAGE() could look them up later. This should be
  considered before the MFC of the commit is done.
  
  Sponsored by:	The FreeBSD Foundation
  Reviewed by:	alc
  MFC after:	1 month

Modified:
  head/sys/vm/vm_page.c
  head/sys/vm/vm_page.h
  head/sys/vm/vm_phys.c
  head/sys/vm/vm_phys.h

Modified: head/sys/vm/vm_page.c
==============================================================================
--- head/sys/vm/vm_page.c	Sat May 12 20:41:40 2012	(r235371)
+++ head/sys/vm/vm_page.c	Sat May 12 20:42:56 2012	(r235372)
@@ -633,6 +633,30 @@ vm_page_unhold_pages(vm_page_t *ma, int 
 		mtx_unlock(mtx);
 }
 
+vm_page_t
+PHYS_TO_VM_PAGE(vm_paddr_t pa)
+{
+	vm_page_t m;
+
+#ifdef VM_PHYSSEG_SPARSE
+	m = vm_phys_paddr_to_vm_page(pa);
+	if (m == NULL)
+		m = vm_phys_fictitious_to_vm_page(pa);
+	return (m);
+#elif defined(VM_PHYSSEG_DENSE)
+	long pi;
+
+	pi = atop(pa);
+	if (pi >= first_page && pi < vm_page_array_size) {
+		m = &vm_page_array[pi - first_page];
+		return (m);
+	}
+	return (vm_phys_fictitious_to_vm_page(pa));
+#else
+#error "Either VM_PHYSSEG_DENSE or VM_PHYSSEG_SPARSE must be defined."
+#endif
+}
+
 /*
  *	vm_page_getfake:
  *

Modified: head/sys/vm/vm_page.h
==============================================================================
--- head/sys/vm/vm_page.h	Sat May 12 20:41:40 2012	(r235371)
+++ head/sys/vm/vm_page.h	Sat May 12 20:42:56 2012	(r235372)
@@ -321,19 +321,7 @@ extern long first_page;			/* first physi
 
 vm_page_t vm_phys_paddr_to_vm_page(vm_paddr_t pa);
 
-static __inline vm_page_t PHYS_TO_VM_PAGE(vm_paddr_t pa);
-
-static __inline vm_page_t
-PHYS_TO_VM_PAGE(vm_paddr_t pa)
-{
-#ifdef VM_PHYSSEG_SPARSE
-	return (vm_phys_paddr_to_vm_page(pa));
-#elif defined(VM_PHYSSEG_DENSE)
-	return (&vm_page_array[atop(pa) - first_page]);
-#else
-#error "Either VM_PHYSSEG_DENSE or VM_PHYSSEG_SPARSE must be defined."
-#endif
-}
+vm_page_t PHYS_TO_VM_PAGE(vm_paddr_t pa);
 
 extern struct vpglocks vm_page_queue_lock;
 

Modified: head/sys/vm/vm_phys.c
==============================================================================
--- head/sys/vm/vm_phys.c	Sat May 12 20:41:40 2012	(r235371)
+++ head/sys/vm/vm_phys.c	Sat May 12 20:42:56 2012	(r235372)
@@ -87,6 +87,15 @@ static struct vm_phys_seg vm_phys_segs[V
 
 static int vm_phys_nsegs;
 
+#define VM_PHYS_FICTITIOUS_NSEGS	8
+static struct vm_phys_fictitious_seg {
+	vm_paddr_t	start;
+	vm_paddr_t	end;
+	vm_page_t	first_page;
+} vm_phys_fictitious_segs[VM_PHYS_FICTITIOUS_NSEGS];
+static struct mtx vm_phys_fictitious_reg_mtx;
+MALLOC_DEFINE(M_FICT_PAGES, "", "");
+
 static struct vm_freelist
     vm_phys_free_queues[VM_RAW_NFREELIST][VM_NFREEPOOL][VM_NFREEORDER];
 static struct vm_freelist
@@ -366,6 +375,8 @@ vm_phys_init(void)
 	for (flind = 0; flind < vm_nfreelists; flind++)
 		vm_phys_lookup_lists[0][flind] = &vm_phys_free_queues[flind];
 #endif
+
+	mtx_init(&vm_phys_fictitious_reg_mtx, "vmfctr", NULL, MTX_DEF);
 }
 
 /*
@@ -510,6 +521,112 @@ vm_phys_paddr_to_vm_page(vm_paddr_t pa)
 	return (NULL);
 }
 
+vm_page_t
+vm_phys_fictitious_to_vm_page(vm_paddr_t pa)
+{
+	struct vm_phys_fictitious_seg *seg;
+	vm_page_t m;
+	int segind;
+
+	m = NULL;
+	for (segind = 0; segind < VM_PHYS_FICTITIOUS_NSEGS; segind++) {
+		seg = &vm_phys_fictitious_segs[segind];
+		if (pa >= seg->start && pa < seg->end) {
+			m = &seg->first_page[atop(pa - seg->start)];
+			KASSERT((m->flags & PG_FICTITIOUS) != 0,
+			    ("%p not fictitious", m));
+			break;
+		}
+	}
+	return (m);
+}
+
+int
+vm_phys_fictitious_reg_range(vm_paddr_t start, vm_paddr_t end,
+    vm_memattr_t memattr)
+{
+	struct vm_phys_fictitious_seg *seg;
+	vm_page_t fp;
+	long i, page_count;
+	int segind;
+#ifdef VM_PHYSSEG_DENSE
+	long pi;
+	boolean_t malloced;
+#endif
+
+	page_count = (end - start) / PAGE_SIZE;
+
+#ifdef VM_PHYSSEG_DENSE
+	pi = atop(start);
+	if (pi >= first_page && atop(end) < vm_page_array_size) {
+		fp = &vm_page_array[pi - first_page];
+		malloced = FALSE;
+	} else
+#endif
+	{
+		fp = malloc(page_count * sizeof(struct vm_page), M_FICT_PAGES,
+		    M_WAITOK | M_ZERO);
+#ifdef VM_PHYSSEG_DENSE
+		malloced = TRUE;
+#endif
+	}
+	for (i = 0; i < page_count; i++) {
+		vm_page_initfake(&fp[i], start + PAGE_SIZE * i, memattr);
+		pmap_page_init(&fp[i]);
+		fp[i].oflags &= ~(VPO_BUSY | VPO_UNMANAGED);
+	}
+	mtx_lock(&vm_phys_fictitious_reg_mtx);
+	for (segind = 0; segind < VM_PHYS_FICTITIOUS_NSEGS; segind++) {
+		seg = &vm_phys_fictitious_segs[segind];
+		if (seg->start == 0 && seg->end == 0) {
+			seg->start = start;
+			seg->end = end;
+			seg->first_page = fp;
+			mtx_unlock(&vm_phys_fictitious_reg_mtx);
+			return (0);
+		}
+	}
+	mtx_unlock(&vm_phys_fictitious_reg_mtx);
+#ifdef VM_PHYSSEG_DENSE
+	if (malloced)
+#endif
+		free(fp, M_FICT_PAGES);
+	return (EBUSY);
+}
+
+void
+vm_phys_fictitious_unreg_range(vm_paddr_t start, vm_paddr_t end)
+{
+	struct vm_phys_fictitious_seg *seg;
+	vm_page_t fp;
+	int segind;
+#ifdef VM_PHYSSEG_DENSE
+	long pi;
+#endif
+
+#ifdef VM_PHYSSEG_DENSE
+	pi = atop(start);
+#endif
+
+	mtx_lock(&vm_phys_fictitious_reg_mtx);
+	for (segind = 0; segind < VM_PHYS_FICTITIOUS_NSEGS; segind++) {
+		seg = &vm_phys_fictitious_segs[segind];
+		if (seg->start == start && seg->end == end) {
+			seg->start = seg->end = 0;
+			fp = seg->first_page;
+			seg->first_page = NULL;
+			mtx_unlock(&vm_phys_fictitious_reg_mtx);
+#ifdef VM_PHYSSEG_DENSE
+			if (pi < first_page || atop(end) >= vm_page_array_size)
+#endif
+				free(fp, M_FICT_PAGES);
+			return;
+		}
+	}
+	mtx_unlock(&vm_phys_fictitious_reg_mtx);
+	KASSERT(0, ("Unregistering not registered fictitious range"));
+}
+
 /*
  * Find the segment containing the given physical address.
  */

Modified: head/sys/vm/vm_phys.h
==============================================================================
--- head/sys/vm/vm_phys.h	Sat May 12 20:41:40 2012	(r235371)
+++ head/sys/vm/vm_phys.h	Sat May 12 20:42:56 2012	(r235372)
@@ -57,6 +57,10 @@ vm_page_t vm_phys_alloc_contig(u_long np
     u_long alignment, vm_paddr_t boundary);
 vm_page_t vm_phys_alloc_freelist_pages(int flind, int pool, int order);
 vm_page_t vm_phys_alloc_pages(int pool, int order);
+int vm_phys_fictitious_reg_range(vm_paddr_t start, vm_paddr_t end,
+    vm_memattr_t memattr);
+void vm_phys_fictitious_unreg_range(vm_paddr_t start, vm_paddr_t end);
+vm_page_t vm_phys_fictitious_to_vm_page(vm_paddr_t pa);
 void vm_phys_free_contig(vm_page_t m, u_long npages);
 void vm_phys_free_pages(vm_page_t m, int order);
 void vm_phys_init(void);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201205122042.q4CKgvWJ051542>