kernel - VM PAGER part 1/2 - Remove vm_page_alloc()
authorMatthew Dillon <dillon@apollo.backplane.com>
Sun, 14 Feb 2010 02:09:49 +0000 (18:09 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Sun, 14 Feb 2010 02:12:29 +0000 (18:12 -0800)
* Break out the individual VM object allocation functions and remove
  the vm_pager_alloc() ops vector.

* This is in preparation for giving the vnode_pager_alloc() some
  additional arguments to match recent buffer cache work.

13 files changed:
sys/dev/disk/vn/vn.c
sys/kern/sysv_shm.c
sys/vfs/tmpfs/tmpfs_subr.c
sys/vm/default_pager.c
sys/vm/device_pager.c
sys/vm/phys_pager.c
sys/vm/swap_pager.c
sys/vm/vm_map.c
sys/vm/vm_mmap.c
sys/vm/vm_pager.c
sys/vm/vm_pager.h
sys/vm/vnode_pager.c
sys/vm/vnode_pager.h

index 10eb5b8..014c1f8 100644 (file)
@@ -626,9 +626,9 @@ vniocattach_swap(struct vn_softc *vn, struct vn_ioctl *vio, cdev_t dev,
 
        vn->sc_secsize = PAGE_SIZE;
        vn->sc_size = vio->vn_size;
-       vn->sc_object = vm_pager_allocate(OBJT_SWAP, NULL,
-                                         vn->sc_secsize * (off_t)vio->vn_size,
-                                         VM_PROT_DEFAULT, 0);
+       vn->sc_object = swap_pager_alloc(NULL,
+                                        vn->sc_secsize * (off_t)vio->vn_size,
+                                        VM_PROT_DEFAULT, 0);
        IFOPT(vn, VN_RESERVE) {
                if (swap_pager_reserve(vn->sc_object, 0, vn->sc_size) < 0) {
                        vm_pager_deallocate(vn->sc_object);
index 06768ca..a462399 100644 (file)
@@ -563,10 +563,10 @@ shmget_allocate_segment(struct proc *p, struct shmget_args *uap, int mode)
         */
        if (shm_use_phys) {
                shm_handle->shm_object =
-                  vm_pager_allocate(OBJT_PHYS, NULL, size, VM_PROT_DEFAULT, 0);
+                  phys_pager_alloc(NULL, size, VM_PROT_DEFAULT, 0);
        } else {
                shm_handle->shm_object =
-                  vm_pager_allocate(OBJT_SWAP, NULL, size, VM_PROT_DEFAULT, 0);
+                  swap_pager_alloc(NULL, size, VM_PROT_DEFAULT, 0);
        }
        vm_object_clear_flag(shm_handle->shm_object, OBJ_ONEMAPPING);
        vm_object_set_flag(shm_handle->shm_object, OBJ_NOSPLIT);
index e644e42..00c986b 100644 (file)
@@ -162,7 +162,7 @@ tmpfs_alloc_node(struct tmpfs_mount *tmp, enum vtype type,
 
        case VREG:
                nnode->tn_reg.tn_aobj =
-                   vm_pager_allocate(OBJT_SWAP, NULL, 0, VM_PROT_DEFAULT, 0);
+                   swap_pager_alloc(NULL, 0, VM_PROT_DEFAULT, 0);
                nnode->tn_reg.tn_aobj_pages = 0;
                nnode->tn_size = 0;
                break;
index b8222e6..fad31d6 100644 (file)
@@ -49,7 +49,6 @@
 #include <vm/vm_pager.h>
 #include <vm/swap_pager.h>
 
-static vm_object_t default_pager_alloc (void *, off_t, vm_prot_t, off_t);
 static void default_pager_dealloc (vm_object_t);
 static int default_pager_getpage (vm_object_t, vm_page_t *, int);
 static void default_pager_putpages (vm_object_t, vm_page_t *, int, 
@@ -59,7 +58,6 @@ static boolean_t default_pager_haspage (vm_object_t, vm_pindex_t);
  * pagerops for OBJT_DEFAULT - "default pager".
  */
 struct pagerops defaultpagerops = {
-       default_pager_alloc,
        default_pager_dealloc,
        default_pager_getpage,
        default_pager_putpages,
@@ -69,7 +67,7 @@ struct pagerops defaultpagerops = {
 /*
  * no_pager_alloc just returns an initialized object.
  */
-static vm_object_t
+vm_object_t
 default_pager_alloc(void *handle, off_t size, vm_prot_t prot, off_t offset)
 {
        vm_object_t object;
index 12dff3a..89f2bfd 100644 (file)
@@ -56,7 +56,6 @@
 #include <vm/vm_pager.h>
 #include <vm/vm_zone.h>
 
-static vm_object_t dev_pager_alloc (void *, off_t, vm_prot_t, off_t);
 static void dev_pager_dealloc (vm_object_t);
 static int dev_pager_getpage (vm_object_t, vm_page_t *, int);
 static void dev_pager_putpages (vm_object_t, vm_page_t *, int, 
@@ -74,14 +73,13 @@ static void dev_pager_putfake (vm_page_t);
 static int dev_pager_alloc_lock, dev_pager_alloc_lock_want;
 
 struct pagerops devicepagerops = {
-       dev_pager_alloc,
        dev_pager_dealloc,
        dev_pager_getpage,
        dev_pager_putpages,
        dev_pager_haspage
 };
 
-static vm_object_t
+vm_object_t
 dev_pager_alloc(void *handle, off_t size, vm_prot_t prot, off_t foff)
 {
        cdev_t dev;
index 5df8f63..1dd3235 100644 (file)
@@ -41,7 +41,7 @@
 
 #include <sys/thread2.h>
 
-static vm_object_t
+vm_object_t
 phys_pager_alloc(void *handle, off_t size, vm_prot_t prot, off_t foff)
 {
        vm_object_t object;
@@ -149,7 +149,6 @@ phys_pager_haspage(vm_object_t object, vm_pindex_t pindex)
 }
 
 struct pagerops physpagerops = {
-       phys_pager_alloc,
        phys_pager_dealloc,
        phys_pager_getpage,
        phys_pager_putpages,
index 03f1e0e..78a2ac6 100644 (file)
@@ -227,15 +227,11 @@ rb_swblock_condcmp(struct swblock *swb, void *data)
  * (see vm/swap_pager.h).
  */
 
-static vm_object_t
-               swap_pager_alloc (void *handle, off_t size,
-                                 vm_prot_t prot, off_t offset);
 static void    swap_pager_dealloc (vm_object_t object);
 static int     swap_pager_getpage (vm_object_t, vm_page_t *, int);
 static void    swap_chain_iodone(struct bio *biox);
 
 struct pagerops swappagerops = {
-       swap_pager_alloc,       /* allocate an OBJT_SWAP object         */
        swap_pager_dealloc,     /* deallocate an OBJT_SWAP object       */
        swap_pager_getpage,     /* pagein                               */
        swap_pager_putpages,    /* pageout                              */
@@ -415,7 +411,7 @@ swap_pager_swap_init(void)
  *     already exists.
  */
 
-static vm_object_t
+vm_object_t
 swap_pager_alloc(void *handle, off_t size, vm_prot_t prot, off_t offset)
 {
        vm_object_t object;
index 8c6fe39..e684370 100644 (file)
@@ -2755,8 +2755,19 @@ vm_map_split(vm_map_entry_t entry)
        offidxend = offidxstart + OFF_TO_IDX(e - s);
        size = offidxend - offidxstart;
 
-       new_object = vm_pager_allocate(orig_object->type, NULL,
-                                      IDX_TO_OFF(size), VM_PROT_ALL, 0);
+       switch(orig_object->type) {
+       case OBJT_DEFAULT:
+               new_object = default_pager_alloc(NULL, IDX_TO_OFF(size),
+                                                VM_PROT_ALL, 0);
+               break;
+       case OBJT_SWAP:
+               new_object = swap_pager_alloc(NULL, IDX_TO_OFF(size),
+                                             VM_PROT_ALL, 0);
+               break;
+       default:
+               /* not reached */
+               KKASSERT(0);
+       }
        if (new_object == NULL)
                return;
 
index af9d97f..15e25c8 100644 (file)
@@ -1097,7 +1097,6 @@ vm_mmap(vm_map_t map, vm_offset_t *addr, vm_size_t size, vm_prot_t prot,
        struct vnode *vp;
        struct thread *td = curthread;
        struct proc *p;
-       objtype_t type;
        int rv = KERN_SUCCESS;
        off_t objsize;
        int docow;
@@ -1156,29 +1155,64 @@ vm_mmap(vm_map_t map, vm_offset_t *addr, vm_size_t size, vm_prot_t prot,
         * Lookup/allocate object.
         */
        if (flags & MAP_ANON) {
-               type = OBJT_DEFAULT;
                /*
                 * Unnamed anonymous regions always start at 0.
                 */
-               if (handle == NULL)
+               if (handle) {
+                       /*
+                        * Default memory object
+                        */
+                       object = default_pager_alloc(handle, objsize,
+                                                    prot, foff);
+                       if (object == NULL)
+                               return(ENOMEM);
+                       docow = MAP_PREFAULT_PARTIAL;
+               } else {
+                       /*
+                        * Implicit single instance of a default memory
+                        * object, so we don't need a VM object yet.
+                        */
                        foff = 0;
+                       object = NULL;
+                       docow = 0;
+               }
                vp = NULL;
        } else {
                vp = (struct vnode *)handle;
                if (vp->v_type == VCHR) {
-                       type = OBJT_DEVICE;
+                       /*
+                        * Device mappings (device size unknown?).
+                        * Force them to be shared.
+                        */
                        handle = (void *)(intptr_t)vp->v_rdev;
+                       object = dev_pager_alloc(handle, objsize, prot, foff);
+                       if (object == NULL)
+                               return(EINVAL);
+                       docow = MAP_PREFAULT_PARTIAL;
+                       flags &= ~(MAP_PRIVATE|MAP_COPY);
+                       flags |= MAP_SHARED;
                } else {
+                       /*
+                        * Regular file mapping (typically).  The attribute
+                        * check is for the link count test only.  Mmapble
+                        * vnodes must already have a VM object assigned.
+                        */
                        struct vattr vat;
                        int error;
 
                        error = VOP_GETATTR(vp, &vat);
                        if (error)
                                return (error);
-                       objsize = vat.va_size;
-                       type = OBJT_VNODE;
+                       docow = MAP_PREFAULT_PARTIAL;
+                       object = vnode_pager_reference(vp);
+                       if (object == NULL && vp->v_type == VREG) {
+                               kprintf("Warning: cannot mmap vnode %p, no "
+                                       "object\n", vp);
+                               return(EINVAL);
+                       }
+
                        /*
-                        * if it is a regular file without any references
+                        * If it is a regular file without any references
                         * we do not need to sync it.
                         */
                        if (vp->v_type == VREG && vat.va_nlink == 0) {
@@ -1187,24 +1221,9 @@ vm_mmap(vm_map_t map, vm_offset_t *addr, vm_size_t size, vm_prot_t prot,
                }
        }
 
-       if (handle == NULL) {
-               object = NULL;
-               docow = 0;
-       } else {
-               object = vm_pager_allocate(type, handle, objsize, prot, foff);
-               if (object == NULL)
-                       return (type == OBJT_DEVICE ? EINVAL : ENOMEM);
-               docow = MAP_PREFAULT_PARTIAL;
-       }
-
        /*
-        * Force device mappings to be shared.
+        * Deal with the adjusted flags
         */
-       if (type == OBJT_DEVICE || type == OBJT_PHYS) {
-               flags &= ~(MAP_PRIVATE|MAP_COPY);
-               flags |= MAP_SHARED;
-       }
-
        if ((flags & (MAP_ANON|MAP_SHARED)) == 0)
                docow |= MAP_COPY_ON_WRITE;
        if (flags & MAP_NOSYNC)
index 401a1fc..4c93a07 100644 (file)
@@ -100,7 +100,6 @@ extern struct pagerops physpagerops;
 int cluster_pbuf_freecnt = -1; /* unlimited to begin with */
 
 static int dead_pager_getpage (vm_object_t, vm_page_t *, int);
-static vm_object_t dead_pager_alloc (void *, off_t, vm_prot_t, off_t);
 static void dead_pager_putpages (vm_object_t, vm_page_t *, int, int, int *);
 static boolean_t dead_pager_haspage (vm_object_t, vm_pindex_t);
 static void dead_pager_dealloc (vm_object_t);
@@ -111,15 +110,9 @@ dead_pager_getpage(vm_object_t obj, vm_page_t *mpp, int seqaccess)
        return VM_PAGER_FAIL;
 }
 
-static vm_object_t
-dead_pager_alloc(void *handle, off_t size, vm_prot_t prot, off_t off)
-{
-       return NULL;
-}
-
 static void
 dead_pager_putpages(vm_object_t object, vm_page_t *m, int count, int flags,
-    int *rtvals)
+                   int *rtvals)
 {
        int i;
 
@@ -142,7 +135,6 @@ dead_pager_dealloc(vm_object_t object)
 }
 
 static struct pagerops deadpagerops = {
-       dead_pager_alloc,
        dead_pager_dealloc,
        dead_pager_getpage,
        dead_pager_putpages,
@@ -219,23 +211,6 @@ vm_pager_bufferinit(void)
        cluster_pbuf_freecnt = nswbuf / 2;
 }
 
-/*
- * Allocate an instance of a pager of the given type.
- * Size, protection and offset parameters are passed in for pagers that
- * need to perform page-level validation (e.g. the device pager).
- */
-vm_object_t
-vm_pager_allocate(objtype_t type, void *handle, vm_ooffset_t size,
-                 vm_prot_t prot, off_t off)
-{
-       struct pagerops *ops;
-
-       ops = pagertab[type];
-       if (ops)
-               return ((*ops->pgo_alloc) (handle, size, prot, off));
-       return (NULL);
-}
-
 void
 vm_pager_deallocate(vm_object_t object)
 {
index e4f4cf3..737fe04 100644 (file)
@@ -61,7 +61,6 @@ struct buf;
 struct bio;
 
 struct pagerops {
-       vm_object_t (*pgo_alloc)(void *, vm_ooffset_t, vm_prot_t, vm_ooffset_t);
        void (*pgo_dealloc) (vm_object_t);
        int (*pgo_getpage) (vm_object_t, vm_page_t *, int);
        void (*pgo_putpages) (vm_object_t, vm_page_t *, int, int, int *);
@@ -101,7 +100,13 @@ extern struct vm_map pager_map;
 extern int pager_map_size;
 extern struct pagerops *pagertab[];
 
-vm_object_t vm_pager_allocate (objtype_t, void *, off_t, vm_prot_t, off_t);
+vm_object_t default_pager_alloc(void *, off_t, vm_prot_t, off_t);
+vm_object_t dev_pager_alloc(void *, off_t, vm_prot_t, off_t);
+vm_object_t phys_pager_alloc(void *, off_t, vm_prot_t, off_t);
+vm_object_t swap_pager_alloc(void *, off_t, vm_prot_t, off_t);
+vm_object_t vnode_pager_alloc (void *, off_t, vm_prot_t, off_t);
+vm_object_t vnode_pager_reference (struct vnode *);
+
 void vm_pager_bufferinit (void);
 void vm_pager_deallocate (vm_object_t);
 static __inline int vm_pager_get_page (vm_object_t, vm_page_t *, int);
index 2aabc9f..23edb14 100644 (file)
@@ -81,7 +81,6 @@ static void vnode_pager_putpages (vm_object_t, vm_page_t *, int, boolean_t, int
 static boolean_t vnode_pager_haspage (vm_object_t, vm_pindex_t);
 
 struct pagerops vnodepagerops = {
-       vnode_pager_alloc,
        vnode_pager_dealloc,
        vnode_pager_getpage,
        vnode_pager_putpages,
@@ -169,6 +168,53 @@ vnode_pager_alloc(void *handle, off_t size, vm_prot_t prot, off_t offset)
        return (object);
 }
 
+/*
+ * Add a ref to a vnode's existing VM object, return the object or
+ * NULL if the vnode did not have one.  This does not create the
+ * object (we can't since we don't know what the proper blocksize/boff
+ * is to match the VFS's use of the buffer cache).
+ */
+vm_object_t
+vnode_pager_reference(struct vnode *vp)
+{
+       vm_object_t object;
+
+       /*
+        * Prevent race condition when allocating the object. This
+        * can happen with NFS vnodes since the nfsnode isn't locked.
+        */
+       while (vp->v_flag & VOLOCK) {
+               vsetflags(vp, VOWANT);
+               tsleep(vp, 0, "vnpobj", 0);
+       }
+       vsetflags(vp, VOLOCK);
+
+       /*
+        * Prevent race conditions against deallocation of the VM
+        * object.
+        */
+       while (((object = vp->v_object) != NULL) &&
+               (object->flags & OBJ_DEAD)) {
+               vm_object_dead_sleep(object, "vadead");
+       }
+
+       /*
+        * The object is expected to exist, the caller will handle
+        * NULL returns if it does not.
+        */
+       if (object) {
+               object->ref_count++;
+               vref(vp);
+       }
+
+       vclrflags(vp, VOLOCK);
+       if (vp->v_flag & VOWANT) {
+               vclrflags(vp, VOWANT);
+               wakeup(vp);
+       }
+       return (object);
+}
+
 static void
 vnode_pager_dealloc(vm_object_t object)
 {
index 0a9997b..986e057 100644 (file)
@@ -52,7 +52,6 @@
 #include <vm/vm_object.h>
 #endif
 
-vm_object_t vnode_pager_alloc (void *, off_t, vm_prot_t, off_t);
 void vnode_pager_freepage (vm_page_t);
 struct vnode *vnode_pager_lock (vm_object_t);