FBSD: Handle F_UNLCK in VOP_ADVLOCK
[openafs.git] / src / afs / FBSD / osi_vnodeops.c
index 7ae6571..9ebf840 100644 (file)
@@ -54,6 +54,9 @@
 #include <sys/malloc.h>
 #include <sys/namei.h>
 #include <sys/unistd.h>
+#if __FreeBSD_version >= 1000030
+#include <sys/rwlock.h>
+#endif
 #include <vm/vm_page.h>
 #include <vm/vm_object.h>
 #include <vm/vm_pager.h>
@@ -76,7 +79,6 @@ static vop_mkdir_t    afs_vop_mkdir;
 static vop_mknod_t     afs_vop_mknod;
 static vop_open_t      afs_vop_open;
 static vop_pathconf_t  afs_vop_pathconf;
-static vop_poll_t      afs_vop_poll;
 static vop_print_t     afs_vop_print;
 static vop_putpages_t  afs_vop_putpages;
 static vop_read_t      afs_vop_read;
@@ -117,7 +119,6 @@ struct vop_vector afs_vnodeops = {
        .vop_mknod =            afs_vop_mknod,
        .vop_open =             afs_vop_open,
        .vop_pathconf =         afs_vop_pathconf,
-       .vop_poll =             afs_vop_poll,
        .vop_print =            afs_vop_print,
        .vop_putpages =         afs_vop_putpages,
        .vop_read =             afs_vop_read,
@@ -154,7 +155,6 @@ int afs_vop_getpages(struct vop_getpages_args *);
 int afs_vop_putpages(struct vop_putpages_args *);
 int afs_vop_ioctl(struct vop_ioctl_args *);
 static int afs_vop_pathconf(struct vop_pathconf_args *);
-int afs_vop_poll(struct vop_poll_args *);
 int afs_vop_fsync(struct vop_fsync_args *);
 int afs_vop_remove(struct vop_remove_args *);
 int afs_vop_link(struct vop_link_args *);
@@ -197,7 +197,7 @@ struct vnodeopv_entry_desc afs_vnodeop_entries[] = {
     {&vop_mknod_desc, (vop_t *) afs_vop_mknod},        /* mknod */
     {&vop_open_desc, (vop_t *) afs_vop_open},  /* open */
     {&vop_pathconf_desc, (vop_t *) afs_vop_pathconf},  /* pathconf */
-    {&vop_poll_desc, (vop_t *) afs_vop_poll},  /* select */
+    {&vop_poll_desc, (vop_t *) vop_nopoll},    /* select */
     {&vop_print_desc, (vop_t *) afs_vop_print},        /* print */
     {&vop_read_desc, (vop_t *) afs_vop_read},  /* read */
     {&vop_readdir_desc, (vop_t *) afs_vop_readdir},    /* readdir */
@@ -266,6 +266,14 @@ static __inline void ma_vm_page_unlock(vm_page_t m) {};
 #define        MA_PCPU_ADD(c, n) (c) += (n)
 #endif
 
+#if __FreeBSD_version >= 1000030
+#define AFS_VM_OBJECT_WLOCK(o) VM_OBJECT_WLOCK(o)
+#define AFS_VM_OBJECT_WUNLOCK(o)       VM_OBJECT_WUNLOCK(o)
+#else
+#define AFS_VM_OBJECT_WLOCK(o) VM_OBJECT_LOCK(o)
+#define AFS_VM_OBJECT_WUNLOCK(o)       VM_OBJECT_UNLOCK(o)
+#endif
+
 #ifdef AFS_FBSD70_ENV
 #ifndef AFS_FBSD80_ENV
 /* From kern_lock.c */
@@ -501,14 +509,12 @@ afs_vop_lookup(ap)
     lockparent = flags & LOCKPARENT;
     wantparent = flags & (LOCKPARENT | WANTPARENT);
 
-#ifdef AFS_FBSD80_ENV
+#if __FreeBSD_version < 1000021
     cnp->cn_flags |= MPSAFE; /* steel */
 #endif
 
-#ifndef AFS_FBSD70_ENV
     if (flags & ISDOTDOT)
-       VOP_UNLOCK(dvp, 0, p);
-#endif
+       MA_VOP_UNLOCK(dvp, 0, p);
 
     AFS_GLOCK();
     error = afs_lookup(VTOAFS(dvp), name, &vcp, cnp->cn_cred);
@@ -533,7 +539,7 @@ afs_vop_lookup(ap)
      * we also always return the vnode locked. */
 
     if (flags & ISDOTDOT) {
-       MA_VOP_UNLOCK(dvp, 0, p);
+       /* vp before dvp since we go root to leaf, and .. comes first */
        ma_vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
        ma_vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
        /* always return the child locked */
@@ -695,7 +701,7 @@ afs_vop_close(ap)
        code = afs_close(avc, ap->a_fflag, ap->a_cred);
     else
        code = afs_close(avc, ap->a_fflag, afs_osi_credp);
-    osi_FlushPages(avc, ap->a_cred);   /* hold bozon lock, but not basic vnode lock */
+    osi_FlushPages(avc, ap->a_cred);   /* hold GLOCK, but not basic vnode lock */
     AFS_GUNLOCK();
     return code;
 }
@@ -765,8 +771,8 @@ afs_vop_read(ap)
     int code;
     struct vcache *avc = VTOAFS(ap->a_vp);
     AFS_GLOCK();
-    osi_FlushPages(avc, ap->a_cred);   /* hold bozon lock, but not basic vnode lock */
-    code = afs_read(avc, ap->a_uio, ap->a_cred, 0, 0, 0);
+    osi_FlushPages(avc, ap->a_cred);   /* hold GLOCK, but not basic vnode lock */
+    code = afs_read(avc, ap->a_uio, ap->a_cred, 0);
     AFS_GUNLOCK();
     return code;
 }
@@ -775,102 +781,134 @@ afs_vop_read(ap)
  *     struct vnode *a_vp;
  *     vm_page_t *a_m;
  *     int a_count;
- *     int a_reqpage;
- *     vm_oofset_t a_offset;
+ *     int *a_rbehind;
+ *     int *a_rahead;
  * };
  */
 int
 afs_vop_getpages(struct vop_getpages_args *ap)
 {
     int code;
-    int i, nextoff, size, toff, npages;
+    int i, nextoff, size, toff, npages, count;
     struct uio uio;
     struct iovec iov;
     struct buf *bp;
     vm_offset_t kva;
     vm_object_t object;
+    vm_page_t *pages;
     struct vnode *vp;
     struct vcache *avc;
 
+    memset(&uio, 0, sizeof(uio));
+    memset(&iov, 0, sizeof(iov));
+
     vp = ap->a_vp;
     avc = VTOAFS(vp);
+    pages = ap->a_m;
+#ifdef FBSD_VOP_GETPAGES_BUSIED
+    npages = ap->a_count;
+    if (ap->a_rbehind)
+        *ap->a_rbehind = 0;
+    if (ap->a_rahead)
+        *ap->a_rahead = 0;
+#else
+    npages = btoc(ap->a_count);
+#endif
+
     if ((object = vp->v_object) == NULL) {
        printf("afs_getpages: called with non-merged cache vnode??\n");
        return VM_PAGER_ERROR;
     }
-    npages = btoc(ap->a_count);
+
     /*
      * If the requested page is partially valid, just return it and
      * allow the pager to zero-out the blanks.  Partially valid pages
      * can only occur at the file EOF.
      */
-
     {
-       vm_page_t m = ap->a_m[ap->a_reqpage];
-
-       VM_OBJECT_LOCK(object);
+#ifdef FBSD_VOP_GETPAGES_BUSIED
+       AFS_VM_OBJECT_WLOCK(object);
+       ma_vm_page_lock_queues();
+       if(pages[npages - 1]->valid != 0) {
+           if (--npages == 0) {
+               ma_vm_page_unlock_queues();
+               AFS_VM_OBJECT_WUNLOCK(object);
+               return (VM_PAGER_OK);
+           }
+       }
+#else
+       vm_page_t m = pages[ap->a_reqpage];
+       AFS_VM_OBJECT_WLOCK(object);
        ma_vm_page_lock_queues();
        if (m->valid != 0) {
            /* handled by vm_fault now        */
            /* vm_page_zero_invalid(m, TRUE); */
            for (i = 0; i < npages; ++i) {
                if (i != ap->a_reqpage) {
-                   ma_vm_page_lock(ap->a_m[i]);
-                   vm_page_free(ap->a_m[i]);
-                   ma_vm_page_unlock(ap->a_m[i]);
+                   ma_vm_page_lock(pages[i]);
+                   vm_page_free(pages[i]);
+                   ma_vm_page_unlock(pages[i]);
                }
            }
            ma_vm_page_unlock_queues();
-           VM_OBJECT_UNLOCK(object);
+           AFS_VM_OBJECT_WUNLOCK(object);
            return (0);
        }
+#endif
        ma_vm_page_unlock_queues();
-       VM_OBJECT_UNLOCK(object);
+       AFS_VM_OBJECT_WUNLOCK(object);
     }
     bp = getpbuf(&afs_pbuf_freecnt);
 
     kva = (vm_offset_t) bp->b_data;
-    pmap_qenter(kva, ap->a_m, npages);
+    pmap_qenter(kva, pages, npages);
     MA_PCPU_INC(cnt.v_vnodein);
     MA_PCPU_ADD(cnt.v_vnodepgsin, npages);
 
+#ifdef FBSD_VOP_GETPAGES_BUSIED
+    count = ctob(npages);
+#else
+    count = ap->a_count;
+#endif
     iov.iov_base = (caddr_t) kva;
-    iov.iov_len = ap->a_count;
+    iov.iov_len = count;
     uio.uio_iov = &iov;
     uio.uio_iovcnt = 1;
-    uio.uio_offset = IDX_TO_OFF(ap->a_m[0]->pindex);
-    uio.uio_resid = ap->a_count;
+    uio.uio_offset = IDX_TO_OFF(pages[0]->pindex);
+    uio.uio_resid = count;
     uio.uio_segflg = UIO_SYSSPACE;
     uio.uio_rw = UIO_READ;
     uio.uio_td = curthread;
 
     AFS_GLOCK();
-    osi_FlushPages(avc, osi_curcred());        /* hold bozon lock, but not basic vnode lock */
-    code = afs_read(avc, &uio, osi_curcred(), 0, 0, 0);
+    osi_FlushPages(avc, osi_curcred());        /* hold GLOCK, but not basic vnode lock */
+    code = afs_read(avc, &uio, osi_curcred(), 0);
     AFS_GUNLOCK();
     pmap_qremove(kva, npages);
 
     relpbuf(bp, &afs_pbuf_freecnt);
 
-    if (code && (uio.uio_resid == ap->a_count)) {
-       VM_OBJECT_LOCK(object);
+    if (code && (uio.uio_resid == count)) {
+#ifndef FBSD_VOP_GETPAGES_BUSIED
+       AFS_VM_OBJECT_WLOCK(object);
        ma_vm_page_lock_queues();
        for (i = 0; i < npages; ++i) {
            if (i != ap->a_reqpage)
-               vm_page_free(ap->a_m[i]);
+               vm_page_free(pages[i]);
        }
        ma_vm_page_unlock_queues();
-       VM_OBJECT_UNLOCK(object);
+       AFS_VM_OBJECT_WUNLOCK(object);
+#endif
        return VM_PAGER_ERROR;
     }
 
-    size = ap->a_count - uio.uio_resid;
-    VM_OBJECT_LOCK(object);
+    size = count - uio.uio_resid;
+    AFS_VM_OBJECT_WLOCK(object);
     ma_vm_page_lock_queues();
     for (i = 0, toff = 0; i < npages; i++, toff = nextoff) {
        vm_page_t m;
        nextoff = toff + PAGE_SIZE;
-       m = ap->a_m[i];
+       m = pages[i];
 
        /* XXX not in nfsclient? */
        m->flags &= ~PG_ZERO;
@@ -890,15 +928,15 @@ afs_vop_getpages(struct vop_getpages_args *ap)
             * Read operation filled a partial page.
             */
            m->valid = 0;
-           vm_page_set_valid(m, 0, size - toff);
-#ifndef AFS_FBSD80_ENV
-           vm_page_undirty(m);
-#else
+           vm_page_set_validclean(m, 0, size - toff);
            KASSERT(m->dirty == 0, ("afs_getpages: page %p is dirty", m));
-#endif
        }
 
+#ifndef FBSD_VOP_GETPAGES_BUSIED
        if (i != ap->a_reqpage) {
+#if __FreeBSD_version >= 1000042
+           vm_page_readahead_finish(m);
+#else
            /*
             * Whether or not to leave the page activated is up in
             * the air, but we should put the page on a page queue
@@ -932,11 +970,13 @@ afs_vop_getpages(struct vop_getpages_args *ap)
                vm_page_free(m);
                ma_vm_page_unlock(m);
            }
+#endif /* __FreeBSD_version 1000042 */
        }
+#endif   /* ndef FBSD_VOP_GETPAGES_BUSIED */
     }
     ma_vm_page_unlock_queues();
-    VM_OBJECT_UNLOCK(object);
-    return 0;
+    AFS_VM_OBJECT_WUNLOCK(object);
+    return VM_PAGER_OK;
 }
 
 int
@@ -951,7 +991,7 @@ afs_vop_write(ap)
     int code;
     struct vcache *avc = VTOAFS(ap->a_vp);
     AFS_GLOCK();
-    osi_FlushPages(avc, ap->a_cred);   /* hold bozon lock, but not basic vnode lock */
+    osi_FlushPages(avc, ap->a_cred);   /* hold GLOCK, but not basic vnode lock */
     code =
        afs_write(VTOAFS(ap->a_vp), ap->a_uio, ap->a_ioflag, ap->a_cred, 0);
     AFS_GUNLOCK();
@@ -984,6 +1024,9 @@ afs_vop_putpages(struct vop_putpages_args *ap)
     struct vnode *vp;
     struct vcache *avc;
 
+    memset(&uio, 0, sizeof(uio));
+    memset(&iov, 0, sizeof(iov));
+
     vp = ap->a_vp;
     avc = VTOAFS(vp);
     /* Perhaps these two checks should just be KASSERTs instead... */
@@ -1066,40 +1109,6 @@ afs_vop_ioctl(ap)
     }
 }
 
-/* ARGSUSED */
-int
-afs_vop_poll(ap)
-     struct vop_poll_args      /* {
-                                * struct vnode *a_vp;
-                                * int  a_events;
-                                * struct ucred *a_cred;
-                                * struct thread *td;
-                                * } */ *ap;
-{
-    /*
-     * We should really check to see if I/O is possible.
-     */
-    return (1);
-}
-
-/*
- * Mmap a file
- *
- * NB Currently unsupported.
- */
-/* ARGSUSED */
-int
-afs_vop_mmap(ap)
-     struct vop_mmap_args      /* {
-                                * struct vnode *a_vp;
-                                * int  a_fflags;
-                                * struct ucred *a_cred;
-                                * struct thread *td;
-                                * } */ *ap;
-{
-    return (EINVAL);
-}
-
 int
 afs_vop_fsync(ap)
      struct vop_fsync_args     /* {
@@ -1374,7 +1383,8 @@ afs_vop_symlink(struct vop_symlink_args *ap)
     newvp = NULL;
 
     error =
-       afs_symlink(VTOAFS(dvp), name, ap->a_vap, ap->a_target, cnp->cn_cred);
+       afs_symlink(VTOAFS(dvp), name, ap->a_vap, ap->a_target, NULL,
+                   cnp->cn_cred);
     if (error == 0) {
        error = afs_lookup(VTOAFS(dvp), name, &vcp, cnp->cn_cred);
        if (error == 0) {
@@ -1454,8 +1464,6 @@ afs_vop_readlink(ap)
     return error;
 }
 
-extern int prtactive;
-
 int
 afs_vop_inactive(ap)
      struct vop_inactive_args  /* {
@@ -1465,9 +1473,6 @@ afs_vop_inactive(ap)
 {
     struct vnode *vp = ap->a_vp;
 
-    if (prtactive && vp->v_usecount != 0)
-       vprint("afs_vop_inactive(): pushing active", vp);
-
     AFS_GLOCK();
     afs_InactiveVCache(VTOAFS(vp), 0); /* decrs ref counts */
     AFS_GUNLOCK();
@@ -1596,12 +1601,27 @@ afs_vop_advlock(ap)
                                 * int  a_flags;
                                 * } */ *ap;
 {
-    int error;
+    int error, a_op;
     struct ucred cr = *osi_curcred();
 
+    a_op = ap->a_op;
+    if (a_op == F_UNLCK) {
+       /*
+        * When a_fl->type is F_UNLCK, FreeBSD passes in an a_op of F_UNLCK.
+        * This is (confusingly) different than how you actually release a lock
+        * with fcntl(), which is done with an a_op of F_SETLK and an l_type of
+        * F_UNLCK. Pretend we were given an a_op of F_SETLK in this case,
+        * since this is what afs_lockctl expects.
+        */
+       a_op = F_SETLK;
+    }
+
     AFS_GLOCK();
     error =
-       afs_lockctl(VTOAFS(ap->a_vp), ap->a_fl, ap->a_op, &cr, (int)ap->a_id);
+       afs_lockctl(VTOAFS(ap->a_vp),
+               ap->a_fl,
+               a_op, &cr,
+               (int)(intptr_t)ap->a_id);       /* XXX: no longer unique! */
     AFS_GUNLOCK();
     return error;
 }