[BACK]Return to uvm_vnode.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / uvm

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/sys/uvm/uvm_vnode.c between version 1.22.2.1 and 1.22.2.1.2.4

version 1.22.2.1, 1999/04/16 16:29:56 version 1.22.2.1.2.4, 1999/07/31 19:04:49
Line 47 
Line 47 
   
 #include "fs_nfs.h"  #include "fs_nfs.h"
 #include "opt_uvmhist.h"  #include "opt_uvmhist.h"
   #include "opt_ddb.h"
   
 /*  /*
  * uvm_vnode.c: the vnode pager.   * uvm_vnode.c: the vnode pager.
Line 54 
Line 55 
   
 #include <sys/param.h>  #include <sys/param.h>
 #include <sys/systm.h>  #include <sys/systm.h>
   #include <sys/kernel.h>
 #include <sys/proc.h>  #include <sys/proc.h>
 #include <sys/malloc.h>  #include <sys/malloc.h>
 #include <sys/vnode.h>  #include <sys/vnode.h>
Line 61 
Line 63 
 #include <sys/ioctl.h>  #include <sys/ioctl.h>
 #include <sys/fcntl.h>  #include <sys/fcntl.h>
 #include <sys/conf.h>  #include <sys/conf.h>
   #include <sys/pool.h>
   #include <sys/mount.h>
   
 #include <miscfs/specfs/specdev.h>  #include <miscfs/specfs/specdev.h>
   
Line 90  lock_data_t uvn_sync_lock;   /* locks sy
Line 94  lock_data_t uvn_sync_lock;   /* locks sy
  * functions   * functions
  */   */
   
 static int                 uvn_asyncget __P((struct uvm_object *, vaddr_t,  static int              uvn_asyncget __P((struct uvm_object *, vaddr_t,
                                             int));                                              int));
 struct uvm_object         *uvn_attach __P((void *, vm_prot_t));  struct uvm_object *     uvn_attach __P((void *, vm_prot_t));
 static void                uvn_cluster __P((struct uvm_object *, vaddr_t,  static void             uvn_cluster __P((struct uvm_object *, vaddr_t,
                                            vaddr_t *, vaddr_t *));                                           vaddr_t *, vaddr_t *));
 static void                uvn_detach __P((struct uvm_object *));  static void             uvn_detach __P((struct uvm_object *));
 static boolean_t           uvn_flush __P((struct uvm_object *, vaddr_t,  static int              uvn_findpage __P((struct uvm_object *, vaddr_t,
                                          vaddr_t, int));                                            struct vm_page **, int));
 static int                 uvn_get __P((struct uvm_object *, vaddr_t,  static boolean_t        uvn_flush __P((struct uvm_object *, vaddr_t,
                                         vm_page_t *, int *, int,                                         vaddr_t, int));
                                         vm_prot_t, int, int));  static int              uvn_get __P((struct uvm_object *, vaddr_t,
 static void                uvn_init __P((void));                                       vm_page_t *, int *, int,
 static int                 uvn_io __P((struct uvm_vnode *, vm_page_t *,                                       vm_prot_t, int, int));
                                       int, int, int));  static void             uvn_init __P((void));
 static int                 uvn_put __P((struct uvm_object *, vm_page_t *,  static int              uvn_put __P((struct uvm_object *, vm_page_t *,
                                         int, boolean_t));                                       int, boolean_t));
 static void                uvn_reference __P((struct uvm_object *));  static void             uvn_reference __P((struct uvm_object *));
 static boolean_t           uvn_releasepg __P((struct vm_page *,  static boolean_t        uvn_releasepg __P((struct vm_page *,
                                               struct vm_page **));                                             struct vm_page **));
   static void             uvn_doasyncget __P((struct vm_page **, size_t,
                                               daddr_t));
   
 /*  /*
  * master pager structure   * master pager structure
Line 173  uvn_attach(arg, accessprot)
Line 179  uvn_attach(arg, accessprot)
         struct vnode *vp = arg;          struct vnode *vp = arg;
         struct uvm_vnode *uvn = &vp->v_uvm;          struct uvm_vnode *uvn = &vp->v_uvm;
         struct vattr vattr;          struct vattr vattr;
         int oldflags, result;          int result;
         struct partinfo pi;          struct partinfo pi;
         u_quad_t used_vnode_size;          off_t used_vnode_size;
         UVMHIST_FUNC("uvn_attach"); UVMHIST_CALLED(maphist);          UVMHIST_FUNC("uvn_attach"); UVMHIST_CALLED(maphist);
   
         UVMHIST_LOG(maphist, "(vn=0x%x)", arg,0,0,0);          UVMHIST_LOG(maphist, "(vn=0x%x)", arg,0,0,0);
Line 186  uvn_attach(arg, accessprot)
Line 192  uvn_attach(arg, accessprot)
          * first get a lock on the uvn.           * first get a lock on the uvn.
          */           */
         simple_lock(&uvn->u_obj.vmobjlock);          simple_lock(&uvn->u_obj.vmobjlock);
         while (uvn->u_flags & UVM_VNODE_BLOCKED) {          while (uvn->u_flags & VXLOCK) {
                 uvn->u_flags |= UVM_VNODE_WANTED;                  uvn->u_flags |= VXWANT;
                 UVMHIST_LOG(maphist, "  SLEEPING on blocked vn",0,0,0,0);                  UVMHIST_LOG(maphist, "  SLEEPING on blocked vn",0,0,0,0);
                 UVM_UNLOCK_AND_WAIT(uvn, &uvn->u_obj.vmobjlock, FALSE,                  UVM_UNLOCK_AND_WAIT(uvn, &uvn->u_obj.vmobjlock, FALSE,
                     "uvn_attach", 0);                      "uvn_attach", 0);
Line 199  uvn_attach(arg, accessprot)
Line 205  uvn_attach(arg, accessprot)
          * if we're mapping a BLK device, make sure it is a disk.           * if we're mapping a BLK device, make sure it is a disk.
          */           */
         if (vp->v_type == VBLK && bdevsw[major(vp->v_rdev)].d_type != D_DISK) {          if (vp->v_type == VBLK && bdevsw[major(vp->v_rdev)].d_type != D_DISK) {
                 simple_unlock(&uvn->u_obj.vmobjlock); /* drop lock */                  simple_unlock(&uvn->u_obj.vmobjlock);
                 UVMHIST_LOG(maphist,"<- done (VBLK not D_DISK!)", 0,0,0,0);                  UVMHIST_LOG(maphist,"<- done (VBLK not D_DISK!)", 0,0,0,0);
                 return(NULL);                  return(NULL);
         }          }
   
         /*          /* check for new writeable uvn */
          * now we have lock and uvn must not be in a blocked state.          if ((accessprot & VM_PROT_WRITE) != 0 &&
          * first check to see if it is already active, in which case              (uvn->u_flags & VDIRTY) == 0) {
          * we can bump the reference count, check to see if we need to                  simple_lock(&uvn_wl_lock);
          * add it to the writeable list, and then return.                  LIST_INSERT_HEAD(&uvn_wlist, uvn, u_wlist);
          */                  simple_unlock(&uvn_wl_lock);
         if (uvn->u_flags & UVM_VNODE_VALID) {   /* already active? */                  /* we are now on wlist! */
                   uvn->u_flags |= VDIRTY;
                 /* regain VREF if we were persisting */          }
                 if (uvn->u_obj.uo_refs == 0) {  #ifdef DIAGNOSTIC
                         VREF(vp);          if (vp->v_type != VREG) {
                         UVMHIST_LOG(maphist," VREF (reclaim persisting vnode)",                  panic("uvn_attach: vp %p not VREG", vp);
                             0,0,0,0);          }
                 }  #endif
                 uvn->u_obj.uo_refs++;           /* bump uvn ref! */  
   
                 /* check for new writeable uvn */  
                 if ((accessprot & VM_PROT_WRITE) != 0 &&  
                     (uvn->u_flags & UVM_VNODE_WRITEABLE) == 0) {  
                         simple_lock(&uvn_wl_lock);  
                         LIST_INSERT_HEAD(&uvn_wlist, uvn, u_wlist);  
                         simple_unlock(&uvn_wl_lock);  
                         /* we are now on wlist! */  
                         uvn->u_flags |= UVM_VNODE_WRITEABLE;  
                 }  
   
                 /* unlock and return */  
                 simple_unlock(&uvn->u_obj.vmobjlock);  
                 UVMHIST_LOG(maphist,"<- done, refcnt=%d", uvn->u_obj.uo_refs,  
                     0, 0, 0);  
                 return (&uvn->u_obj);  
         }  
   
         /*          /*
          * need to call VOP_GETATTR() to get the attributes, but that could           * set up our idea of the size
          * block (due to I/O), so we want to unlock the object before calling.           * if this hasn't been done already.
          * however, we want to keep anyone else from playing with the object  
          * while it is unlocked.   to do this we set UVM_VNODE_ALOCK which  
          * prevents anyone from attaching to the vnode until we are done with  
          * it.  
          */           */
         uvn->u_flags = UVM_VNODE_ALOCK;          if (uvn->u_size == VSIZENOTSET) {
   
           uvn->u_flags = VXLOCK;
         simple_unlock(&uvn->u_obj.vmobjlock); /* drop lock in case we sleep */          simple_unlock(&uvn->u_obj.vmobjlock); /* drop lock in case we sleep */
                 /* XXX: curproc? */                  /* XXX: curproc? */
   
         if (vp->v_type == VBLK) {          if (vp->v_type == VBLK) {
                 /*                  /*
                  * We could implement this as a specfs getattr call, but:                   * We could implement this as a specfs getattr call, but:
Line 271  uvn_attach(arg, accessprot)
Line 256  uvn_attach(arg, accessprot)
                         used_vnode_size = vattr.va_size;                          used_vnode_size = vattr.va_size;
         }          }
   
         /* relock object */  
         simple_lock(&uvn->u_obj.vmobjlock);  
   
         if (result != 0) {  
                 if (uvn->u_flags & UVM_VNODE_WANTED)  
                         wakeup(uvn);  
                 uvn->u_flags = 0;  
                 simple_unlock(&uvn->u_obj.vmobjlock); /* drop lock */  
                 UVMHIST_LOG(maphist,"<- done (VOP_GETATTR FAILED!)", 0,0,0,0);  
                 return(NULL);  
         }  
   
         /*          /*
          * make sure that the newsize fits within a vaddr_t           * make sure that the newsize fits within a vaddr_t
          * XXX: need to revise addressing data types           * XXX: need to revise addressing data types
          */           */
 #ifdef DEBUG  
         if (vp->v_type == VBLK)  
                 printf("used_vnode_size = %qu\n", (long long)used_vnode_size);  
 #endif  
         if (used_vnode_size > (vaddr_t) -PAGE_SIZE) {          if (used_vnode_size > (vaddr_t) -PAGE_SIZE) {
 #ifdef DEBUG  #ifdef DEBUG
                 printf("uvn_attach: vn %p size truncated %qx->%x\n", vp,                  printf("uvn_attach: vn %p size truncated %qx->%x\n", vp,
Line 299  uvn_attach(arg, accessprot)
Line 269  uvn_attach(arg, accessprot)
                 used_vnode_size = (vaddr_t) -PAGE_SIZE;                  used_vnode_size = (vaddr_t) -PAGE_SIZE;
         }          }
   
         /*          /* relock object */
          * now set up the uvn.          simple_lock(&uvn->u_obj.vmobjlock);
          */  
         uvn->u_obj.pgops = &uvm_vnodeops;          if (uvn->u_flags & VXWANT)
         TAILQ_INIT(&uvn->u_obj.memq);                  wakeup(uvn);
         uvn->u_obj.uo_npages = 0;          uvn->u_flags = 0;
         uvn->u_obj.uo_refs = 1;                 /* just us... */  
         oldflags = uvn->u_flags;          if (result != 0) {
         uvn->u_flags = UVM_VNODE_VALID|UVM_VNODE_CANPERSIST;                  simple_unlock(&uvn->u_obj.vmobjlock); /* drop lock */
         uvn->u_nio = 0;                  UVMHIST_LOG(maphist,"<- done (VOP_GETATTR FAILED!)", 0,0,0,0);
                   return(NULL);
           }
         uvn->u_size = used_vnode_size;          uvn->u_size = used_vnode_size;
   
         /* if write access, we need to add it to the wlist */  
         if (accessprot & VM_PROT_WRITE) {  
                 simple_lock(&uvn_wl_lock);  
                 LIST_INSERT_HEAD(&uvn_wlist, uvn, u_wlist);  
                 simple_unlock(&uvn_wl_lock);  
                 uvn->u_flags |= UVM_VNODE_WRITEABLE;    /* we are on wlist! */  
         }          }
   
         /*          /* unlock and return */
          * add a reference to the vnode.   this reference will stay as long  
          * as there is a valid mapping of the vnode.   dropped when the  
          * reference count goes to zero [and we either free or persist].  
          */  
         VREF(vp);  
         simple_unlock(&uvn->u_obj.vmobjlock);          simple_unlock(&uvn->u_obj.vmobjlock);
         if (oldflags & UVM_VNODE_WANTED)          UVMHIST_LOG(maphist,"<- done, refcnt=%d", uvn->u_obj.uo_refs,
                 wakeup(uvn);              0, 0, 0);
           return (&uvn->u_obj);
         UVMHIST_LOG(maphist,"<- done/VREF, ret 0x%x", &uvn->u_obj,0,0,0);  
         return(&uvn->u_obj);  
 }  }
   
   
Line 350  static void
Line 309  static void
 uvn_reference(uobj)  uvn_reference(uobj)
         struct uvm_object *uobj;          struct uvm_object *uobj;
 {  {
 #ifdef DIAGNOSTIC  
         struct uvm_vnode *uvn = (struct uvm_vnode *) uobj;  
 #endif  
         UVMHIST_FUNC("uvn_reference"); UVMHIST_CALLED(maphist);          UVMHIST_FUNC("uvn_reference"); UVMHIST_CALLED(maphist);
   
         simple_lock(&uobj->vmobjlock);          VREF((struct vnode *)uobj);
 #ifdef DIAGNOSTIC  
         if ((uvn->u_flags & UVM_VNODE_VALID) == 0) {  
                 printf("uvn_reference: ref=%d, flags=0x%x\n", uvn->u_flags,  
                     uobj->uo_refs);  
                 panic("uvn_reference: invalid state");  
         }  
 #endif  
         uobj->uo_refs++;  
         UVMHIST_LOG(maphist, "<- done (uobj=0x%x, ref = %d)",  
         uobj, uobj->uo_refs,0,0);  
         simple_unlock(&uobj->vmobjlock);  
 }  }
   
 /*  /*
Line 382  static void
Line 327  static void
 uvn_detach(uobj)  uvn_detach(uobj)
         struct uvm_object *uobj;          struct uvm_object *uobj;
 {  {
         struct uvm_vnode *uvn;  
         struct vnode *vp;  
         int oldflags;  
         UVMHIST_FUNC("uvn_detach"); UVMHIST_CALLED(maphist);          UVMHIST_FUNC("uvn_detach"); UVMHIST_CALLED(maphist);
           vrele((struct vnode *)uobj);
         simple_lock(&uobj->vmobjlock);  
   
         UVMHIST_LOG(maphist,"  (uobj=0x%x)  ref=%d", uobj,uobj->uo_refs,0,0);  
         uobj->uo_refs--;                        /* drop ref! */  
         if (uobj->uo_refs) {                    /* still more refs */  
                 simple_unlock(&uobj->vmobjlock);  
                 UVMHIST_LOG(maphist, "<- done (rc>0)", 0,0,0,0);  
                 return;  
         }  
   
         /*  
          * get other pointers ...  
          */  
   
         uvn = (struct uvm_vnode *) uobj;  
         vp = (struct vnode *) uobj;  
   
         /*  
          * clear VTEXT flag now that there are no mappings left (VTEXT is used  
          * to keep an active text file from being overwritten).  
          */  
         vp->v_flag &= ~VTEXT;  
   
         /*  
          * we just dropped the last reference to the uvn.   see if we can  
          * let it "stick around".  
          */  
   
         if (uvn->u_flags & UVM_VNODE_CANPERSIST) {  
                 /* won't block */  
                 uvn_flush(uobj, 0, 0, PGO_DEACTIVATE|PGO_ALLPAGES);  
                 simple_unlock(&uobj->vmobjlock);  
                 vrele(vp);                      /* drop vnode reference */  
                 UVMHIST_LOG(maphist,"<- done/vrele!  (persist)", 0,0,0,0);  
                 return;  
         }  
   
         /*  
          * its a goner!  
          */  
   
         UVMHIST_LOG(maphist,"  its a goner (flushing)!", 0,0,0,0);  
   
         uvn->u_flags |= UVM_VNODE_DYING;  
   
         /*  
          * even though we may unlock in flush, no one can gain a reference  
          * to us until we clear the "dying" flag [because it blocks  
          * attaches].  we will not do that until after we've disposed of all  
          * the pages with uvn_flush().  note that before the flush the only  
          * pages that could be marked PG_BUSY are ones that are in async  
          * pageout by the daemon.  (there can't be any pending "get"'s  
          * because there are no references to the object).  
          */  
   
         (void) uvn_flush(uobj, 0, 0, PGO_CLEANIT|PGO_FREE|PGO_ALLPAGES);  
   
         UVMHIST_LOG(maphist,"  its a goner (done flush)!", 0,0,0,0);  
   
         /*  
          * given the structure of this pager, the above flush request will  
          * create the following state: all the pages that were in the object  
          * have either been free'd or they are marked PG_BUSY|PG_RELEASED.  
          * the PG_BUSY bit was set either by us or the daemon for async I/O.  
          * in either case, if we have pages left we can't kill the object  
          * yet because i/o is pending.  in this case we set the "relkill"  
          * flag which will cause pgo_releasepg to kill the object once all  
          * the I/O's are done [pgo_releasepg will be called from the aiodone  
          * routine or from the page daemon].  
          */  
   
         if (uobj->uo_npages) {          /* I/O pending.  iodone will free */  
 #ifdef DIAGNOSTIC  
                 /*  
                  * XXXCDC: very unlikely to happen until we have async i/o  
                  * so print a little info message in case it does.  
                  */  
                 printf("uvn_detach: vn %p has pages left after flush - "  
                     "relkill mode\n", uobj);  
 #endif  
                 uvn->u_flags |= UVM_VNODE_RELKILL;  
                 simple_unlock(&uobj->vmobjlock);  
                 UVMHIST_LOG(maphist,"<- done! (releasepg will kill obj)", 0, 0,  
                     0, 0);  
                 return;  
         }  
   
         /*  
          * kill object now.   note that we can't be on the sync q because  
          * all references are gone.  
          */  
         if (uvn->u_flags & UVM_VNODE_WRITEABLE) {  
                 simple_lock(&uvn_wl_lock);              /* protect uvn_wlist */  
                 LIST_REMOVE(uvn, u_wlist);  
                 simple_unlock(&uvn_wl_lock);  
         }  
 #ifdef DIAGNOSTIC  
         if (uobj->memq.tqh_first != NULL)  
                 panic("uvn_deref: vnode VM object still has pages afer "  
                     "syncio/free flush");  
 #endif  
         oldflags = uvn->u_flags;  
         uvn->u_flags = 0;  
         simple_unlock(&uobj->vmobjlock);  
   
         /* wake up any sleepers */  
         if (oldflags & UVM_VNODE_WANTED)  
                 wakeup(uvn);  
   
         /*  
          * drop our reference to the vnode.  
          */  
         vrele(vp);  
         UVMHIST_LOG(maphist,"<- done (vrele) final", 0,0,0,0);  
   
         return;  
 }  }
   
 /*  /*
Line 538  uvm_vnp_terminate(vp)
Line 364  uvm_vnp_terminate(vp)
         struct vnode *vp;          struct vnode *vp;
 {  {
         struct uvm_vnode *uvn = &vp->v_uvm;          struct uvm_vnode *uvn = &vp->v_uvm;
         int oldflags;          if (uvn->u_flags & VDIRTY) {
         UVMHIST_FUNC("uvm_vnp_terminate"); UVMHIST_CALLED(maphist);                  simple_lock(&uvn_wl_lock);
                   LIST_REMOVE(uvn, u_wlist);
         /*                  uvn->u_flags &= ~(VDIRTY);
          * lock object and check if it is valid                  simple_unlock(&uvn_wl_lock);
          */  
         simple_lock(&uvn->u_obj.vmobjlock);  
         UVMHIST_LOG(maphist, "  vp=0x%x, ref=%d, flag=0x%x", vp,  
             uvn->u_obj.uo_refs, uvn->u_flags, 0);  
         if ((uvn->u_flags & UVM_VNODE_VALID) == 0) {  
                 simple_unlock(&uvn->u_obj.vmobjlock);  
                 UVMHIST_LOG(maphist, "<- done (not active)", 0, 0, 0, 0);  
                 return;  
         }  
   
         /*  
          * must be a valid uvn that is not already dying (because XLOCK  
          * protects us from that).   the uvn can't in the the ALOCK state  
          * because it is valid, and uvn's that are in the ALOCK state haven't  
          * been marked valid yet.  
          */  
   
 #ifdef DEBUG  
         /*  
          * debug check: are we yanking the vnode out from under our uvn?  
          */  
         if (uvn->u_obj.uo_refs) {  
                 printf("uvm_vnp_terminate(%p): terminating active vnode "  
                     "(refs=%d)\n", uvn, uvn->u_obj.uo_refs);  
         }  
 #endif  
   
         /*  
          * it is possible that the uvn was detached and is in the relkill  
          * state [i.e. waiting for async i/o to finish so that releasepg can  
          * kill object].  we take over the vnode now and cancel the relkill.  
          * we want to know when the i/o is done so we can recycle right  
          * away.   note that a uvn can only be in the RELKILL state if it  
          * has a zero reference count.  
          */  
   
         if (uvn->u_flags & UVM_VNODE_RELKILL)  
                 uvn->u_flags &= ~UVM_VNODE_RELKILL;     /* cancel RELKILL */  
   
         /*  
          * block the uvn by setting the dying flag, and then flush the  
          * pages.  (note that flush may unlock object while doing I/O, but  
          * it will re-lock it before it returns control here).  
          *  
          * also, note that we tell I/O that we are already VOP_LOCK'd so  
          * that uvn_io doesn't attempt to VOP_LOCK again.  
          *  
          * XXXCDC: setting VNISLOCKED on an active uvn which is being terminated  
          *      due to a forceful unmount might not be a good idea.  maybe we  
          *      need a way to pass in this info to uvn_flush through a  
          *      pager-defined PGO_ constant [currently there are none].  
          */  
         uvn->u_flags |= UVM_VNODE_DYING|UVM_VNODE_VNISLOCKED;  
   
         (void) uvn_flush(&uvn->u_obj, 0, 0, PGO_CLEANIT|PGO_FREE|PGO_ALLPAGES);  
   
         /*  
          * as we just did a flush we expect all the pages to be gone or in  
          * the process of going.  sleep to wait for the rest to go [via iosync].  
          */  
   
         while (uvn->u_obj.uo_npages) {  
 #ifdef DIAGNOSTIC  
                 struct vm_page *pp;  
                 for (pp = uvn->u_obj.memq.tqh_first ; pp != NULL ;  
                      pp = pp->listq.tqe_next) {  
                         if ((pp->flags & PG_BUSY) == 0)  
                                 panic("uvm_vnp_terminate: detected unbusy pg");  
                 }  
                 if (uvn->u_nio == 0)  
                         panic("uvm_vnp_terminate: no I/O to wait for?");  
                 printf("uvm_vnp_terminate: waiting for I/O to fin.\n");  
                 /*  
                  * XXXCDC: this is unlikely to happen without async i/o so we  
                  * put a printf in just to keep an eye on it.  
                  */  
 #endif  
                 uvn->u_flags |= UVM_VNODE_IOSYNC;  
                 UVM_UNLOCK_AND_WAIT(&uvn->u_nio, &uvn->u_obj.vmobjlock, FALSE,  
                     "uvn_term",0);  
                 simple_lock(&uvn->u_obj.vmobjlock);  
         }  
   
         /*  
          * done.   now we free the uvn if its reference count is zero  
          * (true if we are zapping a persisting uvn).   however, if we are  
          * terminating a uvn with active mappings we let it live ... future  
          * calls down to the vnode layer will fail.  
          */  
   
         oldflags = uvn->u_flags;  
         if (uvn->u_obj.uo_refs) {  
   
                 /*  
                  * uvn must live on it is dead-vnode state until all references  
                  * are gone.   restore flags.    clear CANPERSIST state.  
                  */  
   
                 uvn->u_flags &= ~(UVM_VNODE_DYING|UVM_VNODE_VNISLOCKED|  
                       UVM_VNODE_WANTED|UVM_VNODE_CANPERSIST);  
   
         } else {  
   
                 /*  
                  * free the uvn now.   note that the VREF reference is already  
                  * gone [it is dropped when we enter the persist state].  
                  */  
                 if (uvn->u_flags & UVM_VNODE_IOSYNCWANTED)  
                         panic("uvm_vnp_terminate: io sync wanted bit set");  
   
                 if (uvn->u_flags & UVM_VNODE_WRITEABLE) {  
                         simple_lock(&uvn_wl_lock);  
                         LIST_REMOVE(uvn, u_wlist);  
                         simple_unlock(&uvn_wl_lock);  
                 }  
                 uvn->u_flags = 0;       /* uvn is history, clear all bits */  
         }          }
   
         if (oldflags & UVM_VNODE_WANTED)  
                 wakeup(uvn);            /* object lock still held */  
   
         simple_unlock(&uvn->u_obj.vmobjlock);  
         UVMHIST_LOG(maphist, "<- done", 0, 0, 0, 0);  
   
 }  }
   
 /*  /*
Line 708  uvn_releasepg(pg, nextpgp)
Line 411  uvn_releasepg(pg, nextpgp)
         if (!nextpgp)          if (!nextpgp)
                 uvm_unlock_pageq();                  uvm_unlock_pageq();
   
   #if 1
           /* XXX I'm sure we need to do something here. */
           uvn = uvn;
   #else
         /*          /*
          * now see if we need to kill the object           * now see if we need to kill the object
          */           */
Line 716  uvn_releasepg(pg, nextpgp)
Line 423  uvn_releasepg(pg, nextpgp)
                         panic("uvn_releasepg: kill flag set on referenced "                          panic("uvn_releasepg: kill flag set on referenced "
                             "object!");                              "object!");
                 if (uvn->u_obj.uo_npages == 0) {                  if (uvn->u_obj.uo_npages == 0) {
                         if (uvn->u_flags & UVM_VNODE_WRITEABLE) {                          if (uvn->u_flags & VDIRTY) {
                                 simple_lock(&uvn_wl_lock);                                  simple_lock(&uvn_wl_lock);
                                 LIST_REMOVE(uvn, u_wlist);                                  LIST_REMOVE(uvn, u_wlist);
                                 simple_unlock(&uvn_wl_lock);                                  simple_unlock(&uvn_wl_lock);
Line 725  uvn_releasepg(pg, nextpgp)
Line 432  uvn_releasepg(pg, nextpgp)
                         if (uvn->u_obj.memq.tqh_first)                          if (uvn->u_obj.memq.tqh_first)
         panic("uvn_releasepg: pages in object with npages == 0");          panic("uvn_releasepg: pages in object with npages == 0");
 #endif  #endif
                         if (uvn->u_flags & UVM_VNODE_WANTED)                          if (uvn->u_flags & VXWANT)
                                 /* still holding object lock */                                  /* still holding object lock */
                                 wakeup(uvn);                                  wakeup(uvn);
   
Line 734  uvn_releasepg(pg, nextpgp)
Line 441  uvn_releasepg(pg, nextpgp)
                         return (FALSE);                          return (FALSE);
                 }                  }
         }          }
   #endif
         return (TRUE);          return (TRUE);
 }  }
   
Line 838  uvn_flush(uobj, start, stop, flags)
Line 546  uvn_flush(uobj, start, stop, flags)
         int flags;          int flags;
 {  {
         struct uvm_vnode *uvn = (struct uvm_vnode *) uobj;          struct uvm_vnode *uvn = (struct uvm_vnode *) uobj;
           struct vnode *vp = (struct vnode *)uobj;
         struct vm_page *pp, *ppnext, *ptmp;          struct vm_page *pp, *ppnext, *ptmp;
         struct vm_page *pps[MAXBSIZE >> PAGE_SHIFT], **ppsp;          struct vm_page *pps[MAXBSIZE >> PAGE_SHIFT], **ppsp;
           int s;
         int npages, result, lcv;          int npages, result, lcv;
         boolean_t retval, need_iosync, by_list, needs_clean;          boolean_t retval, need_iosync, by_list, needs_clean;
         vaddr_t curoff;          vaddr_t curoff;
         u_short pp_version;          u_short pp_version;
         UVMHIST_FUNC("uvn_flush"); UVMHIST_CALLED(maphist);          UVMHIST_FUNC("uvn_flush"); UVMHIST_CALLED(maphist);
   
           if (uvn->u_size == VSIZENOTSET) {
   #ifdef DEBUG
                   void vp_name(void *);
   
                   printf("uvn_flush: size not set vp %p\n", uvn);
                   if ((flags & PGO_ALLPAGES) == 0)
                           printf("... and PGO_ALLPAGES not set: "
                                  "start 0x%lx end 0x%lx flags 0x%x\n",
                                  start, stop, flags);
                   vprint("uvn_flush VSIZENOTSET", vp);
                   vp_name(uvn);
   #endif
                   flags |= PGO_ALLPAGES;
           }
   
         curoff = 0;     /* XXX: shut up gcc */          curoff = 0;     /* XXX: shut up gcc */
         /*          /*
          * get init vals and determine how we are going to traverse object           * get init vals and determine how we are going to traverse object
Line 855  uvn_flush(uobj, start, stop, flags)
Line 580  uvn_flush(uobj, start, stop, flags)
         retval = TRUE;          /* return value */          retval = TRUE;          /* return value */
         if (flags & PGO_ALLPAGES) {          if (flags & PGO_ALLPAGES) {
                 start = 0;                  start = 0;
                 stop = round_page(uvn->u_size);                  stop = -1;
                 by_list = TRUE;         /* always go by the list */                  by_list = TRUE;         /* always go by the list */
         } else {          } else {
                 start = trunc_page(start);                  start = trunc_page(start);
                 stop = round_page(stop);                  stop = round_page(stop);
                 if (stop > round_page(uvn->u_size))                  if (stop > round_page(uvn->u_size)) {
                         printf("uvn_flush: strange, got an out of range "                          printf("uvn_flush: oor vp %p start 0x%x stop 0x%x "
                             "flush (fixed)\n");                                 "size 0x%x\n", uvn, (int)start, (int)stop,
                                  (int)round_page(uvn->u_size));
                   }
   
                 by_list = (uobj->uo_npages <=                  by_list = (uobj->uo_npages <=
                     ((stop - start) >> PAGE_SHIFT) * UVN_HASH_PENALTY);                      ((stop - start) >> PAGE_SHIFT) * UVN_HASH_PENALTY);
Line 886  uvn_flush(uobj, start, stop, flags)
Line 613  uvn_flush(uobj, start, stop, flags)
         if ((flags & PGO_CLEANIT) != 0 &&          if ((flags & PGO_CLEANIT) != 0 &&
             uobj->pgops->pgo_mk_pcluster != NULL) {              uobj->pgops->pgo_mk_pcluster != NULL) {
                 if (by_list) {                  if (by_list) {
                         for (pp = uobj->memq.tqh_first ; pp != NULL ;                          for (pp = TAILQ_FIRST(&uobj->memq);
                             pp = pp->listq.tqe_next) {                               pp != NULL ;
                                 if (pp->offset < start || pp->offset >= stop)                               pp = TAILQ_NEXT(pp, listq)) {
                                   if (pp->offset < start ||
                                       (pp->offset >= stop && stop != -1))
                                         continue;                                          continue;
                                 pp->flags &= ~PG_CLEANCHK;                                  pp->flags &= ~PG_CLEANCHK;
                         }                          }
Line 910  uvn_flush(uobj, start, stop, flags)
Line 639  uvn_flush(uobj, start, stop, flags)
          */           */
   
         if (by_list) {          if (by_list) {
                 pp = uobj->memq.tqh_first;                  pp = TAILQ_FIRST(&uobj->memq);
         } else {          } else {
                 curoff = start;                  curoff = start;
                 pp = uvm_pagelookup(uobj, curoff);                  pp = uvm_pagelookup(uobj, curoff);
Line 931  uvn_flush(uobj, start, stop, flags)
Line 660  uvn_flush(uobj, start, stop, flags)
                          */                           */
   
                         if (pp->offset < start || pp->offset >= stop) {                          if (pp->offset < start || pp->offset >= stop) {
                                 ppnext = pp->listq.tqe_next;                                  ppnext = TAILQ_NEXT(pp, listq);
                                 continue;                                  continue;
                         }                          }
   
Line 1039  ReTry:
Line 768  ReTry:
   
                 /* locked: page queues, uobj */                  /* locked: page queues, uobj */
                 result = uvm_pager_put(uobj, pp, &ppsp, &npages,                  result = uvm_pager_put(uobj, pp, &ppsp, &npages,
                            flags | PGO_DOACTCLUST, start, stop);                                         flags | PGO_DOACTCLUST, start, stop);
                 /* unlocked: page queues, uobj */                  /* unlocked: page queues, uobj */
   
                 /*                  /*
Line 1163  ReTry:
Line 892  ReTry:
                         if (result != VM_PAGER_PEND) {                          if (result != VM_PAGER_PEND) {
                                 if (ptmp->flags & PG_WANTED)                                  if (ptmp->flags & PG_WANTED)
                                         /* still holding object lock */                                          /* still holding object lock */
                                         thread_wakeup(ptmp);                                          wakeup(ptmp);
   
                                 ptmp->flags &= ~(PG_WANTED|PG_BUSY);                                  ptmp->flags &= ~(PG_WANTED|PG_BUSY);
                                 UVM_PAGE_OWN(ptmp, NULL);                                  UVM_PAGE_OWN(ptmp, NULL);
Line 1205  ReTry:
Line 934  ReTry:
                                 } else {                                  } else {
                                         if (result != VM_PAGER_OK) {                                          if (result != VM_PAGER_OK) {
                                                 printf("uvn_flush: obj=%p, "                                                  printf("uvn_flush: obj=%p, "
                                                    "offset=0x%lx.  error "                                                     "offset=0x%lx.  error %d\n",
                                                    "during pageout.\n",                                                      pp->uobject, pp->offset,
                                                     pp->uobject, pp->offset);                                                      result);
                                                 printf("uvn_flush: WARNING: "                                                  printf("uvn_flush: WARNING: "
                                                     "changes to page may be "                                                      "changes to page may be "
                                                     "lost!\n");                                                      "lost!\n");
Line 1232  ReTry:
Line 961  ReTry:
          * now wait for all I/O if required.           * now wait for all I/O if required.
          */           */
         if (need_iosync) {          if (need_iosync) {
   
                 UVMHIST_LOG(maphist,"  <<DOING IOSYNC>>",0,0,0,0);                  UVMHIST_LOG(maphist,"  <<DOING IOSYNC>>",0,0,0,0);
                 while (uvn->u_nio != 0) {  
                         uvn->u_flags |= UVM_VNODE_IOSYNC;                  /*
                         UVM_UNLOCK_AND_WAIT(&uvn->u_nio, &uvn->u_obj.vmobjlock,                   * XXX this doesn't use the new two-flag scheme,
                           FALSE, "uvn_flush",0);                   * but to use that, all i/o initiators will have to change.
                    */
   
                   s = splbio();
                   while (vp->v_numoutput != 0) {
                           UVMHIST_LOG(ubchist, "waiting for vp %p num %d",
                                       vp, vp->v_numoutput,0,0);
   
                           vp->v_flag |= VBWAIT;
                           UVM_UNLOCK_AND_WAIT(&vp->v_numoutput,
                                               &uvn->u_obj.vmobjlock,
                                               FALSE, "uvn_flush",0);
                         simple_lock(&uvn->u_obj.vmobjlock);                          simple_lock(&uvn->u_obj.vmobjlock);
                 }                  }
                 if (uvn->u_flags & UVM_VNODE_IOSYNCWANTED)                  splx(s);
                         wakeup(&uvn->u_flags);  
                 uvn->u_flags &= ~(UVM_VNODE_IOSYNC|UVM_VNODE_IOSYNCWANTED);  
         }          }
   
         /* return, with object locked! */          /* return, with object locked! */
Line 1266  uvn_cluster(uobj, offset, loffset, hoffs
Line 1003  uvn_cluster(uobj, offset, loffset, hoffs
         vaddr_t offset;          vaddr_t offset;
         vaddr_t *loffset, *hoffset; /* OUT */          vaddr_t *loffset, *hoffset; /* OUT */
 {  {
         struct uvm_vnode *uvn = (struct uvm_vnode *) uobj;          struct uvm_vnode *uvn = (struct uvm_vnode *)uobj;
         *loffset = offset;  
   
         if (*loffset >= uvn->u_size)          *loffset = offset;
                 panic("uvn_cluster: offset out of range");          *hoffset = min(offset + MAXBSIZE, round_page(uvn->u_size));
   
         /*  
          * XXX: old pager claims we could use VOP_BMAP to get maxcontig value.  
          */  
         *hoffset = *loffset + MAXBSIZE;  
         if (*hoffset > round_page(uvn->u_size)) /* past end? */  
                 *hoffset = round_page(uvn->u_size);  
   
         return;  
 }  }
   
 /*  /*
  * uvn_put: flush page data to backing store.   * uvn_put: flush page data to backing store.
  *   *
  * => prefer map unlocked (not required)  
  * => object must be locked!   we will _unlock_ it before starting I/O.   * => object must be locked!   we will _unlock_ it before starting I/O.
  * => flags: PGO_SYNCIO -- use sync. I/O   * => flags: PGO_SYNCIO -- use sync. I/O
  * => note: caller must set PG_CLEAN and pmap_clear_modify (if needed)   * => note: caller must set PG_CLEAN and pmap_clear_modify (if needed)
  * => XXX: currently we use VOP_READ/VOP_WRITE which are only sync.  
  *      [thus we never do async i/o!  see iodone comment]  
  */   */
   
 static int  static int
Line 1299  uvn_put(uobj, pps, npages, flags)
Line 1023  uvn_put(uobj, pps, npages, flags)
         struct vm_page **pps;          struct vm_page **pps;
         int npages, flags;          int npages, flags;
 {  {
         int retval;          struct vnode *vp = (struct vnode *)uobj;
           int error, sync;
   
         /* note: object locked */          sync = (flags & PGO_SYNCIO) ? 1 : 0;
         retval = uvn_io((struct uvm_vnode*)uobj, pps, npages, flags, UIO_WRITE);  
         /* note: object unlocked */  
   
         return(retval);          simple_lock_assert(&uobj->vmobjlock, SLOCK_LOCKED);
           simple_unlock(&uobj->vmobjlock);
           error = VOP_PUTPAGES(vp, pps, npages, sync, NULL);
           simple_lock_assert(&uobj->vmobjlock, SLOCK_UNLOCKED);
   
           return uvm_errno2vmerror(error);
 }  }
   
   
Line 1326  uvn_get(uobj, offset, pps, npagesp, cent
Line 1054  uvn_get(uobj, offset, pps, npagesp, cent
         vaddr_t offset;          vaddr_t offset;
         struct vm_page **pps;           /* IN/OUT */          struct vm_page **pps;           /* IN/OUT */
         int *npagesp;                   /* IN (OUT if PGO_LOCKED) */          int *npagesp;                   /* IN (OUT if PGO_LOCKED) */
         int centeridx, advice, flags;          int centeridx;
         vm_prot_t access_type;          vm_prot_t access_type;
           int advice, flags;
 {  {
         vaddr_t current_offset;          struct vnode *vp = (struct vnode *)uobj;
         struct vm_page *ptmp;          int error;
         int lcv, result, gotpages;          UVMHIST_FUNC("uvn_get"); UVMHIST_CALLED(ubchist);
         boolean_t done;          UVMHIST_LOG(ubchist, "vp %p off 0x%x", vp, (int)offset, 0,0);
         UVMHIST_FUNC("uvn_get"); UVMHIST_CALLED(maphist);  
         UVMHIST_LOG(maphist, "flags=%d", flags,0,0,0);          simple_lock_assert(&uobj->vmobjlock, SLOCK_LOCKED);
           error = VOP_GETPAGES(vp, offset, pps, npagesp, centeridx,
         /*                               access_type, advice, flags);
          * step 1: handled the case where fault data structures are locked.          simple_lock_assert(&uobj->vmobjlock, flags & PGO_LOCKED ?
          */                             SLOCK_LOCKED : SLOCK_UNLOCKED);
           return uvm_errno2vmerror(error);
         if (flags & PGO_LOCKED) {  }
   
                 /*  
                  * gotpages is the current number of pages we've gotten (which  
                  * we pass back up to caller via *npagesp.  
                  */  
   
                 gotpages = 0;  
   
                 /*  
                  * step 1a: get pages that are already resident.   only do this  
                  * if the data structures are locked (i.e. the first time  
                  * through).  
                  */  
   
                 done = TRUE;    /* be optimistic */  
   
                 for (lcv = 0, current_offset = offset ; lcv < *npagesp ;  
                     lcv++, current_offset += PAGE_SIZE) {  
   
                         /* do we care about this page?  if not, skip it */  
                         if (pps[lcv] == PGO_DONTCARE)  
                                 continue;  
   
                         /* lookup page */  
                         ptmp = uvm_pagelookup(uobj, current_offset);  
   
                         /* to be useful must get a non-busy, non-released pg */  
                         if (ptmp == NULL ||  
                             (ptmp->flags & (PG_BUSY|PG_RELEASED)) != 0) {  
                                 if (lcv == centeridx || (flags & PGO_ALLPAGES)  
                                     != 0)  
                                 done = FALSE;   /* need to do a wait or I/O! */  
                                 continue;  
                         }  
   
                         /*  
                          * useful page: busy/lock it and plug it in our  
                          * result array  
                          */  
                         ptmp->flags |= PG_BUSY;         /* loan up to caller */  
                         UVM_PAGE_OWN(ptmp, "uvn_get1");  
                         pps[lcv] = ptmp;  
                         gotpages++;  
   
                 }       /* "for" lcv loop */  
   
                 /*  /*
                  * XXX: given the "advice", should we consider async read-ahead?   * uvn_findpages:
                  * XXX: fault current does deactive of pages behind us.  is   * return the page for the uobj and offset requested, allocating if needed.
                  * this good (other callers might now).   * => uobj must be locked.
                  */   * => returned page will be BUSY.
                 /*   */
                  * XXX: read-ahead currently handled by buffer cache (bread)  
                  * level.  
                  * XXX: no async i/o available.  
                  * XXX: so we don't do anything now.  
                  */  
   
                 /*  void
                  * step 1c: now we've either done everything needed or we to  uvn_findpages(uobj, offset, npagesp, pps, flags)
                  * unlock and do some waiting or I/O.          struct uvm_object *uobj;
                  */          vaddr_t offset;
           int *npagesp;
           struct vm_page **pps;
           int flags;
   {
           int i, rv, npages;
   
                 *npagesp = gotpages;            /* let caller know */          rv = 0;
                 if (done)          npages = *npagesp;
                         return(VM_PAGER_OK);            /* bingo! */          for (i = 0; i < npages; i++, offset += PAGE_SIZE) {
                 else                  rv += uvn_findpage(uobj, offset, &pps[i], flags);
                         /* EEK!   Need to unlock and I/O */  
                         return(VM_PAGER_UNLOCK);  
         }          }
           *npagesp = rv;
   }
   
         /*  
          * step 2: get non-resident or busy pages.  
          * object is locked.   data structures are unlocked.  
          *  
          * XXX: because we can't do async I/O at this level we get things  
          * page at a time (otherwise we'd chunk).   the VOP_READ() will do  
          * async-read-ahead for us at a lower level.  
          */  
   
         for (lcv = 0, current_offset = offset ;  
                          lcv < *npagesp ; lcv++, current_offset += PAGE_SIZE) {  
   
                 /* skip over pages we've already gotten or don't want */  
                 /* skip over pages we don't _have_ to get */  
                 if (pps[lcv] != NULL || (lcv != centeridx &&  
                     (flags & PGO_ALLPAGES) == 0))  
                         continue;  
   
                 /*  
                  * we have yet to locate the current page (pps[lcv]).   we first  
                  * look for a page that is already at the current offset.   if  
                  * we fine a page, we check to see if it is busy or released.  
                  * if that is the case, then we sleep on the page until it is  
                  * no longer busy or released and repeat the lookup.    if the  
                  * page we found is neither busy nor released, then we busy it  
                  * (so we own it) and plug it into pps[lcv].   this breaks the  
                  * following while loop and indicates we are ready to move on  
                  * to the next page in the "lcv" loop above.  
                  *  
                  * if we exit the while loop with pps[lcv] still set to NULL,  
                  * then it means that we allocated a new busy/fake/clean page  
                  * ptmp in the object and we need to do I/O to fill in the data.  
                  */  
   
                 while (pps[lcv] == NULL) {      /* top of "pps" while loop */  static int
   uvn_findpage(uobj, offset, pps, flags)
                         /* look for a current page */          struct uvm_object *uobj;
                         ptmp = uvm_pagelookup(uobj, current_offset);          vaddr_t offset;
           struct vm_page **pps;
           int flags;
   {
           struct vm_page *ptmp;
           UVMHIST_FUNC("uvn_findpage"); UVMHIST_CALLED(ubchist);
           UVMHIST_LOG(ubchist, "vp %p off 0x%lx", uobj, offset,0,0);
   
                         /* nope?   allocate one now (if we can) */          simple_lock_assert(&uobj->vmobjlock, SLOCK_LOCKED);
           if (*pps != NULL) {
                   UVMHIST_LOG(ubchist, "dontcare", 0,0,0,0);
                   return 0;
           }
           for (;;) {
                   /* look for an existing page */
                   ptmp = uvm_pagelookup(uobj, offset);
   
                   /* nope?   allocate one now */
                   if (ptmp == NULL) {
                           if (flags & UFP_NOALLOC) {
                                   UVMHIST_LOG(ubchist, "noalloc", 0,0,0,0);
                                   return 0;
                           }
                           ptmp = uvm_pagealloc(uobj, offset, NULL, 0);
                         if (ptmp == NULL) {                          if (ptmp == NULL) {
                                   if (flags & UFP_NOWAIT) {
                                 ptmp = uvm_pagealloc(uobj, current_offset,                                          UVMHIST_LOG(ubchist, "nowait",0,0,0,0);
                                     NULL, 0);                                          return 0;
   
                                 /* out of RAM? */  
                                 if (ptmp == NULL) {  
                                         simple_unlock(&uobj->vmobjlock);  
                                         uvm_wait("uvn_getpage");  
                                         simple_lock(&uobj->vmobjlock);  
   
                                         /* goto top of pps while loop */  
                                         continue;  
                                 }                                  }
                                   simple_unlock(&uobj->vmobjlock);
                                 /*                                  uvm_wait("uvn_fp1");
                                  * got new page ready for I/O.  break pps  
                                  * while loop.  pps[lcv] is still NULL.  
                                  */  
                                 break;  
                         }  
   
                         /* page is there, see if we need to wait on it */  
                         if ((ptmp->flags & (PG_BUSY|PG_RELEASED)) != 0) {  
                                 ptmp->flags |= PG_WANTED;  
                                 UVM_UNLOCK_AND_WAIT(ptmp,  
                                     &uobj->vmobjlock, 0, "uvn_get",0);  
                                 simple_lock(&uobj->vmobjlock);                                  simple_lock(&uobj->vmobjlock);
                                 continue;       /* goto top of pps while loop */                                  continue;
                         }                          }
                           UVMHIST_LOG(ubchist, "alloced",0,0,0,0);
                         /*                          break;
                          * if we get here then the page has become resident                  } else if (flags & UFP_NOCACHE) {
                          * and unbusy between steps 1 and 2.  we busy it                          UVMHIST_LOG(ubchist, "nocache",0,0,0,0);
                          * now (so we own it) and set pps[lcv] (so that we                          return 0;
                          * exit the while loop).  
                          */  
                         ptmp->flags |= PG_BUSY;  
                         UVM_PAGE_OWN(ptmp, "uvn_get2");  
                         pps[lcv] = ptmp;  
                 }                  }
   
                 /*                  /* page is there, see if we need to wait on it */
                  * if we own the a valid page at the correct offset, pps[lcv]                  if ((ptmp->flags & (PG_BUSY|PG_RELEASED)) != 0) {
                  * will point to it.   nothing more to do except go to the                          if (flags & UFP_NOWAIT) {
                  * next page.                                  UVMHIST_LOG(ubchist, "nowait",0,0,0,0);
                  */                                  return 0;
                           }
                 if (pps[lcv])                          ptmp->flags |= PG_WANTED;
                         continue;                       /* next lcv */                          UVM_UNLOCK_AND_WAIT(ptmp, &uobj->vmobjlock, 0,
                                               "uvn_fp2",0);
                 /*                          simple_lock(&uobj->vmobjlock);
                  * we have a "fake/busy/clean" page that we just allocated.  do                          continue;
                  * I/O to fill it with valid data.  note that object must be                  }
                  * locked going into uvn_io, but will be unlocked afterwards.  
                  */                  /* skip PG_RDONLY pages if requested */
                   if ((flags & UFP_NORDONLY) && (ptmp->flags & PG_RDONLY)) {
                 result = uvn_io((struct uvm_vnode *) uobj, &ptmp, 1,                          UVMHIST_LOG(ubchist, "nordonly",0,0,0,0);
                     PGO_SYNCIO, UIO_READ);                          return 0;
                   }
                 /*                  /* BUSY the page and we're done. */
                  * I/O done.   object is unlocked (by uvn_io).   because we used                  ptmp->flags |= PG_BUSY;
                  * syncio the result can not be PEND or AGAIN.   we must relock                  UVM_PAGE_OWN(ptmp, "uvn_findpage");
                  * and check for errors.                  UVMHIST_LOG(ubchist, "found",0,0,0,0);
                  */                  break;
           }
                 /* lock object.   check for errors.   */          *pps = ptmp;
                 simple_lock(&uobj->vmobjlock);          return 1;
                 if (result != VM_PAGER_OK) {  
                         if (ptmp->flags & PG_WANTED)  
                                 /* object lock still held */  
                                 thread_wakeup(ptmp);  
   
                         ptmp->flags &= ~(PG_WANTED|PG_BUSY);  
                         UVM_PAGE_OWN(ptmp, NULL);  
                         uvm_lock_pageq();  
                         uvm_pagefree(ptmp);  
                         uvm_unlock_pageq();  
                         simple_unlock(&uobj->vmobjlock);  
                         return(result);  
                 }  
   
                 /*  
                  * we got the page!   clear the fake flag (indicates valid  
                  * data now in page) and plug into our result array.   note  
                  * that page is still busy.  
                  *  
                  * it is the callers job to:  
                  * => check if the page is released  
                  * => unbusy the page  
                  * => activate the page  
                  */  
   
                 ptmp->flags &= ~PG_FAKE;                /* data is valid ... */  
                 pmap_clear_modify(PMAP_PGARG(ptmp));    /* ... and clean */  
                 pps[lcv] = ptmp;  
   
         }       /* lcv loop */  
   
         /*  
          * finally, unlock object and return.  
          */  
   
         simple_unlock(&uobj->vmobjlock);  
         return (VM_PAGER_OK);  
 }  }
   
 /*  /*
Line 1582  uvn_asyncget(uobj, offset, npages)
Line 1192  uvn_asyncget(uobj, offset, npages)
 }  }
   
 /*  /*
  * uvn_io: do I/O to a vnode  
  *  
  * => prefer map unlocked (not required)  
  * => object must be locked!   we will _unlock_ it before starting I/O.  
  * => flags: PGO_SYNCIO -- use sync. I/O  
  * => XXX: currently we use VOP_READ/VOP_WRITE which are only sync.  
  *      [thus we never do async i/o!  see iodone comment]  
  */  
   
 static int  
 uvn_io(uvn, pps, npages, flags, rw)  
         struct uvm_vnode *uvn;  
         vm_page_t *pps;  
         int npages, flags, rw;  
 {  
         struct vnode *vn;  
         struct uio uio;  
         struct iovec iov;  
         vaddr_t kva, file_offset;  
         int waitf, result, got, wanted;  
         UVMHIST_FUNC("uvn_io"); UVMHIST_CALLED(maphist);  
   
         UVMHIST_LOG(maphist, "rw=%d", rw,0,0,0);  
   
         /*  
          * init values  
          */  
   
         waitf = (flags & PGO_SYNCIO) ? M_WAITOK : M_NOWAIT;  
         vn = (struct vnode *) uvn;  
         file_offset = pps[0]->offset;  
   
         /*  
          * check for sync'ing I/O.  
          */  
   
         while (uvn->u_flags & UVM_VNODE_IOSYNC) {  
                 if (waitf == M_NOWAIT) {  
                         simple_unlock(&uvn->u_obj.vmobjlock);  
                         UVMHIST_LOG(maphist,"<- try again (iosync)",0,0,0,0);  
                         return(VM_PAGER_AGAIN);  
                 }  
                 uvn->u_flags |= UVM_VNODE_IOSYNCWANTED;  
                 UVM_UNLOCK_AND_WAIT(&uvn->u_flags, &uvn->u_obj.vmobjlock,  
                         FALSE, "uvn_iosync",0);  
                 simple_lock(&uvn->u_obj.vmobjlock);  
         }  
   
         /*  
          * check size  
          */  
   
         if (file_offset >= uvn->u_size) {  
                         simple_unlock(&uvn->u_obj.vmobjlock);  
                         UVMHIST_LOG(maphist,"<- BAD (size check)",0,0,0,0);  
 #ifdef DIAGNOSTIC  
                         printf("uvn_io: note: size check fired\n");  
 #endif  
                         return(VM_PAGER_BAD);  
         }  
   
         /*  
          * first try and map the pages in (without waiting)  
          */  
   
         kva = uvm_pagermapin(pps, npages, NULL, M_NOWAIT);  
         if (kva == NULL && waitf == M_NOWAIT) {  
                 simple_unlock(&uvn->u_obj.vmobjlock);  
                 UVMHIST_LOG(maphist,"<- mapin failed (try again)",0,0,0,0);  
                 return(VM_PAGER_AGAIN);  
         }  
   
         /*  
          * ok, now bump u_nio up.   at this point we are done with uvn  
          * and can unlock it.   if we still don't have a kva, try again  
          * (this time with sleep ok).  
          */  
   
         uvn->u_nio++;                   /* we have an I/O in progress! */  
         simple_unlock(&uvn->u_obj.vmobjlock);  
         /* NOTE: object now unlocked */  
         if (kva == NULL) {  
                 kva = uvm_pagermapin(pps, npages, NULL, M_WAITOK);  
         }  
   
         /*  
          * ok, mapped in.  our pages are PG_BUSY so they are not going to  
          * get touched (so we can look at "offset" without having to lock  
          * the object).  set up for I/O.  
          */  
   
         /*  
          * fill out uio/iov  
          */  
   
         iov.iov_base = (caddr_t) kva;  
         wanted = npages << PAGE_SHIFT;  
         if (file_offset + wanted > uvn->u_size)  
                 wanted = uvn->u_size - file_offset;     /* XXX: needed? */  
         iov.iov_len = wanted;  
         uio.uio_iov = &iov;  
         uio.uio_iovcnt = 1;  
         uio.uio_offset = file_offset;  
         uio.uio_segflg = UIO_SYSSPACE;  
         uio.uio_rw = rw;  
         uio.uio_resid = wanted;  
         uio.uio_procp = NULL;  
   
         /*  
          * do the I/O!  (XXX: curproc?)  
          */  
   
         UVMHIST_LOG(maphist, "calling VOP",0,0,0,0);  
   
         /*  
          * This process may already have this vnode locked, if we faulted in  
          * copyin() or copyout() on a region backed by this vnode  
          * while doing I/O to the vnode.  If this is the case, don't  
          * panic.. instead, return the error to the user.  
          *  
          * XXX this is a stopgap to prevent a panic.  
          * Ideally, this kind of operation *should* work.  
          */  
         result = 0;  
         if ((uvn->u_flags & UVM_VNODE_VNISLOCKED) == 0)  
                 result = vn_lock(vn, LK_EXCLUSIVE | LK_RETRY | LK_RECURSEFAIL);  
   
         if (result == 0) {  
                 /* NOTE: vnode now locked! */  
   
                 if (rw == UIO_READ)  
                         result = VOP_READ(vn, &uio, 0, curproc->p_ucred);  
                 else  
                         result = VOP_WRITE(vn, &uio, 0, curproc->p_ucred);  
   
                 if ((uvn->u_flags & UVM_VNODE_VNISLOCKED) == 0)  
                         VOP_UNLOCK(vn, 0);  
         }  
   
         /* NOTE: vnode now unlocked (unless vnislocked) */  
   
         UVMHIST_LOG(maphist, "done calling VOP",0,0,0,0);  
   
         /*  
          * result == unix style errno (0 == OK!)  
          *  
          * zero out rest of buffer (if needed)  
          */  
   
         if (result == 0) {  
                 got = wanted - uio.uio_resid;  
   
                 if (wanted && got == 0) {  
                         result = EIO;           /* XXX: error? */  
                 } else if (got < PAGE_SIZE * npages && rw == UIO_READ) {  
                         memset((void *) (kva + got), 0,  
                                (npages << PAGE_SHIFT) - got);  
                 }  
         }  
   
         /*  
          * now remove pager mapping  
          */  
         uvm_pagermapout(kva, npages);  
   
         /*  
          * now clean up the object (i.e. drop I/O count)  
          */  
   
         simple_lock(&uvn->u_obj.vmobjlock);  
         /* NOTE: object now locked! */  
   
         uvn->u_nio--;                   /* I/O DONE! */  
         if ((uvn->u_flags & UVM_VNODE_IOSYNC) != 0 && uvn->u_nio == 0) {  
                 wakeup(&uvn->u_nio);  
         }  
         simple_unlock(&uvn->u_obj.vmobjlock);  
         /* NOTE: object now unlocked! */  
   
         /*  
          * done!  
          */  
   
         UVMHIST_LOG(maphist, "<- done (result %d)", result,0,0,0);  
         if (result == 0)  
                 return(VM_PAGER_OK);  
         else  
                 return(VM_PAGER_ERROR);  
 }  
   
 /*  
  * uvm_vnp_uncache: disable "persisting" in a vnode... when last reference  
  * is gone we will kill the object (flushing dirty pages back to the vnode  
  * if needed).  
  *  
  * => returns TRUE if there was no uvm_object attached or if there was  
  *      one and we killed it [i.e. if there is no active uvn]  
  * => called with the vnode VOP_LOCK'd [we will unlock it for I/O, if  
  *      needed]  
  *  
  * => XXX: given that we now kill uvn's when a vnode is recycled (without  
  *      having to hold a reference on the vnode) and given a working  
  *      uvm_vnp_sync(), how does that effect the need for this function?  
  *      [XXXCDC: seems like it can die?]  
  *  
  * => XXX: this function should DIE once we merge the VM and buffer  
  *      cache.  
  *  
  * research shows that this is called in the following places:  
  * ext2fs_truncate, ffs_truncate, detrunc[msdosfs]: called when vnode  
  *      changes sizes  
  * ext2fs_write, WRITE [ufs_readwrite], msdosfs_write: called when we  
  *      are written to  
  * ex2fs_chmod, ufs_chmod: called if VTEXT vnode and the sticky bit  
  *      is off  
  * ffs_realloccg: when we can't extend the current block and have  
  *      to allocate a new one we call this [XXX: why?]  
  * nfsrv_rename, rename_files: called when the target filename is there  
  *      and we want to remove it  
  * nfsrv_remove, sys_unlink: called on file we are removing  
  * nfsrv_access: if VTEXT and we want WRITE access and we don't uncache  
  *      then return "text busy"  
  * nfs_open: seems to uncache any file opened with nfs  
  * vn_writechk: if VTEXT vnode and can't uncache return "text busy"  
  */  
   
 boolean_t  
 uvm_vnp_uncache(vp)  
         struct vnode *vp;  
 {  
         struct uvm_vnode *uvn = &vp->v_uvm;  
   
         /*  
          * lock uvn part of the vnode and check to see if we need to do anything  
          */  
   
         simple_lock(&uvn->u_obj.vmobjlock);  
         if ((uvn->u_flags & UVM_VNODE_VALID) == 0 ||  
                         (uvn->u_flags & UVM_VNODE_BLOCKED) != 0) {  
                 simple_unlock(&uvn->u_obj.vmobjlock);  
                 return(TRUE);  
         }  
   
         /*  
          * we have a valid, non-blocked uvn.   clear persist flag.  
          * if uvn is currently active we can return now.  
          */  
   
         uvn->u_flags &= ~UVM_VNODE_CANPERSIST;  
         if (uvn->u_obj.uo_refs) {  
                 simple_unlock(&uvn->u_obj.vmobjlock);  
                 return(FALSE);  
         }  
   
         /*  
          * uvn is currently persisting!   we have to gain a reference to  
          * it so that we can call uvn_detach to kill the uvn.  
          */  
   
         VREF(vp);                       /* seems ok, even with VOP_LOCK */  
         uvn->u_obj.uo_refs++;           /* value is now 1 */  
         simple_unlock(&uvn->u_obj.vmobjlock);  
   
   
 #ifdef DEBUG  
         /*  
          * carry over sanity check from old vnode pager: the vnode should  
          * be VOP_LOCK'd, and we confirm it here.  
          */  
         if (!VOP_ISLOCKED(vp)) {  
                 boolean_t is_ok_anyway = FALSE;  
 #ifdef NFS  
                 extern int (**nfsv2_vnodeop_p) __P((void *));  
                 extern int (**spec_nfsv2nodeop_p) __P((void *));  
                 extern int (**fifo_nfsv2nodeop_p) __P((void *));  
   
                 /* vnode is NOT VOP_LOCKed: some vnode types _never_ lock */  
                 if (vp->v_op == nfsv2_vnodeop_p ||  
                     vp->v_op == spec_nfsv2nodeop_p) {  
                         is_ok_anyway = TRUE;  
                 }  
                 if (vp->v_op == fifo_nfsv2nodeop_p) {  
                         is_ok_anyway = TRUE;  
                 }  
 #endif  /* NFS */  
                 if (!is_ok_anyway)  
                         panic("uvm_vnp_uncache: vnode not locked!");  
         }  
 #endif  /* DEBUG */  
   
         /*  
          * now drop our reference to the vnode.   if we have the sole  
          * reference to the vnode then this will cause it to die [as we  
          * just cleared the persist flag].   we have to unlock the vnode  
          * while we are doing this as it may trigger I/O.  
          *  
          * XXX: it might be possible for uvn to get reclaimed while we are  
          * unlocked causing us to return TRUE when we should not.   we ignore  
          * this as a false-positive return value doesn't hurt us.  
          */  
         VOP_UNLOCK(vp, 0);  
         uvn_detach(&uvn->u_obj);  
         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);  
   
         /*  
          * and return...  
          */  
   
         return(TRUE);  
 }  
   
 /*  
  * uvm_vnp_setsize: grow or shrink a vnode uvn   * uvm_vnp_setsize: grow or shrink a vnode uvn
  *   *
  * grow   => just update size value   * grow   => just update size value
Line 1922  uvm_vnp_setsize(vp, newsize)
Line 1220  uvm_vnp_setsize(vp, newsize)
          * lock uvn and check for valid object, and if valid: do it!           * lock uvn and check for valid object, and if valid: do it!
          */           */
         simple_lock(&uvn->u_obj.vmobjlock);          simple_lock(&uvn->u_obj.vmobjlock);
         if (uvn->u_flags & UVM_VNODE_VALID) {  
   
                 /*          /*
                  * make sure that the newsize fits within a vaddr_t           * make sure that the newsize fits within a vaddr_t
                  * XXX: need to revise addressing data types           * XXX: need to revise addressing data types
                  */           */
   
                 if (newsize > (vaddr_t) -PAGE_SIZE) {          if (newsize > (vaddr_t) -PAGE_SIZE) {
 #ifdef DEBUG  #ifdef DEBUG
                         printf("uvm_vnp_setsize: vn %p size truncated "                  printf("uvm_vnp_setsize: vn %p size truncated "
                                "%qx->%lx\n", vp, (long long)newsize,                         "%qx->%lx\n", vp, (long long)newsize,
                                (vaddr_t)-PAGE_SIZE);                         (vaddr_t)-PAGE_SIZE);
 #endif  #endif
                         newsize = (vaddr_t)-PAGE_SIZE;                  newsize = (vaddr_t)-PAGE_SIZE;
                 }  
   
                 /*  
                  * now check if the size has changed: if we shrink we had better  
                  * toss some pages...  
                  */  
   
                 if (uvn->u_size > newsize) {  
                         (void)uvn_flush(&uvn->u_obj, (vaddr_t) newsize,  
                             uvn->u_size, PGO_FREE);  
                 }  
                 uvn->u_size = (vaddr_t)newsize;  
         }          }
         simple_unlock(&uvn->u_obj.vmobjlock);  
   
         /*          /*
          * done           * now check if the size has changed: if we shrink we had better
            * toss some pages...
          */           */
         return;  
           if (uvn->u_size > newsize && uvn->u_size != VSIZENOTSET) {
                   (void) uvn_flush(&uvn->u_obj, (vaddr_t)newsize,
                                    uvn->u_size, PGO_FREE);
           }
           uvn->u_size = (vaddr_t)newsize;
           simple_unlock(&uvn->u_obj.vmobjlock);
 }  }
   
 /*  /*
Line 1990  uvm_vnp_sync(mp)
Line 1281  uvm_vnp_sync(mp)
          */           */
         SIMPLEQ_INIT(&uvn_sync_q);          SIMPLEQ_INIT(&uvn_sync_q);
         simple_lock(&uvn_wl_lock);          simple_lock(&uvn_wl_lock);
         for (uvn = uvn_wlist.lh_first ; uvn != NULL ;          for (uvn = LIST_FIRST(&uvn_wlist); uvn != NULL;
             uvn = uvn->u_wlist.le_next) {               uvn = LIST_NEXT(uvn, u_wlist)) {
   
                 vp = (struct vnode *) uvn;                  vp = (struct vnode *) uvn;
                 if (mp && vp->v_mount != mp)                  if (mp && vp->v_mount != mp)
Line 2000  uvm_vnp_sync(mp)
Line 1291  uvm_vnp_sync(mp)
                 /* attempt to gain reference */                  /* attempt to gain reference */
                 while ((got_lock = simple_lock_try(&uvn->u_obj.vmobjlock)) ==                  while ((got_lock = simple_lock_try(&uvn->u_obj.vmobjlock)) ==
                                                                 FALSE &&                                                                  FALSE &&
                                 (uvn->u_flags & UVM_VNODE_BLOCKED) == 0)                                  (uvn->u_flags & VXLOCK) == 0)
                         /* spin */ ;                          /* spin */ ;
   
                 /*                  /*
Line 2017  uvm_vnp_sync(mp)
Line 1308  uvm_vnp_sync(mp)
                  * note that uvn must already be valid because we found it on                   * note that uvn must already be valid because we found it on
                  * the wlist (this also means it can't be ALOCK'd).                   * the wlist (this also means it can't be ALOCK'd).
                  */                   */
                 if (!got_lock || (uvn->u_flags & UVM_VNODE_BLOCKED) != 0) {                  if (!got_lock || (uvn->u_flags & VXLOCK) != 0) {
                         if (got_lock)                          if (got_lock)
                                 simple_unlock(&uvn->u_obj.vmobjlock);                                  simple_unlock(&uvn->u_obj.vmobjlock);
                         continue;               /* skip it */                          continue;               /* skip it */
                 }                  }
   
                 /*                  vget(vp, LK_INTERLOCK);
                  * gain reference.   watch out for persisting uvns (need to  
                  * regain vnode REF).  
                  */  
                 if (uvn->u_obj.uo_refs == 0)  
                         VREF(vp);  
                 uvn->u_obj.uo_refs++;  
                 simple_unlock(&uvn->u_obj.vmobjlock);  
   
                 /*                  /*
                  * got it!                   * got it!
Line 2047  uvm_vnp_sync(mp)
Line 1331  uvm_vnp_sync(mp)
   
         for (uvn = uvn_sync_q.sqh_first ; uvn ; uvn = uvn->u_syncq.sqe_next) {          for (uvn = uvn_sync_q.sqh_first ; uvn ; uvn = uvn->u_syncq.sqe_next) {
                 simple_lock(&uvn->u_obj.vmobjlock);                  simple_lock(&uvn->u_obj.vmobjlock);
 #ifdef DIAGNOSTIC  
                 if (uvn->u_flags & UVM_VNODE_DYING) {  
                         printf("uvm_vnp_sync: dying vnode on sync list\n");  
                 }  
 #endif  
                 uvn_flush(&uvn->u_obj, 0, 0,                  uvn_flush(&uvn->u_obj, 0, 0,
                     PGO_CLEANIT|PGO_ALLPAGES|PGO_DOACTCLUST);                            PGO_CLEANIT|PGO_ALLPAGES|PGO_DOACTCLUST);
   
                 /*                  /*
                  * if we have the only reference and we just cleaned the uvn,                   * if we have the only reference and we just cleaned the uvn,
                  * then we can pull it out of the UVM_VNODE_WRITEABLE state                   * then we can pull it out of the VDIRTY state
                  * thus allowing us to avoid thinking about flushing it again                   * thus allowing us to avoid thinking about flushing it again
                  * on later sync ops.                   * on later sync ops.
                  */                   */
                 if (uvn->u_obj.uo_refs == 1 &&                  if (uvn->u_obj.uo_refs == 1 && (uvn->u_flags & VDIRTY)) {
                     (uvn->u_flags & UVM_VNODE_WRITEABLE)) {                          simple_lock(&uvn_wl_lock);
                         LIST_REMOVE(uvn, u_wlist);                          LIST_REMOVE(uvn, u_wlist);
                         uvn->u_flags &= ~UVM_VNODE_WRITEABLE;                          uvn->u_flags &= ~VDIRTY;
                           simple_unlock(&uvn_wl_lock);
                 }                  }
   
                 simple_unlock(&uvn->u_obj.vmobjlock);                  simple_unlock(&uvn->u_obj.vmobjlock);
Line 2078  uvm_vnp_sync(mp)
Line 1358  uvm_vnp_sync(mp)
          */           */
         lockmgr(&uvn_sync_lock, LK_RELEASE, (void *)0);          lockmgr(&uvn_sync_lock, LK_RELEASE, (void *)0);
 }  }
   
   
   /*
    * uvm_vnp_zerorange:  set a range of bytes in a file to zero.
    */
   
   void
   uvm_vnp_zerorange(vp, off, len)
           struct vnode *vp;
           off_t off;
           size_t len;
   {
           void *win;
   
           /*
            * XXX invent kzero() and use it
            */
   
           while (len) {
                   vsize_t bytelen = len;
   
                   win = ubc_alloc(&vp->v_uvm.u_obj, off, &bytelen, UBC_WRITE);
                   memset(win, 0, bytelen);
                   ubc_release(win, 0);
   
                   off += bytelen;
                   len -= bytelen;
           }
   }
   
   /*
    * uvn_doasyncget: start one readahead i/o.
    */
   
   static void
   uvn_doasyncget(pgs, bytes, blkno)
           struct vm_page **pgs;
           size_t bytes;
           daddr_t blkno;
   {
           struct buf *bp;
           struct vnode *vp = (struct vnode *)pgs[0]->uobject;
           int pages = roundup(bytes, PAGE_SIZE) >> PAGE_SHIFT;
           int s;
           UVMHIST_FUNC("uvn_doasyncget"); UVMHIST_CALLED(ubchist);
   
           UVMHIST_LOG(ubchist, "vp %p offset 0x%x bytes 0x%x blkno 0x%x",
                       vp, (int)pgs[0]->offset, (int)bytes, (int)blkno);
   
           s = splbio();
           bp = pool_get(&bufpool, PR_WAITOK);
           splx(s);
           bp->b_data = (void *)uvm_pagermapin(pgs, pages, M_WAITOK);
           bp->b_flags = B_BUSY|B_READ|B_CALL|B_ASYNC;
           bp->b_iodone = uvm_aio_biodone;
           bp->b_lblkno = 0;
           bp->b_blkno = blkno;
           bp->b_bufsize = pages << PAGE_SHIFT;
           bp->b_bcount = bytes;
           bp->b_vp = vp;
           UVMHIST_LOG(ubchist, "bp %p", bp, 0,0,0);
   
           VOP_STRATEGY(bp);
   }
   
   #define MAXRAPAGES 16
   
   /*
    * asynchronously create pages for a vnode and read their data.
    */
   
   void
   uvm_vnp_asyncget(vp, off, len)
           struct vnode *vp;
           off_t off;
           size_t len;
   {
           off_t filesize = vp->v_uvm.u_size;
           struct vm_page *pgs[MAXRAPAGES];
           struct uvm_object *uobj = &vp->v_uvm.u_obj;
           daddr_t lbn, blkno;
           int bshift = vp->v_mount->mnt_fs_bshift;
           int dev_bshift = vp->v_mount->mnt_dev_bshift;
           int i, npages, npgs, startidx, run, bytes, startpage, endpage;
           int count;
           UVMHIST_FUNC("uvn_asyncget"); UVMHIST_CALLED(ubchist);
   
           if (off != trunc_page(off)) {
                   panic("off 0x%x not page-aligned", (int)off);
           }
   
           UVMHIST_LOG(ubchist, "asyncget off 0x%x len 0x%x",
                       (int)off, (int)len,0,0);
   
           count = round_page(len) >> PAGE_SHIFT;
           while (count > 0) {
                   if (off >= filesize) {
                           return;
                   }
   
                   lbn = off >> bshift;
                   if (VOP_BMAP(vp, lbn, NULL, &blkno, &run) != 0) {
                           return;
                   }
   
                   UVMHIST_LOG(ubchist, "bmap lbn 0x%x bn 0x%x",
                               (int)lbn, (int)blkno,0,0);
   
                   /* don't do readahead past file holes... */
                   if (blkno == (daddr_t)-1) {
                           return;
                   }
   
                   startpage = off >> PAGE_SHIFT;
                   endpage = min(roundup(off + 1 + (run << bshift), 1 << bshift),
                                 round_page(filesize)) >> PAGE_SHIFT;
                   npages = min(endpage - startpage, min(count, MAXRAPAGES));
   
                   UVMHIST_LOG(ubchist, "off 0x%x run 0x%x "
                               "startpage %d endpage %d",
                               (int)off, run, startpage, endpage);
                   UVMHIST_LOG(ubchist, "runend 0x%x fileend 0x%x sum 0x%x",
                               (int)roundup(off + 1 + (run << bshift),
                                            (1 << bshift)),
                               (int)round_page(filesize),
                               (int)(off + 1 + (run << bshift)), 0);
   
                   if (npages == 0) {
                           return;
                   }
   
                   memset(pgs, 0, npages * sizeof(pgs[0]));
   
                   simple_lock(&uobj->vmobjlock);
                   npgs = npages;
                   uvn_findpages(uobj, off, &npgs, pgs, UFP_NOWAIT | UFP_NOCACHE);
                   simple_unlock(&uobj->vmobjlock);
   
                   blkno += (off - (lbn << bshift)) >> dev_bshift;
   
                   /*
                    * activate any pages we just allocated.
                    */
   
                   for (i = 0; i < npages; i++) {
                           if (pgs[i] == NULL) {
                                   continue;
                           }
                           uvm_pageactivate(pgs[i]);
                   }
   
                   /*
                    * start i/os on the pages.
                    */
   
                   for (i = 0; i < npages; i++) {
                           for (startidx = i; i < npages; i++) {
                                   if (pgs[i] == NULL) {
                                           break;
                                   }
                           }
                           if (i > startidx) {
                                   bytes = min((i - startidx) << PAGE_SHIFT,
                                               filesize - pgs[startidx]->offset);
                                   bytes = roundup(bytes, 1 << dev_bshift);
   
                                   UVMHIST_LOG(ubchist, "bytes i %d startidx %d "
                                               "filesize 0x%x pgoff 0x%x",
                                               i, startidx, (int)filesize,
                                               (int)pgs[startidx]->offset);
   
                                   uvn_doasyncget(&pgs[startidx], bytes,
                                                  blkno + startidx *
                                                  (PAGE_SIZE >> dev_bshift));
                           }
                   }
   
                   off += npages << PAGE_SHIFT;
                   count -= npages;
   
                   /* XXX for now, don't loop */
                   return;
           }
   }

Legend:
Removed from v.1.22.2.1  
changed lines
  Added in v.1.22.2.1.2.4

CVSweb <webmaster@jp.NetBSD.org>