[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.17 and 1.17.2.6

version 1.17, 1998/11/04 06:21:40 version 1.17.2.6, 1999/04/30 04:29:15
Line 50 
Line 50 
  */   */
   
 #include "fs_nfs.h"  #include "fs_nfs.h"
   #include "opt_uvm.h"
 #include "opt_uvmhist.h"  #include "opt_uvmhist.h"
   
 /*  /*
Line 58 
Line 59 
   
 #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 94  lock_data_t uvn_sync_lock;   /* locks sy
Line 96  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 **));
   
 /*  /*
  * master pager structure   * master pager structure
Line 180  uvn_attach(arg, accessprot)
Line 182  uvn_attach(arg, accessprot)
         struct vattr vattr;          struct vattr vattr;
         int oldflags, result;          int oldflags, 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 201  uvn_attach(arg, accessprot)
Line 203  uvn_attach(arg, accessprot)
         }          }
   
         /*          /*
          * if we're maping 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);
         }          }
   
         /*          oldflags = 0;
          * now we have lock and uvn must not be in a blocked state.  
          * first check to see if it is already active, in which case  
          * we can bump the reference count, check to see if we need to  
          * add it to the writeable list, and then return.  
          */  
         if (uvn->u_flags & UVM_VNODE_VALID) {   /* already active? */  
   
                 /* regain VREF if we were persisting */  
                 if (uvn->u_obj.uo_refs == 0) {  
                         VREF(vp);  
                         UVMHIST_LOG(maphist," VREF (reclaim persisting vnode)",  
                             0,0,0,0);  
                 }  
                 uvn->u_obj.uo_refs++;           /* bump uvn ref! */  
   
                 /* check for new writeable uvn */  #ifdef DIAGNOSTIC
                 if ((accessprot & VM_PROT_WRITE) != 0 &&          if (vp->v_type != VREG) {
                     (uvn->u_flags & UVM_VNODE_WRITEABLE) == 0) {                  panic("uvn_attach: vp %p not VREG", vp);
                         simple_lock(&uvn_wl_lock);          }
                         LIST_INSERT_HEAD(&uvn_wlist, uvn, u_wlist);  #endif
                         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.  
          */           */
           if (uvn->u_size == VSIZENOTSET) {
   
         uvn->u_flags = UVM_VNODE_ALOCK;          uvn->u_flags = UVM_VNODE_ALOCK;
         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 276  uvn_attach(arg, accessprot)
Line 250  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
          */           */
 if (vp->v_type == VBLK) printf("used_vnode_size = %qu\n", used_vnode_size);  
         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 301  if (vp->v_type == VBLK) printf("used_vno
Line 263  if (vp->v_type == VBLK) printf("used_vno
                 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 & UVM_VNODE_WANTED)
         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) {  
           /* check for new writeable uvn */
           if ((accessprot & VM_PROT_WRITE) != 0 &&
               (uvn->u_flags & UVM_VNODE_WRITEABLE) == 0) {
                 simple_lock(&uvn_wl_lock);                  simple_lock(&uvn_wl_lock);
                 LIST_INSERT_HEAD(&uvn_wlist, uvn, u_wlist);                  LIST_INSERT_HEAD(&uvn_wlist, uvn, u_wlist);
                   uvn->u_flags |= UVM_VNODE_WRITEABLE;
                 simple_unlock(&uvn_wl_lock);                  simple_unlock(&uvn_wl_lock);
                 uvn->u_flags |= UVM_VNODE_WRITEABLE;    /* we are on wlist! */                  /* we are now 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 352  static void
Line 313  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 384  static void
Line 331  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);
   
         simple_lock(&uobj->vmobjlock);          vrele((struct vnode *)uobj);
   
         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 540  uvm_vnp_terminate(vp)
Line 369  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;  
         UVMHIST_FUNC("uvm_vnp_terminate"); UVMHIST_CALLED(maphist);  
   
         /*          if (uvn->u_flags & UVM_VNODE_WRITEABLE) {
          * lock object and check if it is valid                  simple_lock(&uvn_wl_lock);
          */                  LIST_REMOVE(uvn, u_wlist);
         simple_lock(&uvn->u_obj.vmobjlock);                  uvn->u_flags &= ~(UVM_VNODE_WRITEABLE);
         UVMHIST_LOG(maphist, "  vp=0x%x, ref=%d, flag=0x%x", vp,                  simple_unlock(&uvn_wl_lock);
             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 710  uvn_releasepg(pg, nextpgp)
Line 417  uvn_releasepg(pg, nextpgp)
         if (!nextpgp)          if (!nextpgp)
                 uvm_unlock_pageq();                  uvm_unlock_pageq();
   
   #ifdef UBC
           /* 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 736  uvn_releasepg(pg, nextpgp)
Line 447  uvn_releasepg(pg, nextpgp)
                         return (FALSE);                          return (FALSE);
                 }                  }
         }          }
   #endif
         return (TRUE);          return (TRUE);
 }  }
   
Line 840  uvn_flush(uobj, start, stop, flags)
Line 552  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 npages, result, lcv;          int npages, result, lcv;
Line 848  uvn_flush(uobj, start, stop, flags)
Line 561  uvn_flush(uobj, start, stop, flags)
         u_short pp_version;          u_short pp_version;
         UVMHIST_FUNC("uvn_flush"); UVMHIST_CALLED(maphist);          UVMHIST_FUNC("uvn_flush"); UVMHIST_CALLED(maphist);
   
   #ifdef UBC
           if (uvn->u_size == VSIZENOTSET) {
                   void vp_name(void *);
   
   #ifdef DEBUG
                   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);
                   vp_name(uvn);
   #endif
                   flags |= PGO_ALLPAGES;
           }
   #if 0
           /* XXX unfortunately this is legitimate */
           if ((flags & PGO_FREE) && uobj->uo_refs) {
                   printf("uvn_flush: PGO_FREE on ref'd vp %p\n", uobj);
                   Debugger();
           }
   #endif
   #endif
   
         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 857  uvn_flush(uobj, start, stop, flags)
Line 593  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;
   #ifdef UBC
                   stop = -1;
   #else
                 stop = round_page(uvn->u_size);                  stop = round_page(uvn->u_size);
   #endif
                 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 size 0x%x\n", uvn, (int)start, (int)stop, (int)round_page(uvn->u_size));
                             "flush (fixed)\n");                  }
   
                 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 888  uvn_flush(uobj, start, stop, flags)
Line 628  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 912  uvn_flush(uobj, start, stop, flags)
Line 654  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 933  uvn_flush(uobj, start, stop, flags)
Line 675  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 1041  ReTry:
Line 783  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 1165  ReTry:
Line 907  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 1207  ReTry:
Line 949  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 1236  ReTry:
Line 978  ReTry:
         if (need_iosync) {          if (need_iosync) {
   
                 UVMHIST_LOG(maphist,"  <<DOING IOSYNC>>",0,0,0,0);                  UVMHIST_LOG(maphist,"  <<DOING IOSYNC>>",0,0,0,0);
   #ifdef UBC
                   /*
                    * XXX this doesn't use the new two-flag scheme,
                    * but to use that, all i/o initiators will have to change.
                    */
   
                   while (vp->v_numoutput != 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);
                   }
   #else
                 while (uvn->u_nio != 0) {                  while (uvn->u_nio != 0) {
                         uvn->u_flags |= UVM_VNODE_IOSYNC;                          uvn->u_flags |= UVM_VNODE_IOSYNC;
                         UVM_UNLOCK_AND_WAIT(&uvn->u_nio, &uvn->u_obj.vmobjlock,                          UVM_UNLOCK_AND_WAIT(&uvn->u_nio, &uvn->u_obj.vmobjlock,
Line 1245  ReTry:
Line 1001  ReTry:
                 if (uvn->u_flags & UVM_VNODE_IOSYNCWANTED)                  if (uvn->u_flags & UVM_VNODE_IOSYNCWANTED)
                         wakeup(&uvn->u_flags);                          wakeup(&uvn->u_flags);
                 uvn->u_flags &= ~(UVM_VNODE_IOSYNC|UVM_VNODE_IOSYNCWANTED);                  uvn->u_flags &= ~(UVM_VNODE_IOSYNC|UVM_VNODE_IOSYNCWANTED);
   #endif
         }          }
   
         /* return, with object locked! */          /* return, with object locked! */
Line 1269  uvn_cluster(uobj, offset, loffset, hoffs
Line 1026  uvn_cluster(uobj, offset, loffset, hoffs
         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;
           UVMHIST_FUNC("uvn_cluster"); UVMHIST_CALLED(ubchist);
   
         *loffset = offset;          *loffset = offset;
   
         if (*loffset >= uvn->u_size)          if (*loffset >= uvn->u_size)
                 panic("uvn_cluster: offset out of range");  #ifdef UBC
           {
                   /* XXX nfs writes cause trouble with this */
                   *loffset = *hoffset = offset;
   UVMHIST_LOG(ubchist, "uvn_cluster: offset out of range: vp %p loffset 0x%x",
                         uobj, (int)*loffset, 0,0);
   Debugger();
                   return;
           }
   #else
                   panic("uvn_cluster: offset out of range: vp %p loffset 0x%x",
                         uobj, (int) *loffset);
   #endif
   
         /*          /*
          * XXX: old pager claims we could use VOP_BMAP to get maxcontig value.           * XXX: old pager claims we could use VOP_BMAP to get maxcontig value.
Line 1301  uvn_put(uobj, pps, npages, flags)
Line 1072  uvn_put(uobj, pps, npages, flags)
         struct vm_page **pps;          struct vm_page **pps;
         int npages, flags;          int npages, flags;
 {  {
         int retval;          int retval, sync;
   
           sync = (flags & PGO_SYNCIO) ? 1 : 0;
   
         /* note: object locked */          /* note: object locked */
         retval = uvn_io((struct uvm_vnode*)uobj, pps, npages, flags, UIO_WRITE);          simple_lock_assert(&uobj->vmobjlock, SLOCK_LOCKED);
   
           /* XXX why would the VOP need it locked? */
           /* currently, just to increment vp->v_numoutput (aka uvn->u_nio) */
           simple_unlock(&uobj->vmobjlock);
           retval = VOP_PUTPAGES((struct vnode *)uobj, pps, npages, sync, &retval);
         /* note: object unlocked */          /* note: object unlocked */
           simple_lock_assert(&uobj->vmobjlock, SLOCK_UNLOCKED);
   
         return(retval);          return(retval);
 }  }
Line 1331  uvn_get(uobj, offset, pps, npagesp, cent
Line 1110  uvn_get(uobj, offset, pps, npagesp, cent
         int centeridx, advice, flags;          int centeridx, advice, flags;
         vm_prot_t access_type;          vm_prot_t access_type;
 {  {
         vaddr_t current_offset;          struct vnode *vp = (struct vnode *)uobj;
         struct vm_page *ptmp;          int error;
         int lcv, result, gotpages;  
         boolean_t done;  
         UVMHIST_FUNC("uvn_get"); UVMHIST_CALLED(maphist);  
         UVMHIST_LOG(maphist, "flags=%d", flags,0,0,0);  
   
         /*  
          * step 1: handled the case where fault data structures are locked.  
          */  
   
         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 */          simple_lock_assert(&uobj->vmobjlock, SLOCK_LOCKED);
                         if (pps[lcv] == PGO_DONTCARE)          error = VOP_GETPAGES(vp, offset, pps, npagesp, centeridx,
                                 continue;                               access_type, advice, flags);
           simple_lock_assert(&uobj->vmobjlock, flags & PGO_LOCKED ?
                         /* lookup page */                             SLOCK_LOCKED : SLOCK_UNLOCKED);
                         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 */          return error ? VM_PAGER_ERROR : VM_PAGER_OK;
   }
   
                 /*  /*
                  * 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 ;  static int
                          lcv < *npagesp ; lcv++, current_offset += PAGE_SIZE) {  uvn_findpage(uobj, offset, pps, flags)
           struct uvm_object *uobj;
                 /* skip over pages we've already gotten or don't want */          vaddr_t offset;
                 /* skip over pages we don't _have_ to get */          struct vm_page **pps;
                 if (pps[lcv] != NULL || (lcv != centeridx &&          int flags;
                     (flags & PGO_ALLPAGES) == 0))  {
                         continue;          struct vm_page *ptmp;
           UVMHIST_FUNC("uvn_findpage"); UVMHIST_CALLED(ubchist);
           UVMHIST_LOG(ubchist, "vp %p off 0x%lx", uobj, offset,0,0);
   
                 /*          simple_lock_assert(&uobj->vmobjlock, SLOCK_LOCKED);
                  * 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 */          if (*pps == PGO_DONTCARE) {
                   UVMHIST_LOG(ubchist, "dontcare", 0,0,0,0);
                         /* look for a current page */                  return 0;
                         ptmp = uvm_pagelookup(uobj, current_offset);          }
   #ifdef DIAGNOTISTIC
           if (*pps != NULL) {
                   panic("uvn_findpage: *pps not NULL");
           }
   #endif
   
                         /* nope?   allocate one now (if we can) */          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);
                         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);      /* alloc */                                          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.  
                  */  
   
                 result = uvn_io((struct uvm_vnode *) uobj, &ptmp, 1,  
                     PGO_SYNCIO, UIO_READ);  
   
                 /*  
                  * I/O done.   object is unlocked (by uvn_io).   because we used  
                  * syncio the result can not be PEND or AGAIN.   we must relock  
                  * and check for errors.  
                  */  
   
                 /* lock object.   check for errors.   */  
                 simple_lock(&uobj->vmobjlock);  
                 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);  
                 }                  }
   
                 /*                  /* BUSY the page and we're done. */
                  * we got the page!   clear the fake flag (indicates valid                  ptmp->flags |= PG_BUSY;
                  * data now in page) and plug into our result array.   note                  UVM_PAGE_OWN(ptmp, "uvn_findpage");
                  * that page is still busy.                  UVMHIST_LOG(ubchist, "found",0,0,0,0);
                  *                  break;
                  * it is the callers job to:          }
                  * => check if the page is released          *pps = ptmp;
                  * => unbusy the page          return 1;
                  * => 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 1584  uvn_asyncget(uobj, offset, npages)
Line 1245  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);  
   
         if ((uvn->u_flags & UVM_VNODE_VNISLOCKED) == 0)  
                 vn_lock(vn, LK_EXCLUSIVE | LK_RETRY);  
         /* 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   * 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   * is gone we will kill the object (flushing dirty pages back to the vnode
  * if needed).   * if needed).
Line 1800  boolean_t
Line 1284  boolean_t
 uvm_vnp_uncache(vp)  uvm_vnp_uncache(vp)
         struct vnode *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);          return(TRUE);
 }  }
   
Line 1910  uvm_vnp_setsize(vp, newsize)
Line 1316  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);
   #ifdef UBC
   #else
         if (uvn->u_flags & UVM_VNODE_VALID) {          if (uvn->u_flags & UVM_VNODE_VALID) {
   #endif
                 /*                  /*
                  * 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
Line 1930  uvm_vnp_setsize(vp, newsize)
Line 1338  uvm_vnp_setsize(vp, newsize)
                  * toss some pages...                   * toss some pages...
                  */                   */
   
   #ifdef UBC
                   if (uvn->u_size > newsize && uvn->u_size != VSIZENOTSET) {
   #else
   /*
                 if (uvn->u_size > newsize) {                  if (uvn->u_size > newsize) {
                         (void)uvn_flush(&uvn->u_obj, (vaddr_t) newsize,  */
                             uvn->u_size, PGO_FREE);  #endif
                           (void)uvn_flush(&uvn->u_obj, (vaddr_t)newsize,
                                           uvn->u_size, PGO_FREE);
                 }                  }
   #ifdef DEBUGxx
   printf("uvm_vnp_setsize: vp %p newsize 0x%x\n", vp, (int)newsize);
   #endif
                 uvn->u_size = (vaddr_t)newsize;                  uvn->u_size = (vaddr_t)newsize;
   #ifdef UBC
   #else
         }          }
   #endif
         simple_unlock(&uvn->u_obj.vmobjlock);          simple_unlock(&uvn->u_obj.vmobjlock);
   
         /*  
          * done  
          */  
         return;  
 }  }
   
 /*  /*
Line 1977  uvm_vnp_sync(mp)
Line 1392  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 1987  uvm_vnp_sync(mp)
Line 1402  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 & UVM_VNODE_BLOCKED) == 0)
                         /* spin */ ;                          /* spin */ ;
   
                 /*                  /*
Line 2014  uvm_vnp_sync(mp)
Line 1429  uvm_vnp_sync(mp)
                  * gain reference.   watch out for persisting uvns (need to                   * gain reference.   watch out for persisting uvns (need to
                  * regain vnode REF).                   * regain vnode REF).
                  */                   */
   #ifdef UBC
                   vget(vp, LK_INTERLOCK);
   #else
                 if (uvn->u_obj.uo_refs == 0)                  if (uvn->u_obj.uo_refs == 0)
                         VREF(vp);                          VREF(vp);
                 uvn->u_obj.uo_refs++;                  uvn->u_obj.uo_refs++;
                 simple_unlock(&uvn->u_obj.vmobjlock);                  simple_unlock(&uvn->u_obj.vmobjlock);
   #endif
   
                 /*                  /*
                  * got it!                   * got it!
Line 2034  uvm_vnp_sync(mp)
Line 1453  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 UBC
   #else
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
                 if (uvn->u_flags & UVM_VNODE_DYING) {                  if (uvn->u_flags & UVM_VNODE_DYING) {
                         printf("uvm_vnp_sync: dying vnode on sync list\n");                          printf("uvm_vnp_sync: dying vnode on sync list\n");
                 }                  }
 #endif  #endif
   #endif
                   /*
                    * XXX use PGO_SYNCIO for now to avoid problems with
                    * uvmexp.paging.
                    */
   
                 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|PGO_SYNCIO);
   
                 /*                  /*
                  * if we have the only reference and we just cleaned the uvn,                   * if we have the only reference and we just cleaned the uvn,
Line 2050  uvm_vnp_sync(mp)
Line 1477  uvm_vnp_sync(mp)
                  */                   */
                 if (uvn->u_obj.uo_refs == 1 &&                  if (uvn->u_obj.uo_refs == 1 &&
                     (uvn->u_flags & UVM_VNODE_WRITEABLE)) {                      (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 &= ~UVM_VNODE_WRITEABLE;
                           simple_unlock(&uvn_wl_lock);
                 }                  }
   
                 simple_unlock(&uvn->u_obj.vmobjlock);                  simple_unlock(&uvn->u_obj.vmobjlock);
Line 2065  uvm_vnp_sync(mp)
Line 1494  uvm_vnp_sync(mp)
          */           */
         lockmgr(&uvn_sync_lock, LK_RELEASE, (void *)0);          lockmgr(&uvn_sync_lock, LK_RELEASE, (void *)0);
 }  }
   
   
   /*
    * uvm_vnp_setpageblknos:  find pages and set their blknos.
    * this is used for two purposes:  updating blknos in existing pages
    * when the data is relocated on disk, and preallocating pages when
    * those pages are about to be completely overwritten.
    *
    * => vp's uobj should not be locked, and is returned not locked.
    */
   
   void
   uvm_vnp_setpageblknos(vp, off, len, blkno, ufp_flags, zero)
           struct vnode *vp;
           off_t off, len;
           daddr_t blkno;
           int ufp_flags;
           boolean_t zero;
   {
           int i;
           int npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
           struct vm_page *pgs[16];
           struct uvm_object *uobj = &vp->v_uvm.u_obj;
   
           simple_lock(&uobj->vmobjlock);
           while (npages > 0) {
                   int pages = min(npages, 16);
   
                   memset(pgs, 0, pages);
                   uvn_findpages(uobj, trunc_page(off), &pages, pgs, ufp_flags);
                   for (i = 0; i < pages; i++) {
                           if (pgs[i] == NULL) {
                                   continue;
                           }
                           pgs[i]->blkno = blkno;
                           blkno += PAGE_SIZE >> DEV_BSHIFT;
                           if (zero) {
                                   uvm_pagezero(pgs[i]);
                           }
                   }
                   uvm_pager_dropcluster(uobj, NULL, pgs, &pages, PGO_PDFREECLUST,
                                         0);
   
                   off += pages << PAGE_SHIFT;
                   npages -= pages;
           }
           simple_unlock(&uobj->vmobjlock);
   }
   
   
   /*
    * uvm_vnp_zerorange:  set a range of bytes in a file to zero.
    * this is called from fs-specific code when truncating a file
    * to zero the part of last block that is past the new end-of-file.
    */
   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);
                   len -= bytelen;
           }
   }

Legend:
Removed from v.1.17  
changed lines
  Added in v.1.17.2.6

CVSweb <webmaster@jp.NetBSD.org>